如何实现两个div元素间的矩形碰撞检测?
解决类谷歌恐龙游戏的矩形碰撞检测问题
我正在做一个类似谷歌恐龙游戏的课程项目,需要实现绿色div(角色macaco)和红色div(障碍物obstaculo)之间的矩形碰撞检测。之前尝试定义过macaco和obstaculo的尺寸变量,但因为变量名和DOM元素重名导致跳跃功能失效,不得不注释掉,现在需要解决这个碰撞检测问题。
原代码核心问题
- 直接给DOM元素对象(
macaco、obstaculo)访问x、y属性,但DOM元素本身不具备这些属性,导致碰撞逻辑完全无法触发。 - 注释的尺寸变量与DOM元素变量同名,会覆盖DOM元素引用,进而导致跳跃功能失效。
解决方案
核心修复点
- 用
getBoundingClientRect()获取实时位置:该方法能获取元素当前相对于视口的位置和尺寸(包含left、top、width、height等属性),完美适配CSS动画中的元素位置变化。 - 避免变量名冲突:不要用与DOM元素相同的变量名存储碰撞检测用的尺寸位置数据。
- 持续检测碰撞:通过
requestAnimationFrame循环检测,与浏览器刷新频率同步,保证检测的实时性和性能。
修改后的完整代码
HTML代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Inicio esqueleto</title> <link rel="stylesheet" type="text/css" href="estilo.css"> </head> <body> <div onclick="saltar()" id="macaco" class="macaco"></div> <div id="obstaculo"></div> <script type="text/javascript"> const macaco = document.getElementById("macaco"); const obstaculo = document.getElementById("obstaculo"); function saltar(){ macaco.classList.add("play"); setTimeout(() => { macaco.classList.remove("play"); }, 1000); } // 碰撞检测函数,基于元素实时位置 function checkCollision() { const macacoRect = macaco.getBoundingClientRect(); const obstaculoRect = obstaculo.getBoundingClientRect(); // 矩形碰撞检测逻辑 if ( macacoRect.left < obstaculoRect.left + obstaculoRect.width && macacoRect.left + macacoRect.width > obstaculoRect.left && macacoRect.top < obstaculoRect.top + obstaculoRect.height && macacoRect.top + macacoRect.height > obstaculoRect.top ) { alert("碰撞发生!"); // 可在此添加游戏结束等碰撞后逻辑 } // 持续调用检测,保证实时性 requestAnimationFrame(checkCollision); } // 启动碰撞检测 checkCollision(); </script> </body> </html>
CSS代码(含小优化)
#macaco { background-color: green; height: 70px; width: 40px; transform: translateX(15vw); position: absolute; bottom: 22px; } #obstaculo { background-color: red; height: 50px; width: 40px; transform: translateX(50vw); position: absolute; bottom: 22px; animation: linear obstaculo 2s infinite; /* 添加infinite让障碍物循环移动,方便测试 */ } .play { animation: linear saltar 1s; } @keyframes saltar { 0% {transform: translatey(0px) translateX(15vw)} 50% {transform: translatey(-120px) translateX(15vw)} 100% {transform: translatey(0px) translateX(15vw)} } @keyframes obstaculo { 0% {transform: translatey(0) translateX(50vw)} 100% {transform: translatey(0) translateX(0vw)} }
额外优化说明
- 给障碍物动画添加
infinite属性,让其循环移动,便于测试碰撞效果。 - 使用
requestAnimationFrame替代setInterval,与浏览器刷新频率同步,性能更优、检测更精准。 - 用
const替代var,符合现代JavaScript规范,避免变量提升问题。
内容的提问来源于stack exchange,提问作者Janner
相关产品推荐
相关产品推荐

