Press "Enter" to skip to content

Learn C# by Building a Simple RPG

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.

 

SECTIONS

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 Edition

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!

474 Comments

  1. Bill
    Bill April 5, 2018

    I’ll be sure to seek your advice if I run into anything else, thank you for your help Scott.

  2. Geoff Harrison
    Geoff Harrison May 21, 2018

    Unfortunately I got to this point and it all went wrong.

    Cutting and pasting the code from Git caused unrecoverable code errors in the generated form code. I had an error message saying that I had not created a method for rtbLocation_TextChanged.

    I could not find a way past this and it is either a choice of giving up or starting all over. Not a fan of starting all over. 🙁

    • Scott Lilly
      Scott Lilly May 21, 2018

      What lesson did you get to? Can you upload your solution (including the directories under it, and all the files in those directories) to GitHub or Dropbox, so I can look at it?

  3. Dan Longhurst
    Dan Longhurst May 31, 2018

    Hi Scott,

    I just wanted to say immensely grateful I am that you have created and shared this walkthrough/guide. I am not finished yet, but I am rolling along with it. I have wanted to learn computer programming for some time now. Your book has really inspired me to do it. Are there any other guides you’ve made like this one? Programming other various games to further learn C#?

    Thank you for reading,
    Dan

    • Scott Lilly
      Scott Lilly May 31, 2018

      Thank you Dan,

      I don’t have PDF versions for anything else. But, I do have lessons on C# Design Patterns (general solutions to common programming issues), a WPF version of the SuperAdventure game (that uses better programming practices than the Windows Form lessons), and just started a new “refactoring” series where I will be improving the code quality of the Windows Form SuperAdventure game – and describing how/why the changes will improve SuperAdventure’s quality.

  4. Chris Mossman
    Chris Mossman July 12, 2018

    Semi-Novice here but… I was able to add Armor items that add additional defense during battles (including a function to ensure that the defense amount is never less than zero resulting in negative damage being done):

    Armor.cs:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace Engine
    {
    public class Armor : Item
    {
    public int MaximumDefense { get; set; }

    public Armor(int id, string name, string namePlural, int maximumDefense) : base(id, name, namePlural)
    {
    MaximumDefense = maximumDefense;
    }
    }
    }

    —–

    Example items:
    Items.Add(new Armor(ITEM_ID_SHIELD, “Shield”, “Basic Shield”, 4));
    Items.Add(new Armor(ITEM_ID_LEATHER_CHEST, “Leather Chest”, “Basic Leather Chestpiece”, 8));

    —–

    damageToPlayer int calculation:
    int damageToPlayer = CheckIfLessThanZero((RandomNumberGenerator.NumberBetween(0, _currentMonster.MaximumDamage) – RandomNumberGenerator.NumberBetween(0, defParse)));

    —–

    Zero check:
    private int CheckIfLessThanZero (int input)
    {
    if (input < 0)
    {
    return 0;
    }
    else
    {
    return input;
    }
    }

    —–

    Happy to share the code with everyone or even work with anyone to make this a little better than a novice could add.

    • Scott Lilly
      Scott Lilly July 12, 2018

      Thanks for sharing Chris!

      In the damageToPlayer calculation, is “defParse” from the MaximumDefense property of the player’s armor?

      There’s also a cool trick you can do with the CheckIfLessThanZero function. There is a Math.Max function that will accept a list of integers and return the largest value. So, the function below will return 0 when “input” is less than 0. Otherwise, it returns “input”.
      private int CheckIfLessThanZero(int input)
      {
      return Math.Max(0, input);
      }

      • Chris Mossman
        Chris Mossman July 13, 2018

        Yes it’s from the MaximumDefense property in the armor, parsing into an int for the function (I may have overthought that a little bit and there is likely an easier way to get the value.)

        Will update the Math.Max function. A lot easier to code that way.

        • Scott Lilly
          Scott Lilly July 13, 2018

          Because the MaximumDefense property is an “int”, it should always have a value – it defaults to “0”. So, you should be able to use it without any parsing.

  5. Zack Jones
    Zack Jones September 3, 2018

    When I got to lesson 11.1 and copy/paste the World.cs static class into my game I got 18 errors that were all similar to this:

    CS1061 ‘Quest’ does not contain a definition for ‘RewardItem’ and no accessible extension method ‘RewardItem’ accepting a first argument of type ‘Quest’ could be found (are you missing a using directive or an assembly reference?)

    Is this expected?

    • Scott Lilly
      Scott Lilly September 3, 2018

      That error message is saying the Quest class does not have a RewardItem property.

      Check your program’s code with the code in Lesson 10.1 – especially the code for the Quest class in step 4. Make sure the RewardItem property exists, its datatype is Item, and it is public.

      If that doesn’t fix the error, can you upload your solution (including the directories under it, and all the files in those directories) to GitHub or Dropbox, so I can look at it?

        • Scott Lilly
          Scott Lilly September 4, 2018

          The errors are all related to name differences.

          In the Quest class, the property “RewardItem” is typed as “Reward Iten” (an “n”, at the end, instead of an “m”). In the Location class, the “LocationTo” properties are named “LocationToThe” (with an additional “The”).

          That is a common reasons for this error message. It also happens if a property is not public, and you try to reference the property from a different project – the default is “internal” (only visible inside the same project), if you don’t explicitly add “public”, “private”, or “protected”.

          Let me know if that doesn’t eliminate the errors, or if you have any questions about the solution.

  6. Zack Jones
    Zack Jones September 4, 2018

    Scott Lilly you are awesome! Thanks for catching my typos and wrongly named variables!

  7. Felipe Pereira
    Felipe Pereira October 2, 2018

    Hi Scott!! Thanks for this tutorial (Learn C# by Building a Simple RPG), the pdf version is gorgeous an I am definitely trying it out.

    I have a question though: could this tutorial be used to develop my game dev skills with game engines?

    One of my professional goals is to develop a “serious” RPG and use it with learning purposes, but I was considering using a game engine (I actually have chosen Unity, for several reasons), since it seems to accelerate the creation of something my boss would be exited about.

    My main concern is to learn how to code properly, with a decent SOLID architecture, and most game engine books (as well as the courses in Udemy, for example) have highly superficial explanations about scripting. Would you recommend something else? Are you developing anything related to game engines?

    PS: the pdf version is really awesome and I have seen published books that are poorer designed and written.

    • Scott Lilly
      Scott Lilly October 3, 2018

      You’re welcome, Felipe.

      The lessons in the PDF are mostly for new programmers to become familiar with the basic commands and concepts of C#. If you want to see a version of the game that has a better architecture, you might want to look at the WPF version here. But, those lessons are also more about C# programing, and not focused on creating a great game.

      I like the Unity programming videos from Quill18 and Brackeys. From what I’ve seen, Unity does make programming games easier. But, that also means you might not need to learn some of the best practices for writing C# programs.

      I suggest you look at design patterns and the C# videos from Tim Corey and Mosh.

      For books, I like “Game Programming Patterns”, “Clean Code: A Handbook of Agile Software Craftsmanship”, “Extreme Programming Explained”, and “Refactoring: Improving the Design of Existing Code”. These books should help you learn the difference between “good code” and “code that works (most of the time)”.

  8. v
    v November 21, 2018

    Hi Sir,

    Your website is just amazing. Thank you for all your efforts.

    Whats your opinion about Tim Corey’s youtube channel. I feel he is giving so much quality content. Would you recommend any other such sources like him for learning programming(not gaming programming)

    • Scott Lilly
      Scott Lilly November 21, 2018

      You’re welcome.

      I like Tim Corey’s channel. He does a lot of excellent videos. I also follow “Programming with Mosh” and “Fun Fun Function”.

  9. Ethan
    Ethan November 25, 2018

    Hey Scott, I’ve been using your tutorial to help myself learn the basics of coding and so far I’m loving it, and I thank you for your hard work. I just hit a road block on trying to save and reload player data from the xml file created in chapter 19.4. I have gone through and double checked that all my code is correct, and the PlayerData.Xml shows up in the file location, yet everytime i open up the game it just creates a new player and ignores the xml file. Any help is appreciated, thank you.

    • Scott Lilly
      Scott Lilly November 25, 2018

      Hi Ethan,

      Can you upload your solution (including the directories under it, and all the files in those directories) to Dropbox, or some other file-sharing site, so I can look at it? Please make sure it includes the PlayerData.xml file.

      • Ethan
        Ethan November 29, 2018

        Hey Scott sorry for the delay I have been very busy with work and have not had time to get on. I appreciate your help and here are the requested files LINK REMOVED FOR PRIVACY

        thanks

        • Scott Lilly
          Scott Lilly November 29, 2018

          I think I found the problems.

          First, line 246 of Player.cs should be like the line below. You want to save the CurrentLocation.ID to the XML file. It was just trying to save CurrentLocation. In C#, when you do that, it writes the name of the class (with its namespace). If you open up the PlayerData.xml file, and look for the CurrentLocation node, you should see the problem. You’ll need to delete the current PlayerData.xml file, and let the program create a new one with the ID stored in that node.

          currentLocation.AppendChild(playerData.CreateTextNode(this.CurrentLocation.ID.ToString()));

          Second, line 99 of Player.cs should be like the line below. Notice that it is “i < quantity". Right now, it has "1 < quantity", which can cause the program to go into an infinite loop if the player has more than 1 of an item in their inventory. for(int i = 0; i < quantity; i++)

          Let me know if that doesn’t fix the program, or if you have any other questions.

          • Ethan
            Ethan December 2, 2018

            Those fixed the solution, thank you for your help!

  10. Bikli Ali
    Bikli Ali December 1, 2018

    Hello Scott, thanks for this tremendous work. If you could add somewhere the “objectives” if the game…I mean it’s not bad to follow your steps but if it was possible to know the requirements at first and then “try” before comparing to your “code”, that would be great. Thanks again Scott

    • Scott Lilly
      Scott Lilly December 3, 2018

      You’re welcome. I’ll take a look at adding an “objectives” section, but it’s been a while since I’ve had time to do much work on the lessons (work has been very busy for a few months).

  11. Jacob Moyer
    Jacob Moyer December 18, 2018

    Is there a copy of the completed project posted anywhere on this site? I had an issue and ended up going to the code of one of the files and copied it into my code but then that caused more issues. Instead of undoing and going back to my original problem, I kept copying code over the code I had and now I don’t know which way is up and I want to try and reset. Figured maybe I can work backwards from a complete copy of the code. I was just starting lesson 17.1 and I remember when I was running the code I got an error with one of the list not populating properly. I was so excited too. I was ready to test the game out!

    • Scott Lilly
      Scott Lilly December 18, 2018

      Hi Jacob,

      There is a copy of the completed version at https://github.com/ScottLilly/SuperAdventure, but that’s the code after lesson lesson 26.2 (and the two bug fix lessons 99.1 and 99.2).

      If you want me to look at the code you have, can you upload your solution (including the directories under it, and all the files in those directories) to GitHub or Dropbox?

  12. Ravi K R
    Ravi K R December 23, 2018

    Hello Scott,

    This is a nice way of learning/teaching concepts, thanks a lot, YOU MADE MY DAY!

    Is there a ASP.NET (WebForms) version of this, I was just curious on how to handle the property changed wiring in a web application, since the concept there would be different?

    Thank You

    Ravi K R

     

    • Scott Lilly
      Scott Lilly December 25, 2018

      You’re welcome Ravi!

      I don’t have an ASP.NET version of this.

      It’s been a few years since I’ve built an ASP.NET website, but you should be able to wire up the buttons using something like this: https://stackoverflow.com/questions/44547143/c-sharp-code-behind-for-button-click-event-asp-net. You might want to look into AJAX (https://www.c-sharpcorner.com/article/ajax-in-asp-net/), if you want the web page to act like a desktop application and update the user interface more smoothly.

      • Ravi
        Ravi January 10, 2019

        Thanks for the update Scott. In case i have my students build an ASP.NET web forms version of this app, i ll post a github link for it here..

          • Evgeny Grishaev
            Evgeny Grishaev January 16, 2019

            Dear Scott Lilly,
            Thank you for your great work. This project fills up my enthusiasm tank to the top! Currently I use Visual Studio Community on Mac (Macbook Air).
            Since there is no WPF, and my machine doesn’t work well with Xcode 9 (requiered to build iOS and nature mac apps), I’m trying to applicate your magnificent tutorial to create game which will work with android. I get to lesson where I shoulf add a reference to connect mainpage with engine, Now I have 3 projects: SOSCRPG, SOSCRPG.android, Engine. Only last two of them have reference buttons. Can you please help me out to find what should I link, or should I find a way to run Visual Studio on Windows?

          • Scott Lilly
            Scott Lilly January 16, 2019

            Hello Evgeny,

            The easiest solution would be to find a way to run Visual Studio on Windows. Some people have used Parallels for Mac to do these lessons on their Macs.

            In the future, Microsoft will release .NET Code 3.0, which will let you build Windows Forms programs and WPF programs on Macs and Linux computers. But, this is not released yet.

            If you can use a Windows computer, you might want to look at Xamarin in the future. Xamarin can help you create programs that run in iOS and Android.

  13. Sowachowski
    Sowachowski February 25, 2019

    Hey, Scott, love this tutorial, it’s helped me loads in coming to learn and understand C#. Now I’m wanting to apply what I learned here to a game engine like Unity. Could you provide any insight for how that could be done? Additionally interested in adding a multiplayer component like in old school MUDs, do you have any advice for that?

    • Scott Lilly
      Scott Lilly February 26, 2019

      Thank you. I have not worked with Unity, but there are two YouTube channels I’ve seen that look good Quill18 and Brackeys.

      I haven’t seen any good guides for creating a multiplayer game. That’s about ten times more difficult than a single-player game (or more). Sending data back and forth to a server is not too difficult. But, you need to handle timing issues and synchronizing communication between all the players’ computers – when they enter the same area, when they leave, if they attack, if they want to trade, etc. You also need to handle network communication problems (which is what I’ve been doing for much of the last two weeks at my day job).

      The best solution (although, probably not the easiest) is find an open-source MUD and read its code. If it’s well-written code, you might be able to get an idea of how it handles all the communication issues. I’ll look around and post on the site if I find anything useful for multi-player.

  14. James Richardson
    James Richardson March 19, 2019

    Hey, Scott. Love the tutorial so far, but I have a few quick questions I was hoping to pick your brain over.
    1.) How would one do the tutorial setup using Visual Studio Code? Particularly interested in the console app part.
    2.) How would one go about ‘publishing’ their game? Like how would you bundle this as a .exe to be distributed?
    3.) Would there be a way to play sound files while running the game? Like having a different song playing depending on the room you’re in or what you’re fighting?
    Cheers! Keep up the great work. This is by far the best tutorial I’ve ever used.

    • Scott Lilly
      Scott Lilly March 26, 2019

      Thanks James,

      1. I haven’t worked with Visual Studio Code. I might test it out after .NET Core 3.0 is released.
      2. Lesson 17.1 has some information on how to copy the game to another computer. Microsoft has also had “Installer” projects you can include in a solution. These can build a single file for a user to run to install the program on their computer. You may also be able to use a tool named WiX to create an installer.
      3. I haven’t tried adding sound to the game, but you could try the method here: https://stackoverflow.com/questions/3502311/how-to-play-a-sound-in-c-net. You could also add speech to the game, like when the player trades with the trader, using the techniques in my Jarvis program.

  15. Mike Atencio
    Mike Atencio April 10, 2019

    Hi Scott,
    This looks really great.
    I wish you would create a race car rally game complete with checkpoints. That would be great to build and learn from also.
    Thanks for taking time to do this class for all of us.

  16. Bill B.
    Bill B. April 16, 2019

    Hey Scott! I’ve had a lot of fun following these lessons and it definitely teaches a lot. I’d say better than some other lessons I’ve taken. I was just curious, I’d like to keep adding to the game indefinitely but I just wanted to know what you feel like is the best way to make certain monsters stats grow along with the player. Maybe like some monsters are easier or more difficult than others but I don’t just want to hard code those stats in every time. I feel like I’ve got some good ideas for the game and this is just part of it. Any help would be greatly appreciated! Thanks!

    • Scott Lilly
      Scott Lilly April 17, 2019

      You’re welcome, Bill! I’m glad to hear you liked it.

      There are a few things I can think of.

      1. Like many adventure games, have a large number of monsters to fight, with the tougher monsters in farther-out locations – the starting locations have rats and spiders, the far mountaintops have giants and dragons. Although, this doesn’t really scale the monsters to the player’s level (other than forcing the player to fewer locations, until they build their skills and levels).

      2. You could use a Factory method to build the monsters (there is an example from the WPF course in lesson 07.1). You could modify the factory to accept the player’s level and use that to apply multipliers to the monster’s hit points and/or damage. You could even build a completely dynamic MonsterFactory. Have a list of base monsters (rat, snake, spider) and a list of prefixes (tiny, medium, giant, rabid, gigantic, etc.). When you pass in a player’s level, you pick the monster name prefix and multipliers for the level to create a “Gigantic Rat” that ten times more hit points than a “Tiny Rat”. For a funny version of this, check out Progress Quest.

      3. You’d probably also want to make the combat logic more complex. The current logic is very simple. But, you could add something where the successful hit percentage varies by the difference between the player’s level and the monster’s level (you’d need to add a Level property for the Monster class). If the player’s level is the same as the monster’s, there might be a 50% chance to hit the monster. If the player’s level is higher, the to-hit percentage increases. If the monster’s level is higher than the player’s, the player’s to-hit percentage decreases (while the monster’s increases).

  17. Chris
    Chris April 24, 2019

    I am a complete beginner and have failed to grasp what I am doing at the very beginning while building the solution.

    I am using Visual Studio 2019 and having problems at step 6 on the PDF document –

    For the UI project to use the code in the Engine project, we need to connect them.
    This is called setting a reference. In the SuperAdventure project, right-click on References 
    Add References…  Solution (which will show you the other projects in the solution) 
    Engine  OK. Now you can see that Engine is listed as a reference in SuperAdventure. This
    means that the SuperAdventure project will be able to use the code in the Engine project.

    I have created Engine.cs but cannot find it listed when adding reference.

    Is this step no longer required in later versions of Visual Studio?

    Kind regards

  18. Chris
    Chris April 24, 2019

    Doh!

    Never mind, I realize I needed to add a new project under the solution.

    Thanks anyway.

    • Scott Lilly
      Scott Lilly April 24, 2019

      No problem! Let me know if you run into any other problems.

  19. Patrick
    Patrick April 25, 2019

    Hello, just a note that I liked this tutorial so much that once i was done, I did it again from start to finish.

    There is one thing I am working on that seems to confound me. I’d like to use the arrow keys for up, down, left, right. Doesn’t have to replace the buttons for movement, but I’d like use the keyboard.

    Most googling of this has KeyDown as the event that handles this, but I’m having trouble with setting this up.

    Any suggestions? Thanks

    • Scott Lilly
      Scott Lilly May 9, 2019

      It’s been a while since I’ve done key presses in a Windows Form program, but I think you need to watch for the KeyUp event. KeyDown is fired when the user presses the key down. The KeyUp event is fired when they take their finger off the key and it returns to the “up” (unpressed) condition.

      According to this question on StackOverflow (https://stackoverflow.com/questions/18604633/catch-keyup-event-on-winform-c-sharp), you may need to set the form’s KeyPreview property – so the program knows it needs to handle the key press as an event, and not as the user trying to type a value into a textbox (or some other control).

      Let me know if that doesn’t work.

      • Patrick
        Patrick October 9, 2019

        Thank you – that’s exactly what I did and after a bit of futzing, was able to create a KeyDown method for the form which would fire off a takeInput(sender, e) method, which just used a Switch statement. Pressing up fires off the btnNorth_Click event. It also allowed me to add

        case System.Windows.Forms.Keys.Up:
        btnNorth_Click(sender, e);
        e.Handled = true;
        break;

        case System.Windows.Forms.Keys.Down:
        btnSouth_Click(sender, e);
        e.Handled = true;
        break;

        It has the nice effect of allowing one to press P to drink a potion and some other nice shortcuts. Thanks again.

        • Scott Lilly
          Scott Lilly October 9, 2019

          You’re welcome. It’s nice to add the keyboard controls to this type of game. Plus, learning more about the different events is very useful. Sometimes I need to add code to a form’s “Close” event, or handle “MouseHover” and “MouseLeave” events. It’s great C# has so many events built-in, and that you don’t need to create everything from scratch.

Leave a Reply

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