Tengo esta funcion para detectar colisiones entre un circulo y un cuadrado
function detectCollision(square, circle) { let distX = Math.abs(circle.x - square.x); let distY = Math.abs(circle.y - square.y); if (distX > square.w / 2 + circle.r) return false; if (distY > square.w / 2 + circle.r) return false; if (distX <= square.w / 2) return true; if (distY <= square.w / 2) return true; let dx = distX - square.w / 2; let dy = distY - square.w / 2; return dx * dx + dy * dy <= circle.r * circle.r; }Funciona perfectamente pero necesito que además la función detecte si el cuadrado está totalmente dentro del círculo
sería como agregar:
if (square is totally inside) console.log("its inside!");Una forma de hacerlo es verificar si alguna de las esquinas del cuadrado sale de cualquiera de los 4 cuadrantes del círculo, respectivamente. Para comprobar que podemos calcular los puntos del perímetro de la circunferencia con seno y coseno, y comprobar si están fuera según el cuadrante:
<canvas height='500' width='500'></canvas> <script> const canvas = document.querySelector('canvas'); const ctx = canvas.getContext('2d'); let circle = { x: 200, y: 200, r: 100 }; let square = { x: 200, y: 120, side: 50 }; ctx.beginPath(); ctx.arc(circle.x, circle.y, circle.r, 0, 2 * Math.PI); ctx.stroke(); ctx.beginPath(); ctx.rect(square.x, square.y, square.side, square.side); ctx.stroke(); function detectContains(circle, square) { let sw = square.side; for(let deg=0; deg<=360; ++deg) { let x = circle.x + circle.r * Math.sin(Math.PI * 2 * deg / 360) let y = circle.y - circle.r * Math.cos(Math.PI * 2 * deg / 360) if(deg >= 0 && deg <= 90) { if(square.x+sw > x && square.y < y) return false; } else if(deg >= 90 && deg <= 180) { if(square.x+sw > x && square.y+sw > y) return false; } else if(deg >= 180 && deg <= 270) { if(square.x > x && square.y+sw > y) return false; } else { if(square.x < x && square.y < y) { return false; } } } return true; } console.log(detectContains(circle, square)) </script>PD: Esto se hace con lo que he aprendido recientemente sobre programación de gráficos, creo que la solución puede ser mucho mejor. Intentaré actualizar una vez que obtenga una mejor solución.
Verificaría la distancia a las esquinas de los cuadrados para ver si todos son menores que el radio.
let canvas = document.getElementById("canvas"); let ctx = canvas.getContext("2d"); canvas.width = 300; canvas.height = 300; let canvasBounds = canvas.getBoundingClientRect(); class Rect { constructor(x, y, w, h) { this.x = x; this.y = y; this.w = w; this.h = h; this.c = "blue"; } draw() { ctx.strokeStyle = this.c; ctx.strokeRect(this.x, this.y, this.w, this.h); } } class Circle { constructor(x, y, r) { this.x = x; this.y = y; this.r = r; } draw() { ctx.strokeStyle = "black"; ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); ctx.stroke(); } } let rect = new Rect(100, 100, 40, 40); let circle = new Circle(100, 100, 75); function detectCollision(square, circle) { let distX = Math.abs(circle.x - (square.x + square.w / 2)); let distY = Math.abs(circle.y - (square.y + square.h / 2)); let dx = distX - square.w / 2; let dy = distY - square.h / 2; if ( distance(square.x, square.y, circle) < circle.r && distance(square.x + square.w, square.y, circle) < circle.r && distance(square.x + square.w, square.y + square.h, circle) < circle.r && distance(square.x, square.y + square.h, circle) < circle.r ) { console.log("it's totally inside") } else if (dx * dx + dy * dy <= circle.r * circle.r) { console.log("it's not totally inside") } else { console.log("there's no collision") } } function distance(ptX, ptY, circle) { return Math.hypot(ptX - circle.x, ptY - circle.y); } canvas.addEventListener("mousemove", (e) => { rect.x = ex - canvasBounds.x - rect.w / 2; rect.y = ey - canvasBounds.y - rect.h / 2; }); function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); rect.draw(); circle.draw(); detectCollision(rect, circle); requestAnimationFrame(animate); } animate(); <canvas id="canvas"></canvas>Es posible que deba hacerlo en pantalla completa para ver el círculo.
Gracias por sus respuestas, no habia pensado en las 4 esquinas, pero se me ocurrio otra forma mas sencilla, la distancia del origen del circulo al origen del cuadrado mas un poco (el "radio" del cuadrado) debe ser menor que el radio del círculo.
let mysquare = { x: 200, y: 200, w: 50 }; let mycircle = { x: 110, y: 110, r: 100 }; function setup() { createCanvas(512, 512); rectMode(CENTER); } function draw() { clear(); fill(255); circle(mycircle.x, mycircle.y, mycircle.r * 2); mysquare.x = mouseX; mysquare.y = mouseY; if (isInside(mysquare, mycircle)) fill(255, 0, 0); square(mysquare.x, mysquare.y, mysquare.w); } function isInside(square, circle) { let dx = Math.abs(circle.x - square.x) + square.w/2; let dy = Math.abs(circle.y - square.y) + square.w/2; return dx ** 2 + dy ** 2 <= circle.r ** 2; } <script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>