En el capítulo anterior, aprendimos a obtener la posición del ratón, y a dibujar un círculo para indicar dicha posición en nuestro canvas. Para realmente poder interactuar entre círculos, crearemos nuestra función Circle, como anteriormente hicimos con Rect:
La función principal para que dos círculos interactuen entre sí, es calcular la distancia entre ellos. Eso nos remonta a nuestras amadas cláses de Física de la secundaria, donde aprendíamos distancia entre vectores. ¿Recuerdan esa fórmula?
Pero ahora que ya tenemos esta formula, podemos crear una función que nos permita calcular la distancia con respecto a otro círculo, la cual agregaremos obviamente al prototipo de la función Circle:
Lo único que hice fue, después de ello, restar la suma del radio de ambos círculos. Esto nos permitirá obtener la distancia respecto a la circunferencia de ambos círculos, y no de su centro. ¿Por qué hago esto? Les explicaré en un momento...
Probemos ahora nuestra nueva función. Crearemos un círculo player, y un círculo target, que será con el que interactuaremos:
Ahora si, probamos el código, podremos analizar con mayor detalle la distancia de ambos círculos, y como en la función, he restado la suma de la circunferencia de ambos círculos, notaremos que al rozarse ambos círculos, la distancia es calculada como 0. ¿Que ocurre si ambos círculos entran en contacto?
¡Así es! Cuando ambos círculos entran en contacto, la distancia retorna un valor negativo. Con esto, no solo hemos encontrado una función que indica la distancia entre ambos círculos, ¡También hemos creado una forma de saber si dos círculos entran en contacto! De forma similar como hicimos con la función Rect.intersect.
Ahora con este conocimiento, podrás crear videojuegos que involucren círculos. ¡Felicidades!
Para hacer mas obvio el momento en que ambos círculos se entran en intersección, he agregado estas líneas en la función run que cambian el color de fondo por uno mas claro cuando ocurre lo anterior mencionado:
function Circle(x,y,radius){
this.x=(x==null)?0:x;
this.y=(y==null)?0:y;
this.radius=(radius==null)?0:radius;
}
Circle.prototype.stroke=function(ctx){
ctx.beginPath();
ctx.arc(this.x,this.y,this.radius,0,Math.PI*2,true);
ctx.stroke();
}
A nuestra función Circle la crearemos pasándole su posición en X y Y (centro) y su radio.La función principal para que dos círculos interactuen entre sí, es calcular la distancia entre ellos. Eso nos remonta a nuestras amadas cláses de Física de la secundaria, donde aprendíamos distancia entre vectores. ¿Recuerdan esa fórmula?
d = √ (x₂ - x₁)² + (y₂ - y₁)²Si alguno de ustedes no la recordaba, no se mortifique, yo tampoco; lo busqué en Google...
Pero ahora que ya tenemos esta formula, podemos crear una función que nos permita calcular la distancia con respecto a otro círculo, la cual agregaremos obviamente al prototipo de la función Circle:
Circle.prototype.distance=function(circle){
if(circle!=null){
var dx=this.x-circle.x;
var dy=this.y-circle.y;
return (Math.sqrt(dx*dx+dy*dy)-(this.radius+circle.radius));
}
}
La formula es clara, solo cambié a códigos lo que presenté antes. Calculo dx restando la posición en X de ambos círculos, y lo mismo con dy. Luego los multiplico por si mismo para elevarlos al cuadrado y saco la raíz cuadrada; ¡Tenemos la distancia!Lo único que hice fue, después de ello, restar la suma del radio de ambos círculos. Esto nos permitirá obtener la distancia respecto a la circunferencia de ambos círculos, y no de su centro. ¿Por qué hago esto? Les explicaré en un momento...
Probemos ahora nuestra nueva función. Crearemos un círculo player, y un círculo target, que será con el que interactuaremos:
var player=new Circle(0,0,5);
var target=new Circle(100,100,10);
De nuestro código anterior, cambiaremos todas las posiciones X y Y por player.x y player.y. Ahora, en nuestra función paint, dibujaremos ambos círculos y al final una línea de texto que indicará la distancia entre ambos objectos: function paint(ctx){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.strokeStyle='#0f0';
player.stroke(ctx);
ctx.strokeStyle='#f00';
target.stroke(ctx);
ctx.fillStyle='#fff';
ctx.fillText('Distance: '+player.distance(target).toFixed(1),10,10);
}
Si corremos nuestro ejemplo, veremos que obtenemos la distancia entre nuestros dos círculos con demasiada precisión en decimales. ¡Demasiados dígitos! Eso es difícil de leer. En la última línea de nuestra función paint, cambiemos player.distance(target)
por player.distance(target).toFixed(1)
. Esta función hará que de todos los decimales en la cantidad, solo se muestre los indicados entre paréntesis. En este caso, 1.Ahora si, probamos el código, podremos analizar con mayor detalle la distancia de ambos círculos, y como en la función, he restado la suma de la circunferencia de ambos círculos, notaremos que al rozarse ambos círculos, la distancia es calculada como 0. ¿Que ocurre si ambos círculos entran en contacto?
¡Así es! Cuando ambos círculos entran en contacto, la distancia retorna un valor negativo. Con esto, no solo hemos encontrado una función que indica la distancia entre ambos círculos, ¡También hemos creado una forma de saber si dos círculos entran en contacto! De forma similar como hicimos con la función Rect.intersect.
Ahora con este conocimiento, podrás crear videojuegos que involucren círculos. ¡Felicidades!
Para hacer mas obvio el momento en que ambos círculos se entran en intersección, he agregado estas líneas en la función run que cambian el color de fondo por uno mas claro cuando ocurre lo anterior mencionado:
if(player.distance(target)<0)
bgColor='#333';
else
bgColor='#000';
No olvides declarar la variable "bgColor" al inicio para que funcione, y modificar el inicio de la función "paint" de la siguiente forma: function paint(ctx){
ctx.fillStyle=bgColor;
ctx.fillRect(0,0,canvas.width,canvas.height);
Código final:
(function(){
'use strict';
window.addEventListener('load',init,false);
var canvas=null,ctx=null;
var mousex=0,mousey=0;
var bgColor='#000';
var player=new Circle(0,0,5);
var target=new Circle(100,100,10);
function init(){
canvas=document.getElementById('canvas');
ctx=canvas.getContext('2d');
canvas.width=300;
canvas.height=200;
run();
}
function run(){
requestAnimationFrame(run);
act();
paint(ctx);
}
function act(){
player.x=mousex;
player.y=mousey;
if(player.x<0)
player.x=0;
if(player.x>canvas.width)
player.x=canvas.width;
if(player.y<0)
player.y=0;
if(player.y>canvas.height)
player.y=canvas.height;
if(player.distance(target)<0)
bgColor='#333';
else
bgColor='#000';
}
function paint(ctx){
ctx.fillStyle=bgColor;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.strokeStyle='#0f0';
player.stroke(ctx);
ctx.strokeStyle='#f00';
target.stroke(ctx);
ctx.fillStyle='#fff';
ctx.fillText('Distance: '+player.distance(target).toFixed(1),10,10);
}
document.addEventListener('mousemove',function(evt){
mousex=evt.pageX-canvas.offsetLeft;
mousey=evt.pageY-canvas.offsetTop;
},false);
function Circle(x,y,radius){
this.x=(x==null)?0:x;
this.y=(y==null)?0:y;
this.radius=(radius==null)?0:radius;
}
Circle.prototype.distance=function(circle){
if(circle!=null){
var dx=this.x-circle.x;
var dy=this.y-circle.y;
return (Math.sqrt(dx*dx+dy*dy)-(this.radius+circle.radius));
}
}
Circle.prototype.stroke=function(ctx){
ctx.beginPath();
ctx.arc(this.x,this.y,this.radius,0,Math.PI*2,true);
ctx.stroke();
}
window.requestAnimationFrame=(function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback){window.setTimeout(callback,17);};
})();
})();
Estimado Karl, este material de ayuda en HTML5 ha sido de gran utilidad para mi, estoy aprendiendo a adentrarme en la programacion HTML5 facil y sencillamente. Espero siga con mas lecciones. Aqui le dejo el link donde estoy subiendo mi primer juego basado en la culebrita (aun en construccion) y voy a seguir subiendo otros juegos que estoy diseñando.
ResponderBorrarhttp://www.espiarts.co.cc/
Muchas gracias. Leonardo
Hola,sabe alguien como rotar una imagen y no un contexto?
ResponderBorrarRotar una imagen como tal, no es posible. Lo que debes hacer, es rotar el contexto, dibujar la imagen, y regresar el contexto a su rotación original. Es una técnica avanzada que aun no he mostrado como hacer. Si necesitas más información al respecto, con gusto podré ayudarte. Suerte ;)
BorrarHola, gracias por contestar tan pronto, he hecho un contexto encima de otro para poder rotarlo. La imagen que hay dentro rota bien. El problema es que la imagen tiene que estar siempre en 0,0 x,y (coche.drawImage(iCoche,0,0);) para que rote como quiero.
ResponderBorrarEl problema viene cuando quiero saber si la imagen a colisionado con algo ya que no tengo referencia x,y de ella porque lo que se mueve o rota es el contexto.
Gracias
Si. Debes primer trasladar el contexto al centro donde quieres dibujar la imagen con ctx.translate, y después rotarlo con ctx.rotate. Esto dibujará la imagen centrada. Esto envuelto claro, en un ctx.save y ctx.restore para devolverlo a su forma original.
BorrarAdelantaré el tema de rotación de imágenes para que puedas tener una idea clara.
como gravo y lo veo en HTML el código de los circulos
ResponderBorrarSigue las instrucciones en la primer entrada: http://juegoscanvas.blogspot.mx/2012/01/parte-1-dibujando-en-el-canvas.html
Borrarlo grabe en notepad++ pero no me corre porque es
ResponderBorraredite:
'use strict';
window.addEventListener('load',init,false);
var canvas=null,ctx=null;
var mousex=0,mousey=0;
var player=new Circle(0,0,5);
var target=new Circle(100,100,10);
function init(){
canvas=document.getElementById('canvas');
canvas.style.background='#000';
ctx=canvas.getContext('2d');
run();
}
function run(){
setTimeout(run,50);
game();
paint(ctx);
}
function game(){
player.x=mousex;
player.y=mousey;
if(player.x<0)
player.x=0;
if(player.x>canvas.width)
player.x=canvas.width;
if(player.y<0)
player.y=0;
if(player.y>canvas.height)
player.y=canvas.height;
if(player.distance(target)<0)
canvas.style.background='#333';
else
canvas.style.background='#000';
}
function paint(ctx){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.strokeStyle='#0f0';
ctx.beginPath();
ctx.arc(player.x,player.y,player.radius,0,Math.PI*2,true);
ctx.stroke();
ctx.strokeStyle='#f00';
ctx.beginPath();
ctx.arc(target.x,target.y,target.radius,0,Math.PI*2,true);
ctx.stroke();
ctx.fillStyle='#fff';
ctx.fillText('Distance: '+player.distance(target).toFixed(1),10,10);
}
document.addEventListener('mousemove',function(evt){
mousex=evt.pageX-canvas.offsetLeft;
mousey=evt.pageY-canvas.offsetTop;
},false);
function Circle(x,y,radius){
this.x=(x==null)?0:x;
this.y=(y==null)?0:y;
this.radius=(radius==null)?0:radius;
this.distance=function(circle){
if(circle!=null){
var dx=this.x-circle.x;
var dy=this.y-circle.y;
return (Math.sqrt(dx*dx+dy*dy)-(this.radius+circle.radius));
}
}
}
¿Lo guardaste como game.js? ¿Guardaste el html también? ¿Corriste el html?
Borrarguarde en una carpeta ambos archivos en js y HTML y me sale al ejecutar en chome o explore
Borrar'use strict'; window.addEventListener('load',init,false); var canvas=null,ctx=null; var mousex=0,mousey=0; var player=new Circle(0,0,5); var target=new Circle(100,100,10); function init(){ canvas=document.getElementById('canvas'); canvas.style.background='#000'; ctx=canvas.getContext('2d'); run(); } function run(){ setTimeout(run,50); game(); paint(ctx); } function game(){ player.x=mousex; player.y=mousey; if(player.x<0) player.x=0; if(player.x>canvas.width) player.x=canvas.width; if(player.y<0) player.y=0; if(player.y>canvas.height) player.y=canvas.height; if(player.distance(target)<0) canvas.style.background='#333'; else canvas.style.background='#000'; } function paint(ctx){ ctx.clearRect(0,0,canvas.width,canvas.height); ctx.strokeStyle='#0f0'; ctx.beginPath(); ctx.arc(player.x,player.y,player.radius,0,Math.PI*2,true); ctx.stroke(); ctx.strokeStyle='#f00'; ctx.beginPath(); ctx.arc(target.x,target.y,target.radius,0,Math.PI*2,true); ctx.stroke(); ctx.fillStyle='#fff'; ctx.fillText('Distance: '+player.distance(target).toFixed(1),10,10); } document.addEventListener('mousemove',function(evt){ mousex=evt.pageX-canvas.offsetLeft; mousey=evt.pageY-canvas.offsetTop; },false); function Circle(x,y,radius){ this.x=(x==null)?0:x; this.y=(y==null)?0:y; this.radius=(radius==null)?0:radius; this.distance=function(circle){ if(circle!=null){ var dx=this.x-circle.x; var dy=this.y-circle.y; return (Math.sqrt(dx*dx+dy*dy)-(this.radius+circle.radius)); } } }
Este blog ha sido eliminado por un administrador de blog.
BorrarVerdaderamente me preocupa en hecho que no te funcione. He puesto los archivos en un zip para que los descargues, esperando esto resuelva tus dudas respecto al problema:
Borrarhttps://sites.google.com/site/juegoscanvas/circulos.zip
Borré también el correo que dejaste, para evitar que los SPAMbots lo encuentren. Avísame si resuelve tu problema o aun quedan dudas.
Que no funcione me parece normal en una persona que no sabe escribir. Antes de meterte en programación debería ir a aprender ortografía.
BorrarComentarios como este no ayudan en nada a los que quieren aprender,
Borrarun hurra para el señor erudito en ortografía!
( por cierto mucha ortografía pero nada de ayuda )
Otra vez yo molestando, estoy haciendo "Pruebas" para aprender mas, se puede hacer un addEventListener a un objeto rectangle como el que usas tu, el que resulta de la funcion constructora, darle click al rectangulo y pase un evento, lo mas facil seria capturar las coordenadas del mouse y si son iguales al de el rectangulo pues que pase el evento con un if, pero que no tecnicamente el objeto rectangulo ¿No es un objeto? y deberia de funcionar el addEventListener(click, funcion_hago_algo_conclick, false)
ResponderBorrarRectangle no es un objeto DOM, algo que puedas insertar en el HTML; tan solo son una serie de coordenadas que usamos para dibujar una figura en el canvas, y dado que no es un objeto DOM, no contiene la función addEventListener.
BorrarLo que se puede hacer, es crear una función Contains que reciba dos coordenadas, y funcione de forma similar a Intersects pasa saber si estas coordenadas están dentro del rectángulo, mandar las coordenadas del ratón a esta función, y compararla al mismo tiempo que un lastPress o lastRelease para saber si ha sido presionado, de forma similar a como se muestra en el siguiente tema.
El verdadero poder del teorema de pitagoras explicado en esta entrada, jaja, ver matemáticas junto a este tipo de realidad es un ejercicio increíble...
ResponderBorrarMuy buenos tutoriales, gracias por tu aporte. Ando buscando algo de información para realizar colisiones entre imágenes al pasar el ratón por encima de ellas. Digamos que me gustaría que varias imágenes sean golpeadas por el mouse y choquen entre ellas, con las paredes del lienzo, con aceleración, que vayan cayendo... Estoy encaminado con éste tipo de tutoriales? Sabes dónde podría encontrar información? Gracias!
ResponderBorrarTemo que la mayoría de lo que he encontrado en Google ha sido con engines prediseñados. Mi mejor consejo para lo que tienes en mente, es que busques un tutorial de cómo hacer un juego de billar (Eso te dará la lógica para aceleración y colisiones), y de ahí aplicar otras fuerzas como gravedad será más sencillo.
Borrar¡Mucha suerte! Felices códigos