当前位置: 首页
编程语言
C++如何检测两个圆形是否相交 _ 游戏开发几何碰撞检测逻辑【干货】

C++如何检测两个圆形是否相交 _ 游戏开发几何碰撞检测逻辑【干货】

热心网友 时间:2026-05-01
转载

C++如何检测两个圆形是否相交 | 游戏开发几何碰撞检测逻辑【干货】 判断两个圆是否相交,核心逻辑其实就一句话:圆心距的平方是否小于等于半径和的平方。如果严格区分,外离是圆心距平方大于半径和的平方,内含则是圆心距平方小于半径差的平方(这里假设第一个圆半径更大)。至于内切和外切这两种临界状态,在实际编

C++如何检测两个圆形是否相交 | 游戏开发几何碰撞检测逻辑【干货】

C++如何检测两个圆形是否相交 _ 游戏开发几何碰撞检测逻辑【干货】

判断两个圆是否相交,核心逻辑其实就一句话:圆心距的平方是否小于等于半径和的平方。如果严格区分,外离是圆心距平方大于半径和的平方,内含则是圆心距平方小于半径差的平方(这里假设第一个圆半径更大)。至于内切和外切这两种临界状态,在实际编程中必须引入一个容差ε来处理,否则浮点误差会让你抓狂。

用距离平方判断比开方更高效

从几何定义上看,两个圆相交的充要条件是圆心距离小于等于半径之和。但如果你在代码里老老实实地写 sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)),那就掉进性能陷阱了。浮点开方运算开销大,还会引入不必要的精度扰动。要知道,游戏循环里每帧可能要进行成百上千次这样的检测,sqrt 函数能不用就不用。

那怎么办?其实很简单,把不等式两边平方一下就行了。因为距离和半径都是非负数,平方操作不会改变不等号的方向。这样一来,判断逻辑就变成了:

dx = x1 - x2;
dy = y1 - y2;
r_sum = r1 + r2;
if (dx * dx + dy * dy <= r_sum * r_sum) {
    // 相交(含内切、外切、相交、包含)
}

这里有个细节需要注意:这个判断条件会把“一个圆完全包含在另一个圆内部”的情况也归类为“相交”。如果你的游戏逻辑需要严格区分“边缘相交”和“完全包含”,比如子弹必须碰到怪物边缘才算击中,被护盾完全包裹不算受伤,那就得在这个基础上再加一层判断。

区分“相交”“内含”“相离”三种状态

对于复杂的游戏逻辑,光知道“是否相交”往往不够。比如,粒子碰撞后需要反弹,这就得明确是“相交”;而判断一个角色是否被保护罩完全覆盖,则需要识别“内含”状态。这就需要我们把距离与半径的关系拆解得更细致一些:

立即学习“C++免费学习笔记(深入)”;

  • dx*dx + dy*dy > (r1 + r2)*(r1 + r2) → 相离
  • dx*dx + dy*dy < (r1 - r2)*(r1 - r2)(这里假设 r1 >= r2)→ 内含(小圆完全在大圆内,无交点)
  • 其余情况 → 相交(含外切、内切、部分重叠)

这里有个关键点要特别注意:计算半径差的平方时,一定要用绝对值差。直接写 (r1 - r2)*(r1 - r2)r2 > r1 时会得到负值,导致判断出错。稳妥的写法是用 abs(r1 - r2) 取绝对值后再平方,或者直接比较 dx*dx + dy*dy((r1 > r2) ? (r1 - r2) : (r2 - r1)) * ... 的结果。

浮点误差下如何处理“恰好相切”

理论上,外切的条件是圆心距严格等于半径和。但在浮点数的世界里,distance == r1 + r2 这种精确相等几乎不可能发生。如果你用 == 来判断相切,那结果永远是“否”。

正确的做法是引入一个容差(epsilon)。如果你确实需要识别“近似相切”的状态(比如触发一个特殊的接触音效),可以这样判断:

float dist_sq = dx*dx + dy*dy;
float r_sum = r1 + r2;
float diff = fabsf(sqrtf(dist_sq) - r_sum); // 这里 sqrt 不可避免,但仅在极少数判定时用
if (diff < 1e-4f) { /* 近似外切 */ }

不过,更推荐的做法是全程使用平方比较,并设置一个容差区间:

float r_sum_sq = (r1 + r2) * (r1 + r2);
float eps = 1e-6f;
if (dist_sq > r_sum_sq && dist_sq < r_sum_sq + eps) { /* 视为刚接触 */ }

话说回来,对于大多数游戏物理碰撞而言,并不需要如此精细地区分相切状态。只要进入“相交”分支就触发碰撞响应,把相切视为相交的一种临界情况来处理,通常就足够了。

结构体封装与成员函数建议

最后,别再用一堆零散的 x, y, r 变量了。定义一个 struct Circle 结构体,并提供一个 intersects(const Circle& other) const 方法,代码的清晰度和复用性会立刻提升一个档次:

struct Circle {
    float x, y, r;
    bool intersects(const Circle& o) const {
        float dx = x - o.x;
        float dy = y - o.y;
        float r_sum = r + o.r;
        return dx*dx + dy*dy <= r_sum * r_sum;
    }
};

如果你的项目后期需要考虑使用SIMD指令集,或者需要进行大批量的碰撞检测(比如成千上万的子弹对敌人),那么可以将数据结构从AoS(数组结构体)转换为SoA(结构体数组)以优化性能。但对于单次检测,没必要过早优化。

真正容易被忽略,却可能引发诡异Bug的细节是:**半径必须是非负数**。如果构造函数不小心传入了一个负半径,r_sum 的计算就会出错,编译器不会报错,但运行时的行为将不可预测。一个良好的习惯是在构造函数或设置函数中加入 assert(r >= 0) 进行断言检查。

来源:https://www.php.cn/faq/2400081.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
Kafka与CentOS其他服务协同配置指南

Kafka与CentOS其他服务协同配置指南

Kafka在CentOS生态中作为数据流通中枢,与EFK日志收集、HDFS存储、HBase、Prometheus+Grafana监控及SparkStreaming流处理系统协同,通过生产者-消费者模式构建实时数据管道,实现解耦、削峰填谷与高效集成。

时间:2026-07-12 06:52
如何使用deluser命令重命名用户的详细操作指南

如何使用deluser命令重命名用户的详细操作指南

在Linux系统管理中,重命名用户需通过删除旧用户并创建新用户实现。操作包括备份数据、用rsync迁移文件、更改文件所有权、删除旧用户及家目录,最后重新登录验证。不同发行版命令略有差异,建议在测试环境演练。

时间:2026-07-12 06:52
详细CentOS系统中C++配置常见问题及解决方法大全

详细CentOS系统中C++配置常见问题及解决方法大全

CentOS配置C++常见问题包括编译器缺失或版本过旧、环境变量错误、依赖库开发包未装、多版本冲突、权限路径问题、内存不足及内核参数不当。需正确安装gcc-c++及devel包,配置PATH与库路径,使用devtoolset或alternatives管理版本,调整权限与ulimit、sysctl参数。

时间:2026-07-12 06:52
CentOS C++环境变量配置方法

CentOS C++环境变量配置方法

在CentOS系统配置C++编译器需设置路径和动态库路径。先验证g++是否已安装,否则使用sudoyuminstallgcc-c++安装。通过whichg++找到安装路径后,在~ bashrc中添加exportPATH=$PATH:该路径并执行source使之生效。动态库路径可用find命令查找后类似加入LD_LIBRARY_PATH。最后用g++编译测试

时间:2026-07-12 06:52
CentOS中C++配置文件位置与路径完整说明

CentOS中C++配置文件位置与路径完整说明

CentOS中C++配置文件包括系统级全局配置( etc profile、 etc bashrc)影响所有用户,用户级配置(~ bashrc)仅影响当前用户,以及第三方库路径和构建工具CMakeLists txt。这些文件共同设置环境变量、库路径及编译选项等详细参数,用于管理相关开发环境。

时间:2026-07-12 06:52
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜