zoukankan      html  css  js  c++  java
  • unity 四边形网格下的移动范围显示

     

    unity 四边形网格下的移动范围显示

    先上效果图,移动力三点,绿色格子消耗一点,棕色格子消耗两点,浅白色是移动范围。

    移动力和消耗点数都可以自定义,下面就开始程序部分的说明,格子是用unity的tilemap去做的,至于怎么刷格子,这里就不说了。

     

    定义一个List,用来存放移动方向。

     

        private static readonly List<Vector3Int> tileOffset = new List<Vector3Int>()
        {
            Vector3Int.down,Vector3Int.right,Vector3Int.up,Vector3Int.left
        };

     

    定义一个Dictionary,用来存格子的消耗点数。

        private static readonly Dictionary<string, int> tileMoveCostDictionary = new Dictionary<string, int>()
        {
            { "Base_Green",1},{"Base_Brown",2 }
        };

    定义三个List,分别用来储存移动范围内格子的tilemap坐标、高于一点消耗的格子的tilemap坐标、高消耗格子当前已经消耗点数(每回合+1点)。

        private List<Vector3Int> movePointRangeList;
        private List<Vector3Int> blockingPointList;
        private List<int> blockingRemainList;

     tilemap坐标如下。

     

    先初始化List,还有定义一个Camera并初始化,用于后面2D射线检测格子。

        void Start()
        {
            mainCamera = Camera.main;
            movePointRangeList = new List<Vector3Int>();
            blockingPointList = new List<Vector3Int>();
            blockingRemainList = new List<int>();
        }

    给白色格子加上BoxCollider2D并加上tag “Infantry”,给Tilemap加上TilemapCollider2D并加上tag “TileMap”,下面是在update里2D射线检测点击的是白色格子还是地图上的格子。

        // Update is called once per frame
        void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                raycastHit2D = Physics2D.Raycast(mainCamera.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
    
                if (raycastHit2D.collider != null)
                {
                    switch (raycastHit2D.transform.tag)
                    {
                        case "Infantry":
                            currentSelect = raycastHit2D.transform;
    
                            if (movePointObjParent.childCount == 0)
                            {
                                DisplayMovementRange(gridLayout.WorldToCell(raycastHit2D.point));
                            }
                            else
                            {
                                currentSelect = null;
    
                                CleanMovementRangeObj();
                            }
                            break;
                        case "TileMap":
                            if (currentSelect != null)
                            {
                                currentSelect.localPosition = gridLayout.CellToLocal(gridLayout.WorldToCell(raycastHit2D.point));
    
                                currentSelect = null;
    
                                CleanMovementRangeObj();
                            }
                            break;
                    }
                }
            }
        }

    再定义一些变量,tilemap和gridlayout就不说了即当前使用的tilemap,movePointPrefab是浅白色格子的prefab,其实就是一个sprite然后做成预制体,movePointObjParent是存放移动范围的GameObject,movementPoints表示移动点数,currentSelect表示当前选中的白色格子,考虑到可能有多个移动对象,所以这里这么处理。

        public Tilemap tilemap;
        public GridLayout gridLayout;
    
        public GameObject movePointPrefab;
        public Transform movePointObjParent;
    
        public int movementPoints;
    
        private Transform currentSelect;

    获取移动范围内的格子的函数如下,遇到高消耗格子就存到blockingPointList里面,然后下一次点数计算时,就把该格子对应响应点数+1,如果小于前面Dictionary里定义的消耗点数,继续放进队列里,直到不满足条件,才让该格子的四个方向进行探索。

        private void DisplayMovementRange(Vector3Int startPos)
        {
            Queue<Vector3Int> currentQueue = new Queue<Vector3Int>();
            Queue<Vector3Int> nextQueue = new Queue<Vector3Int>();
    
            Vector3Int currentPoint;
            Vector3Int nextPoint;
            int value;
    
            nextQueue.Enqueue(startPos);
    
            for (int i = 0; i < movementPoints; i++)
            {
                currentQueue = new Queue<Vector3Int>(nextQueue);
                nextQueue.Clear();
    
                while (currentQueue.Count > 0)
                {
                    currentPoint = currentQueue.Dequeue();
    
                    if (blockingPointList.Contains(currentPoint))
                    {
                        int index = blockingPointList.IndexOf(currentPoint);
                        value = GetTileCost(currentPoint);
    
                        blockingRemainList[index]++;
                        if (blockingRemainList[index] < value)
                        {
                            nextQueue.Enqueue(currentPoint);
                            continue;
                        }
                    }
    
                    //4 Direction
                    for (int j = 0; j < 4; j++)
                    {
                        nextPoint = currentPoint + tileOffset[j];
    
                        if (IsNextPointInRange(nextPoint))
                        {
                            if (!movePointRangeList.Contains(nextPoint))
                            {
                                value = GetTileCost(nextPoint);
    
                                movePointRangeList.Add(nextPoint);
                                nextQueue.Enqueue(nextPoint);
    
                                if (value > 1 && !blockingPointList.Contains(nextPoint))
                                {
                                    blockingPointList.Add(nextPoint);
                                    blockingRemainList.Add(0);
                                }
                            }
                        }
                    }
                }
            }
    
            CreateMovementRangeObj();
        }

    其他的辅助函数如下。

        private int GetTileCost(Vector3Int tilePos)
        {
            int value;
            if (tileMoveCostDictionary.TryGetValue(tilemap.GetTile(tilePos).name, out value))
            {
                return value;
            }
            else
            {
                print("Cannot Find Tile Cost");
                return -1;
            }
        }
    
        private bool IsNextPointInRange(Vector3Int nextPoint)
        {
            return nextPoint.x >= 0 && nextPoint.x < 16 && nextPoint.y >= 0 && nextPoint.y < 16;
        }
    
        private void CreateMovementRangeObj()
        {
            foreach (Vector3Int item in movePointRangeList)
            {
                GameObject obj = Instantiate(movePointPrefab, movePointObjParent);
                obj.transform.localPosition = gridLayout.CellToLocal(item);
            }
    
            movePointRangeList.Clear();
        }
    
        private void CleanMovementRangeObj()
        {
            if (movePointObjParent.childCount == 0)
                return;
    
            for (int i = 0; i < movePointObjParent.childCount; i++)
            {
                Destroy(movePointObjParent.GetChild(i).gameObject);
            }
    
            blockingPointList.Clear();
            blockingRemainList.Clear();
        }

    欢迎交流,转载注明出处:)

  • 相关阅读:
    Tomcat修改端口号
    如何修改localhost为自己指定的域名
    Tomcat启动时启动窗口中文乱码问题的解决方案
    Java Web 项目jsp页面无法加载样式
    vue 父传子(通过属性传递)
    vue 父传子 讲解
    表白小爱心
    响应式开发
    组件的重复调用
    reduce
  • 原文地址:https://www.cnblogs.com/JinT-Hwang/p/10043425.html
Copyright © 2011-2022 走看看