Nuestro rectángulo ya se mueve por el lienzo, pero para verdaderamente interactuar con él, necesitamos indicarle a dónde queremos que vaya. Para eso, necesitamos primero una variable dónde guardar la tecla presionada:
Vayamos ahora al movimiento del rectángulo. Primero, necesitaremos una nueva variable que almacene la dirección de nuestro rectángulo:
Ahora utilizaremos un método simple para tener un tiempo consistente entre dispositivos (Puedes leer más en el Apéndice 2: Tiempo consistente entre dispositivos). La forma más fácil para hacer esto por ahora, es dividir las funciones act y paint en dos llamadas distintas, una optimizada para el re-pintar, y una regulada para las acciones:
Nota que, dado que este hace el ciclo de la función "act" asíncrono de la función "repaint", no puedes confiar que lo que realices en el primero, será dibujado en el segundo; pero esto no suele ser un problema cuando el re-pintado es más rápido que el ciclo de acciones. ¡No olvides llamar a ambas funciones en la función init!
Ahora comencemos por detectar la dirección que tomará nuestro rectángulo dependiendo la última tecla presionada, dentro de la función "act":
Los comentarios también sirven para “eliminar” líneas de código, pero que podríamos querer utilizar después, por ejemplo, la que dibuja en pantalla cuál fue la última tecla presionada (No querremos que la gente que juegue nuestro juego la vea, ¿O si?).
Guarda el juego y abre “index.html”. Si todo está de forma correcta, ahora podrás controlar al pequeño rectángulo usando las flechas del teclado. ¡Felicidades!
Podría dar por concluida la lección de hoy, pero aprovechando que estamos viendo como usar el teclado, te contaré un pequeño truco que se usa para poner “Pausa” a un juego. Comenzaremos por supuesto, creando una variable que indicará si el juego está en pausa:
Al final de la condicional “if (!pause)”, agregaremos estas líneas para que al presionar “KEY_ENTER” (13), se cambie el juego entre pausado y sin pausa:
Por último, dibujaremos en nuestra función “paint” el texto “PAUSE” de forma centrada, si la pausa está activada:
Actualización: Revisen el comentario dejado por Miguel Ángel, quien da algunos tips y buenas prácticas para mejorar este código y futuros. ¡Gracias! :)
var lastPress = null;
Y agregar al final de nuestro código un escucha del teclado que almacene la tecla presionada:document.addEventListener('keydown', function (evt) {
lastPress = evt.which;
}, false);
Mediante este método, podremos tomar decisiones en el juego sabiendo la última tecla presionada. Cada tecla tiene un valor numérico, el cual tendremos que comparar para realizar la acción deseada dependiendo la tecla presionada. Una buena forma de saber cuál ha sido la última tecla presionada, sería agregando esta línea en nuestra función “paint”: ctx.fillText('Last Press: ' + lastPress, 0, 20);
Por ahora no debes preocuparte de eso. Usaremos las teclas izquierda, arriba, derecha y abajo, cuyos valores numéricos son 37, 38, 39 y 40 respectivamente. Para usarlas más facilmente, las guardaremos en valores constantes:var KEY_LEFT = 37,
KEY_UP = 38,
KEY_RIGHT = 39,
KEY_DOWN = 40;
A diferencia de otros lenguajes de programación, JavaScript no tiene constantes, pero las variables se encargarán del trabajo sin problema.Vayamos ahora al movimiento del rectángulo. Primero, necesitaremos una nueva variable que almacene la dirección de nuestro rectángulo:
var dir = 0;
Esta variable “dir” tendrá un valor del 0 al 3, siendo 0 hacia arriba, y rotando en dirección de las manecillas del reloj para demás valores cada cuarto de hora.Ahora utilizaremos un método simple para tener un tiempo consistente entre dispositivos (Puedes leer más en el Apéndice 2: Tiempo consistente entre dispositivos). La forma más fácil para hacer esto por ahora, es dividir las funciones act y paint en dos llamadas distintas, una optimizada para el re-pintar, y una regulada para las acciones:
function repaint() {
window.requestAnimationFrame(repaint);
paint(ctx);
}
function run() {
setTimeout(run, 50);
act();
}
Como puedes ver dentro de la función "run", llamamos a un temporizador "setTimeout", que llama a la función "run" de nuevo cada 50 milisegundos. Esta es una forma simple de tener el juego a 20 ciclos por segundo.Nota que, dado que este hace el ciclo de la función "act" asíncrono de la función "repaint", no puedes confiar que lo que realices en el primero, será dibujado en el segundo; pero esto no suele ser un problema cuando el re-pintado es más rápido que el ciclo de acciones. ¡No olvides llamar a ambas funciones en la función init!
Ahora comencemos por detectar la dirección que tomará nuestro rectángulo dependiendo la última tecla presionada, dentro de la función "act":
// Change Direction
if (lastPress == KEY_UP) {
dir = 0;
}
if (lastPress == KEY_RIGHT) {
dir = 1;
}
if (lastPress == KEY_DOWN) {
dir = 2;
}
if (lastPress == KEY_LEFT) {
dir = 3;
}
Después, moveremos nuestro rectángulo dependiendo la dirección que se haya tomado: // Move Rect
if (dir == 0) {
y -= 10;
}
if (dir == 1) {
x += 10;
}
if (dir == 2) {
y += 10;
}
if (dir == 3) {
x -= 10;
}
Por último, buscaremos si el rectángulo ha salido de la pantalla, y en dado caso, lo regresaremos a la misma: // Out Screen
if (x > canvas.width) {
x = 0;
}
if (y > canvas.height) {
y = 0;
}
if (x < 0) {
x = canvas.width;
}
if (y < 0) {
y = canvas.height;
}
Te habrás dado cuenta que antes de cada bloque de código, agregué una referencia precedida de dos diagonales (//). Esto es un comentario, y son bastante funcionales para describir qué ocurre en cada sección del código, así, si es necesario modificarlo después, podremos identificar con facilidad sus componentes.Los comentarios también sirven para “eliminar” líneas de código, pero que podríamos querer utilizar después, por ejemplo, la que dibuja en pantalla cuál fue la última tecla presionada (No querremos que la gente que juegue nuestro juego la vea, ¿O si?).
Guarda el juego y abre “index.html”. Si todo está de forma correcta, ahora podrás controlar al pequeño rectángulo usando las flechas del teclado. ¡Felicidades!
Pausa
Podría dar por concluida la lección de hoy, pero aprovechando que estamos viendo como usar el teclado, te contaré un pequeño truco que se usa para poner “Pausa” a un juego. Comenzaremos por supuesto, creando una variable que indicará si el juego está en pausa:
var pause = true;
Ahora, encerraremos todo el contenido de nuestra función “act” en una condicional “if (!pause)”, o sea, si el juego no está en pausa. Hasta el momento hemos hecho condicionales de una sola línea, por lo que no hemos usado llaves. Pero en caso de ser utilizada más de una línea en la condicional, se deben usar llaves igual que en las funciones, tal como hacemos en el caso actual.Al final de la condicional “if (!pause)”, agregaremos estas líneas para que al presionar “KEY_ENTER” (13), se cambie el juego entre pausado y sin pausa:
// Pause/Unpause
if (lastPress == KEY_ENTER) {
pause = !pause;
lastPress = null;
}
Es muy importante que estas líneas no las encierres dentro del “if (!pause)”, o de lo contrario, jamás podrás quitar la pausa (Por que jamás entrarás a esa parte del código). La asignación “pause = !pause” indica que cambio su valor por el opuesto (falso si es verdadero o verdadero si es falso), y después nulificamos “lastPress”, o de lo contrario, el juego estaría poniendo y quitando pausa sin fin hasta que se presione otra tecla.Por último, dibujaremos en nuestra función “paint” el texto “PAUSE” de forma centrada, si la pausa está activada:
// Draw pause
if (pause) {
ctx.textAlign = 'center';
ctx.fillText('PAUSE', 150, 75);
ctx.textAlign = 'left';
}
Actualicemos el juego. Ahora cada vez que presionemos la tecla Enter, el juego entrará o saldrá de la pausa.Actualización: Revisen el comentario dejado por Miguel Ángel, quien da algunos tips y buenas prácticas para mejorar este código y futuros. ¡Gracias! :)
Código final:
var KEY_ENTER = 13,
KEY_LEFT = 37,
KEY_UP = 38,
KEY_RIGHT = 39,
KEY_DOWN = 40,
canvas = null,
ctx = null,
lastPress = null,
pause = true,
x = 50,
y = 50,
dir = 0;
window.requestAnimationFrame = (function () {
return window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 17);
};
}());
document.addEventListener('keydown', function (evt) {
lastPress = evt.which;
}, false);
function paint(ctx) {
// Clean canvas
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw square
ctx.fillStyle = '#0f0';
ctx.fillRect(x, y, 10, 10);
// Debug last key pressed
ctx.fillStyle = '#fff';
//ctx.fillText('Last Press: ' + lastPress, 0, 20);
// Draw pause
if (pause) {
ctx.textAlign = 'center';
ctx.fillText('PAUSE', 150, 75);
ctx.textAlign = 'left';
}
}
function act() {
if (!pause) {
// Change Direction
if (lastPress == KEY_UP) {
dir = 0;
}
if (lastPress == KEY_RIGHT) {
dir = 1;
}
if (lastPress == KEY_DOWN) {
dir = 2;
}
if (lastPress == KEY_LEFT) {
dir = 3;
}
// Move Rect
if (dir == 0) {
y -= 10;
}
if (dir == 1) {
x += 10;
}
if (dir == 2) {
y += 10;
}
if (dir == 3) {
x -= 10;
}
// Out Screen
if (x > canvas.width) {
x = 0;
}
if (y > canvas.height) {
y = 0;
}
if (x < 0) {
x = canvas.width;
}
if (y < 0) {
y = canvas.height;
}
}
// Pause/Unpause
if (lastPress == KEY_ENTER) {
pause = !pause;
lastPress = null;
}
}
function repaint() {
window.requestAnimationFrame(repaint);
paint(ctx);
}
function run() {
setTimeout(run, 50);
act();
}
function init() {
// Get canvas and context
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
// Start game
run();
repaint();
}
window.addEventListener('load', init, false);
Siguiente parte: Interactuando con otros elementos.
excelente!
ResponderBorrarMuy buenas, me está encantando tu forma de explicar las cosas. Mira he estado implementando tu código y a la vez aumentando la funcionalidad o corrigiendo cosas, por ejemplo en las lineas
ResponderBorrarif(x<0)
x=canvas.width;
if(y<0)
y=canvas.height;
Creo que hay que asignarle canvas.width - 10 y en la segunda canvas.height-10.
De esta forma no se perderá el cuadrado fuera del lienzo.
Yo personalmente he optado por sustituir ese 10 por una variable llamada desplazamiento en la cabecera del script. De esa forma podemos cuadrados del tamaño de esa variable.
Espero te sirva de ayuda ;)
Y gracias por el tutorial que está fantástico :D
¡Excelentes recomendaciones! Yo personalmente ya uso esos consejos, pero cuando hice el tutorial, quise dejar las cosas simples, y permitir que la gente se percatara de esos detalles como tú y los corrigiera como mejor creyeran :)
BorrarSin embargo, editaré la entrada para redirigir a los usuarios y vean tu comentario, así sepan como mejorar y detallar este código.
Gracias por los consejos ;)
Se ve mas fluido, pero ocurre que se te puede quedar el 'cuadrito' en ese (-10) y desaparecer del canvas
BorrarEste comentario ha sido eliminado por el autor.
BorrarMejor que eso sólo servirá poner un menor igual o mayor igual, debido que al ponerle -10 estas indicando que tu bloque en movimiento es de 10, pero si decides aumentarlo a 20 o más, tendrás que modificar nuevamente esa parte del código. Para que sea más "limpio", intentar con:
Borrarif (x >= canvas.width) x = 0;
if (y >= canvas.height) y = 0;
Gracias por todo Karl :D
Ey muy buena pagina es perfectamente la que andaba buscando, soy novato en esto de la programacion y estoy tratamdo de hacer un juego simple como in block breaker creo. Que esta patina's me ayudara mmucho. Dios te bendiga.
ResponderBorrar¡Muchas gracias y mucha suerte!
BorrarSi necesitas ayuda, estamos aquí con gusto para ayudarte ;)
ey amigo soy yo otra vez el que comento el 24 de diciembre 2012 18:06
Borrarmira este codigo: y si puedes dime porque se ve lento http://breakingbricks.site90.net/
el perdon ya se por que se ve lento no te preocupes
ResponderBorraruna pregunta si solo quisiera q avanzara cuando muevo con flechas como podria hacerlo
ResponderBorrarEso se ve en un tema más adelante: http://juegoscanvas.blogspot.com/2012/04/mover-mientras-se-presiona-tecla.html
BorrarEstoy siguiendo tus tutos y son geniales compañero, fáciles y rápidos, no se como lo haces para explicarlo tan claro, eres de los pocos que consigue transmitir los conocimientos sin que me aburra al leer.
ResponderBorrarMira que llevaba tiempo queriendo hacer un juego para el navegador para poder llegar a más gente, mis antiguos proyectos eran en GDI+ pero Canvas da muchísima más facilidad de desarrollo.
Pues nada, a seguir avanzando con el siguiente tuto hasta acabarlos todos ^^
Gracias Karl y enhorabuena por tus tutoriales. Saludos compañero! :D
¡Muchas gracias por tu comentario!
BorrarAl momento de crear este blog, mi propósito fue desde el comienzo, asegurar el poder transmitir este conocimiento de forma sencilla y completa, sin detallar quizá en la siempre importante teoría, pero transmitiendo también lo importante de ella.
Saber que estoy logrando mi propósito a través de comentarios como el tuyo, son la alegría que me permiten continuar con emoción el desarrollo de este sitio. Espero siga siendo de utilidad para ti.
¡Muchas gracias!
Todo lo contrario, yo soy quién te está agradecido!!
BorrarNo conozco mucha gente que se esfuerce en compartir sus conocimientos y gracias a ti voy a estar este verano entretenido con Canvas, al menos estos 2 próximos meses de calor.
Bueno pues como buen user que soy te animo a seguir, así que intenta no dejarlo, jaja aunque es imposible ya que a todos nos ha pasado con alguna web que con el tiempo nos cansamos de publicar siempre lo mismo...aunque con todo el contenido de Canvas que hay en el blog ya no creo que haya mucho más que ver.
En fin que me enrollo jaja, pues ya te iré comentando por otras entradas tuyas a medida que vaya mejorando mi futuro juego con tus tutos.
Saludos socio! ^^
Sos un genio.
ResponderBorrarEstudie el código 20 veces repitiendo y lo logre entender.
ResponderBorrargracias!!!!!!!!!!!!!!!!!!!! totales
ResponderBorrarUna pregunta, si en lugar de apritar enter para pausar deseo que con un button onclick ¿como modifico el archivo js?
ResponderBorrarEso se ve más adelante, en el tema "Presionando el botón del ratón" ( http://juegoscanvas.blogspot.com/2012/08/presionando-el-boton-del-raton.html )
BorrarComo siempre, estupendo!
ResponderBorrarHola! Quería compartir una modificación que le hice al mostrar el LastPress, para que muestre que tecla en concreto estamos tocando y no el numero soso:
ResponderBorrarDefiní la función (comente con el condicional if por si alguno no conoce el switch):
function transform(x) {
/*if (x===37) {
return "KEY_LEFT"
} else if (x===38) {
return "KEY_UP"
} else if (x===39) {
return "KEY_RIGHT"
} else if (x===40) {
return "KEY_DOWN"
}
else {
return "PRESS A KEY"
}*/
switch (x) {
case 37 : return "KEY_LEFT";
break;
case 38 : return "KEY_UP";
break;
case 39 : return "KEY_RIGHT";
break;
case 40 : return "KEY_DOWN";
break;
default: return "PRESS A KEY";
}
}
Y en paint:
ctx.fillText('Last Press: '+transform(lastPress),0,20);
Saludos!
Gracias por tu sugerencia. El proposito de imprimir lastKey es para averiguar en código de cada tecla en caso de querer usarla luego (Teclas como Control, Shift, ASDW, entre otras populares en algunos juegos).
BorrarPero dado el caso de querer imprimir las teclas usadas, creo que tu técnica es de bastante ayuda.
No, es verdad. No consideré el propósito original y por eso, ahora lo veo, no tiene sentido el switch jaja
BorrarSin embargo, para el propósito de mostrar la tecla presionada, la función es bastante funcional. Seguro a alguien le servirá :)
BorrarKarl tengo una duda..cuando es un cuadrado y solo hay una coordenada se aplica de esta forma pero si por ejemplo tengo una figura mas compleja con multiples coordenadas como lo mueves...es decir ¿hay una forma de "agrupar" la figura? he creado una figura vector con AI y mediante un plugin me lo ha exportado a canvas. pero no puedo imaginarme como moverlo .... te dejo la figura que tengo. es un ovni.
ResponderBorrar// capa1/Forma compuesta/Trazado compuesto
ctx.beginPath();
// capa1/Forma compuesta/Trazado compuesto/Trazado
ctx.moveTo(91.1, 8.8);
ctx.bezierCurveTo(88.8, 6.5, 86.1, 4.4, 82.7, 3.3);
ctx.bezierCurveTo(72.3, -0.3, 62.4, -0.9, 51.6, 1.4);
ctx.bezierCurveTo(48.0, 2.1, 45.1, 3.9, 42.4, 6.1);
ctx.bezierCurveTo(64.6, 2.4, 81.5, 5.7, 91.1, 8.8);
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.closePath();
ctx.lineWidth = 0.2;
ctx.fillStyle = 'red';
ctx.fill();
ctx.strokeStyle = 'black';
ctx.stroke();
// capa1/Forma compuesta/Trazado compuesto/Trazado
ctx.moveTo(130.8, 32.1);
ctx.bezierCurveTo(128.5, 28.9, 117.7, 25.6, 115.9, 25.0);
ctx.bezierCurveTo(109.5, 23.1, 102.8, 21.2, 98.0, 16.3);
ctx.bezierCurveTo(96.7, 14.9, 95.4, 13.4, 94.1, 12.0);
ctx.bezierCurveTo(85.3, 8.6, 66.1, 3.4, 39.3, 8.7);
ctx.bezierCurveTo(37.8, 10.0, 36.4, 11.3, 34.9, 12.5);
ctx.bezierCurveTo(29.5, 16.7, 22.6, 17.8, 16.1, 19.0);
ctx.bezierCurveTo(14.3, 19.3, 3.3, 21.3, 0.5, 24.2);
ctx.bezierCurveTo(15.6, 21.1, 76.6, 11.1, 130.8, 32.1);
ctx.closePath();
ctx.closePath();
ctx.lineWidth = 0.2;
ctx.fillStyle = 'red';
ctx.fill();
ctx.strokeStyle = 'black';
ctx.stroke();
// capa1/Forma compuesta/Trazado compuesto/Trazado
ctx.moveTo(0.0, 26.3);
ctx.bezierCurveTo(0.1, 26.4, 0.2, 26.6, 0.3, 26.7);
ctx.bezierCurveTo(1.8, 28.5, 7.0, 28.7, 9.2, 29.1);
ctx.bezierCurveTo(28.1, 32.7, 44.9, 44.0, 64.3, 45.4);
ctx.bezierCurveTo(64.5, 45.4, 64.6, 45.4, 64.7, 45.4);
ctx.bezierCurveTo(64.7, 45.5, 64.6, 45.5, 64.6, 45.5);
ctx.bezierCurveTo(84.1, 46.5, 102.3, 37.2, 121.6, 35.8);
ctx.bezierCurveTo(123.7, 35.7, 129.0, 36.2, 130.7, 34.6);
ctx.bezierCurveTo(130.8, 34.5, 130.8, 34.4, 130.9, 34.3);
ctx.bezierCurveTo(75.9, 12.6, 13.3, 23.6, 0.0, 26.3);
ctx.closePath();
ctx.closePath();
ctx.lineWidth = 0.2;
ctx.fillStyle = 'red';
ctx.fill();
ctx.strokeStyle = 'black';
ctx.stroke();
¡Vaya! Una imagen vectorial... Esto definitivamente sería muy difícil de agregar una variable a cada coordenada...
BorrarSupongo que la solución más sencilla seria usar ctx.translate, el cual vemos mas adelante en el tema de rotación de imágenes. Si no me equivoco, sería de la siguiente forma:
ctx.save();
ctx.translate(x,y);
// Incluye aquí el dibujado vectorial
ctx.restore();
Sería quizá mas sencillo si pones el dibujado de cada imagen vectorial en una función propia. Espero esto resuelva tu problema. ¡Suerte!
ok gracias lo probaré, aunque ahora que dices lo de la funcion es mas logico no?...como seria con la funcion?
Borrarya lo he probado y va perfecto. gracias de nuevo karl!
BorrarLo he creado de esta forma y me funciona muy bien :D
ResponderBorrarfunction nave (x,y) {
ctx.save();
ctx.translate(x,y);
// aquí el dibujado vectorial
ctx.restore();
}
nave(20,20);
Precisamente así es como se haría con una función.
BorrarAhora podrás dibujar cada gráfico vectorial fácilmente cuantas veces sea necesario desde tu función paint.
el rendimiento del ordenador es aumentado con los dibujos vectoriales con respecto a los mapa de bit? porque un dibujo de ese tamaño a dos colores ocupa muy poco en png por ejemplo. Un saludo y gracias
BorrarVectores y easter tienen ambos ventajas y desventajas. La principal diferencia en cuanto a rendimiento, es que raster ocupa mas RAM y espacio físico, pero vector requiere más CPU para ser procesado. En general con computadoras modernas, si no son tareas intensivas, repercute poco en rendimiento, pero cuando tienes muchas imágenes en proceso, puedes comenzar a ver la diferencia entre ambos.
BorrarHola como puedo hacer que el cuadrado se detenga en la parte inferior del rectángulo y a su vez al quedarse ahi se genere otro cuadro y asi sucesivamente, pero que los cuadros se acumulen
ResponderBorrarLo más sencillo para hacer esto, es que una vez que el cuadro actual "se bloquee", sea al llegar abajo o tocar otro cuadro, este se agregue a un arreglo que contenga todos tus cuadros bloqueados, y recicles tu cuadro modificable agregándolo de nuevo a la parte superior, algo así como esto:
Borrarplayer.y += 10;
if(player.y > canvas.height){
rectArray.push(new Rectangle(player.x, player.y-10, 10, 10));
player.y = 0;
}
Esta misma verificación se haría para cada uno de los elementos de rectArray. Es posible que necesites leer al menos los dos temas siguientes para comprender el uso de Rectángulos y Arreglos, pero una vez que sepas como usarles, comprenderás como implementar este código.
¡Mucha suerte!
Muchas Gracias Excelentes Tutoriales!!!!!
BorrarNo sería mejor usar "¡El método más popular y efectivo! Usar la delta de tiempo"
ResponderBorrarEn mi navegador el demo se ve lento pero con la técnica de "Usar la delta de tiempo" va mejor y mas fluido. Entonces porque no usaste ese metodo?????
Aparte que no le veo bien usar 2 temporizadores al mismo tiempo (setTimeout y requestAnimationFrame) no entiendo como puedes saber que hay una mejor técnica y usar la peor.
Puede que en general delta de tiempo sea mejor, pero eso no quita que este método sea más sencillo, lo que considero conviene más para los que apenas empiezan a programar.
BorrarAdemás, aunque delta de tiempo es en general mejor, hay casos específicos donde es mejor una técnica de ciclos regulares, como el Snake o los juegos de plataformas clásicos.
Tampoco es que esta sea "la peor" técnica, solo es una alternativa a considerar, y analizar cual es la que mejor conviene para el juego que desarrollas. Yo solo explico el abanico de posibilidades, y dejo que estos detalles técnicos sean elegidos por la conveniencia de cada programador y el código que desean desarrollar.
Hola, a ver si alguien me puede ayudar. Estoy creando un juego Mario y necesito que se registren 2 teclas si estan estan pulsadas. Pero cuando lo registro: Tecla.Arriba = true; Tecla.Derecha = true; (que salte y vaya a la derecha, pero lo que hace es congelarse el jugador, no se mueve, pero si solo pulso 1 tecla entonces se mueve. No entiendo xd, a ver como se hará.
ResponderBorrarPosiblemente sea alguna forma en que realices la comparación o la lectura, pero para saber cuál es el problema, habría que revisar tu código. ¿De casualidad el ejemplo de plataformas más adelante en el curso te presenta el mismo problema? Quizá ese pueda ayudarte a averiguar como realizar lo que buscas.
BorrarSe que llego unos cuantos años tarde, pero Karl, tus tutoriales son muy buenos y la buena onda que le pones y la ayuda a la gente son incluso mejores! Espero que hayas disfrutado haciendo esto tanto como nosotros (los usuarios) lo disfrutamos tambien :)
ResponderBorrar¿Como se hace para que el Sprite choque con los bordes?
ResponderBorrarCon este Js:
window.addEventListener('load',init,false);
var canvas=null,ctx=null;
var x=50,y=50;
var lastPress=null;
var pause=true;
var dir=0;
var KEY_ENTER=13;
var KEY_LEFT=37;
var KEY_UP=38;
var KEY_RIGHT=39;
var KEY_DOWN=40;
function init(){
canvas=document.getElementById('canvas');
ctx=canvas.getContext('2d');
run();
repaint();
}
function run(){
setTimeout(run,50);
act();
}
function repaint(){
requestAnimationFrame(repaint);
paint(ctx);
}
function act(){
if(!pause){
// Change Direction
if(lastPress==KEY_UP)
dir=0;
if(lastPress==KEY_RIGHT)
dir=1;
if(lastPress==KEY_DOWN)
dir=2;
if(lastPress==KEY_LEFT)
dir=3;
// Move Rect
if(dir==0)
y-=10;
if(dir==1)
x+=10;
if(dir==2)
y+=10;
if(dir==3)
x-=10;
// Out Screen
if(x>canvas.width)
x=0;
if(y>canvas.height)
y=0;
if(x<0)
x=canvas.width;
if(y<0)
y=canvas.height;
}
// Pause/Unpause
if(lastPress==KEY_ENTER){
pause=!pause;
lastPress=null;
}
}
function paint(ctx){
ctx.fillStyle='Red';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle='blue';
ctx.fillRect(x,y,10,10);
ctx.fillStyle='#fff';
//ctx.fillText('Last Press: '+lastPress,0,20);
if(pause){
ctx.textAlign='center';
ctx.fillText('PAUSE',150,75);
ctx.textAlign='left';
}
}
document.addEventListener('keydown',function(evt){
lastPress=evt.keyCode;
},false);
window.requestAnimationFrame=(function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback){window.setTimeout(callback,17);};
})();
Debes cambiar el código que sigue al comentario "Out of screen" con la acción que desees en su lugar. La pregunta es ¿Qué acción deseas realizar en lugar de regresar por el otro lado de la pantalla?
BorrarEste blog ha sido eliminado por un administrador de blog.
ResponderBorrarNo.
Borrar[Removido por SPAM]
Borrarhola
ResponderBorrartengo una duda
por qué comentaste esta linea //ctx.fillText('Last Press: ' + lastPress, 0, 20);
Para que no aparezca en la versión final del juego, ya que sólo se necesita descomentar cuanto se está depurando la información de las teclas requeridas para tu juego.
Borrarhola
ResponderBorrartengo una duda
por qué comentaste esta linea //ctx.fillText('Last Press: ' + lastPress, 0, 20);
Tío, eres una máquina.
ResponderBorrarMil gracias.
Como único aporte (Aunque quizás quieras mantener el tutorial básico) es sustituir el cambio de dirección en vez de con if, con sendos switch.
Aparte eso. Que muchísimas gracias
Oye y como hago si quiero que cuando el juego este pausado al presionar cualquier tecla de direccion se despause el juego y al pulzar enter se pause
ResponderBorrar¡Esa es una excelente pregunta!
BorrarPara despausar el juego con cualquier tecla, agrega esto dentro de la condición "if(pause)":
// Unpause
if (lastPress != null) {
pause = false;
lastPress = null;
}
Y para pausar el juego, agregas esta línea dentro de la condición opuesta:
// Pause
if (lastPress == KEY_ENTER) {
pause = true;
lastPress = null;
}
gracias ya lo cambie en mi codigo pero ahora surgio un inconveniente, ahora al perder automaticamente se despausa el juego... no hay una forma de hacer un segundo codigo para despausar el juego... por ejemplo: al cargar la pagina se ejecute el codigo:
ResponderBorrar// Unpause
if (lastPress != null) {
pause = false;
lastPress = null;
}
y al perder, para poder despausar el juego se ejecute otro
Puedes usar la booleana gameOver para determinar que código ejecutar para despausar el juego.
BorrarSolo una sugerencia:
ResponderBorrarsi cuando defines la variable "dir", en vez de 0 pones null, al empezar el cuadrado estará quieto, y no moviéndose verticalmente
Hola amigo, buenas noches, estoy siguiendo estos tutoriales y la verdad muy buenos estoy aprendiendo tecnicas que no habia probado nunca en esto de las animaciones, note un error que tal vez quisieras considerar, te explico, con tu codigo aseguras que el cuadrado verde siempre este en pantalla pero...
ResponderBorrarsi apretas una de las dos teclas que modifican x (la derecha o la izquierda) justo cuando la variable y = canvas.height el cuadrado no se vera mas en el canvas... eso pasa por que la variable y se reinicia a 0 cuando y > canvas.height, entonces:
si primero apretamos la flecha abajo, los valores de y iran aumentando constantemente y cuando este valor cumple la condicion y > canvas.height el valor de y se reinicia a 0,
pero suponiendo que justo cuando y = canvas.height, es decir un momento antes de que se reinicie y aparezca el cuadrado arriba del canvas, apretamos la tecla derecha o la tecla izquierda, eso hara que la variable y deje de modificarse (aumentar su valor) y comienze a modificarse la variable x, esto provoca que el cuadrado verde no se vea mas en el canvas, pero esta ahi llendo de izquierda a derecha pero un poquito mas abajo de nuestro canvas, esto se puede solucionar poniendo en el condicional que verifica cuando el cuadrado verde se sale de pantalla if(y>=canvas.height){//codigo} en lugar de if(y>canvas.height){//codigo} y de igual forma en el condicional que controla la poscicion en x.
Espero haber explicado bien, saludos, voy a seguir viendo estos tutos que estan muy buenos.
buenas tardes
ResponderBorrarexclente tutorial, soy nuevo en esto de la programacion y al ejecutar el codigo se me presento un error en esta parte:
function repaint()
{
window.requestAnimationFrame(repaint);
paint(ctx);
}
ya que me indica que "window.requestAnimationFrame " no es una funcion . le agracezco me puedan ayudar
¿Me podrías decir qué navegador y versión estás usando? También, ¿El demo en esta entrada sí funciona para ti?
Borrarestoy usando google chrome como navegador, y dsafortunadamente lo probe con el demo y no me corre, agradezco tu ayuda
Borrarsiento aparecer como desconocido inicialmente
BorrarHe probado múltiples versiones de Chrome, y ninguna me ha dado conflicto alguno. ¿De casualidad podría tratarse de algún Addon o Framework que esté reescribiendo el comportamiento de esta función?
Borrarpues estoy usando xampp, no se si ese pueda ser el problema
ResponderBorrarcomo te podria enviar un print de pantalla para mostrarte l que aparece?
ResponderBorrareste es el codigo en js
ResponderBorrarvar
KEY_ENTER = 13,
KEY_LEFT = 37,
KEY_UP = 38,
KEY_RIGHT = 39,
KEY_DOWN = 40,
canvas = null,
ctx = null,
lastPress = null,
pause = true,
dir = 0,
score = 0,
player = null,
food = null;
window.requestAnimationFrame = (function ()
{
return
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
function (callback)
{
window.setTimeout(callback, 17);
}; }());
document.addEventListener('keydown', function (evt)
{
lastPress = evt.which;
}, false);
function Rectangle(x, y, width, height)
{ this.x = (x == null) ? 0 : x;
this.y = (y == null) ? 0 : y;
this.width = (width == null) ? 0 : width;
this.height = (height == null) ?
this.width : height;
this.intersects = function (rect)
{
if (rect == null)
{
window.console.warn('Missing parameters on function intersects');
}
else
{
return
( this.x < rect.x + rect.width &&
this.x + this.width > rect.x &&
this.y < rect.y + rect.height &&
this.y + this.height > rect.y);
}
};
this.fill = function (ctx)
{
if (ctx == null)
{
window.console.warn('Missing parameters on function fill');
}
else
{ ctx.fillRect(this.x, this.y, this.width, this.height);
}
};
}
function random(max)
{
return Math.floor(Math.random() * max);
}
function paint(ctx) {
// Clean canvas
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw player
ctx.fillStyle = '#0f0';
player.fill(ctx);
// Draw food
ctx.fillStyle = '#f00';
food.fill(ctx);
// Debug last key pressed
ctx.fillStyle = '#fff';
//ctx.fillText('Last Press: '+lastPress,0,20);
// Draw score
ctx.fillText('Score: ' + score, 0, 10);
// Draw pause
if (pause)
{
ctx.textAlign = 'center';
ctx.fillText('PAUSE', 150, 75);
ctx.textAlign = 'left';
}
} function act()
{
if (!pause)
{
// Change Direction
if (lastPress == KEY_UP)
{ dir = 0; }
if (lastPress == KEY_RIGHT)
{ dir = 1; }
if (lastPress == KEY_DOWN)
{ dir = 2; }
if (lastPress == KEY_LEFT)
{ dir = 3; }
// Move Rect
if (dir == 0)
{ player.y -= 10; }
if (dir == 1)
{ player.x += 10; }
if (dir == 2)
{ player.y += 10; }
if (dir == 3)
{ player.x -= 10; }
// Out Screen
if (player.x > canvas.width)
{ player.x = 0; }
if (player.y > canvas.height)
{ player.y = 0; }
if (player.x < 0)
{ player.x = canvas.width; }
if (player.y < 0)
{ player.y = canvas.height; }
// Food Intersects
if (player.intersects(food))
{
score += 1;
food.x = random(canvas.width / 10 - 1) * 10;
food.y = random(canvas.height / 10 - 1) * 10;
}
}
// Pause/Unpause
if (lastPress == KEY_ENTER)
{
pause = !pause;
lastPress = null;
}
}
function repaint()
{
window.requestAnimationFrame(repaint);
paint(ctx);
}
function run()
{
setTimeout(run, 50);
act();
}
function init()
{
// Get canvas and context
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
// Create player and food
player = new Rectangle(40, 40, 10, 10);
food = new Rectangle(80, 80, 10, 10);
// Start game
run();
repaint();
}
window.addEventListener('load', init, false);
Después de probar tu código, me di cuenta que en la función donde personalizas la función window.requestAnimationFrame, das una nueva línea después de "return". Eso hace que interprete que debe retornar vacío, ignorando el resto de la función; por eso da error tu código. Sí eliminas esta nueva línea, tu código deberá funcionar sin problemas.
BorrarHola can, tengo una pregunta trivial, pero solo por inquietud, porque usas en la condicion de pausa el texto centralizado y luego ahi mismo debajo lo haces a la izquierda, que sentido tiene?
ResponderBorrarEste es el codigo al que me refiero:
if (pause) {
ctx.textAlign = 'center';
ctx.fillText('PAUSE', 150, 75);
ctx.textAlign = 'left';
}
Por default todos los textos están alineados a la izquierda. Ahí lo que hago es crear una excepción centrada, y luego regresarlo a su valor default. De no hacerlo, los demás textos se dibujarían centrados a partir de esa instrucción hasta que se dé una nueva.
Borrar