2018年12月18日 星期二

物件跟隨

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PetFlow : MonoBehaviour {

    public Transform player;
    public float maxDis = 5;

    private SmoothFollowerObj posFollow; // 控制位置平滑移動
    private SmoothFollowerObj lookFollow; // 控制朝向平滑轉換

    public Vector3 posistionVector; // 角色位置移動,方向向量
    public Vector3 lookVector; //角色朝向變化,朝向向量

    private Vector3 lastVelocityDir; // 上一次移動方向
    private Vector3 lastPost; // 之前移動目標位置

    void Start()
    {
        posFollow = new SmoothFollowerObj(0.5f, 0.5f);
        lookFollow = new SmoothFollowerObj(0.1f, 0.1f);
        posFollow.Update(transform.position, 0, true); // 初始位置
        lookFollow.Update(player.transform.position, 0, true);

        posistionVector = new Vector3(0, 0.5f, 1.7f);
        lookVector = new Vector3(0, 0, 1.5f);

        lastVelocityDir = player.transform.forward;
        lastPost = player.transform.position;
    }

    void Update()
    {
        float dis = Vector3.Distance(transform.position, player.position);

        if (dis > maxDis)
            PetMoveFlow();
    }

    // 物件移動
    void PetMoveFlow()
    {
        lastVelocityDir += (player.position - lastPost) * 5;
        lastPost = player.position;

        lastVelocityDir += player.transform.forward * Time.deltaTime;
        lastVelocityDir = lastVelocityDir.normalized;

        Vector3 horizontal = transform.position - player.position;
        Vector3 horizontal2 = horizontal;
        Vector3 vertical = player.up;
        Vector3.OrthoNormalize(ref vertical, ref horizontal);  // https://docs.unity3d.com/ScriptReference/Vector3.OrthoNormalize.html api

        // https://docs.unity3d.com/ScriptReference/Vector3-sqrMagnitude.html api
        if (horizontal.sqrMagnitude > horizontal2.sqrMagnitude)
            horizontal = horizontal2;

        transform.position = posFollow.Update(player.position + horizontal * Mathf.Abs(posistionVector.z)
            + vertical * posistionVector.y, Time.deltaTime);

        horizontal = lastVelocityDir;

        Vector3 look = lookFollow.Update(player.position + horizontal * lookVector.z
            - vertical * lookVector.y, Time.deltaTime);

        // https://docs.unity3d.com/ScriptReference/Quaternion.FromToRotation.html api
        transform.rotation = Quaternion.FromToRotation(transform.forward, look - transform.position) * transform.rotation;
    }
}

class SmoothFollowerObj
{
    private Vector3 targetPosistion; // 目標位置
    private Vector3 position; // 位置
    private Vector3 velocity;  // 速率
    private float smoothingTime; // 平滑時間
    private float prediction; // 預測

    public SmoothFollowerObj(float smoothingTime)
    {
        targetPosistion = Vector3.zero;
        position = Vector3.zero;
        this.smoothingTime = smoothingTime;
        prediction = 1;
    }

    public SmoothFollowerObj(float smoothingTime, float prediction)
    {
        targetPosistion = Vector3.zero;
        position = Vector3.zero;
        this.smoothingTime = smoothingTime;
        this.velocity = velocity;
    }

    // 更新位置資訊
    public Vector3 Update(Vector3 targetPosistionNew, float dataTime)
    {
        Vector3 targetvelocity = (targetPosistionNew - targetPosistion) / dataTime; // 獲取目標移動的方向向量
        targetPosistion = targetPosistionNew;

        float d = Mathf.Min(1, dataTime / smoothingTime);
        velocity = velocity * (1 - d) + (targetPosistion + targetvelocity * prediction - position) * d;

        position += velocity * Time.deltaTime;
        return position;
    }

    // 根據傳輸進來數據, 重置本地參數
    public Vector3 Update(Vector3 targetPosistionNew, float dataTime, bool rest) 
    {
        if (rest)
        {
            targetPosistion = targetPosistionNew;
            position = targetPosistionNew;
            velocity = Vector3.zero;

            return position;
        }

        return Update(targetPosistionNew, dataTime);
    }

    public Vector3 GetPosistion() { return position; }
    public Vector3 GetVelocity() { return velocity; }
}

物件跟隨路徑: 

程式碼來源: https://blog.csdn.net/BIGMAD/article/details/71698310

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EditorPathScript : MonoBehaviour {

    public Color rayColor = Color.red;
    public List path_objs = new List();
    Transform[] theArray;

    void OnDrawGizmos(){
        Gizmos.color = rayColor;
        theArray = GetComponentsInChildren();
        path_objs.Clear();
        foreach(Transform path_obj in theArray){
            if(path_obj != this.transform)
                path_objs.Add(path_obj);
        }

        for(int i = 0;i0){
                Vector3 previous = path_objs[i-1].position;
                Gizmos.DrawLine(previous,position);
                Gizmos.DrawWireSphere(position, 0.3f);
            }
        }
    }
}

























using UnityEngine;
using System.Collections;

public class FollowPath : MonoBehaviour {

    public bool StartFollow = false;
    public EditorPathScript PathToFollow;
    public int CurrentWayPointID = 0;
    public float Speed;//移动速度
    public float reachDistance = 0f;//里路径点的最大范围
    public string PathName;//跟随路径的名字
    private string LastName;
    private bool ChangePath = true;



    void Start () {

    }

    void Update () {
        if (!StartFollow)
            return;
        if (ChangePath)
        {
            PathToFollow = GameObject.Find(PathName).GetComponent();
            ChangePath = false;
        }
        if (LastName != PathName)
        {
            ChangePath = true;
        }
        LastName = PathName;




        float distance = Vector3.Distance(PathToFollow.path_objs[CurrentWayPointID].position, transform.position);
        //transform.Translate(PathToFollow.path_objs[CurrentWayPointID].position * Time.deltaTime * Speed, Space.Self);
        transform.position = Vector3.MoveTowards(transform.position, PathToFollow.path_objs[CurrentWayPointID].position, Time.deltaTime * Speed);
        if (distance <= reachDistance)
        {
            CurrentWayPointID++;
        }
        if (CurrentWayPointID >= PathToFollow.path_objs.Count)
        {
            CurrentWayPointID = 0;
        }
    }
}