Tutorial Part 1: Preface and Hello World (SadConsole v8)

Preface

This series of tutorials is aimed at beginners with a little experience in coding – say, with scripting Game Maker Studio or Adventure Game Studio – but not deep experience with object-oriented programming concepts and C#. I modelled this tutorial on the fantastic Complete Roguelike Tutorial, using python+libtcod, which does a great job of explaining terminology. I try to explain relevant OOP concepts along the way, as well as keywords and concepts specific to .NET and C# programming.

If you’re a hardcore C++ coder looking to dive straight in to a SadConsole-based project, you’re probably better off just going to the SadConsole GitHub repo and get gitting.

Goals

Process

Most tutorials are written using an established codebase that has been thoroughly nitpicked before writing about it. I’m not doing that here, because (a) it prevents you and I from making mistakes that we can learn from, and (b) that’s not how projects are done in the real world. That means we’ll be refactoring and rewriting code as we go along, taking advantage of new concepts and fixing errors along the way. If you’re looking for perfect code, you’re looking in several wrong places.

I use Visual Studio Community 2017 for Mac. There are minor UI differences between the Mac and Windows version of VS, so if you’re running Windows you might notice a few menu/UI naming differences along the road. This is not intended to be a Visual Studio tutorial – so if you get stuck, you can do that research on your own. That being said, here are a few steps to get your started…

Installation

  1. Download and install MonoGame 3.7.1 for your particular operating system.
  2. Create a new Solution in Visual Studio 2017. Set the Solution type to be a MonoGame Cross Platform Desktop Project using OpenGL.
  3. You’ll need to change your project properties so that the .NET target framework is v4.6.1 or higher. I use 4.7.1 currently. The Target Framework option is buried in Project Options/Build/General.
  4. Using the NuGet package browser, search for SadConsole and add SadConsole. This is the engine we’ll be using.

Hello World

Now let’s get to work understanding the basics before we turn this Hello World application into a game.

Edit program.cs and replace its contents with the following code:

using System;
using SadConsole;
using Console = SadConsole.Console;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace MyProject
{
    class Program
    {

        public const int Width = 80;
        public const int Height = 25;

        static void Main(string[] args)
        {
            // Setup the engine and creat the main window.
            SadConsole.Game.Create(Width, Height);

            // Hook the start event so we can add consoles to the system.
            SadConsole.Game.OnInitialize = Init;

            // Hook the update event that happens each frame so we can trap keys and respond.
            SadConsole.Game.OnUpdate = Update;
                        
            // Start the game.
            SadConsole.Game.Instance.Run();

            //
            // Code here will not run until the game window closes.
            //
            
            SadConsole.Game.Instance.Dispose();
        }
        
        private static void Update(GameTime time)
        {
            // Called each logic update.
            // As an example, we'll use the F5 key to make the game full screen
            if (SadConsole.Global.KeyboardState.IsKeyReleased(Microsoft.Xna.Framework.Input.Keys.F5))
            {
                SadConsole.Settings.ToggleFullScreen();
            }
        }

        private static void Init()
        {
            // Any custom loading and prep. We will use a sample console for now

            Console startingConsole = new Console(Width, Height);
            startingConsole.FillWithRandomGarbage();
            startingConsole.Fill(new Rectangle(3, 3, 27, 5), null, Color.Black, 0, SpriteEffects.None);
            startingConsole.Print(6, 5, "Hello from SadConsole", ColorAnsi.CyanBright);

            // Set our new console as the thing to render and process
            SadConsole.Global.CurrentScreen = startingConsole;
        }
    }
}

Main is the first method that the game loads. This is where you’ll do some of your heavy duty stuff to set up SadConsole for making a game. This method first uses SadConsole.Game.Create to set a font, and set the width and height of the game. It then calls the Init() method to initialize the game, and prep it for putting something on the screen — we’ll get to that in a bit. Then the SadConsole.Game.OnUpdate property tells the library which method it should call every time an update event is triggered — we’ll deal with that later. Finally, it runs the game using SadConsole.Game.Instance.Run. When the window is closed, SadConsole.Game.Instance disposes of itself.

Run the program. Hit F5 and watch the game switch to fullscreen. Hit F5 again to exit fullscreen, and close the window.

Look up at the top of program-example.cs:

public const int Width = 80; 
public const int Height = 25;

Those two constants set the width and height of the console and program. The width and height are in characters, not in pixels. The font you use (e.g. IBM.Font or Cheepicus12.Font) determines how wide/tall your console will be. Some fonts are taller or fatter than others. I prefer to use an 8×8 px font to make things square and snug.

Now take a look at the Init() method. Notice that the first step is to create a new Console called startingConsole of a specific Width and Height. Consoles are foundational to SadConsole – think of them as giant canvases that you can paint stuff on. Consoles have a specified Width and Height, and there are a few different types of Consoles. But for now, we’re creating the simplest kind of Console.

private static void Init()
{
    // Any custom loading and prep. We will use a sample console for now

    Console startingConsole = new Console(Width, Height);
    startingConsole.FillWithRandomGarbage();
    startingConsole.Fill(new Rectangle(3, 3, 27, 5), null, Color.Black, 0, SpriteEffects.None);
    startingConsole.Print(6, 5, "Hello from SadConsole", ColorAnsi.CyanBright);

    // Set our new console as the thing to render and process
    SadConsole.Global.CurrentScreen = startingConsole;
}

Next, the program uses startingConsole (which you just created) and runs a method called FillWithRandomGarbage(). That’s a built-in method that all Consoles have, and it’s a useful way of testing whether your console is working and can display stuff. startingConsole then uses a Fill() method that creates a Rectangle that is positioned at X=3, Y=3, and has a width of 27 and height of 5. The foreground colour of the rectangle is set to Null, and the background colour is set to Black. The “glyph” or picture that is displayed is set to zero, meaning that this rectangle will be just an empty box with no characters or pictures in it. Finally, there are no SpriteEffects — a topic for much later.

Now we can write some text to the screen using the Console.Print() method. In this case, we’re printing “Hello from SadConsole” at console coordinates x=6 and y=5 (sixth column, fifth row) in a bright Cyan. Every Console has its own set of coordinates that are separate from the coordinates of other consoles.

And finally – this is a critical step – SadConsole sets the Global.CurrentScreen to startingConsole. Global.CurrentScreen keeps track of which console is currently on screen and is being processed. If you forget this step, you’ll end up with an empty black screen. Go ahead – try it. Comment out SadConsole.Global.CurrentScreen = startingConsole; and run the program. See? Uncomment that line, and let’s move on.

Take a look at Update(). This is another critical SadConsole method that you’ll get used to seeing and using everywhere:

private static void Update(GameTime time)
{
     // Called each logic update.

     // As an example, we'll use the F5 key to make the game full screen
     if (SadConsole.Global.KeyboardState.IsKeyReleased(Microsoft.Xna.Framework.Input.Keys.F5))
     {
          SadConsole.Settings.ToggleFullScreen();
     }
}

SadConsole checks an Update(GameTime time) method every time it runs through one cycle of game processing. This is a useful place to add special features like checking if the user has pressed a keyboard key or moved the mouse. It’s also a place where we can do things like update the player’s health, or process enemy attacks. In this case, we’re checking SadConsole.Global.KeyboardState.IsKeyReleased for the F5 key. If that has been released, toggle SadConsole’s FullScreen setting.

In the next tutorial we’ll put a character on the screen and have it move around.

Published on February 28, 2019