You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现两个div元素间的矩形碰撞检测?

解决类谷歌恐龙游戏的矩形碰撞检测问题

我正在做一个类似谷歌恐龙游戏的课程项目,需要实现绿色div(角色macaco)和红色div(障碍物obstaculo)之间的矩形碰撞检测。之前尝试定义过macaco和obstaculo的尺寸变量,但因为变量名和DOM元素重名导致跳跃功能失效,不得不注释掉,现在需要解决这个碰撞检测问题。


原代码核心问题

  1. 直接给DOM元素对象(macaco、obstaculo)访问x、y属性,但DOM元素本身不具备这些属性,导致碰撞逻辑完全无法触发。
  2. 注释的尺寸变量与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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 10:50:37