圆弧裁剪算法c++_一种简单的子弹反射算法

a4b64aff9a2eb35792b21e98d3ebd417.png

本文将介绍一种适用于2D、2.5D视角游戏的子弹弹射算法。游戏场景基于Tile的结构,每个障碍物都可以看做是Unit Tile,也可以称作地块

daa427bf14a064b0f5e8971e73ad5c04.png
来自《王牌坦克大战》

扫描阶段

根据输入线段作为对角线,构建一个矩形区域,该矩形区域内所有可反射的地块元素即为潜在的遮挡障碍。

下面介绍一下客户端的瞄准线关于扫描阶段的思路。

由于场景地图是由Tiled编辑器进行编辑的,所以可以将场景想象成一个大的棋盘。每个地块元素的位置只可能是位于棋盘单元格的中心位置。

首先,利用哈希结构存放地图中所有类型的地块数据。其中,Key值表示地块的格子坐标,Value值对应地块的详细数据集合。

采取类似“栅格化”的策略,将线段端点转换成「格子坐标」,在根据方向、矩形区域的长宽(格子长度)来进行栅格遍历,再通过格子坐标来去查找得到对应的地块元素类型,如果是符合反射需求的地块元素,则加入扫描结果集合中。

检测交点

编码裁剪算法

为地块障碍物以及周边区域进行「二进制编码」 黄色:地块障碍物 蓝色:上、下、左、右四个区域 绿色:左上、右上、左下、右下(相邻蓝色编码「按位与」计算可得)

798389b10aa818d812dd2f5fa3630905.png

分别计算线段两个端点相对于黄色地块的编码分布,可以快速判断不相交的情况:「编码按位与计算不等于0」

如果存在相交可能,根据线段起始点的编码,来获取黄色地块最邻近的两条边(线段),例如:

❝ 起始点位置的编码是0001,则只可能和左边相交 起始点位置的编码是0101,则可能和左边和下边相交

判断两线段相交

当确定输入线段与可能相交的边后,剩下要做的就是判断两条线段是否相交。

已知两向量 「a(x1, y1)」「b(x2, y2)」,它们的叉乘结果就是之间夹角的正弦乘以向量的模,即

因此,根据两向量叉乘结果的正负关系,可以推断出线段端点是在另一条线段端点的同侧还是异侧。

2dd5358e07bcd8575c3e0117904fd722.png

如上图,我们只需要确定c点和d点在线段ab的异侧并且a点和b点在线段cd的异侧,就可得出线段ab与线段cd相交的结论,判断依据就是「同时满足」

其中,叉乘的计算公式为:

计算交点坐标

本质上就是二元二次方程的求解,这里直接给出公式:

确定法线方向

由于地块的摆放是统一规整的,所以反射平面的法线向量也是固定的。

top(0,1)bottom(0,-1)left(-1,0)right(1,0)

理论上来说,入射向量与法线向量的夹角应该是小于90°的,即它们的夹角余弦应该大于0。利用向量的内积运算即可快速的计算出两「单位向量」的夹角余弦:

因此,在之前确定潜在相交边的时候,需要做一个检验判断,即入射方向与边的法线向量的内积,应该是大于0的,否则该边不属于合法边。

ebaacd5186e243c72a336fbf94d38184.png

如上图,线段与地块的交点恰好是地块矩形的某个顶点的话,该点实际上是同属于相邻的两边的,如果我们认为是与右边相交,而使用法线向量(0,1),计算出的反射结果就会是错误的。

「需要特别注意」,如果交点在矩形顶点上,并且入射方向与相邻两边的法线向量夹角都小于90°,取夹角余弦值(内积结果)更大的作为反射法线向量。如下图:

25cd433fe6e60bdb578d15d89603c5c6.png

交点在矩形的左下顶点,并且入射向量与左边与底边的法线向量夹角都小于90°,由于入射向量与底边的法线向量(0,-1)夹角余弦值(内积结果)更大,所以选择底边的法线作为反射法线。

计算反射方向

当已知了入射方向和法线方向,计算反射方向就尤为容易了。

9887ff533f2a31d28bf8039b5a2f97af.png

如上图,已知入射向量 「I」(由瞄准起始点和反射点求出),法线方向 「N」(单位向量),求反射向量 「R」

根据向量加法特性可知:

由于入射角等于反射角,根据等腰三角形特性可知:

所以,

其中,「S」 就是 「-I」 在向量 「N」 上的投影,根据投影公式可知:

最终的反射向量计算公式:

这里对向量「R」进行归一化,即可求出反射方向(单位向量)。接着,再根据反射点和反射方向作为新的起始点和入射方向,继续计算下一轮反射。新的线段长度,需要剔除之前的入射向量的长度,如果小于等于0,则不再进行反射计算。


参考引用

计算交点坐标

求反射向量

向量运算介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值