美文网首页
Unity 2D下的A星寻路算法

Unity 2D下的A星寻路算法

作者: 逗逼熊本熊 | 来源:发表于2017-08-07 00:54 被阅读0次
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    using UnityTileMap;
    
    /// <summary>
    /// 玩家行为,这里是A星算法的关键核心所在
    /// </summary>
    public class PlayerBehaviour : MonoBehaviour
    {
        private TileMapBehaviour m_tileMap; //地图类     
        private LevelBehaviour m_levelBehaviour;  //地下城的每一层的层类
        private SceneFadeInOut m_sceneFadeInOut;    //Scene淡入淡出类
        private int m_x;      //地图width最大格子数
        private int m_y;      //地图height 最大格子数
        private bool m_walking;      //判断是否主角正在行走
    
        // Use this for initialization
        //初始化场景里面的各个对象和组件
        private void Start()
        {
            var tileMapGameObject = GameObject.Find("TileMap");      //找到TileMap这个GameObject;
            m_tileMap = tileMapGameObject.GetComponent<TileMapBehaviour>();    //获取Component
            if (m_tileMap == null)    
                Debug.LogError("TileMapBehaviour not found");
            m_levelBehaviour = tileMapGameObject.GetComponent<LevelBehaviour>(); 
            if (m_levelBehaviour == null)
                Debug.LogError("LevelBehaviour not found");
            m_sceneFadeInOut = GameObject.Find("SceneFader").GetComponent<SceneFadeInOut>();
            if (m_sceneFadeInOut == null)
                Debug.LogError("SceneFadeInOut not found");
        }
    
        // Update is called once per frame
       /// <summary>
       /// per frame check the input!
       /// </summary>
        private void Update()
        {
            ProcessInput();
        }
    
        private void ProcessInput()
        {
            //不能走到一半改变新的地点,必须等待当前走路完成,这一点需要修订
            if (m_walking)   
                return;
    
            if (Input.GetKeyDown(KeyCode.UpArrow))
                TryMoveTo(m_x, m_y + 1);
            if (Input.GetKeyDown(KeyCode.DownArrow))
                TryMoveTo(m_x, m_y - 1);
            if (Input.GetKeyDown(KeyCode.RightArrow))
                TryMoveTo(m_x + 1, m_y);
            if (Input.GetKeyDown(KeyCode.LeftArrow))
                TryMoveTo(m_x - 1, m_y);
            if (Input.GetMouseButtonDown(0))
            {
                // we can make this assumption since the TileMap is on position 0, 0
                // TODO create a world coordinate to tile coordinate lookup
    
                var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                var clicked = new Vector2Int((int)ray.origin.x, (int)ray.origin.y);
                m_walking = true;
                StartCoroutine(WalkTo(clicked, .2f));
            }
        }
    
        // TODO refactor into a reusable "TileWalker" behaviour
        private IEnumerator WalkTo(Vector2Int destination, float stepIntervalSeconds)
        {
            if (m_levelBehaviour.IsWalkeable(destination.x, destination.y))
            {
                var astar = new AStar(m_levelBehaviour);
                var path = astar.Search(new Vector2Int(m_x, m_y), destination).ToList();
                if (path.Count == 0)
                {
                    Debug.Log("No path found");
                    m_walking = false;
                    yield break;
                }
    
                foreach (var i in path)
                {
                    SetTilePosition(i.x, i.y);
                    yield return new WaitForSeconds(stepIntervalSeconds);
                }
            }
            m_walking = false;
        }
    
        private void TryMoveTo(int x, int y)
        {
            if (m_levelBehaviour.IsWalkeable(x, y))
                SetTilePosition(x, y);
        }
    
        public void SetTilePosition(int x, int y)
        {
            m_x = x;
            m_y = y;
            var tileBounds = m_tileMap.GetTileBoundsWorld(x, y);
            transform.position = new Vector3(tileBounds.xMin, tileBounds.yMin + 1, transform.position.z);
    
            // If we walk onto the stairs down...
            if (m_levelBehaviour.GetTile(m_x, m_y) == TileType.StairsDown)
                OnStairsDown();
        }
    
        private void OnStairsDown()
        {
            enabled = false;
            m_sceneFadeInOut.FadeOutThenIn(() =>
                {
                    m_levelBehaviour.StartLevel();
                    enabled = true;
                });
        }
    
        //  果然是A星算法
        //  TODO move this class to outer scope and refine logic specifically for grid
        private class AStarGrid : IAStar<Vector2Int>
        {
            public virtual int HeuristicCostEstimate(Vector2Int a, Vector2Int b)
            {
                return Math.Abs(a.x - b.x) + Math.Abs(a.y - b.y);
            }
    
            public virtual IEnumerable<Vector2Int> GetNeighbourNodes(Vector2Int node)
            {
                for (int y = -1; y <= 1; y++)
                {
                    for (int x = -1; x <= 1; x++)
                        yield return new Vector2Int(node.x + x, node.y + y);
                }
            }
        }
    
        private class AStar : AStarGrid
        {
            private readonly LevelBehaviour m_levelBehaviour;
    
            public AStar(LevelBehaviour levelBehaviour)
            {
                m_levelBehaviour = levelBehaviour;
            }
    
            public override IEnumerable<Vector2Int> GetNeighbourNodes(Vector2Int node)
            {
                // only return neighbour tiles that are walkable
                return base.GetNeighbourNodes(node).Where(x => m_levelBehaviour.IsWalkeable(x.x, x.y));
            }
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Unity 2D下的A星寻路算法

          本文链接:https://www.haomeiwen.com/subject/ntgkzttx.html