赞
踩
在rts游戏中会出现大量单位集体行动,或者设置守卫自动巡逻这种,需要在服务端控制其移动但又不想让他们移动时重叠在一起,所以需要一个规避算法
AI流程如下
public Vector3 Evade(Target targets) { // 加速度 Vector3 acceleration = Vector3.zero; // 首先找到角色将要碰撞的目标 // 第一次碰撞时间 float shortestTime = float.PositiveInfinity; // 第一个会碰撞的目标以及其他我们需要且可以避免重新计算的数据 MovementAIRigidbody firstTarget = null; // 最小间隔 float firstMinSeparation = 0; // 距离 float firstDistance = 0; // 半径 float firstRadius = 0; // 相对位置 Vector3 firstRelativePos = Vector3.zero; // 相对速度 Vector3 firstRelativeVel = Vector3.zero; //从敌人列表里面找 foreach (targetType tar in targets) { // 计算碰撞时间 Vector3 relativePos = rb.Position - tar .rPosition; Vector3 relativeVel = rb.Velocity - tar .Velocity; float distance = relativePos.magnitude; float relativeSpeed = relativeVel.magnitude; //速度相等pass if (relativeSpeed == 0) { continue; } /// 相对位置在相对速度上的投影除以相对速度 // 点积的几何意义,a·b 为a在b上的投影的长度乘以b的长度,所以在这里除以相对速度模长的平方,所得即为以当前相对速度,移动相对位置在相对速度的投影的模长距离所需要的时间 float timeToCollision = -1 * Vector3.Dot(relativePos, relativeVel) / (relativeSpeed * relativeSpeed); /* 检查它们是否会相撞*/ // 间隔 Vector3 separation = relativePos + relativeVel * timeToCollision; // 最小间隔 float minSeparation = separation.magnitude; // 判断是否满足需要规避的条件 if (minSeparation > rb.Radius + r.Radius + distanceBetween) { continue; } /*检查它是否是最短的,即最近的,最迫切需要规避的*/ if (timeToCollision > 0 && timeToCollision < shortestTime) { shortestTime = timeToCollision; firstTarget = r; firstMinSeparation = minSeparation; firstDistance = distance; firstRelativePos = relativePos; firstRelativeVel = relativeVel; firstRadius = r.Radius; } } /* 计算转向*/ /*如果没有目标就退出*/ if (firstTarget == null) { return acceleration; } /* * 如果即将碰撞,或者已经碰撞了,那么根据当前位置进行转向,减速为主 */ if (firstMinSeparation <= 0 || firstDistance < rb.Radius + firstRadius + distanceBetween) { acceleration = rb.ColliderPosition - firstTarget.ColliderPosition; (我在使用中发现某些情况会卡住方向完全相同的单位移动,目前的解决方案是手动加一个偏移) (acceleration.z += 0.3)// 手动偏移 } /*否则计算计算未来的规避*/ else { // 因为前面计算的时间是一个负值,这样不论如何两个向量相减都会给被减向量产生一个向侧面的分量,这样的加速度就可以使对象出现规避动作,除方向完全相同的情况,这种情况同个负加速度解决。如果需要绕开时,最好更改寻路逻辑 acceleration = firstRelativePos + firstRelativeVel * shortestTime; } /*避免目标*/ acceleration.Normalize(); // maxAcceleration一个预先设定好的加速度,可以根据需求更改加速度大小 acceleration *= maxAcceleration; return acceleration; } } // 简单的寻路(直线寻找) public void Seek(Target target) { // 加速度上限 max_acceleration = 10 Vector3 velocity = tarhetPosition - selfPoision; float distance = velocity.magnitude(); if(distance < (自己给定的停止距离) { 加速度置零 } velocity.normalize(); acceleration = velocity - self.velocity; if (加速度过大的时候限制其上限) { acceleration.normalize(); acceleration *= max_acceleration; } return acceleration }
这是在GitHub上面项目中学习到拆解出来的,原项目位置:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。