< Return to Video

2D Roguelike 4 of 14 : Board Manager

  • 0:03 - 0:06
    In this video we're going to create our
  • 0:06 - 0:08
    board manager script, which is going to
  • 0:08 - 0:11
    procedurally generate our levels
  • 0:11 - 0:15
    so that they're different each time the player plays.
  • 0:15 - 0:18
    We're going to start by creating two empty scripts,
  • 0:18 - 0:22
    our board manager and game manager scripts.
  • 0:22 - 0:25
    We'll choose Create - C# Script.
  • 0:26 - 0:28
    Call the first one BoardManager.
  • 0:31 - 0:33
    Call the second GameManager.
  • 0:34 - 0:36
    We'll also create an empty game object
  • 0:36 - 0:38
    called GameManager.
  • 0:44 - 0:47
    Let's start by adding our level generation code
  • 0:47 - 0:48
    to BoardManager.
  • 0:48 - 0:50
    We'll open it in MonoDevelop.
  • 0:51 - 0:53
    The BoardManager script is going
  • 0:53 - 0:55
    to lay out our randomly
  • 0:55 - 0:58
    generated levels for us each time
  • 0:58 - 1:00
    the player starts a new level
  • 1:00 - 1:03
    based on the current level number.
  • 1:04 - 1:06
    The first thing that we're going to add is a
  • 1:06 - 1:09
    namespace declaration using System.
  • 1:09 - 1:11
    We're going to do this so that we can use the
  • 1:11 - 1:13
    serialisable attribute.
  • 1:13 - 1:16
    Using serialisable just allows us to
  • 1:16 - 1:18
    modify how variables will appear
  • 1:18 - 1:20
    in the inspector and in the editor
  • 1:20 - 1:24
    and to show and hide them using a fold out.
  • 1:25 - 1:26
    We're also going to add
  • 1:26 - 1:28
    using Systems.Collections.Generic
  • 1:28 - 1:30
    so that we can use lists.
  • 1:31 - 1:32
    Finally we're going to include
  • 1:32 - 1:34
    using Random and we're going to
  • 1:34 - 1:38
    set that to equal UnityEngine.Random.
  • 1:39 - 1:41
    We need to specify this because there's a class
  • 1:41 - 1:44
    called Random in both the system
  • 1:44 - 1:46
    and UnityEngine namespaces.
  • 1:48 - 1:50
    In our class we're going to start by
  • 1:50 - 1:55
    declaring a serialisable public class called Count.
  • 1:57 - 2:00
    In Count we're going to declare two public
  • 2:00 - 2:04
    variables called Minimum and Maximum of the type int.
  • 2:06 - 2:08
    We're also going to include an assignment
  • 2:08 - 2:10
    instructor for Count so that we can
  • 2:10 - 2:13
    set the values of minimum and maximum
  • 2:13 - 2:15
    when we declare a new count.
  • 2:15 - 2:18
    We're going to give it parameters Min and Max,
  • 2:18 - 2:20
    which we're going to use to set the values of
  • 2:20 - 2:22
    minimum and maximum.
  • 2:24 - 2:26
    Next we're going to declare our variables.
  • 2:27 - 2:29
    We'll start with our public variables,
  • 2:29 - 2:33
    the first two will be an integer for columns,
  • 2:33 - 2:35
    and an integer for rose
  • 2:35 - 2:38
    These will delineate the dimensions of our game board
  • 2:38 - 2:40
    and will allow us to make our game board
  • 2:40 - 2:43
    larger or smaller by changing them
  • 2:43 - 2:44
    if we want to.
  • 2:44 - 2:46
    In this case we're going to initialise them each to 8
  • 2:46 - 2:49
    meaning we're going to have an 8 by 8 game board.
  • 2:50 - 2:53
    Next we're going to use Count to specify
  • 2:53 - 2:56
    a random range for how many walls
  • 2:56 - 2:59
    we want to spawn in each level.
  • 3:00 - 3:02
    In this case this means that we'll have
  • 3:02 - 3:05
    a minimum of 5 walls per level,
  • 3:05 - 3:08
    and a maximum of 9 walls per level.
  • 3:11 - 3:15
    We're going to do the same for our Food items.
  • 3:17 - 3:20
    Next we're going to declare some variables
  • 3:20 - 3:23
    to hold the prefabs that we're going to spawn
  • 3:23 - 3:25
    to make up our game board.
  • 3:25 - 3:27
    We're going to have a single game object called
  • 3:27 - 3:30
    Exit because there's only one exit object.
  • 3:31 - 3:33
    For other objects we're going to use
  • 3:33 - 3:35
    a raise so that we can parse in
  • 3:35 - 3:37
    multiple objects and then choose
  • 3:37 - 3:40
    one of them that we want to spawn
  • 3:40 - 3:42
    among the variations.
  • 3:42 - 3:44
    Let's start with floor tiles.
  • 3:47 - 3:50
    We'll also do the same for wallTiles,
  • 3:50 - 3:54
    foodTiles, enemyTiles and our outerWallTiles.
  • 3:56 - 3:58
    We're going to fill each of these arrays
  • 3:58 - 4:00
    with our different prefabs to choose between
  • 4:00 - 4:02
    in the inspector.
  • 4:03 - 4:06
    Next we're going to declare a couple of private variables
  • 4:06 - 4:10
    including a transform called boardHolder.
  • 4:11 - 4:13
    BoardHolder is just something that we're going to use
  • 4:13 - 4:15
    to keep the hierarchy clean because we're going to be
  • 4:15 - 4:17
    spawning a lot of game objects we're going to child
  • 4:17 - 4:20
    them all to Board holder
  • 4:20 - 4:22
    so that we can collapse them in the hierarchy
  • 4:22 - 4:25
    and not fill our hierarchy with objects.
  • 4:26 - 4:28
    We're also going to declare a private list
  • 4:28 - 4:31
    of vector3s called 'gridPos'.
  • 4:31 - 4:33
    We're going to use this to track
  • 4:33 - 4:36
    all of the different possible positions
  • 4:36 - 4:38
    on our game board and to keep track of
  • 4:38 - 4:40
    whether an object has been spawned in that
  • 4:40 - 4:42
    position or not.
  • 4:43 - 4:46
    Next we're going to declare a function called
  • 4:46 - 4:49
    InitialiseList that's going to return Void.
  • 4:49 - 4:52
    In InitialiseList we're going to start by
  • 4:52 - 4:54
    clearing our list of grid positions
  • 4:54 - 4:58
    by calling the Clear function on our list.
  • 4:59 - 5:02
    Next we're going to use a pair of nested For loops
  • 5:02 - 5:04
    to fill our list
  • 5:04 - 5:08
    with each of the positions on our game board
  • 5:08 - 5:12
    as a vector3, we'll start with the X axis.
  • 5:14 - 5:16
    So this first loop is going to run
  • 5:16 - 5:21
    for as long as X is less than our number of columns.
  • 5:21 - 5:26
    And then we're going to do the same along the Y axis inside that.
  • 5:31 - 5:34
    Inside that loop we're going to add
  • 5:34 - 5:38
    a new vector3 with our X and our Y values
  • 5:38 - 5:40
    to our List grid positions.
  • 5:41 - 5:43
    What we're doing here is we're creating
  • 5:43 - 5:45
    a list of possible positions
  • 5:45 - 5:49
    to place Walls, Enemies or Pickups.
  • 5:49 - 5:51
    The reason that we're looping from one
  • 5:51 - 5:53
    to columns -1
  • 5:53 - 5:56
    is so that we can leave a border of floor tiles
  • 5:56 - 5:58
    directly within the outer walls,
  • 5:58 - 6:01
    this is going to mean that we're not going to create
  • 6:01 - 6:03
    a completely impassable level.
  • 6:05 - 6:07
    Next we're going to declare a new
  • 6:07 - 6:09
    private function that's going to return void
  • 6:09 - 6:11
    called BoardSetup.
  • 6:11 - 6:13
    We're going to use BoardSetup to
  • 6:13 - 6:15
    setup the outer wall and
  • 6:15 - 6:18
    the floor of our game board.
  • 6:18 - 6:20
    We'll start by setting boardHolder to
  • 6:20 - 6:22
    equal the transform of a new
  • 6:22 - 6:24
    game object called Board.
  • 6:26 - 6:28
    Next we're going to use the same type
  • 6:28 - 6:32
    of loop pattern to lay out the floor
  • 6:32 - 6:34
    and the outer wall tiles.
  • 6:34 - 6:36
    So we're going to use another for loop along the
  • 6:36 - 6:39
    X axis and along the Y axis.
  • 6:43 - 6:45
    The reason that each of these loops
  • 6:45 - 6:51
    is going to go from -1 to columns 1 or to rows 1
  • 6:51 - 6:53
    is because we're building an edge
  • 6:53 - 6:55
    around the active portion of the game board
  • 6:55 - 6:58
    using the outer wall objects.
  • 7:00 - 7:03
    Next we're going to choose a floor tile at random
  • 7:03 - 7:06
    from our array floor tiles
  • 7:06 - 7:09
    and prepare to instantiate it.
  • 7:12 - 7:14
    So what we're doing here is we're declaring a
  • 7:14 - 7:16
    variable of the type GameObject
  • 7:16 - 7:18
    called toInstantiate
  • 7:18 - 7:20
    and setting it to equal
  • 7:20 - 7:24
    an index in our array of game objects called floorTiles
  • 7:24 - 7:26
    which we're choosing randomly
  • 7:26 - 7:31
    between 0 and the length of the array floor tiles.
  • 7:31 - 7:34
    This means that we don't have to pre-specify the length,
  • 7:34 - 7:36
    we can just take the length and choose
  • 7:36 - 7:38
    a number within that array.
  • 7:40 - 7:42
    Next we're going to check
  • 7:42 - 7:45
    if we're in one of the outer wall positions,
  • 7:45 - 7:48
    and if so we're going to choose an
  • 7:48 - 7:51
    outer wall tile to instantiate.
  • 7:51 - 7:53
    So we're going to check if X is either
  • 7:53 - 7:56
    equal to -1 or our value for columns,
  • 7:56 - 7:59
    or Y is equal to -1 or our value for rows
  • 7:59 - 8:02
    and if so we're going to set to instantiate
  • 8:02 - 8:04
    to a randomly chosen tile from
  • 8:04 - 8:06
    our outer wall tiles array.
  • 8:11 - 8:13
    Once we've chosen what tile we want to
  • 8:13 - 8:16
    instantiate we're actually going to instantiate it.
  • 8:17 - 8:19
    So we're going to declare a variable of the type
  • 8:19 - 8:22
    GameObject called instance and then we're going to assign that
  • 8:22 - 8:25
    to the object that we're instantiating.
  • 8:25 - 8:27
    So we're going to call Instantiate,
  • 8:27 - 8:31
    parse in toInstantiate, the prefab that we chose,
  • 8:31 - 8:34
    at a new vector3
  • 8:34 - 8:36
    which is going to be based on our current
  • 8:36 - 8:38
    X and Y coordinates in the loop
  • 8:38 - 8:41
    and we're going to parse in 0 for the Z axis
  • 8:41 - 8:43
    because we're working in 2D.
  • 8:43 - 8:45
    Quaternion.identity just means it's going to be
  • 8:45 - 8:47
    instantiated with no rotation
  • 8:47 - 8:50
    and we're going to cast it to a game object.
  • 8:50 - 8:54
    With that done we're going to set the parent
  • 8:54 - 8:56
    of our newly instantiated game object
  • 8:56 - 8:58
    to boardHolder.
  • 9:02 - 9:04
    BoardSetup if going to lay out our
  • 9:04 - 9:07
    outer wall tiles and our background of floor tiles.
  • 9:07 - 9:09
    What we're going to do next is we're going to
  • 9:09 - 9:11
    start writing some of the functions which are going to
  • 9:11 - 9:15
    place the random objects on the game board
  • 9:15 - 9:19
    like Walls, Enemies and Power ups.
  • 9:21 - 9:23
    We're going to decal re a new function
  • 9:23 - 9:28
    that returns a vector3 called RandomPosition.
  • 9:28 - 9:30
    In RandomPosition we're going to declare
  • 9:30 - 9:33
    an integer called randomIndex
  • 9:33 - 9:36
    and generate a random number within a range for that.
  • 9:37 - 9:39
    The range that we're going to generate the number within
  • 9:39 - 9:41
    is going to be between 0
  • 9:41 - 9:43
    and the number of positions
  • 9:43 - 9:47
    stored in our gridPositions list,
  • 9:47 - 9:51
    which we're accessing using gridPositions.Count.
  • 9:52 - 9:54
    Next we're going to declare a vector3
  • 9:54 - 9:56
    called randomPositions and we're going to
  • 9:56 - 9:59
    set it to equal the gridPositions
  • 9:59 - 10:02
    stored in our gridPositions list
  • 10:02 - 10:05
    at our randomly selected index.
  • 10:06 - 10:08
    To make sure that we don't spawn two objects
  • 10:08 - 10:11
    at the same location we're going to remove
  • 10:11 - 10:14
    that grid position from our list.
  • 10:14 - 10:16
    We're doing this by using the RemoveAt command
  • 10:16 - 10:20
    and providing the index randomIndex.
  • 10:20 - 10:22
    Next we're going to return the value of
  • 10:22 - 10:24
    randomPosition so that we can use it
  • 10:24 - 10:27
    to spawn our object in a random location.
  • 10:27 - 10:29
    Now that we've generated a random position
  • 10:29 - 10:32
    from our list and made sure that it's not a duplicate,
  • 10:32 - 10:34
    we're going to write a function to actually
  • 10:34 - 10:38
    spawn our tiles at the random position that we've chosen.
  • 10:39 - 10:43
    This is going to be called LayoutObjectAtRandom
  • 10:43 - 10:45
    and it's going to take 3 parameters.
  • 10:45 - 10:48
    An array of game objects called tileArray,
  • 10:48 - 10:52
    a minimum integer called and a maximum integer.
  • 10:52 - 10:54
    The first thing that we're going to do is that we're going to
  • 10:54 - 10:56
    declare an integer called objectCount
  • 10:56 - 11:00
    and initialise it with a random value between
  • 11:00 - 11:03
    minimum and maximum + 1.
  • 11:03 - 11:05
    ObjectCount is going to control
  • 11:05 - 11:07
    how many of a given object
  • 11:07 - 11:11
    we're going to spawn, for example the number of walls in a level.
  • 11:11 - 11:14
    Next we're going to write a for loop.
  • 11:14 - 11:16
    We're going to repeat the for loop for as long as
  • 11:16 - 11:18
    i is less than our object count,
  • 11:18 - 11:20
    meaning we're going to spawn the number of objects
  • 11:20 - 11:23
    specified by objectCount.
  • 11:23 - 11:26
    We're going to start by choosing a random position
  • 11:26 - 11:28
    by calling our RandomPosition function.
  • 11:28 - 11:32
    Next we're going to choose a random tile
  • 11:32 - 11:37
    from our array of game objects tileArray to spawn.
  • 11:37 - 11:39
    We're going to do this by generating a
  • 11:39 - 11:45
    random number by using Random.Range between 0 and tileArray.length.
  • 11:45 - 11:48
    We're going to instantiate the tile that
  • 11:48 - 11:51
    we've chosen at our random position.
  • 11:52 - 11:55
    We can delete our start and update functions.
  • 11:55 - 11:59
    And declare a new public function that returns void
  • 11:59 - 12:03
    called SetupScene, which takes a parameter of the type int
  • 12:03 - 12:04
    called Level.
  • 12:04 - 12:07
    And notice that SetupScene is the single public
  • 12:07 - 12:09
    function in this class.
  • 12:09 - 12:11
    This is the one that is going to be called by the game
  • 12:11 - 12:14
    manager when it's time to actually setup the board.
  • 12:15 - 12:17
    Within SetupScene the first thing that we're going to do
  • 12:17 - 12:19
    is call BoardSetup.
  • 12:19 - 12:22
    Next we're going to call initialiseList.
  • 12:22 - 12:25
    We're going to call LayoutObjectAtRandom
  • 12:25 - 12:29
    and we're going to parse in our array of wallTiles
  • 12:29 - 12:34
    and also our minimum and our maximum wallCount values.
  • 12:34 - 12:37
    Next we're going to do the same for our foodTiles.
  • 12:43 - 12:46
    Instead of generating a random number of enemies
  • 12:46 - 12:48
    we're going to generate a number of enemies
  • 12:48 - 12:51
    based on the level number
  • 12:51 - 12:53
    using MathF.Log
  • 12:53 - 12:56
    to great a logarithmic difficulty progression.
  • 12:57 - 12:59
    MathF.Log returns a float
  • 12:59 - 13:01
    and so we're going to cast that to an integer.
  • 13:02 - 13:05
    This means that we'll have one enemy at level two,
  • 13:05 - 13:07
    two enemies at level four,
  • 13:07 - 13:08
    three enemies at level eight,
  • 13:08 - 13:11
    and that the difficulty will continually scale up
  • 13:11 - 13:14
    as the player ascends in level.
  • 13:14 - 13:17
    Now that we've got the number of enemies we want to spawn
  • 13:17 - 13:20
    we're going to lay them out using LayoutObjectAtRandom.
  • 13:21 - 13:23
    Note that the minimum and maximum values in this
  • 13:23 - 13:27
    case are the same because we're not specifying a random range.
  • 13:27 - 13:29
    Finally we're going to instantiate the exit.
  • 13:29 - 13:31
    The exit is always going to be placed in the same
  • 13:31 - 13:34
    place and is always going to be the same object
  • 13:34 - 13:35
    so we're just going to call
  • 13:35 - 13:38
    Instantiate and parse in the prefab Exit.
  • 13:39 - 13:41
    The exit is always going to be in the upper right corner
  • 13:41 - 13:43
    of the level, which is why we're using
  • 13:43 - 13:46
    columns -1 and rows -1
  • 13:46 - 13:48
    and this means that if we choose to resize
  • 13:48 - 13:52
    our game board the exit will still be placed correctly.
  • 13:53 - 13:55
    Let's save our script.
  • 13:56 - 13:58
    Now that we've got our level generation code
  • 13:58 - 14:00
    written in our Board Manager
  • 14:00 - 14:02
    in the next video we're going to start writing
  • 14:02 - 14:06
    our Game Manager and setup the Game Manager prefab.
Title:
2D Roguelike 4 of 14 : Board Manager
Description:

more » « less
Video Language:
Arabic
Duration:
14:09

English subtitles

Revisions