主要基类解读:
通过移动物体类(Vehicle)中的属性:maxForce, maxSpeed,mass......等等
了解到此AI通过模拟物体所受外力来控制物体移动的速度大小以及方向。
涉及公式:
acceleration = steeringForce / mass; (a = F/m)
moveDistance =velocity *Time.fixedDeltaTIme;(s = v*t)
velocity +=acceleation * Time.fixedDeltaTime; (V +=at)
运算流程:
通过获取的steering类(选择的行为类)为给予Vehicle类(物体类)外力的作用计算出外力给予物体的加速度。
通过AILocomotion类通过初速度和以上获取的加速度来求得末速度。
将当前朝向和末速度进行球型插值运算,插值为damping(转向值)*Time.deltaTime获取下一帧物体的朝向。
注:因为最终速度方向为目标所在位置,所以通过当前朝向和末速度做球型插值运算,可以使问题改变朝向到目标物体的方向。
书本中案例代码类图
案例代码:
行为类:
public abstract class Steering : MonoBehaviour {
//表示每个操控力的权重
public float weight = 1;
//计算控制力的方法 由子类实现
public virtual Vector3 Force()
return new Vector3(0, 0, 0);
}
交通工具(进行移动的物品)类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Vehicle : MonoBehaviour {
private Steering[] steerings; //这个AI角色包含的操控行为列表;
public float maxSpeed = 10; //设置这个AI角色能等到的最大速度
public float maxForce = 100;//设置能涉及啊到这个AI角色的力的最大值
protected float sqrMaxSpeed; //最大速度平方
public float mass = 1; //物体质量
public Vector3 velocity; //角色速度
public float damping = 0.9f; //控制转向速度
public float computeInterval = 0.2f; //控制电脑刷新间隔
public bool isPlanar = true; //是否在二维平面上,如果是,计算两个GameObject得距离时,忽略Y值的不同
private Vector3 steeringForce; //计算得到的控制力;
protected Vector3 acceleration; //AI角色的加速度
private float timer; //计时器
protected void Start () {
steeringForce = new Vector3(0, 0, 0);
sqrMaxSpeed = maxSpeed * maxSpeed;
timer = 0;
steerings = GetComponents<Steering>();//获得AI角色所包含的操控行为列表;
}
// Update is called once per frame
void Update () {
timer += Time.deltaTime;
steeringForce = new Vector3(0, 0, 0);
//如果距离上次计算操控力的时间大于设定的时间间隔computeInterval;
//再次计算操控力
if(timer > computeInterval)
{
//将操控行为列表中的所有操控行为为对应的操控力进行带权重的求和;
foreach(Steering s in steerings)
{
if (s.enabled)
steeringForce += s.Force() * s.weight;
}
//使操控力不大于MaxForce;
steeringForce = Vector3.ClampMagnitude(steeringForce, maxForce);
//力除以质量,求出加速度;
acceleration = steeringForce / mass;
//重新计时
timer = 0;
}
}
}
AI运动类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AILocomotion : Vehicle {
//组件
private CharacterController controller;
//组件
private Rigidbody theRigidbody;
//AI每次的移动距离
private Vector3 moveDistance;
// Use this for initialization
void Start () {
controller = GetComponent<CharacterController>();
theRigidbody = GetComponent<Rigidbody>();
moveDistance = new Vector3(0, 0, 0);
base.Start();
}
// Update is called once per frame
void FixedUpdate () {
//计算速度
velocity += acceleration * Time.fixedDeltaTime;
//限制速度,要低于最大速度
if (velocity.sqrMagnitude > sqrMaxSpeed)
velocity = velocity.normalized * maxSpeed;
//计算AI角色的移动距离
moveDistance = velocity * Time.fixedDeltaTime;
//如果要求AI角色在平面上移动,那么将y置0
if (isPlanar)
{
velocity.y = 0;
moveDistance.y = 0;
}
//如果AI角色控制器添加成功,那么利用控制器使其移动
if (controller != null)
controller.SimpleMove(velocity);
//如果AI角色没有角色控制器,也没有Rigidbody
//或只有一者
else if (theRigidbody == null || theRigidbody.isKinematic)
transform.position += moveDistance;
else
theRigidbody.MovePosition(theRigidbody.position + moveDistance);
//****测试出现问题--过度旋转
//Damping转向速度默认0.9过慢 导致看起来过度旋转
if (velocity.sqrMagnitude > 0.00001)
{
//通过当前朝向与速度方向的插值,计算新的朝向
Vector3 newForward = Vector3.Slerp(transform.forward, velocity, damping * Time.deltaTime);
//将y设置为0;
if (isPlanar)
newForward.y = 0;
//将向前方向设置为新的朝向
transform.forward = newForward;
}
//播放行走动画
//gameObject.GetComponent<Animation>().Play("Walk");
}
}
参考书籍:《unity3d人工智能编程精粹》 王洪源等著