Rogue C# – Working with Classes and Objects

In the previous chapters of the series, we setup the main form for our roguelike game; now it’s time to add code that will handle the core functions of the game. C# is an object-oriented language, meaning that it makes constant use of classes to organize and contain (or encapsulate) various functions. The algorithm spelled out in the last chapter is complex enough to justify a dedicated class that will generate and display the map, a function that is central to the game of Rogue.

This post is part of a series on creating a roguelike game in C#. For the latest chapters and more information, please visit the Official Project Page on ComeauSoftware.com. The current code for this project is also available on Github.

Classes

Among other things, a class is a way of organizing code and functionality within a program. It also acts as a blueprint from which individual objects can be created and used within your code. Each one of the objects that you create from a class implements all the properties, functions, events and other features specified by the code within the class.

Object-oriented programming (OOP) is the practice of grouping all code into these classes based on subjects or concepts that you need to use within your program. For example, in the roguelike game we’re developing, there are different types of objects (classes can also be called types) that we’ll need to track during the game.

  • The player’s character
  • Monsters
  • Collectible items such as scrolls, potions and weapons
  • The game map

Very often, the definition of a class starts with a list of properties that describe the object to be created from the class. For example, there are 26 different monsters in the original Rogue such as the rattlesnake and the centaur so a Monster class would immediately need a Name property. Each type of monster has its own number of hit points (HP) or the amount of damage it can take before it’s defeated. That would be another property in the class. The player’s character also has specific properties like the name that the player chooses when the game starts, hit points that increase during the game and other stats like Strength.

A class can be used to create many different objects that will exist at the same time. For example, on any game level, there will be many monsters of different types and many items to be collected so all of these objects will exist simultaneously based on the same class blueprint. On the other hand, there will only be one player and one game map at any one time but the classes for those objects will still define the properties that can be set for those objects.

Classes are also used to hold methods and functions specific to an object type. Scrolls and potions have specific effects such as restoring the player’s strength or revealing the entire map. These tasks can be carried out by functions defined within the class. Each time an object is created from the class, it has access to those functions.

Benefits of OOP

The most obvious benefit of object-oriented programming is to organize your code in a way that identifies the concepts that you’re working with. This makes the code more maintainable by any programmer who understands how OOP works.

OOP also helps avoid repetition of code; this is often expressed as DRY – “Don’t Repeat Yourself”. It’s less likely that you’ll accidently duplicate code if you can easily find it within the classes that you’ve created. Frequently used functions can also be stored within a special class and called as needed. For example, .NET has the Math class which has many common math functions like rounding and exponentiation that can be called from anywhere in your code.

Finally, when your code is well organized, it can be more compact and the program won’t have to jump all over the place to get something done. Your thought process in designing the app might be better organized as well. This can lead to a faster program.

Adding the first classes

Remember that the current code for this project is available on Github.

There are actually two classes that I want to add at this point – one will use the other. For now, we’re just going to add the class declarations and another item that will use them.

  • The MapLevel class will contain all the code for generating the game map itself on each level, including the code for drawing the rooms and the hallways between them.
  • The MapSpace class will be a smaller class to define an individual space on the map, including the actual character within the space and the one to be displayed.
  • The levelMap array will hold all the information about the map using MapSpace objects to store the characters. The array will be maintained as a property of the object created from the MapLevel class.

Adding a class to your program is easy …

  1. In the Solution Explorer, right-click on your project name (not the solution itself) and choose Add and Class from the menu. You can also use the SHIFT-ALT-C combination to bring up the same window.
  2. Select Class from the list of items that can be added to the project. It’s the first in the list.
  3. At the bottom of the window, you can type in a name for your class. I’d suggest MapLevel.cs.
  4. Click the Add button.

Incidentally, notice that the .cs extension used for this class file is also used for the DungeonMap form that we customized earlier. That’s because Windows forms are also objects based on classes! Classes can inherit other classes in order to obtain and reuse their functions. The basic Form class is inherited by the specific class in the project, in this case DungeonMap.

public partial class DungeonMain : Form

The DungeonMap class adds its own features and then generates an object when the form is loaded in the program. We’ll look at form classes and class inheritance later in the course.

Once you click Add, Visual Studio will create the class and open it for editing.

Notice at the top of the code, there are a number of lines that start with using. These are importing namespaces into the class for reference. All classes in .NET, both the native classes in the language’s library and the ones you create, are contained within these namespaces which help to organize the classes by subject and function. You’ll continue to see this as you work with C# and you’ll even be adding some of your own.

Notice, after the using statements, the next line references the namespace DungeonGame which is the name of the project. So, the project has its own namespace it can use to classify code that belongs to the project itself.

Finally, you have a simple MapLevel class declaration:

internal class MapLevel
{

}

The default internal keyword shown above modifies the scope of the class or where it is accessible from within the code. There are other modifiers like public and private. In this case, internal means that the class is only accessible from within the same project or assembly (often the same as a project). Don’t worry about this for now, you’ll see more examples of scope later and get more familiar with how it works.

The curly braces define the limits of the class itself; anything within these braces will be part of the class. C# uses braces to limit the boundaries of everything from classes to functions and properties and it’s very easy to delete a brace and have a lot of errors showing in your code. Generally, correct bracing within classes and procedures should cause the code to auto-indent and format itself.

If you’re following along with this project on your own, I want you to enter the following code between the two braces:

// Array to hold map definition.
private MapSpace[,] levelMap = new MapSpace[80, 25];

internal class MapSpace{

}

The first line is just a comment that will be ignored by the code. The two forward slashes at the beginning mark it as a comment. Good commenting is important for your code, especially if other people have to read it later.

The second line declares a two-dimensional array in memory that will hold a collection of MapSpace objects. Arrays in C# and other languages are collections of items of the same type that are maintained in memory so they can be referenced by the program. They can have multiple dimensions just like an Excel worksheet has two dimensions and workbook could be said to have three.

The square brackets after the word MapSpace identify it as an array rather than a single MapSpace object and the comma between them indicates that there’s more than one dimension. The statement is basically saying, “Create a two-dimensional array of MapSpace objects in memory with 80 elements in one direction and 25 in the other.“. This array is going to hold the information that will simulate an 80 x 25 character display using the information in the MapSpace objects it contains.

The private keyword in this statement limits the scope of the array to within this class. The array cannot be accessed by code from outside – there will be a different arrangement for that I’ll get into later.

Don’t forget the semi-colon at the end of the line. C# uses these to recognize when a code line is finished. Also, remember that everything in C# is case-sensitive so “MapSpace” is not the same as “mapspace” and “LevelMap” would not be the same as “levelMap”.

You might already recognize that the last two lines declare a new MapSpace class within the MapLevel class. This is perfectly okay in C# and the internal keyword again limits the scope, this time to the MapLevel class itself. Nothing outside the MapLevel class will be able to reference the MapSpace class. A class file within Solution Explorer can also hold numerous independent classes or partial classes but it’s probably easier to keep each one to its own file.

At this point, you should be able to press F5 and run the program. None of this code will do anything yet but you will see the form that we customized earlier. If you get any errors or see red squiggly lines under any of the code that you entered, make sure that it’s exactly as shown above and try again.

Exploring Further

I actually introduced arrays in this chapter before I’ve even talked about storing single values but don’t worry, I’ll be talking more about both in upcoming chapters. Meanwhile, there are plenty of great references if you want to read up about the basics of arrays. They’re not really difficult as long as you stick to the spreadsheet and workbook comparison I used earlier and you’ll see them used pretty heavily here so you’ll get plenty of exposure.

W3Schools – C# Arrays

Microsoft Learn – Arrays

Understanding Classes – Microsoft Learning

Object Oriented Programming is actually a complex subject that might take someone weeks or even months to get a good handle on. I’ve tried to simplify it in this lesson but don’t feel bad if it still feels overwhelming. You’ll see plenty more examples of it in the upcoming chapters and you’ll have the chance to put it into practice.

In the next lesson, we’ll add more code and look at the use of constants in C#.

Next –