当正方形完全在圆内时检测碰撞
Detect collision when a square is totally inside a circle
我有这个功能来检测圆和正方形之间的碰撞
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;
}
它完美运行,但我还需要它,该函数检测正方形是否完全在圆内
这就像添加:
if (square is totally inside) console.log("its inside!");
执行此操作的一种方法是检查正方形的角是否分别超出圆的 4 个象限中的任何一个。为了检查我们是否可以使用 sin 和 cos 计算沿圆周长的点,并根据象限检查它们是否在外部:
<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>
PS:这是用我最近学的图形编程的知识做的,我觉得解决方案可以好很多。一旦有更好的解决方案,我会尝试更新。
我会检查到方角的距离,看看它们是否都小于半径。
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 = e.x - canvasBounds.x - rect.w / 2;
rect.y = e.y - 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>
您可能需要全屏才能看到圆圈
谢谢你的回答,我没有想过4个角,但我想出了另一种更简单的方法,从圆的原点到正方形的原点的距离加上一点(“半径”正方形)必须小于圆的半径。
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>
我有这个功能来检测圆和正方形之间的碰撞
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;
}
它完美运行,但我还需要它,该函数检测正方形是否完全在圆内
这就像添加:
if (square is totally inside) console.log("its inside!");
执行此操作的一种方法是检查正方形的角是否分别超出圆的 4 个象限中的任何一个。为了检查我们是否可以使用 sin 和 cos 计算沿圆周长的点,并根据象限检查它们是否在外部:
<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>
PS:这是用我最近学的图形编程的知识做的,我觉得解决方案可以好很多。一旦有更好的解决方案,我会尝试更新。
我会检查到方角的距离,看看它们是否都小于半径。
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 = e.x - canvasBounds.x - rect.w / 2;
rect.y = e.y - 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>
您可能需要全屏才能看到圆圈
谢谢你的回答,我没有想过4个角,但我想出了另一种更简单的方法,从圆的原点到正方形的原点的距离加上一点(“半径”正方形)必须小于圆的半径。
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>