You need to enable JavaScript to run this app. 圆形与正方形碰撞检测:如何获取碰撞接触位置实现游戏防穿透?
优惠活动
大模型
产品
解决方案
定价
更多

圆形与正方形碰撞检测:如何获取碰撞接触位置实现游戏防穿透?

游戏场景下圆与矩形碰撞检测的可落地改造方案

该类通用函数仅返回布尔碰撞结果,缺失游戏阻挡逻辑必需的两个关键信息:矩形与圆形的实际接触点位置、将圆形移出碰撞重叠区所需的最小位移向量。原有函数的几何判断逻辑本身完全正确,不需要推翻重写,只需要把判断分支的输出从简单的true/false,替换为结构化的碰撞细节即可。

核心逻辑优化思路

  • 无需在原有坐标轴差计算的基础上额外叠加复杂几何计算,只需要先定位矩形边界上距离圆心最近的点,所有碰撞判断、位置计算都基于这个最近点推导
  • 所有快速排除无碰撞的判断逻辑和原函数完全一致,仅当确认发生碰撞时,才计算需要返回的位置、方向、距离信息,保证运行性能
  • 覆盖圆心完全落入矩形内部的边界场景,避免角落判断逻辑出现除零错误

分场景计算规则

  • 边碰撞场景:圆心垂直方向落在矩形上下边界范围内,水平方向与矩形左/右边界的距离小于圆半径,此时接触点落在矩形的垂直边上,推出方向为水平方向
  • 边碰撞场景:圆心水平方向落在矩形左右边界范围内,垂直方向与矩形上/下边界的距离小于圆半径,此时接触点落在矩形的水平边上,推出方向为垂直方向
  • 角碰撞场景:圆心既不在矩形水平投影范围内,也不在垂直投影范围内,此时接触点为矩形的对应角点,推出方向为从角点指向圆心的连线方向

改造后可直接复用的检测函数

function rccol(rect, circle){
    // 拆解矩形四周边界坐标
    const rectLeft = rect.x;
    const rectRight = rect.x + rect.width;
    const rectTop = rect.y;
    const rectBottom = rect.y + rect.height;

    // 定位矩形上距离圆心最近的点
    const closestX = Math.max(rectLeft, Math.min(circle.x, rectRight));
    const closestY = Math.max(rectTop, Math.min(circle.y, rectBottom));

    // 计算圆心到最近点的距离平方,快速判断是否碰撞
    const dx = circle.x - closestX;
    const dy = circle.y - closestY;
    const distSq = dx * dx + dy * dy;

    // 距离大于圆半径,无碰撞
    if(distSq > circle.radius * circle.radius) return null;

    // 处理碰撞逻辑,计算需要返回的全部参数
    const dist = Math.sqrt(distSq);
    let normalX, normalY, penetration;

    // 兜底:圆心完全在矩形内部时的推出方向计算
    if(dist === 0) {
        const dLeft = circle.x - rectLeft;
        const dRight = rectRight - circle.x;
        const dTop = circle.y - rectTop;
        const dBottom = rectBottom - circle.y;
        const minSideDist = Math.min(dLeft, dRight, dTop, dBottom);
        penetration = circle.radius + minSideDist;
        if(minSideDist === dLeft) {normalX = -1; normalY = 0;}
        else if(minSideDist === dRight) {normalX = 1; normalY = 0;}
        else if(minSideDist === dTop) {normalX = 0; normalY = -1;}
        else {normalX = 0; normalY = 1;}
    } else {
        normalX = dx / dist;
        normalY = dy / dist;
        penetration = circle.radius - dist;
    }

    return {
        contactPoint: {x: closestX, y: closestY},
        pushOutVector: {x: normalX * penetration, y: normalY * penetration},
        normal: {x: normalX, y: normalY}
    };
}

游戏开发中的使用提示

  • 每帧玩家移动完成后调用该检测函数,拿到返回的pushOutVector后直接叠加到玩家碰撞盒的坐标上,即可实现墙体阻挡、不穿透的效果
  • 检测全程优先用平方距离做无碰撞快速排除,仅在确认发生碰撞时计算平方根,可大幅降低高频检测的性能消耗
  • 如果需要做碰撞反馈(比如粒子效果、音效触发),可以直接使用返回的contactPoint坐标定位触发位置,不需要额外做坐标换算

内容的提问来源于stack exchange,提问作者kriskotoo BG

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.07 20:06:03