2016年5月10日 星期二

Unity AI 基本移動

-----------------------------------------------------------------
Steering 類別(功能: 各種行為)
-----------------------------------------------------------------
using UnityEngine;
using System.Collections;

public abstract class Steering : MonoBehaviour {

    public float weight = 1; // 表示每個控制力的權數

    // 計算操控力的方法,由衍生類別實現
    public virtual Vector3 Force() {
        return new Vector3(0,0,0);
    }
}
-----------------------------------------------------------------
Vehicle 類別(功能: AI 設定)
-----------------------------------------------------------------
using UnityEngine;
using System.Collections;

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;                                      // AI 品質
    public Vector3 velocity;                                    // AI速度
    public float damping = 0.9f;                                // 轉制轉向時的速度
    public float computeInterval = 0.2f;                        // 操作力的計算時間
    public bool isPlanar = true;                                // 是否在二維平面上,如果是計算兩個遊戲物件的距離
    private Vector3 steeringForce;                              // 計算獲得操作力
    protected Vector3 acceleration;                             // AI 加速度
    private float timer;                                        // 計時器

    protected void Start() {

        steeringForce = new Vector3(0,0,0);
        sqrMaxSpeed = maxSpeed * maxSpeed;
        timer = 0;

        // 獲得AI包含操作行為列表
        steerings = GetComponents<Steering>();                   
    }

    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;
        }
    }
}


-----------------------------------------------------------------
AILocomotion 類別(功能: 移動)
-----------------------------------------------------------------
using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(CharacterController))]
public class AILocomotion : Vehicle {

    private CharacterController controller;                     // AI 角色控制器
    private Rigidbody theRigidbody;                             // AI Rigidbody
    private Vector3 moveDiestance;                              // AI 每次移動距離

    void Start() {
        controller = GetComponent<CharacterController>();
        theRigidbody = GetComponent<Rigidbody>();
        moveDiestance = new Vector3(0, 0, 0);

        base.Start();
    }

    void FixedUpdate() {

        // 計算數度
        velocity += acceleration * Time.fixedDeltaTime;
        
        // 限制速度,要低於最大速度
        if (velocity.sqrMagnitude > sqrMaxSpeed)
            velocity = velocity.normalized * maxSpeed;
        
        // 計算AI移動距離
        moveDiestance = velocity * Time.fixedDeltaTime;

        // 如果AI平面上,Y將為0
        if (isPlanar) {
            velocity.y = 0;
            moveDiestance.y = 0;
        }

        // 如果 AI 增加角色控制器,那麼利用角色控制器使其移動
        if (controller != null)
            controller.SimpleMove(velocity);
        // AI角色沒有Rigidbody || 但是要由動力學的方式控制它的運動
        else if (theRigidbody.Equals(null) || theRigidbody.isKinematic)
            transform.position += moveDiestance;
        // 用Rigidbody控制AI角色的運動
        else
            theRigidbody.MovePosition(theRigidbody.position + moveDiestance);

        //更新朝向,如果速度大於一個設定值(為了防止抖動)
        if (velocity.sqrMagnitude > 0.00001f) {
            // 透過目前朝向與速度方向的內插,計算新的朝向
            Vector3 newForward = Vector3.Slerp(transform.forward, velocity, damping * Time.deltaTime);
            // 將y設定為0
            if (isPlanar) {
                newForward.y = 0;
            }
        }
    }
}
-----------------------------------------------------------------
結果圖:
-----------------------------------------------------------------




沒有留言:

張貼留言