Rogue C# – First Project Review
At the beginning of this series, I talked about a former student who wondered how software applications actually came together beyond the coding of small bits of code here and there. In this chapter, I want to review what we’ve done so far in this series to show how everything has contributed and where it’s going from here so you’ll have a better understanding of how an application grows.
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.
Walking the Project Map
Project Conception
When I first came up with this project, I knew that I wanted to start a large tutorial project centered around the development of a single, large application. I chose the game of Rogue because I’d always enjoyed it and wanted to take a crack at writing one. I knew it was ambitious and would be hard, especially with this level of documentation but that only told me that I needed to do it because, otherwise, it would be one that always “could have done”. I honestly questioned the level of interest in a Rogue clone because of the game’s age but I’ve since found that there’s a sizeable community of roguelike enthusiasts and developers.
The introduction to this series laid out the project definition and its intended audience or user base and set limits on its scope. These are all important when starting a new development project.
Defining Requirements
Requirements are essential for any software project. Without a specific set of requirements there’s no clarity on how the program should function or be tested. This project is a little different as it’s being patterned after an existing program but it was still necessary to break down that program’s operation into an initial set of requirements. Requirements fall into multiple categories, including functional and technical requirements so the process of deciding on a programming language and other technical resources, including the choice of graphics and other UI decisions, also fall under this category. Even the choice of algorithms for essential parts of the program and the definition of the object model could be defined under the technical specification.
Creating the App
Many software developers will tell you that code actually comes last after the functional and technical requirements are thoroughly defined. This can make coding the easiest part as most of the decisions are already made. In this series, I’ve actually been going back and forth as I wanted to focus on the C# language and the process of coding for this series so I went ahead and created the app and then put together a basic UI in Visual Studio. This was also necessary since we needed a visual way to test the game map that is central to the game. That’s simply what was appropriate for this project. In the background, however, I was doing quite a bit of research and review of the game and what might be needed.
If you’re a new programmer and eager to start coding, it’s certainly okay to noodle around with code and do some proofs-of-concept while defining the requirements. It’s just important to remember that the more preparation and thought you put in beforehand, the less chance there is that you’ll end up having to discard what you’ve created and restart or do major refactoring in the middle of development.
Foundations and Options
One thing you might have noticed in some of these chapters is that I tend to look ahead to how a specific coding choice might be used later. As I add code, I’m also looking at its effect on the entire project. For example, I’ve used more constants in this project than any other project I’ve ever worked on. I used them here because there are a lot of values the code needs to reference that I want to define beforehand. I also wanted to be able to quickly change them throughout the code when necessary. This has come in useful when adjusting the amount of gold in the rooms and the construction of the rooms themselves.
Starting with Core Functions
As I said earlier, I focused on the game map first because it’s so central to the game itself. I figured once that was in place, I could add features as I went. Still, anticipation of future needs is important.
- I’ve never been a big fan of arrays but it seemed like the way to go for this project as I was emulating the old 80 x 25 game screen that Rogue used and wanted to have specific information for each space on the map. Of course, this meant 2000 elements in the array, each populated by a MapSpace object and I’ve always kept one eye on what this would mean for the memory requirements of the game.
- Programming is often about breaking large problems down into smaller ones and turning them into code. The algorithms for creating the map were a good example of this. Just before starting the project, I actually noticed for the first time that the Rogue game map was based on a 3 x 3 grid of rooms. Once I saw that, I had a start on how to construct it. I decided to divide the process into the creation of the rooms and then the generation of the hallways between them. After that, each element such as doorways and gold deposits fell into one of those categories.
- Sometimes, we have to get a little creative in solving those problems. Throwing away a map and starting over was not my first choice during map generation but I reached a point where the number of unusable maps I was seeing just wasn’t high enough to justify more tweaking of the code. That’s when I decided to write some map verification code that would test the map and redo it if it didn’t work.
Once the map was in place, there were a few more essentials to the game and it was a matter of deciding in what order they could be done.
- Responding to key commands from the user
- Letting the player move around on the map
- Enabling the player to progress through multiple levels
As I added each feature, I thoroughly tested it to make sure it was working before moving on to the next. Fortunately, the repetitive nature of this game makes that pretty easy.
Adding Features
There are a couple of necessary cosmetic features that are still essential to the game like a title screen, scoreboard and victory level and I’ll be getting to those soon but the last couple of chapters of the series have been refinements to the map that are actually somewhat optional.
- Hidden doorways – It’s not really necessary to hide doorways in a roguelike but it does make the game a little more challenging.
- Fog of War – Some games that use map discovery allow the user to turn it off if they choose and that might be an option that I could code in later.
Once you get into this part of the program development, it can become very iterative; new changes are identified, requirements are written, then the features are designed, implemented and tested. This is an example of the Software Development Life Cycle (SDLC).
What’s Next?
While the initial requirements for a working program are done, a few things that are actually pretty essential to the game still need to be added before I would consider putting any kind of version number on it.
- Turn management (Done)- Rogue is a turn-based game where the player moves and then all opponents have their turn. A number of effects such as hunger and various scrolls and potions are also governed by a specific number of turns. Some actions on the part of the player, like viewing inventory, don’t start a turn. The game needs to count the number of turns from the beginning of the current game and decide when each one begins and ends.
- Hunger and food collection (Done) – Once turn management is in place, we can have the player get hungry at specific intervals to add challenge to the game.
- Fast Play (Done) – This allows the player to keep moving until they reach an obstruction like a doorway or a collectible item without having to hit the arrow keys over and over.
- Player inventory (Done) – The player needs to be able to collect and access things like food and weapons in order to keep going.
- Player Stats (Done) – Stats like experience and strength are needed before we can introduce monsters and fights.
- Title screen, death screen (done) and victory level – These are needed to complete the game cycle. Ideally, the player should be able to start a new game if they die or reach the victory level.
Once those are in place, we’ll have a working game in which the player walks around collecting gold and hoping to find enough food to keep going to Level 26 and back.
Then come the inventory items other than food and monsters to fight but that’s a whole new barrel of monkeys.
Sign up for our newsletter to receive updates about new projects, including the upcoming book "Self-Guided SQL"!
We respect your privacy and will never share your information with third-parties. See our privacy policy for more information.
0