Quisiera saber cómo puedo hacer que, teniendo dos círculos, como objetos independientes, los cuales están rebotando dentro del canvas de forma libre, cuando se encuentren reboten entre ellos y cambien su dirección.
Adjunto mi código JS para mi canvas, para que sepan cómo lo tengo planteado, gracias:
// Función que crea un circulo. function circle(x, y, r, color) { contexto.fillStyle = color; contexto.beginPath(); contexto.arc(x, y, r, 0, Math.PI*2, true); contexto.closePath(); contexto.fill(); } // Función que crea un rectangulo. function rect(x, y, w, h, color) { contexto.fillStyle = color; contexto.fillRect(x, y, w, h); } // Función que crea un objeto pelota function Pelota(x, y, r, color) { this.x = x; this.y = y; this.r = r; this.color = color; this.dx = 1; this.dy = 1.1; this.speed = 2; this.center = this.r/2; this.update = function() { if (this.x+this.center > ancho_rectangulo || this.x-this.center < 0) { this.dx = -this.dx; } if (this.y+this.center > alto_rectangulo || this.y-this.center < 0) { this.dy = -this.dy; } this.x += this.dx * this.speed; this.y += this.dy * this.speed; } this.draw = function() { circle(this.x, this.y, this.r, this.color); } } //Función que actualiza y dibuja la pelota. function gameLoop() { limpiar(); // Si (pelota.x > width) entonces clearInterval(intervalId); pelota1.update(); pelota1.draw(); pelota2.update(); pelota2.draw(); } // Función que limpia los pasos de la pelota function limpiar() { contexto.fillStyle = "grey"; rect(0, 0, ancho_rectangulo, alto_rectangulo); } // Función para iniciar el programa function init() { canvas = document.getElementById("miCanvas"); contexto = canvas.getContext("2d"); ancho_rectangulo = canvas.width; alto_rectangulo = canvas.height; pelota1 = new Pelota(50, 50, 10, "silver"); pelota2 = new Pelota(50, 250, 10, "black"); setInterval(gameLoop, 20); //Llama a la función gameLoop cada 20 milisegundos de forma indefinida. } window.onload = init; // Variables. var canvas, contexto, ancho_rectangulo, alto_rectangulo;
Respuestas
Así por encima será igual que en cualquier lenguaje, en cada loop tendrás que mirar si ambos centros estan a x distancia y si es así es que están tocándose. Oseáse si en cada tick de reloj la distancia entre centros es menor que el radio 1 + el radio 2 (creo que será la formula) entonces hay contacto y si hay contacto pos habrá que modificar los valores que sean de movimiento. no?
@aprendizenlared
Sí, creo que lo he pillado, gracias por tu tiempo y por contestar.
@ucip3
Estaba leyendo en esta pregunta de StackOverflow posibles soluciones a este problema.
Algunos usuarios sugieren que si es importante ofrecer un gran rendimiento en las animaciones, que sacrifiques un poco la precisión de las colisiones. Para ello, tienes que aproximar los objetos circulares por el mínimo rectángulo envolvente y después, utilizar esta fórmula para detectar colisiones:
function hanColisionado(rectanguloA, rectanguloB) { return !( ((rectanguloA.y + rectanguloA.height) < (rectanguloB.y)) || (rectanguloA.y > (rectanguloB.y + rectanguloB.height)) || ((rectanguloA.x + rectanguloA.width) < rectanguloB.x) || (rectanguloA.x > (rectanguloB.x + rectanguloB.width)) ); }
Si en cambio quieres detectar las colisiones con precisión para los objetos circulares, puedes utilizar la siguiente fórmula:
function hanColisionado(x1, y1, w1, x2, y2, w2) { var xd = x1 - x2; var yd = y1 - y2; var wt = w2 + w1; return (xd * xd + yd * yd <= wt * wt); }
Donde (x1, y1)
es el centro del primer círculo y w1
su diámetro; mientras que (x2, y2)
es el centro del segundo círculo y w2
es su diámetro.
@javiereguiluz