[英]How to detect a collision between a circle and a rectangle?
有一個碰撞函數可以找到兩個 div(圓形和矩形)的邊界,第一個條件有效但其余條件無效,到目前為止我不知道我做錯了什么。 基本上,這個想法是讓圓圈不要超出矩形的邊緣。
const $circle = document.getElementById("circle");
const $box = document.getElementById("box");
let mtop = 0;
let mleft = 0;
let boxTop = 0;
let boxLeft = 0;
let boxRight = 0;
let boxBottom = 0;
document.addEventListener("keydown", (e) =>{
if(e.keyCode == "39") {
mleft++;
$circle.style.marginLeft = mleft +"px";
colission();
}
if(e.keyCode == "37"){
mleft --;
$circle.style.marginLeft = mleft +"px"
// colission();
}
if(e.keyCode == "38"){
mtop --;
$circle.style.marginTop = mtop + "px";
//colission();
}
if(e.keyCode == "40"){
mtop ++;
$circle.style.marginTop = mtop + "px";
//colission();
}
e.preventDefault();
})
function colission(){
let boxPos = $box.getBoundingClientRect();
let boxTop = boxPos.top;
let boxLeft = boxPos.left;
let boxRight = boxPos.right;
let boxBottom = boxPos.bottom;
let circlePos = $circle.getBoundingClientRect();
let circleTop = circlePos.top;
let circleLeft = circlePos.left;
let circleRight = circlePos.right;
let circlebottom = circlePos.bottom;
if(Math.round(circleRight) == Math.round(boxRight)){
mleft = mleft - 2;
}
/*if(Math.round(circleLeft) == Math.round(boxLeft)){
mleft = mleft - 2;
}
if(Math.round(circleTop) == Math.round(boxTop)){
mtop = mtop -2;
}
if(Math.round(circlebottom) == Math.round(boxBottom)){
mtop = mtop -2;
}*/
}
這是您問題的解決方案, collision
函數在collision
返回true
,否則返回false
。 然后,您可以實現一些邏輯來防止發生碰撞時的最后一個用戶操作(嘗試使用鍵盤箭頭進行演示):
document.addEventListener('keydown', (function() { function collision(box, circle) { const { top: boxTop, left: boxLeft, right: boxRight, bottom: boxBottom, } = box.getBoundingClientRect(); const { top: circleTop, left: circleLeft, right: circleRight, bottom: circleBottom, } = circle.getBoundingClientRect(); const circleRadius = (circleBottom - circleTop ) / 2; const circleCenterX = (circleLeft + circleRight ) / 2; const circleCenterY = (circleTop + circleBottom ) / 2; /** * Distance between the center of the circle and the nearest point of * the rectangle (on the X axis) */ const deltaX = circleCenterX - Math.max(boxLeft, Math.min(circleCenterX, boxRight)); /** * Distance between the center of the circle and the nearest point of * the rectangle (on the Y axis) */ const deltaY = circleCenterY - Math.max(boxTop, Math.min(circleCenterY, boxBottom)); /** * Is the distance between the center of the circle and the nearest point * of the rectangle inferior to the circle radius ? */ return deltaX ** 2 + deltaY ** 2 < circleRadius ** 2; } const circle = document.getElementById('circle'); const rectangle = document.getElementById('rectangle'); let circleTop = 26; let circleLeft = 8; return function(e) { e.preventDefault(); if(e.keyCode === 37) { circleLeft -= 1; } if(e.keyCode === 38) { circleTop -= 1; } if(e.keyCode === 39) { circleLeft += 1; } if(e.keyCode === 40) { circleTop += 1; } circle.style.top = `${circleTop}px`; circle.style.left = `${circleLeft}px`; if (collision(rectangle, circle)) { rectangle.style['background-color'] = 'red'; circle.style['background-color'] = 'red'; } else { rectangle.style['background-color'] = 'blue'; circle.style['background-color'] = 'blue'; } } })());
.shape { position: absolute; background-color: blue; } #circle { border-radius: 50%; height: 20px; width: 20px; } #rectangle { height: 20px; width: 50px; top: 40px; left: 40px; }
<div>Use the keyboard arrows to move the circle</div> <div class="shape" id="circle"></div> <div class="shape" id="rectangle"></div>
編輯:實際問題是關於不應超出矩形的圓
然后只需檢查圓的邊界是否在矩形的邊界內:
document.addEventListener('keydown', (function() { function isInInterval(value, interval) { const [min, max] = interval; return value >= min && value <= max; } function collision(box, circle) { const { top: boxTop, left: boxLeft, right: boxRight, bottom: boxBottom, } = box.getBoundingClientRect(); const { top: circleTop, left: circleLeft, right: circleRight, bottom: circleBottom, } = circle.getBoundingClientRect(); return !( isInInterval(circleLeft, [boxLeft, boxRight]) && isInInterval(circleRight, [boxLeft, boxRight]) && isInInterval(circleTop, [boxTop, boxBottom]) && isInInterval(circleBottom, [boxTop, boxBottom]) ); } const circle = document.getElementById('circle'); const rectangle = document.getElementById('rectangle'); let circleTop = 26; let circleLeft = 8; return function(e) { e.preventDefault(); if(e.keyCode === 37) { circleLeft -= 1; } if(e.keyCode === 38) { circleTop -= 1; } if(e.keyCode === 39) { circleLeft += 1; } if(e.keyCode === 40) { circleTop += 1; } circle.style.top = `${circleTop}px`; circle.style.left = `${circleLeft}px`; if (collision(rectangle, circle)) { rectangle.style['background-color'] = 'red'; circle.style['background-color'] = 'red'; } else { rectangle.style['background-color'] = 'blue'; circle.style['background-color'] = 'blue'; } } })());
.shape { position: absolute; background-color: red; } #circle { border-radius: 50%; height: 20px; width: 20px; } #rectangle { height: 20px; width: 50px; top: 40px; left: 40px; }
<div>Use the keyboard arrows to move the circle</div> <div class="shape" id="circle"></div> <div class="shape" id="rectangle"></div>
謝謝你的回答,我已經可以解決問題了
const $circle = document.getElementById("circle"); const $box = document.getElementById("box"); let mtop = 0; let mleft = 0; let boxTop = 0; let boxLeft = 0; let boxRight = 0; let boxBottom = 0; document.addEventListener("keydown", (e) =>{ e.preventDefault(); let boxPos = $box.getBoundingClientRect(); let boxTop = boxPos.top; let boxLeft = boxPos.left; let boxRight = boxPos.right; let boxBottom = boxPos.bottom; let circlePos = $circle.getBoundingClientRect(); let circleTop = circlePos.top; let circleLeft = circlePos.left; let circleRight = circlePos.right; let circlebottom = circlePos.bottom; if(e.keyCode === 39) { mleft++; $circle.style.marginLeft = mleft +"px"; if(Math.trunc(circleRight) === Math.trunc(boxRight)){ mleft = mleft - 5; } } if(e.keyCode === 37){ mleft--; $circle.style.marginLeft = mleft +"px" if(Math.trunc(circleLeft) === Math.trunc(boxLeft)){ mleft = mleft + 5; } } if(e.keyCode === 38){ mtop--; $circle.style.marginTop = mtop + "px"; if(Math.trunc(circleTop) === Math.trunc(boxTop)){ mtop = mtop + 5; } } if(e.keyCode === 40){ mtop++; $circle.style.marginTop = mtop + "px"; if(Math.trunc(circlebottom) === Math.trunc(boxBottom)){ mtop = mtop - 5; } } })
:root { --main-color: red; --second-color: blue; } .container { background-color: var(--main-color); border: black; width: 50%; height: 60%; position: absolute; } #circle{ position: absolute; width: 60px; height: 60px; left: 0; right: 0; border-radius: 100%; background-color: var(--second-color); padding: 10px; }
<div id="box" class="container"> <div id="circle"></div> </div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.