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();
    }

 

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

posted @ 2018-11-30 12:12  黄进钿  阅读(1940)  评论(0编辑  收藏  举报