目的
此例子的AI效果就是要车子在一条连续的封闭的曲线上面不停的自己循环移动。
其它
对车子运动控制,请看上一篇http://www.cnblogs.com/zkzk945/p/5146474.html
基本思路
利用样条曲线(catmull-rom spline)将路径点通过插值形成连续的曲线,根据车子离开路径起始点的距离计算出车子在路径上的目标点,目标点决定了车子的朝向、油门、刹车。
target.position = circuit.GetRoutePoint(progressDistance + m_lookAheadForTargetOffset + m_lookAheadForTargetFactor*speed).pos; target.rotation = Quaternion.LookRotation(circuit.GetRoutePoint(progressDistance + m_lookAheadForTargetOffset + m_lookAheadForTargetFactor * speed).dir);
以上代码就是根据和初始点的距离计算目标点,包括了目标点的位置和朝向。
progressPoint = circuit.GetRoutePoint(progressDistance); //Debug.Log(progressDistance); Vector3 progressDelta = progressPoint.pos - transform.position; if (Vector3.Dot(progressDelta, progressPoint.dir) < 0) { progressDistance += progressDelta.magnitude*0.5f; }
以上代码是为了判断车子是否在目标点的前面,如果是,那么增加progressDistance,可以让target目标点定位到车子的前方去,这样target点就会在样条曲线上面循环移动,那么车子也会尾随其移动。
//遇到转角或者控制节点,减速处理 float desiredSpeed = m_carController.MaxSpeed; Vector3 delta = m_target.position - transform.position; float distanceCautiousFactor = Mathf.InverseLerp(m_cautiousMaxDistance, 0, delta.magnitude); float spinningAngle = m_rigidbody.angularVelocity.magnitude*m_cautiousMaxDistance; float cautiousnessRequired = Mathf.Max(Mathf.InverseLerp(0, m_cautiousMaxAngle, spinningAngle), distanceCautiousFactor); desiredSpeed = Mathf.Lerp(m_carController.MaxSpeed, m_carController.MaxSpeed*m_cautiousSpeedFactor, cautiousnessRequired);
以上代码是在转角点时对期望速度的处理,根据车子和目标点的距离、车子本身的角速度,求得一个紧张系数,当车子距离目标点越紧或者角速度越大,紧张系数也就越大,这样车子就需要减慢速度,以防止翻车。
Vector3 offsetTargetPos = m_target.position; offsetTargetPos += m_target.right* (Mathf.PerlinNoise(Time.time*m_lateralWanderSpeed, m_randomPerlin)*2 - 1)* m_lateralWanderDistance; Vector3 localTarget = transform.InverseTransformPoint(offsetTargetPos); float targetAngle = Mathf.Atan2(localTarget.x, localTarget.z) * Mathf.Rad2Deg; float steer = Mathf.Clamp(targetAngle * m_steerSensitivity, -1, 1); float accelBrakeSensitivity = (desiredSpeed < m_carController.CurrentSpeed) ? m_brakeSensitivity : m_accelSensitivity; float accle = Mathf.Clamp((desiredSpeed - m_carController.CurrentSpeed)*accelBrakeSensitivity, -1, 1); //Debug.Log(accle); //Debug.Log((1 - m_accelWanderAmount) + // (Mathf.PerlinNoise(Time.time*m_accelWanderSpeed, m_randomPerlin)*m_accelWanderAmount)); accle *= (1 - m_accelWanderAmount) + (Mathf.PerlinNoise(Time.time*m_accelWanderSpeed, m_randomPerlin)*m_accelWanderAmount); //Debug.Log(accle); m_carController.Move(steer, accle, accle, 0f);
首先对目标点进行柏林噪声随机,然后根据目标点算出方向盘的方向。然后根据期望速度和当前速度计算出油门或者刹车输入,最后手动传给控制汽车移动的函数,实现了汽车的自动化运行。
源码
http://git.oschina.net/zkzk945/CarAIDemo521