Learn C# by Building a Simple RPG – Index

Giant Spider!
Mandatory Giant Spider!

If you want to write a Role Playing Game, but don’t know how to program, or just want to learn how to program in C#, then you’re at right the place.

These lessons will take you from a complete beginner, to being an author of a Role Playing Game, for free.

This isn’t the world’s greatest game. In fact, it’s very short and kind of ugly.

However, as you create it, you’ll learn the most common C# programming practices and techniques. Then, if you want, you can improve the game, adding more features and your own special touch to it.


NOTE: If you already know the basics of C# programming (classes, properties, functions, “if” statements, etc.), you might want to look at the newer “Build a C#/WPF RPG” lessons. The code in those lessons is more like how I would write a “real” professional program – using better design and architecture.


One of the awesome students here created a PDF document of the lessons. You can get a copy of it here. You can also download the source code files for the lessons here. Thank you, Mark!



Lesson 00.1 – What is in these lessons?

Lesson 00.2 – General information about programming in C#

Lesson 00.3 – The parts of Visual Studio

Lesson 01.1 – Defining classes and objects for the game

Lesson 02.1 – Installing Visual Studio Community 2017

Lesson 02.2 – Building the solution for the game

Lesson 03.1 – Building the first screen

Lesson 04.1 – Creating the Player class and its properties

Lesson 05.1 – Creating objects from classes

Lesson 06.1 – Creating the remaining classes

Lesson 07.1 – Inheritance and base classes

Lesson 08.1 – Setting properties with a class constructor

Lesson 08.2 – Using class constructors with derived classes

Lesson 09.1 – Using your classes as datatypes

Lesson 10.1 – Creating collections of objects

Lesson 11.1 – Using a static class

Lesson 12.1 – Add the remaining UI controls

Lesson 13.1 – Functions, procedures, and methods

Lesson 13.2 – Creating functions to handle user input

Lesson 14.1 – Variables

Lesson 14.2 – If statements

Lesson 14.3 – Foreach loops

Lesson 15.1 – Getting random numbers for the game

Lesson 16.1 – Writing the function to move the player

Lesson 16.2 – Refactoring the player movement function

Lesson 16.3 – Functions to use weapons and potions

Lesson 17.1 – Running the game on another computer

Lesson 18.1 – Future enhancements for the game

Bonus lessons (enhancements to the game)

Lesson 19.1 – Scroll to the bottom of a rich text box

Lesson 19.2 – Use a calculated value for a property

Lesson 19.3 – Clean up the source code by converting foreach to LINQ

Lesson 19.4 – Saving and loading the player information

Lesson 19.5 – Changing dropdown default values

Lesson 19.6 – Increase maximum hit points when the player gains a level

Improving SuperAdventure’s code quality by refactoring

Lesson 20.1 – Refactoring the SuperAdventure program

Lesson 20.2 – Binding a custom object’s properties to UI controls

Lesson 20.3 – Binding list properties to datagridviews

Lesson 20.4 – Binding child list properties to a combobox

Lesson 20.5 – Moving the game logic functions from the UI project to the Engine project

Adding a vendor to locations (with buying and selling items)

Lesson 21.0 – Plans for adding a vendor to locations

Lesson 21.1 – Adding a price to game items

Lesson 21.2 – Create the vendor class and add it to locations

Lesson 21.3 – Add a button and create its eventhandler in code, without the UI design screen

Lesson 21.4 – Completing the trading screen

Use SQL to save and restore player’s game data

Lesson 22.1 – Installing MS SQL Server on your computer

Lesson 22.2 – Creating database tables from classes

Lesson 22.3 – Creating the SQL to save and load the saved game data

Creating a console UI for SuperAdventure

Lesson 23.1 – Creating a console front-end for the game

Final refactoring (cleanup) of the SuperAdventure source code

Lesson 24.1 – Make the SuperAdventure source code easier to understand and modify

New game features

Lesson 25.1 – Select a random monster at a location

Lesson 26.1 Displaying a World Map

Lesson 26.2 – Hiding Unvisited Locations on the World Map


Bug Fixes

Lesson 99.1 – Preventing duplicate quests

Lesson 99.2 – Setting CurrentWeapon when the player has multiple weapons


Share your personal, expanded versions of SuperAdventure here!

403 thoughts on “Learn C# by Building a Simple RPG – Index

  1. Here you go:


    Didn’t work on it for a while and was frustrated after several trys 😀

    Hope you can help me with it 😉

    1. I had some code to allow spawning different monsters at a location. However, I could not find it.

      I’ll write something new, post it in a few days, and let you know when it is ready.

  2. hi Scott ,i have visualy looked at few of your lessons and i think there good.i need some advice on whether i should go through them all,i am currently struggling to learn c# i want to learn it so i could make games on unity  ,do you think its worth my time? like its alot of lesson and then its like what if i dont need alot of what ive learnt from the lessons-for unity scripting .

    i would be grateful if you would reply.


    1. If you only want to create games in Unity, you might want to follow a different guide – one specifically for Unity.

      This is more of a guide for learning C#, while using Visual Studio. The “game” is not the main focus. Unity has a different editor, and (I believe) built-in classes and libraries, that are designed to build a game faster. The Quill18Creates channel on YouTube looks like a good one for Unity.

  3. I’ve been having issues with Lesson 16. I’m attempting to run the program to see if the MoveTo function works, so I may not be supposed to do that, but I would assume that the thing could run before I add the battle logic, right? Well, I keep getting an error on this line while building and running it in debug.

    rtbMessages.Text += “You receive the ” + newLocation.QuestAvailableHere.Name + ” quest.” + Environment.NewLine;


    Is this going to be fixed in the next lesson or did I do something wrong? It’s more likely the latter since I messed up the Quest part and I had to go back to PlayerQuest and fix the constructor.

    1. That error should not be happening.

      There are four classes where I think the error might be happening, but I would need to see the source code, to find the exact location. Can you upload your solution (and all the files, in all the solution’s sub-directories) to GitHub, or Dropbox, so I can look for the error?

        1. Double-check the SuperAdventure.cs class with the code here: Lesson 16.1 source code. In the MoveTo function, it looks like there is a line missing – line 100. This is the “if” statement that checks if there is a quest at the location. If you correct the MoveTo function to have that condition, the error should go away.

          Please let me know if that does not solve the problem.

  4. Oh! Okay, I looked at it some more since I was a bit bored waiting, and saw that it was forcing it to look for a quest and give the player a quest in a no quest area. That was why it’s null. I added a simple if statement just checking if there was a quest, and if there wasn’t, it would skip that whole block of code. I showed my changes in a new branch on GitHub. I think it would have been fixed once I got to the refactoring though.

    1. That’s the basic solution. However, you would probably want to add that “if” at line 100, instead of line 234. That will correctly match it with the “else” statement on line 232.

      Because that code has several levels of curly braces, it might be better to copy the code for that function from the Gist page, and paste it over the current MoveTo function. It’s easy to get something out of position, when the “if: statements go that many levels deep (something we would want to clean, in a more “professional” version of this program).

      1. Just saw your above comment to my original post. I basically just did what you did in a different position. Thanks for the help and definitely for the entire tutorial.

  5. SoI’ve been working on this for about two weeks now and I’m at the point where I am adding my own stuff into it. However I have an issue when I go to debug the program. I get a NullReferenceException that seems to be linked to the player.XML file. When ever I delete the file, it loads up normally, obviously without any of the saved stuff from the previous run.


    I am getting the error in player.cs line 151. I am going to try to do a release to see if the issue persists there as well.


    Link to player.cs on pastebin: http://pastebin.com/S7XkuBr5


    Appreciate your help, without this tutorial I would never of gotten as far as I have.

      1. I didn’t see any obvious errors.

        Can you run the game, exit from it (to save the XML file), and see if the XML file has a value in the “CurrentLocation” node? If there is a value there, make sure you have a location with that ID in your World class. That’s the only other thing I can think of right now.

        If you want to see what is happening when the game reads and writes the XML file, you could use the debugger (tips for how to use it, in this article). I’d set breakpoints in the Player class, on lines 100 (to see what is happening when the game reads the XML file), and line 571 (to watch what is being written in the XML file).

        If that doesn’t help you find the source of the problem, I would need to have the complete solution, so I can run the game, and watch what is happening. You could upload it to GitHub, or Dropbox, so I could look at it.

  6. So I figured out the problem, it was in my world.cs and right after the connecting of the Cells to each other there is a place to add the locations to the static list, Noticed that the ones I could save in where listed there and the ones I could not save in where not, adding the ones not listed than going into the XML file and changing the location ID to some place that I could not previously load into, debug the game and it worked!


    Thanks for your help!

  7. Hello Scott, great tutorial!

    Are you able to create a tutorial for “How to exclude hard-coded stuff”?
    My World.cs is growing so fast and the performence ist dying..

    Just for the “great parts” like the mapping-code, or the item-parts, that would be extremly amazing.

    Thanks for this lessons so far, great Job.


    1. Thank you! I’ve thought about creating a lesson (or an app) to help create the game data in an XML file, and edit it through a simple user interface. I’ll think about what it would require, and see if I can do that. I might need to do it in the new C#/WPF version of the tutorial – although it should be easy to adapt for people using the Windows Forms version of the tutorial.

      I’ll let you know when (or if) that is ready. It will probably take a while to do.

  8. Hi Scott, thanks for the amazing tutorial. We just opened our “Game Design” undergraduate program this year and I am the instructor of the “Introduction to Programming” course given in C#. I covered the major topics using “The C# Player’s Guide” book and I will be grateful if I can use your tutorial and PDF document of the lessons for the remaining weeks. Can I integrate your lessons into my course?

  9. Hello Scott. There is something I have wanted to try, but I feel as though I am running in circles a bit. I was wondering if you might create a lesson that could help, either here or in your new tutorial. Or, should it be the case, if you might tell me which of the existing lessons could be adapted for what I am trying to do. To help explain, I added something for “fire damage,” and that can exist by itself as a “spell” or as part of another class, such as an “enchantment” on a weapon. Right now, though, I have each effect individually coded.

    What I hope to accomplish is twofold: first, to code the fire effect in one place that can be called by the spell or the enchantment, and second, to make it flexible enough that I could add, for example, a cold effect that could be run through the same method. Broadly speaking, I am curious if there is some efficient, reasonable way to code a modular system for applying varied effects with different classes. Would that be something you might add as a lesson, or would that be going beyond the “simple” scope?

  10. Um, So I’m using this tutorial as a sort of way to learn C# (Mainly because I really only need to learn the basics to start off and this is the only thing I’ve found that actually teaches me what I want and need to know without it just entirely flying by my head) Anyways I’m at the point of implementing health and damage and all that and I want to figure out how to do stats.

    My only problem with stats is that I have no clue what I’m doing. I’m sort of straying from the tutorial as I already know a bit of C# (Admittedly I learned what I do know from doing this tutorial at an earlier point). Really the only thing I’m stumped on is doing the stats. After that I’m basically home free and I know most of the rest.

    So I was wondering if you could help me figure out how to do the player stats? I mean I know how to set them but what I haven’t been able to figure out is how to access them in a battle.

    1. For the player stats, are you talking about things like strength, dexterity, constitution, etc.?

      If so, I would make them new public properties in the Player class. Then, I would modify the functions for attacking, and using potions. I would probably modify the lines that use random numbers – to determine if the player hits the monster, if the player is hit by the monster, and how much damage is done. If the player has a low dexterity, I might subtract five points from the random number that determines if the hit the monster (to make the player less likely to hit the monster). If they have a high dexterity, I would add five points. If they have a low strength, maybe subtract one point when we calculate how much damage they do to the monster. For a high strength, add a point of damage.

      Then, be sure to modify the player save and load functions to include the new properties.

      Does that make sense?

  11. I went through the tutorial and my program worked but there were a few logic errors on my end connecting things, I wanted to just use the source code so I could alter it to add things to the game at this point.

    I tried copying all of the source files into Visual Studio from the Lesson Folders but they are giving me errors. Would we be able to get a final source folder specifying which files go into Engine and which files go into SuperAdventure? Or even just a Visual Studio project folder?

  12. Hi! First of all, i’d like to thank you for this lessons, they helped me with OOP ( I’m kinda bad at working with objects/classes ).

    I’ve a question that’s not about the code itself. As much as I know, having too many classes is a bad practice, so i was wondering why did you use derived classes.

    Is it bad practice? Or there’s a reason to do it in this situation?

    1. You’re welcome.

      A big reason why I used derived classes was to show how class inheritance works. If I were creating this game as a “real” program, I would design many things differently. However, for a tutorial, I wanted to show different things you may encounter when creating your own programs.

  13. Greetings Scott Lilly! I am having some problems with my program specifically the SuperAdventure.cs I get so many errors and lots of ambuguity. I am new to programming and I would imagine there may be others with the same problems. I followed each step but I think when you were cleaning code I could have missed something. Thanks so much for the free lessons I’ve actually gone through it all twice. First I coded myself and couldnt run but second time I went through copy and pasting and I still coulding run program/

    Thanks so much for you time! It is greatly appreciated

          1. Would be awesome to have sort of guide/tutorial for working with TCP/IP, WinSockets, COMUART and other stuff related to IoT and development. I’m working as hardware developer and doing simple devices with MCU and number of perepherials. Had to dig into C# since I need to accept and visualise received data.
            Any plans?
            Best Regards,

          2. I haven’t done anything with hardware yet – although, there are a lot of tempting devices available nowadays. After I finish my current projects, I’ll see if I can come up with an interesting project.

  14. Scott,
    You can get starter kit for 10$-30$ and this will give you all necessar stuff to get into hardware development. Believe me, its exciting! If you have basic electronics knowledge – this wont be a problem to master fast, since MCU requiers C / C++ code.
    You can upgrade Super Adventure guide adding hardware features. If you’ll need help choosing hardware and parts – I can help you with it

  15. Hello, I have a bit of a problem. I followed the guide and I think I did everything properly. The problem is in Program.cs, at the line:
    Applocation.Run(new SuperAdventure());
    I found a comment about this issue, wrote it as advised, and now it underlines SuperAdventure() and when debbuged, nothing happens. The error says “This name space is aviliable but is not a valid type”, or something like this. I read the code, tryed to imply logic to find the problem, but I can’t detect nothing. My form name is SuperAdventure, my Class is called SuperAdventure, and I have:
    public SuperAdventure()
    in the SuperAdventure.cs.
    Where am I wrong, or what have I missed?

      1. Yup, all set and done. It appears, that I somehow missed this lesson. Thank you a lot and sorry for wasting your time. I should have looked better :/

  16. Hey Scott. Last year I followed your tutorial. Before that I studied two full microsoft books on C#. But your tutorial helped me get some minor practical experience and after that I took a pragmatic course on asp.net mvc5 and EF 6. All this helped me to start my career as a Junior developer in .net, but I feel your simple tutorial helped me a lot in getting my feet wet from just theory to practical stuff 🙂 So I especially came back here to thank you man. You’re a boss! 🙂 thanks!

    Kind regards,

    J from the Netherlands.

  17. Hello, Mr. Lilly.

    As my quest to expand on the game continues, I’ve finally gotten around to trying to add a very crucial feature: NPCs that the player can just talk to. I’ve made an NPC class, added a List of NPC to the Location class, added some NPCs to a location in World.CS, and run into trouble. When the game first starts and tries to add an NPC to a location, it fails and the game can’t start. It tells me is this:

    “An unhandled exception of type ‘System.TypeInitializationException’ occurred in ClassLibrary1.dll

    Additional information: The type initializer for ‘Engine.World’ threw an exception.”

    Naturally, I’ve looked up the error, but none of the common fixes seem to work for me. I’ve stepped through the debugger numerous times, and I’ve noticed that the exception is thrown when World.cs tries to assign the NPCs Name variable with the information that was sent to the constructor. On the line ‘Name = name’ in NPC.cs, it immediately goes to the CreateDefaultPlayer function in Player.CS and gives me the above error message. Are there some advanced debugging techniques I can use to try to resolve the issue? This seems like a very unusual problem.

    1. That is the error you get when a static “constructor” methods fails. Unfortunately, it isn’t a useful error message. 🙁

      Are you building the NPCs in the World class, like the items, monsters, etc.? Is there a private List variable? Do you have a PopulateNPCs function that creates new NPC objects, and adds them to the list variable? Do you call the PopulateNPC function before you call the PopulateLocation function – so the list will have the NPC objects created, before you try to add them to the list of NPCs available at a Location? Do you have an NPCByID function?

      If you’re having trouble finding the problem with the debugger, you might try commenting out (or removing) the new NPC code. Then, add one step at a time (create the private List variable, create an empty PopulateNPC function, add it to the “constructor”, have PopulateNPC create a new NPC object, have it set property values on the NPC object, have it add the object to the private List variable, etc.) After each step, run the program and see if it works. If you get an error after adding one of the steps, then you know exactly which line has the problem.

      1. I’d been building the NPCs in World.cs, but now I’ve made it more nuanced with PopulateNPCs (which is called before PopulateLocations) and NPCByID. I imagined implementing them more like vendors, which were built during PopulateLocations, which gave me an idea after reading your response.

        If I have an area contain just a single NPC rather than a List, the game runs just fine, but I have my doubts that it creates everything properly. As soon as I make it back into a List, the exact same problem persists where trying to add to the List causes the program to end up in CreateDefaultPlayer in Player.cs and World.cs throws an exception. The new additions helped me see the problem more clearly, however.

        What actually happens is that, for some strange, strange reason, somewhere between trying to add the NPC to the Location and throwing an exception, ItemByID is called. This can’t be seen when NPCsLivingHere in Location.cs is a List, but can be viewed through the debugger just fine when there can be just one. Because of this sudden turn to ItemByID, I’m fairly certain that, even though the game runs, the test-NPC I’m using isn’t created correctly. I haven’t the slightest idea why this happens, as I’m sure that “voodoo magic” is an unacceptable answer.

        In following your advice, I’ve learned more about the issue I’m having, but am somehow also more confused. ItemByID being called during a line that doesn’t call it and then subsequently moving to another class that has no relation to the function from before goes against every convention of logic I’ve been taught in programming. You’ve already given me such great advice, but I have to ask since you have so much more experience than me: Can you make sense of this? Do issues like this happen often?

        Anything you can tell me would be greatly appreciated.

        1. Are you familiar with using the callstack, for debugging? I haven’t created anything on how to use it, but this article might help you. That should let you see how the code is getting to the ItemByID function: which function called it, and which function called the previous function, etc. I’m certain it’s not “voodoo”.

          If you try that, and can’t find the source of the problem, please upload the current version of your program to GitHub.

          1. I found the callstack very useful, though it technically brought me no closer to finding the source of the trouble.

            What actually happens is that, after going through the Designer file and there is no save file found, the game starts to create the default player and goes to World.cs when it starts to add the rusty sword to the player’s inventory. The program seems to go through the entire World.cs file at this time, including creating and trying to add NPCs. Whatever causes the static constructor to fail and cause the exception to be thrown is still a mystery to me, but at least it now makes sense why the program ends up in CreateDefaultPlayer.

            Here is the link to the project on GitHub: LINK REMOVED FOR PRIVACY

            I’m very much looking forward to learning what the heck is going on. As many times as I’ve looked, I still don’t see anything outside the ordinary with the code I’ve written.

            Here are some code lines that will be helpful to know, I think:

            -A List of NPC NPCsLivingHere is created on line 29 of Location.cs
            -NPCs are populated starting on line 155 in World.cs.
            -An NPC is added to a location on line 194 in World.cs.
            -NPCByID starts on line 414 in World.cs.

            I thank you in advance for your time.

  18. YouTube is telling me that the video is unavailable. I’m not seeing anything very-recently uploaded on your channel, so I assume something went wrong quickly after the video was put up.

    1. Can you try it again? I thought I set it to “Unlisted” (so it could be linked to, but wouldn’t show up in the list of all other videos). However, it was still “Private”.

      1. Excellent! But I can’t help but feel a little foolish for not realizing I had to initialize the List first. I highly doubt I’ll ever forget again though, and your approach to debugging it has been noted and kept in mind. I’m glad it was just a misstep on my part, as some people, according to what I’ve read, had this error for reasons beyond their control.

        As always, you have been a great help, Mr. Lilly. I feel like I’ve learned in about a month what I’d gotten in a whole semester.

        1. There is a saying, “Good judgement is the result of experience. Experience is the result of bad judgement.” In programming, the lessons we remember best, are often the ones we learned from our bugs. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *