【UNITY教程 学习】2D Roguelike tutorial学习

2D Roguelike tutorial中的两个prefab
https://unity3d.com/cn/learn/tutorials/projects/2d-roguelike-tutorial

总述:此教程是中级教程,此篇博客旨在记录学习教程的过程中没弄懂的地方,针对每个地方会单独列段落、放官方文档链接和学习心得。

1. Setup and Assets

涉及内容:Prefab的Animation和AnimatorController、Sprite的切割和使用、GameObject的layer和sorting Layer。

2.Level Generation

涉及内容:关卡的自动生成(主要是代码的组织模式)
Writing the Board Manager

对代码结构的思考

        [Serializable]
        public class Count
        {
            public int minimum;             //Minimum value for our Count class.
            public int maximum;             //Maximum value for our Count class.


            //Assignment constructor.
            public Count (int min, int max)
            {
                minimum = min;
                maximum = max;
            }
        }


        public int columns = 8;                             //Number of columns in our game board.
        public int rows = 8;                                //Number of rows in our game board.
        public Count wallCount = new Count (5, 9);          //Lower and upper limit for our random number of walls per level.
        public Count foodCount = new Count (1, 5);          //Lower and upper limit for our random number of food items per level.
        public GameObject exit;                             //Prefab to spawn for exit.
        public GameObject[] floorTiles;                     //Array of floor prefabs.
        public GameObject[] wallTiles;                      //Array of wall prefabs.
        public GameObject[] foodTiles;                      //Array of food prefabs.
        public GameObject[] enemyTiles;                     //Array of enemy prefabs.
        public GameObject[] outerWallTiles;                 //Array of outer tile prefabs.

首先声明变量:
public变量,用于在对应的GameObject里面便于改动一些值(如columns、rows),这样可以提高代码的可重用性。

        private Transform boardHolder;                                  //A variable to store a reference to the transform of our Board object.
        private List <Vector3> gridPositions = new List <Vector3> ();   //A list of possible locations to place tiles.

两个private变量,boardHolder用于在Hierarchy中将instanciate的各种GameObject存放在其中,以免造成混乱(注意它是Transform属性的变量);而gridPositions则是声明了游戏中要用到的“点阵”。它们是private变量是因为它们不需要显示在UNITY的inspector中。

然后是各个函数
1)InitialiseList ()
将List gridPosition初始化为根据rows和columns决定的一个队列。

        //Clears our list gridPositions and prepares it to generate a new board.
        void InitialiseList ()
        {
            //Clear our list gridPositions.
            gridPositions.Clear ();

            //Loop through x axis (columns).
            for(int x = 1; x < columns-1; x++)
            {
                //Within each column, loop through y axis (rows).
                for(int y = 1; y < rows-1; y++)
                {
                    //At each index add a new Vector3 to our list with the x and y coordinates of that position.
                    gridPositions.Add (new Vector3(x, y, 0f));
                }
            }
        }

2)BoardSetup ()
对游戏区域的最外圈绘制outerWallTiles以及中间区域绘制floorTiles。
两点需要注意:①boardHolder = new GameObject (“Board”).transform;
这样可以构造一个新的GameObject。
②Instantiate (toInstantiate, new Vector3 (x, y, 0f), Quaternion.identity) as GameObject;
as GameObject 这小段是因为直接Instantiate的结果是Object,需要转换为GameObject。
③instance.transform.SetParent (boardHolder);
这样将新创建的GameObject放进Board里。

        //Sets up the outer walls and floor (background) of the game board.
        void BoardSetup ()
        {
            //Instantiate Board and set boardHolder to its transform.
            boardHolder = new GameObject ("Board").transform;

            //Loop along x axis, starting from -1 (to fill corner) with floor or outerwall edge tiles.
            for(int x = -1; x < columns + 1; x++)
            {
                //Loop along y axis, starting from -1 to place floor or outerwall tiles.
                for(int y = -1; y < rows + 1; y++)
                {
                    //Choose a random tile from our array of floor tile prefabs and prepare to instantiate it.
                    GameObject toInstantiate = floorTiles[Random.Range (0,floorTiles.Length)];

                    //Check if we current position is at board edge, if so choose a random outer wall prefab from our array of outer wall tiles.
                    if(x == -1 || x == columns || y == -1 || y == rows)
                        toInstantiate = outerWallTiles [Random.Range (0, outerWallTiles.Length)];

                    //Instantiate the GameObject instance using the prefab chosen for toInstantiate at the Vector3 corresponding to current grid position in loop, cast it to GameObject.
                    GameObject instance =
                        Instantiate (toInstantiate, new Vector3 (x, y, 0f), Quaternion.identity) as GameObject;

                    //Set the parent of our newly instantiated object instance to boardHolder, this is just organizational to avoid cluttering hierarchy.
                    instance.transform.SetParent (boardHolder);
                }
            }
        }

3)Vector3 RandomPosition ()
生成一个随机的有效位置,返回这个随机位置。
注意到它这里是先将随机的所有可能都在InitialiseList()中已经放在了gridPosition中了,然后使用一个randomIndex在所有可能中筛选出随机的个体,并且用RemoveAt方法将被随机出(被使用)
的个体从List中删除来确保不会重复。

        //RandomPosition returns a random position from our list gridPositions.
        Vector3 RandomPosition ()
        {
            //Declare an integer randomIndex, set it's value to a random number between 0 and the count of items in our List gridPositions.
            int randomIndex = Random.Range (0, gridPositions.Count);

            //Declare a variable of type Vector3 called randomPosition, set it's value to the entry at randomIndex from our List gridPositions.
            Vector3 randomPosition = gridPositions[randomIndex];

            //Remove the entry at randomIndex from the list so that it can't be re-used.
            gridPositions.RemoveAt (randomIndex);

            //Return the randomly selected Vector3 position.
            return randomPosition;
        }

4)LayoutObjectAtRandom (GameObject[] tileArray, int minimum, int maximum)
放置地图上随机物品(包括墙、食物和敌人)。

        //LayoutObjectAtRandom accepts an array of game objects to choose from along with a minimum and maximum range for the number of objects to create.
        void LayoutObjectAtRandom (GameObject[] tileArray, int minimum, int maximum)
        {
            //Choose a random number of objects to instantiate within the minimum and maximum limits
            int objectCount = Random.Range (minimum, maximum+1);

            //Instantiate objects until the randomly chosen limit objectCount is reached
            for(int i = 0; i < objectCount; i++)
            {
                //Choose a position for randomPosition by getting a random position from our list of available Vector3s stored in gridPosition
                Vector3 randomPosition = RandomPosition();

                //Choose a random tile from tileArray and assign it to tileChoice
                GameObject tileChoice = tileArray[Random.Range (0, tileArray.Length)];

                //Instantiate tileChoice at the position returned by RandomPosition with no change in rotation
                Instantiate(tileChoice, randomPosition, Quaternion.identity);
            }
        }

5)public void SetupScene (int level)
public主函数,用于被GameManager调用,根据所给level生成关卡。

        //SetupScene initializes our level and calls the previous functions to lay out the game board
        public void SetupScene (int level)
        {
            //Creates the outer walls and floor.
            BoardSetup ();

            //Reset our list of gridpositions.
            InitialiseList ();

            //Instantiate a random number of wall tiles based on minimum and maximum, at randomized positions.
            LayoutObjectAtRandom (wallTiles, wallCount.minimum, wallCount.maximum);

            //Instantiate a random number of food tiles based on minimum and maximum, at randomized positions.
            LayoutObjectAtRandom (foodTiles, foodCount.minimum, foodCount.maximum);

            //Determine number of enemies based on current level number, based on a logarithmic progression
            int enemyCount = (int)Mathf.Log(level, 2f);

            //Instantiate a random number of enemies based on minimum and maximum, at randomized positions.
            LayoutObjectAtRandom (enemyTiles, enemyCount, enemyCount);

            //Instantiate the exit tile in the upper right hand corner of our game board
            Instantiate (exit, new Vector3 (columns - 1, rows - 1, 0f), Quaternion.identity);
        }

小Tips

    ①Serializable 使该GameObject 中被Serializable修饰的属性类在GameObject里面显示为一个由该类的实例为父对象的一个树结构,且该类的不同实例共用此类中定义的变量名。
      使用Serializable使需要
      1.先using System然后再在属性类前写[Serializable]。
      2.直接在属性类前写[System.Serializable]。
    ②Random.Range(min,max)方法对于float型变量其min和max都是inclusive的;而对于int型变量则是min为inclusive、max为exclusive,所以需要注意。
阅读更多
换一批

没有更多推荐了,返回首页