敌⼈
在我们正常的开发过程中,除了⼀些必要的射线检测,为了性能着想,我们都会尽可能的不使⽤unity的物理系统,因为unity为了让物体具备真实的运动效果,通常底层会有⼤量的算法,就⽐如collider的触发器,看似⼀句api就搞定的触发,实际上底层经过⼤量的运算,这种运算是⼗分消耗性能的。当然,如今我们处在性能过盛的时代,⼤多数⼈不必要考虑这⽅⾯的消耗,但是就我⽽⾔,性能这东西,能抠⼀点是⼀点,等到你的游戏成型之后,你就会有⼤惊喜,这也就是为什么Unity开发为什么⾮常注重优化的原因。项⽬往往到了中期,⽼⼤打⼿⼀呼,全部⼈⼿⾥活先停⼀停,搞⼀波优化再开⼯,这样的事情屡见不鲜。
我们在开发⼀些⽐较⼤型的3D游戏过程中,逻辑代码⾮常多,很多技能,位置的运算其实是很复杂的,如果每个⼩兵、防御塔之类的都⽤触发器,那么1000个⼩兵就是1000个触发器,这是很恐怖的,为了不增加CPU的压⼒,使得游戏更加流畅,我们就会⾃⼰使⽤公式去模拟⼀些物理⾏为。如果你只是开发⼀个⼩型的,休闲益智的⼩游戏,就没有必要纠结这些了,物理系统该上就上,这些游戏⼤多时间短任务急,内容也不多,⽤物理系统能给⾃⼰省不少事情。这⾥会写3种算法,个⼈改良的,感觉⽐较好⽤⽐较实⽤,所以记录下来。⼀、圆形攻击判断
圆形适⽤于360度⽆死⾓的检测,就像英雄联盟,⼀旦你进⼊防御塔的攻击范围,⽆论你是在哪个位置,打你没商量,这种算法是最简单的,也不需要很多的位置运算,逻辑就是以防御塔⾃⾝为圆⼼,触发攻击的范围是半径(这个⾃⼰设定,看各⾃的需求),计算圆⼼与英雄根节点的距离再跟半径对⽐,通常会有三个结果,圆上,圆内,圆外加上⾃⼰的逻辑即可,下图的逻辑就跟农药⼀样,当你到⼀定范围,先是警⽰,再进去就发动攻击。
1 ///
4 /// 英雄⽅位
5 /// 攻击距离 6 /// 警告距离
7 void RoundAttackLogic(Transform hero,float attackRadius,float warnningRadius) 8 {
9 float tmpDis = Vector3.Distance(hero.position, transform.position);10 if (tmpDis > attackRadius)11 {
12 if (tmpDis <= warnningRadius)13 {
14 //警告15 }16 }17 else18 {
19 //攻击20 }21 }
⼆、扇形攻击判断
扇形攻击是从圆形攻击演变⽽来,复杂了那么⼀丢丢。圆形攻击判断是360⽆死⾓的,那么策划同学过来了,说我现在不做防御塔了,我要做⼀个灯塔。好样的,那么这样再继续使⽤圆形攻击判断显然是不⾏的。⼤家都知道,灯塔是从⼀点出发,越往远处照射范围就越⼤,还有⼀点,就是灯塔照射范围存在⾓度,并不是周围全部扫描,就类似于⼀个扇形。算法逻辑还是先算距离,但是这⾥不同的是算扇形原点和英雄之间的向量,因为现在存在⾓度需求,我们必须⽤向量,因为向量有⼤⼩有⽅向,我们能算出⾓度,这样才符合需求。让灯塔的Z轴永远处于照射⾓度的中分线上,做灯塔圆⼼与英雄之间的向量AB,之后AB的单位向量与Z的单位向量做向量的点乘(不明⽩的去看⼀下向量的知识,由AB 点乘 Z = |AB| |Z| COSX 变形⽽来),这样可以得到两个向量之间的⾓度余弦值,通过反三⾓函数Acos得到弧度,之后弧度转⾓度得到向量之间的夹⾓,AB的模就是圆⼼距离英雄的距离,那么现在夹⾓有了,距离有了,就完事具备了。
1 /// 2 /// 扇形攻击逻辑判断 3 ///
4 /// 英雄坐标
5 /// 攻击⾓度 6 /// 攻击半径
7 void SectorAttack(Transform hero,float attackAngle,float attackRadius) 8 {
9 Vector3 tmpVec = hero.position - transform.position;
10 float cosValue = Vector3.Dot(tmpVec.normalized, transform.forward);11 float realAngle = Mathf.Acos(cosValue) * Mathf.Rad2Deg;
12 if (realAngle <= attackAngle / 2 && tmpVec.magnitude <= attackRadius)13 {
14 //攻击15 }16 }
三、矩形攻击判断
做完了上⾯那些,那么恭喜你,策划同学⼜该来找你了(哈哈哈哈哈哈),这次策划同学说我们不做防御塔,也不做灯塔了,我们改防御强吧。需求是这样的,墙⾯向外延伸发电,进到触犯范围就直接放电攻击。这下好了,扇形,圆形都不能⽤了,给你来⽅形了,半圆是不能代替矩形,这样就会导致我还没进⼊范围,你就开始攻击,这不合逻辑。于是就有了矩形攻击判定,思想是⼀样的,做向量,然后向量点乘,这⾥对⽐扇形的向量计算⼜是不⼀样的,注意了!还是前⾯⼀样,做墙根节点与英雄的向量AB,然后与墙前⽅的单位向量做点乘(这⾥为什么是前⽅呢,你见过哪个防御强是防着墙后⾃⼰⼈的...),注意啦!!!这⾥我没有说AB的单位向量!!!⽽是直接⽤AB向量来点乘!!!还是上⾯的公式变形,当两个向量点乘,其中⼀个向量为单位向量时,得到的是另外⼀条向量在这条单位向量⽅向上投影长,⽽矩形攻击正式⽤到这个概念。现在没有半径,那我们就算英雄是否墙前⽅规定的范围内,AB点乘墙的forward,得到AB在不在墙的防御范围内,也得到了在墙的前⽅还是后⽅,没错,这个点乘出来的值是有正有负的,前⾯说到,两个向量点乘,也能得到其夹⾓的余弦值,这也很好的反应了⾝前⾝后的问题,算出来的值,以墙的forward的0度,0-90 ⼤于0, 90-270⼩于0, 270-360⼤于0,这既是投影长也是余弦值。同
样的⽅法再⽤于左右两侧,就能知道到底在不在范围了。
1 ///
4 /// 英雄
5 /// 前⽅防御范围 6 /// 左右防御范围
7 void RectAttack(Transform hero, float forwardAttack, float sizeAttack) 8 {
9 Vector3 delteA = hero.position - transform.position;
10 float forwardDis = Vector3.Dot(delteA, transform.forward);11 if (forwardDis <= forwardAttack && forwardDis > 0)12 {
13 float bothSize = Mathf.Abs(Vector3.Dot(delteA, transform.right));//能进到这⾥说明前⽅满⾜条件,⽽左右两边正负都⾏,所以只判断距离14 if (bothSize < sizeAttack)15 {
16 //攻击17 }18 }19 }
最后,这⾥⾯都是⽤的向量的知识,我只能这么说,如果你做Unity开发,向量,矩阵是必须会的东西,不⽤深刻理解,但⾄少得明⽩什么意思,这些知识不⽌运⽤于⽅位坐标的运算,包括shader的顶点计算,像素计算都会使⽤到,不明⽩的建议补⼀下该⽅⾯的知识
因篇幅问题不能全部显示,请点此查看更多更全内容