Creating and Drawing a Game Map in VB.NET (FIXED PER REQUEST)

This is the seventh part of a nine-part article series that teaches you Visual Basic.Net through the development of a text-based PC game similar to Rogue or Nethack. In this installment, you'll learn how to build the map, starting with the creation of some basic tiles. We'll be dealing with arrays, entity classes and more. Let's get started.

Contributed by
Rating: 3 stars3 stars3 stars3 stars3 stars / 9
July 08, 2008
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Creating Some Basic Tiles Through Subclassing

Before we start working with the map as a whole, let's create a few basic tiles to work with by subclassing the Tile class. The first tile we'll create is a basic floor tile. It won't be flashy at all. It will have a gray foreground and a black background, it will be represented by a period, and the user will, of course, be able to walk over it. Create a new class in Visual Studio called BasicTile (in BasicTile.vb):


Public Class BasicTile


End Class


The first thing we need to do is set our class to inherit from the Tile class. This is very easy. All we have to do is use the Inherits keyword and then specify the parent class. As is characteristic of BASIC languages, the result is very straightforward and readable:


Public Class BasicTile

 Inherits Tile


End Class


Notice how the Inherits statement is put on a new line. This is required.

Immediately, Visual Studio should complain that we have to create a constructor because the parent class does not have a parameterless constructor which can be called by default. This is easy to do. Let's create a parameterless constructor that sets up everything. In this constructor, we will have to call Tile's constructor, which will set the fields to the values we specify. Let's go ahead and create it:

Public Sub New()

 MyBase.New(".", ConsoleColor.Gray, ConsoleColor.Black, True)

End Sub

One of the first things you should notice is the use of the MyBase keyword. The MyBase keyword simply provides access to the parent class. Above, we use MyBase to call the parent class's constructor. Also, notice how, when working with characters, we do not use single quotes as we might in other languages. Instead, we just use double quotes, which other languages often reserve for strings. Besides, the single quote mark in Visual Basic is taken to be a comment.

Now we have a basic floor tile. Next is a wall tile. It will be represented by the number sign, will have a gray foreground and a black background, and it will, of course, not be passable by the player. Create a class called WallTile (in WallTile.vb). The process is the same as before, except the name of the class is, obviously, different, and the values we pass to Tile's constructor are different:


Public Class WallTile

 Inherits Tile


 Public Sub New()

 MyBase.New("#", ConsoleColor.Gray, ConsoleColor.Black, False)

 End Sub

End Class


The final basic tile we'll need is a blank tile. This tile will have a blank space associated with it, and it will be used to fill in if the physical map isn't as big as the available size. Make a class called BlankTile:


Public Class BlankTile

 Inherits Tile


 Public Sub New()

 MyBase.New(" ", ConsoleColor.Black, ConsoleColor.Black, False)

 End Sub

End Class


Creating the Map Array and a Basic Map

Great. We now have three simple tiles to work with, and we can begin to work with the map array. As stated before, the map will be represented by a two-dimensional array. In this way, we can treat the array as a coordinate system of sorts. One dimension's index will represent the x-coordinate of the tile, and the other dimension's index will represent the y-coordinate of the tile. This works out to be nice and neat.

As with player, our map array will be a field of the Game module. This is the easiest way to work with it. Let's go ahead and create a field for the map. Let's make the map 60x20. So, the upper bound for the x-coordinate will be 59, and the upper bound for the y-coordinate will be 19:

Dim map(59, 19) As Tile

Next, we need a map. Ordinarily, we may want to automatically generate a map, or else read an existing map from a file. However, let's keep this basic for now and create a map by hand. More ambitious projects will have to wait until later. Let's start with something simple. We'll make a large square room occupying the entire available space. We can create a room like this with a loop. We'll loop through every space in the map. This will require one loop for the x-coordinates and another embedded within that for the y-coordinates. If we're at the edge of the map, we'll place a WallTile. Otherwise, we need a BlankTile. Let's put this in a method called CreateBasicMap:


Sub CreateBasicMap()


 ' Get the x- and y- coordinates for the right and bottom

 ' edges of the map

 Dim xLimit As Integer = map.GetUpperBound(0)

 Dim yLimit As Integer = map.GetUpperBound(1)


 For x As Integer = 0 To xLimit

 For y As Integer = 0 To yLimit

 If x = 0 Or x = xLimit Or y = 0 Or y = yLimit Then

 map(x, y) = New WallTile()

 Else

 map(x, y) = New BasicTile()

 End If

 Next

 Next

End Sub

We use a For loop because we need to be able to go tile-by-tile and also check to see if we're at an edge. The outer loop iterates over the x values, and the inner loop iterates over the y values. So, the method essentially creates the map column-by-column. Also, notice the use of the Or operator. We check multiple conditions, any of which, if true, indicate that we're at an edge of the map. Go ahead and call CreateBasicMap in Main:

CreateBasicMap()

Drawing the Map

Now we have a map. That didn't take much, did it? We need to draw it out to the screen now, one tile at a time. This will enable us to see what it looks like for the first time. To draw it out to the screen, we once again need two loops, but rather than going through the map column-by-column, we'll need to go through row-by-row. This way, we can just call Write for each tile, and we only have to manually adjust the cursor's position at the end of each row. Once again, we'll place this code in a separate method, so as not to clog up Main. The method will be called DrawMap:


Sub DrawMap()

 For y As Integer = 0 To map.GetUpperBound(1)

Console.SetCursorPosition(0, y)

 For x As Integer = 0 To map.GetUpperBound(0)

DrawTile(x, y)

 Next

 Next

End Sub

As noted, the outer loop goes by row, and the inner loop goes by column. At the start of each iteration of the outer loop, we set the cursor to the beginning of the appropriate row. As we draw the tiles, the cursor will automatically shift right. Notice how I've called a method called DrawTile. We'll be drawing tiles frequently, and so it's best to have a separate method for this. Inside of DrawTile, we apply our knowledge of console output:

Sub DrawTile(ByVal x As Integer, ByVal y As Integer)

Console.ForegroundColor = map(x, y).ForeGroundColor

Console.BackgroundColor = map(x, y).BackgroundColor

Console.Write(map(x, y).Symbol)

Console.ResetColor()

End Sub

We first have to set the colors. Then, we write out the tile's symbol and then clean up by changing back to the default color.

Now we can see the map in action. In Main, call DrawMap:


DrawMap()


It's also a good idea to call ReadKey temporarily. That way, the console won't close before we can see the map. Just remember to erase it afterward:


Console.ReadKey()

Run the program, and, after you enter your name, you should see the map we just created.

Creating the Entity Class

The map is missing something very important, though-the player. Fortunately, displaying the player is easy enough, but first we need to consider something else first. Yes, we'll have the player walking around the screen, but we'll also have other entities (monsters, etc.) moving around the screen as well. Here, we have some common behavior shared between players and other entities. Both groups have a location, both groups are represented by a symbol, and both groups have names associated with them. This is a great opportunity for inheritance to play a role. Let's create a class called Entity that represents all the entities on the map, including the player. Then, let's rework Adventurer to inherit from this class.

The Entity class will have fields and properties for a name, a location, a symbol, and a foreground color. Let's go ahead and create the class-it's a little lengthy:


Public Class Entity

 Private _name As String

 Private _symbol As Char

 Private _color As ConsoleColor

 Private _x As Integer

 Private _y As Integer


 Public Property Name() As String

 Get

 Return _name

 End Get

 Set(ByVal value As String)

_name = value

 End Set

 End Property

 Public Property Symbol() As Char

 Get

 Return _symbol

 End Get

 Set(ByVal value As Char)

_symbol = value

 End Set

 End Property

 Public Property Color() As ConsoleColor

 Get

 Return _color

 End Get

 Set(ByVal value As ConsoleColor)

_color = value

 End Set

 End Property

 Public Property X() As Integer

 Get

 Return _x

 End Get

 Set(ByVal value As Integer)

_x = value

 End Set

 End Property

 Public Property Y() As Integer

 Get

 Return _y

 End Get

 Set(ByVal value As Integer)

_y = value

 End Set

 End Property

End Class

We also need a constructor to assign initial values to the fields:

Public Sub New(ByVal name As String, ByVal symbol As Char, _

 ByVal color As ConsoleColor, ByVal x As Integer, _

 ByVal y As Integer)

_name = name

_symbol = symbol

_color = color

_x = x

_y = y

End Sub

The Entity class is long, but we can now drastically reduce the size of Adventurer, since the functionality we provided previously is now provided in Entity. All we need to do now is call the constructor. Replace the entire Adventurer class with this:

Public Class Adventurer

 Inherits Entity


 Public Sub New(ByVal name As String, ByVal x As Integer, _

 ByVal y As Integer)

 MyBase.New(name, "@", ConsoleColor.Cyan, x, y)

 End Sub

End Class

There, that's shorter than before. However, since the constructor's parameters have changed, we need to modify Main a bit, where we create the Adventurer:

player = New Adventurer(name, 1, 1)

Now we can create a method that will draw not only the player, but every other entity as well. The method will accept an Entity object and will then draw it on the proper location on the screen:

Sub DrawEntity(ByVal toBeDrawn As Entity)

Console.SetCursorPosition(toBeDrawn.X, toBeDrawn.Y)

Console.ForegroundColor = toBeDrawn.Color

Console.Write(toBeDrawn.Symbol)

Console.ResetColor()

End Sub

The method is similar to DrawTile, except it specifies a parameter and sets the cursor to the proper location itself. In Main, after the call to DrawMap, call DrawEntity and pass player (since, after all, an Adventurer is an Entity):

DrawEntity(player)

This will draw the player on the screen. Run the program, and you should see the player in the top left-hand corner of the screen.

Now that we have drawing taken care of, it's time to move on to movement. The game is finally starting to take shape.

blog comments powered by Disqus
VISUAL BASIC.NET ARTICLES

- Basic Form Properties and Modality in VB.NET
- Multiple Document Interfaces in Visual Basic
- Visual Basic for Beginners
- ASP.NET Image to PDF with VB.Net
- MySQL in ASP.NET: Mono using VB.NET
- AsyncFileUpload File Type and File Size Vali...
- Visual Studio: Adding Functionality and Style
- Clocks and Countdowns
- User-defined Functions using Visual Basic Ap...
- Understanding Object Binding in VBA
- Mastering the Message Box
- Testing a Windows Forms Application
- Using Visual Basic.NET Features to Code a Wi...
- Correcting Code in a Windows Forms Applicati...
- Write Readable Code and Comments for Windows...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 5 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials