A* Pathfinding Project (Unity A*尋路外掛程式) 使用教程

來源:互聯網
上載者:User

標籤:

Unity4.6 後續版本都已經內建了尋路AI了,之前的文章有介紹

Unity3d 尋路功能 介紹及項目示範

然而兩年來項目中一直使用的是 A* Pathfinding 這個外掛程式的,所以抽時間來寫下這個外掛程式的簡單使用。

根據遊戲的類型,使用到的外掛程式功能可能會不一樣,我這裡只介紹最簡單的,也是使用的最多的簡單尋路。複雜的如跟隨、動態,都有對應的例子來學習。

我也一直都沒有去看……

轉自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

下面是動態圖,藉助 A* 外掛程式,編寫很少的代碼就可以做到尋路。


1、建立情境

在情境中添加一些Cube 作為障礙物 Obstacles,添加一個 Capsule 作為Player,然後添加一個Plane 作為地面,再添加一個Plane,作為斜坡測試。



在建立一個GameObject,改名為 A* ,添加A Star Path (Path finder) 組件。


2、編輯情境,指定障礙物

A* 外掛程式中,是根據 Layer 來判斷障礙物的,所以我們要把 作為障礙物的 Cubes 都設定到 Obstacle 這一個Layer。


然後給我們的地板,設定Layer 為 Ground ,兩塊地板都是

轉自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

3、產生尋路網格

選中 A* ,在Inspector 中,展開 。查看下面的面板。


中,

黑色箭頭所指是寬高,這裡的寬高,是指格子的數量。這裡用到的就是 A* 的格子尋路。

調整寬高,覆蓋整個Plane。

紅色箭頭所指,是左上、右上、左下、右下、中心 四個點,選中其中一個點,就可以調整這個點的位置。

選中中心,點擊藍色箭頭所指的 Snap Size,會根據中心的位置來自動對齊。



繼續設定。

紅框中的Collision Testing,是產生 禁止通過 格子的。

因為我們的 Cubes 是障礙物,所以在 Mask 中選擇 Cubes 所在的Layer - Obstacles。


黃色框中的Height Testing 是用來 讓尋路節點 與 Ground 進行檢測的,比如要爬坡的時候就需要檢測高度。


設定完成後,點擊Scan,就會產生尋路網格。

轉自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

4、編寫尋路 AI 代碼

產生尋路網格之後,我們在代碼中就可以使用 A* 來進行尋路了。

首先在 Player 這個 Capsule 上添加Seeker 組件。

然後建立指令碼 AStarPlayer.cs 作為測試代碼。


在代碼中,首先我們從 螢幕發射射線,來定位目標位置。

然後使用 Seeker 來開始產生最短路徑。

Seeker產生路徑成功後,會把每一個節點的位置儲存在 List中。

我們按照順序讀取 List 中的位置,位移Player 到對應的位置,就完成了尋路。


下面是完整代碼:

using UnityEngine;using System.Collections;using Pathfinding;public class AStarPlayer : MonoBehaviour {    //目標位置;     Vector3 targetPosition;    Seeker seeker;    CharacterController characterController;    //計算出來的路線;     Path path;    //移動速度;     float playerMoveSpeed = 10f;    //當前點    int currentWayPoint = 0;    bool stopMove = true;    //Player中心點;    float playerCenterY = 1.0f;// Use this for initializationvoid Start ()     {        seeker = GetComponent<Seeker>();        playerCenterY = transform.localPosition.y;}    //尋路結束;    public void OnPathComplete(Path p)    {        Debug.Log("OnPathComplete error = "+p.error);        if (!p.error)        {            currentWayPoint = 0;            path = p;            stopMove = false;        }        for (int index = 0; index < path.vectorPath.Count; index++)        {            Debug.Log("path.vectorPath["+index+"]="+path.vectorPath[index]);        }    }// Update is called once per framevoid Update ()     {        if (Input.GetMouseButtonDown(0))        {            RaycastHit hit;            if (!Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 100))            {                return;            }            if (!hit.transform)            {                return;            }            targetPosition = hit.point;// new Vector3(hit.point.x, transform.localPosition.y, hit.point.z);            Debug.Log("targetPosition=" + targetPosition);            seeker.StartPath(transform.position, targetPosition,OnPathComplete);        }}    void FixedUpdate()    {        if (path == null || stopMove)        {            return;        }        //根據Player當前位置和 下一個尋路點的位置,計算方向;        Vector3 currentWayPointV = new Vector3(path.vectorPath[currentWayPoint].x, path.vectorPath[currentWayPoint].y + playerCenterY, path.vectorPath[currentWayPoint].z);        Vector3 dir = (currentWayPointV - transform.position).normalized;        //計算這一幀要朝著 dir方向 移動多少距離;        dir *= playerMoveSpeed * Time.fixedDeltaTime;        //計算加上這一幀的位移,是不是會超過下一個節點;        float offset = Vector3.Distance(transform.localPosition, currentWayPointV);        if (offset < 0.1f)        {            transform.localPosition = currentWayPointV;            currentWayPoint++;            if (currentWayPoint == path.vectorPath.Count)            {                stopMove = true;                currentWayPoint = 0;                path = null;            }        }        else        {            if (dir.magnitude > offset)            {                Vector3 tmpV3 = dir * (offset / dir.magnitude);                dir = tmpV3;                currentWayPoint++;                if (currentWayPoint == path.vectorPath.Count)                {                    stopMove = true;                    currentWayPoint = 0;                    path = null;                }            }            transform.localPosition += dir;        }    }}

至此簡單的尋路了。


在A* 的Example 中,有很多個例子。

最簡單的尋路指令碼寫法是 直接繼承 AIPath 。

下面建立一個 指令碼 PlayerAI.cs 繼承 AIPath 來作為測試

using UnityEngine;using System.Collections;using Pathfinding.RVO;namespace Pathfinding{    [RequireComponent(typeof(Seeker))]    [RequireComponent(typeof(CharacterController))]    public class PlayerAI : AIPath    {        /** Minimum velocity for moving */        public float sleepVelocity = 0.4F;        /** Speed relative to velocity with which to play animations */        public float animationSpeed = 0.2F;        /** Effect which will be instantiated when end of path is reached.         * \see OnTargetReached */        public GameObject endOfPathEffect;        public new void Start()        {            //Call Start in base script (AIPath)            base.Start();        }        /** Point for the last spawn of #endOfPathEffect */        protected Vector3 lastTarget;        public override void OnTargetReached()        {            if (endOfPathEffect != null && Vector3.Distance(tr.position, lastTarget) > 1)            {                GameObject.Instantiate(endOfPathEffect, tr.position, tr.rotation);                lastTarget = tr.position;            }        }        public override Vector3 GetFeetPosition()        {            return tr.position;        }        protected new void Update()        {            if (Input.GetMouseButtonDown(0))            {                RaycastHit hit;                if (!Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 100))                {                    return;                }                if (!hit.transform)                {                    return;                }                target.localPosition = hit.point;            }            //Get velocity in world-space            Vector3 velocity;            if (canMove)            {                //Calculate desired velocity                Vector3 dir = CalculateVelocity(GetFeetPosition());                //Rotate towards targetDirection (filled in by CalculateVelocity)                RotateTowards(targetDirection);                dir.y = 0;                if (dir.sqrMagnitude > sleepVelocity * sleepVelocity)                {                    //If the velocity is large enough, move                }                else                {                    //Otherwise, just stand still (this ensures gravity is applied)                    dir = Vector3.zero;                }                if (this.rvoController != null)                {                    rvoController.Move(dir);                    velocity = rvoController.velocity;                }                else                    if (navController != null)                    {#if FALSEnavController.SimpleMove (GetFeetPosition(), dir);#endif                        velocity = Vector3.zero;                    }                    else if (controller != null)                    {                        controller.SimpleMove(dir);                        velocity = controller.velocity;                    }                    else                    {                        Debug.LogWarning("No NavmeshController or CharacterController attached to GameObject");                        velocity = Vector3.zero;                    }            }            else            {                velocity = Vector3.zero;            }        }    }}

代碼量少,但是不如自己寫的直觀。


兩種不同的指令碼都可以實現尋路效果。


樣本項目打包下載:

http://pan.baidu.com/s/1hsm6YNi








A* Pathfinding Project (Unity A*尋路外掛程式) 使用教程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.