2016年5月11日 星期三

AI 追隨目標減速到達

---------------------------------------------------------------------
SteeringForArrive 類別(功能: 減速到達)
---------------------------------------------------------------------
using UnityEngine;
using System.Collections;

public class SteeringForArrive : Steering {

    public bool isPlaner = true;
    public float arrivalDistance = 0.3f;        // 距離到達
    public float characterRadius = 1.2f;        // 角色半徑
    public float showDownDistance;
    public GameObject target;
    private Vector3 desiredVelocity;
    private Vehicle vehicle;
    private float maxSpeed;

    void Start() {

        vehicle = GetComponent<Vehicle>();
        maxSpeed = vehicle.maxSpeed;
        isPlaner = vehicle.isPlanar;
    }

    public override Vector3 Force()
    {
        Vector3 toTarget = target.transform.position - transform.position;
        Vector3 desiredVelocity;
        Vector3 returnForce;

        if (isPlaner)
            toTarget.y = 0;
        float distance = toTarget.magnitude;

        // 如果AI與目標距離之間大於設定的距離減速半徑
        if (distance > showDownDistance) {
            // 預期速度AI與目標之間的距離
            desiredVelocity = toTarget.normalized * maxSpeed;
            // 傳回預期速度與目前速度差
            returnForce = desiredVelocity - vehicle.velocity;
        }else{
            // 計算預期速度,並傳回預期速度與目前速度差
            desiredVelocity = toTarget - vehicle.velocity;
            // 傳回預期速度與目前速度的差
            returnForce = desiredVelocity - vehicle.velocity;
        }

        return returnForce;
    }

    void OnDrawGizmos() {
        // 繪製圓形圖示
        Gizmos.DrawWireSphere(target.transform.position, showDownDistance);
    }
}

AI 基本追隨物件 (非閃避障礙物)

之前程式搭配連結 
-----------------------------------------------------------------
SteeringForSeek  類別(功能: 追隨)
-----------------------------------------------------------------
using UnityEngine;
using System.Collections;

public class SteeringForSeek : Steering {

    public GameObject target;           // 需要尋找的目標物體
    private Vector3 desiredVelocity;    // 預期速度
    private Vehicle vehicle;            // AI數據
    private float maxSpeed;             // 最大速度
    private bool isPlanar;              // 二維平面上

    void Start() {
        // Vehicle資訊,取得AI最大速度及二維平面
        vehicle = GetComponent<Vehicle>();
        maxSpeed = vehicle.maxSpeed;
        isPlanar = vehicle.isPlanar;
    }

    public override Vector3 Force()
    {
        desiredVelocity = (target.transform.position - transform.position).normalized * maxSpeed;
        if (isPlanar)
            desiredVelocity.y = 0;
        return (desiredVelocity - vehicle.velocity);
    }
}

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;
            }
        }
    }
}
-----------------------------------------------------------------
結果圖:
-----------------------------------------------------------------