算法与游戏之AABB碰撞盒算法

news/2024/10/21 4:04:04/

笔者介绍:姜雪伟IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。


AABB(Axis-Aligned Bounding Box)包围盒被称为轴对其包围盒。其在坐标系中的表示如下图:




在Cocos2d-x 3.x版本中,为开发者提供了AABB类,用于保存包围盒的最大顶点与最小顶点的信息,并且为每个Sprite3D对象提供了获取AABB包围盒的接口,在AABB类同时提供了判断碰撞检测的方法。有一点需要注意的是,AABB类中一开始保存的最大顶点与最小顶点的信息实际上是物体坐标系中的信息,在碰撞检测时需要将其转换成世界坐标系中的点,可通过AABB类中的transform()方法来完成。下面对AABB的源码进行分析:

#include "3d/CCAABB.h"NS_CC_BEGINAABB::AABB()
{reset();
}AABB::AABB(const Vec3& min, const Vec3& max)
{set(min, max);
}AABB::AABB(const AABB& box)
{set(box._min,box._max);
}//获取包围盒中心点坐标
Vec3 AABB::getCenter()
{Vec3 center;center.x = 0.5f*(_min.x+_max.x);center.y = 0.5f*(_min.y+_max.y);center.z = 0.5f*(_min.z+_max.z);return center;
}
//获取包围盒八个顶点信息
void AABB::getCorners(Vec3 *dst) const
{assert(dst);// 朝着Z轴正方向的面// 左上顶点坐标dst[0].set(_min.x, _max.y, _max.z);// 左下顶点坐标dst[1].set(_min.x, _min.y, _max.z);// 右下顶点坐标dst[2].set(_max.x, _min.y, _max.z);// 右上顶点坐标dst[3].set(_max.x, _max.y, _max.z);// 朝着Z轴负方向的面// 右上顶点坐标dst[4].set(_max.x, _max.y, _min.z);// 右下顶点坐标.dst[5].set(_max.x, _min.y, _min.z);// 左下顶点坐标.dst[6].set(_min.x, _min.y, _min.z);// 左上顶点坐标.dst[7].set(_min.x, _max.y, _min.z);
}
//判断两个包围盒是否碰撞
bool AABB::intersects(const AABB& aabb) const
{//就是各轴互相是否包含,(aabb 包含当前包围盒)||  (当前的包围盒包含 aabb)return ((_min.x >= aabb._min.x && _min.x <= aabb._max.x) || (aabb._min.x >= _min.x && aabb._min.x <= _max.x)) &&((_min.y >= aabb._min.y && _min.y <= aabb._max.y) || (aabb._min.y >= _min.y && aabb._min.y <= _max.y)) &&((_min.z >= aabb._min.z && _min.z <= aabb._max.z) || (aabb._min.z >= _min.z && aabb._min.z <= _max.z));
}//判断点和包围盒是否碰撞
bool AABB::containPoint(const Vec3& point) const
{if (point.x < _min.x) return false;if (point.y < _min.y) return false;if (point.z < _min.z) return false;if (point.x > _max.x) return false;if (point.y > _max.y) return false;if (point.z > _max.z) return false;returntrue;
}//生成一个新的包围盒同时容纳两个包围盒,新的包围盒的_min 各轴要是其他两个最小的那个,_max各轴要是其他两个最大的那个
void AABB::merge(const AABB& box)
{//计算新的最小点坐标_min.x = std::min(_min.x, box._min.x);_min.y = std::min(_min.y, box._min.y);_min.z = std::min(_min.z, box._min.z);//计算新的最大点坐标_max.x = std::max(_max.x, box._max.x);_max.y = std::max(_max.y, box._max.y);_max.z = std::max(_max.z, box._max.z);
}
//设置最大顶点与最小顶点
void AABB::set(const Vec3& min, const Vec3& max)
{this->_min = min;this->_max = max;
}
//顶点复位初始化信息
void AABB::reset()
{_min.set(99999.0f, 99999.0f, 99999.0f);_max.set(-99999.0f, -99999.0f, -99999.0f);
}
//检测坐标信息是否有误
bool AABB::isEmpty() const
{return _min.x > _max.x || _min.y > _max.y || _min.z > _max.z;
}
//由给定点坐标点重新确定最大最小的坐标向量
void AABB::updateMinMax(const Vec3* point, ssize_t num)
{for (ssize_t i = 0; i < num; i++){// 左边点.if (point[i].x < _min.x)_min.x = point[i].x;//最低点if (point[i].y < _min.y)_min.y = point[i].y;// 最远点.if (point[i].z < _min.z)_min.z = point[i].z;// 右边最大点if (point[i].x > _max.x)_max.x = point[i].x;// 最高点if (point[i].y > _max.y)_max.y = point[i].y;// 最近点if (point[i].z > _max.z)_max.z = point[i].z;}
}
//通过给定的变换矩阵对包围盒进行变换
void AABB::transform(const Mat4& mat)
{Vec3 corners[8];//保存包围盒八个顶点//朝向z轴正方向的面// 左-顶-前corners[0].set(_min.x, _max.y, _max.z);// 左-低-前corners[1].set(_min.x, _min.y, _max.z);// 右-低-前.corners[2].set(_max.x, _min.y, _max.z);// 右-顶-前corners[3].set(_max.x, _max.y, _max.z);//朝向z轴负方向的面// 右-顶-背面.corners[4].set(_max.x, _max.y, _min.z);// 右-底-背面.corners[5].set(_max.x, _min.y, _min.z);// 左-底-背面.corners[6].set(_min.x, _min.y, _min.z);// 左-顶-背面.corners[7].set(_min.x, _max.y, _min.z);//顶点变换for (int i = 0; i <8; i++)mat.transformPoint(&corners[i]);   //mat 是变换矩阵,变换&corners[i] 向量。//复位最大顶点最小顶点reset();//重新计算最大最小点信息updateMinMax(corners, 8);
}

当然在AABB类中也使用了矩阵转换函数,因为场景中的物体是可以移动旋转的,下面把AABB碰撞盒的变换函数给大家展示一下:

void AABB::transform(const Mat4& mat)
{Vec3corners[8];// 左-顶-前.corners[0].set(_min.x, _max.y, _max.z);// 左-底-前面.corners[1].set(_min.x, _min.y, _max.z);// 右-底-前.corners[2].set(_max.x, _min.y, _max.z);// 右-顶-前面.corners[3].set(_max.x, _max.y, _max.z);// 右-顶-背面.corners[4].set(_max.x, _max.y, _min.z);// 右-底-背面.corners[5].set(_max.x, _min.y, _min.z);// 左-底-背面.corners[6].set(_min.x, _min.y, _min.z);// 左-顶-背面.corners[7].set(_min.x, _max.y, _min.z);// 重新计算点的最大和最小值for (int i = 0; i <8; i++)mat.transformPoint(&corners[i]);reset();updateMinMax(corners, 8);
}

物体在游戏场景中并不是静止不动的,而是可以移动、旋转的,它自身的碰撞盒也要根据物体的变化而变换。在函数的最后是碰撞盒顶点的更新函数如下所示:

void AABB::updateMinMax(const Vec3*point, ssize_tnum)
{for (ssize_t i = 0; i < num; i++){// 左边最大点.if(point[i].x<_min.x)_min.x = point[i].x;// 最低的点.if(point[i].y<_min.y)_min.y = point[i].y;// 最远的点.if(point[i].z<_min.z)_min.z = point[i].z;// 右边最大点.if(point[i].x>_max.x)_max.x = point[i].x;// 最高的点.if (point[i].y>_max.y)_max.y = point[i].y;// 最近的点.if(point[i].z>_max.z)_max.z = point[i].z;}
}


AABB碰撞盒的每个顶点都需要随时更新变换位置,相比于OBB碰撞盒盒,AABB碰撞盒算法更简单,在程序上更容易实现,它应用在场景中的效果如下图:



总结:

AABB碰撞盒其实就是一个立方体,它在程序中计算效率比较高,但是在碰撞检测方面做得比较粗糙,比如一把水壶,它用AABB立方体包围后,会有很多空隙,检测效果并不是很理想,但是运算性能非常好。



http://www.ppmy.cn/news/254574.html

相关文章

小米游戏本如何关掉小米游戏盒子弹窗提醒

小米笔记本算是目前所有笔记本中性价比最高的&#xff0c;像我目前用的这个小米游戏本&#xff0c;八代i7 16g 1060&#xff0c;京东上是小米顶配&#xff0c;&#xff08;工作需要不要说我壕&#xff09;8.8k&#xff0c;性价比还是很高的&#xff08;对比水果笔记本&#xff…

java游戏破解版盒子,37游戏盒子-37游戏盒子最新版 v4.0.0.4 官方版

37游戏盒子 37游戏盒子最新版是一款提供游戏下载辅助软件。37游戏盒子最新版内置海量游戏而且不断更新&#xff0c;让玩家不必到处找游戏。而且还会自动去检测游戏所需要的软件和硬件环境&#xff0c;玩家只需轻松一点&#xff0c;就可以实现游戏的下载、安装、运行全部过程。 …

云计算机怎么打游戏,云即玩游戏盒怎么用 云即玩游戏盒电脑版使用教程

云即玩游戏盒聚合主流模拟器支持&#xff0c;跨多个终端平台&#xff0c;并支持云电脑游戏&#xff0c;是一款功能齐全的综合性PC游戏盒子。本站电脑版游戏软件已更新采用了云即玩游戏盒&#xff0c;有些小伙伴还不清楚怎么用&#xff0c;以下就介绍云即玩游戏盒电脑版使用教程…

云计算机怎么打游戏,云即玩游戏盒该如何使用 云即玩游戏盒电脑版的使用方法...

云即玩游戏盒是一款基于跨终端设备的游戏内容分享软件&#xff0c;致力于回归游戏可玩性.玩家在畅玩经典的PC游戏资源的同时&#xff0c;还可以大屏、多开用电脑玩全部手机游戏&#xff1b;实现低配置电脑可玩高配大型端游大作&#xff0c;随时随地即点即玩,帮助Steam平台玩家用…

UG SolidWorks CATIA proe 三维

单臂机减速机发动机减速机淀粉加工机塑料瓶脱模机水平斯特林发动机&#xff08;附工程图&#xff09;发动机-发动机307数控机床遥控器BRC工业钢丝矫直机食物切割机线刷机设备螺杆冷却机鼓风机平台发动机-发动机农业机械-粮食清理机械机起重机剥皮机&#xff08;附工程图&#x…

【JavaSE】Java(五十五):核心要点总结

文章目录 1. 为什么不允许静态方法访问非静态变量2. Java的内存模型3. 在Java中什么时候用重载什么时候用重写4. 举例说明什么情况下更倾向于用抽象类而不是接口5. 实例化对象有哪几种方式 1. 为什么不允许静态方法访问非静态变量 在Java中&#xff0c;静态方法属于类级别的方法…

如何在ImageSpan上面绘制文本?

简介&#xff1a;TextOnImageSpan 前阵子碰到一个需求&#xff1a;在文本中内嵌图标&#xff0c;并在图标上面绘制特定文本。很自然就会想到用SpannableString去实现&#xff0c;但经过一系列的研究捣鼓&#xff0c;发现根本就没有能在图标上绘制文本的span类&#xff0c;于是乎…

java最好用的浏览器_国内好的pc浏览器评测

结果分析&#xff1a;6款参测浏览器全部通过574项测试都是合格的&#xff0c;CSS标准升级到CSS 3各大浏览器也随之进行了更新&#xff0c;可见有足够的重视&#xff0c;基本功都很扎实。在测试中我们发现通过的速度不一样&#xff0c;QQ浏览器的响应时间最短&#xff0c;应该跟…