As you might guess from someone who's been writing a blog for a decade, text adventures were something I really liked back in the day. I spent a lot of time on classic Infocom games like The Hitchiker's Guide to the Galaxy. But what if you wanted to build your own as a .Net developer? This blog series has some suggestions...
For many people, the answer to this question might be something like "Go and play with Twine", but being a C# nerd, for me it's definitely more fun to implement it in code. So this series of posts will cover some basics of a simple approach you might use to get an adventure engine started.
url copied!
The game needs some sort of world model to descibe where you can be plus what you can see and do. What things are in that world? Well one model might include:
flowchart TD
World --> Rooms
World --> Exits
World --> Items
World --> Characters
Those entities are:
(Technically you could make Characters and Items the same thing - but it can be a useful distinction, especially if you move into multi-player games)
And you can use those entity types to build up a game world. As a simple examle:
flowchart TD beach["Room:
The beach"] sea["Room:
The sea"] gull["Item:
A gull"] beach -- Exit
south --> sea sea -- Exit
north --> beach beach --- gull
Each of these thing is an entity in the world model - and they'll all share some core common properties:
So the individual types can derive from a basic Entity class, and add whatever extras they need.
So you might end up with simple classes for these things that look a bit like:
public abstract class Entity
{
public string Article { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}
public class Room : Entity
{
public Dictionary<string, Room> Exits { get; } = new();
public List<Character> Characters { get; } = new();
public List<Item> Items { get; } = new();
}
And a world class can sit at the root of this model, holding the set of all the things defined:
public class World
{
public List<Room> Rooms { get; } = new();
public List<Character> Characters { get; } = new();
public List<Item> Items { get; } = new();
public Player Player { get; set; }
}
(The Player here is a subclass of Character - which can add some stuff only the player needs)
This isn't everything the model of the world needs - but commands a player can use, and behaviours that entities can display during the game will get covered later in the series.
url copied!
Once you have the types to represent all the entities in your world you can start creating somewhere for your player to explore. For example:
var w = new World();
var beach = new Adventure.Entities.Room()
{
Article = "The",
Name = "beach",
Description = "A wide sandy beach. The waves lap gently to the south, and a path winds off through the sand dunes to the north. Seagulls squawk noisily above you."
};
w.Rooms.Add(beach);
var gull = new Adventure.Entities.Item()
{
Article = "A",
Name = "gull",
Description = "It's a black-headed gull. It is very noisy, and it is clearly scanning the area looking for chips to steal."
};
gull.Room = beach;
w.Items.Add(gull);
beach.Items.Add(gull);
var sea = new Adventure.Entities.Room()
{
Article = "The",
Name = "sea",
Description = "You're standing in the shallows, with waves lapping gently about you. It is icy cold. Behind you the beach looks much warmer."
};
w.Rooms.Add(sea);
beach.Exits.Add("south", sea);
sea.Exits.Add("north", beach);
The code is creating each of the rooms, items and exits between the rooms and configuring them. They need to be added to the world's collections (so they can be looked up later if required) and they also need to be interconnected so that when you process any particular room to display it you can easily determine what stuff needs showing.
(In a fully-fledged engine you'd probably treat the definition of the world as data rather than as code, because you need to be able to load and save game state, or to let the user change between different games - but for a simple example this approach will do)
For ease of reading/writing the code, places like this where you need to create stuff and then perform some required steps can be improved with some helper methods. For example you might create helpers for new rooms and items:
public static class EntityHelpers
{
public static Room CreateRoom(this World world, string article, string name, string description = "")
{
var room = new Room() { Article = article, Name = name, Description = description };
world.Rooms.Add(room);
return room;
}
public static Item CreateItem(this World w, string article, string name, string description = "")
{
var itm = new Item() {
Article = article,
Name = name,
Description = description
};
w.Items.Add(itm);
return itm;
}
public static Room AddItemInRoom(this Room rm, Item itm)
{
rm.Items.Add(itm);
itm.Room = rm;
return rm;
}
public static Room AddExit(this Room fromRoom, string direction, Room toRoom)
{
fromRoom.Exits.Add(direction, toRoom);
return fromRoom;
}
}
And these can allow chained operations, which read a little easier:
var world = new World();
var gull = world
.CreateItem("A", "gull", "It's a black-headed gull. It is very noisy, and it is clearly scanning the area looking for chips to steal.");
var beach = world
.CreateRoom("The", "beach", "A wide sandy beach. The waves lap gently to the south, and a path winds off through the sand dunes to the north. Seagulls squawk noisily above you.")
.AddItemInRoom(gull);
var sea = world
.CreateRoom("The", "sea", "You're standing in the shallows, with waves lapping gently about you. It is icy cold. Behind you the beach looks much warmer.");
world
.AddPath(beach, "south", sea)
.AddPath(sea, "north", beach);
And with that you can model the environment for your adventure. The next part of the series will look at how the player can start to interact with the world. But meanwhile, there's example code for the whole of a simple game available on GitHub, so you can have a play and experiment with the code if you want.
↑ Back to top