How to make a Text Adventure game in Rust - Introduction

In this project, we're going to make a fully functional text adventure game from scratch. This is going to be a substantially larger project than our previous Rock, Paper, Scissors game and will be split up into multiple parts. This project is heavily based on the work of Ruud Helderman and closely follows the content and structure of his excellent tutorial series on the same topic using the C language.

This content and all code is licensed under the MIT License.

An image of a space capsule. The capsule looks rustic and mysterious.
Photo by Frank Cone


Text adventures were among the first widely popular computer games. Some of my first gaming experiences were playing through the Infocom classics Zork and Planetfall. Text adventures challenge the mind and appeal to a more cerebral experience. While many (including sadly the critical mass of people willing to purchase a game) chase after ever increasing levels of realism in graphics, text adventures appeal to the imagination. Like books, a text adventure 'works' by counting on the imagination of the player to build an image far richer than even the best graphics can. In the same way that many avid readers would argue that a good book is better than a movie of the same story, text adventures enable an interactive experience that proceeds at the pace of the reader and allows for a deeply engaging experience. These games and many others like them have worked their way into the lexicon and phrases including 'You are in a maze of twisty passages, all alike' from the original Colossal Cave Adventure continue to appear in pop culture today.

While text adventures are not generally commercially viable now, their progeny, now called Interactive Fiction live on. Interactive Fiction authors and developers have created many high quality games and authoring systems that are mostly freely available. Game engines allow players to continue to access the classics from past years and also author new experiences. Twine and Inform are freely available and continue to be used to create new interactive fiction works. Twine in particular expands the idea of what these creative works can be.

Why This Tutorial, Why Rust?

Why this tutorial then? To paraphrase Ruud Helderman, the author of the series that THIS tutorial is based on, because it will be entertaining, educational, and fun. Text adventure games were groundbreaking when they were first written, but today, their concepts, structure, and simple implementation provide a great opportunity for learning while building a new creative work.

A text adventure provides a good step up in scope from simple 'one-file' games. A text adventure game is a project large enough to need more structure than and will also need to use more advanced data structures. At the same time you can make a text adventure using just the syntax in the language and very few external dependencies, so our focus can remain on the technique, not on learning new libraries.

This has already been done in C, so why Rust? Because I'm learning the language and I'm looking for a slightly more advanced project. I'm still learning though, so I'm probably not going to be writing idiomatic Rust all the time. I'll just write what works and fix things as I go.

This is not going to be a Rust tutorial, but I will reflect on the code and the implementation. Where these differ from what feels right in another language like C, I'll try to highlight that and the rationale for why Rust is different.

Iterative Development

Which brings me to the final point before we begin. I'm going to be following the pattern of our inspiration and building this game iteratively. Each post will build on the previous one and introduce a new concept. Every post will result in a fully functional program and game.

I'll also be posting these pretty much as I complete the steps. I mention this because there will certainly be places where I implement a step and then realize a different approach is needed and a refactoring is appropriate. At least initially, I'll be including those realizations in the posts and you'll see the iterations in the implementation over the course of the posts. Eventually, I may come back and refactor the posts themselves so those decisions fall appropriately in the narrative where they should rather than as they're developed.

0 - Getting Started

To begin navigate to the place where you work on projects. For me, that is the ~/dev directory. Make a new project using cargo and a descriptive name:

$ cargo new reentry
    Created binary (application) 'reentry' package
$ cd reentry

The first command creates a new project with the name 'reentry'. The second switches into the newly created directory.

I'm using the name 'reentry' because the game we'll be making in this tutorial is a space adventure. Rust is a new language using all sorts of advanced technology, my choice of game reflects that. You're free to make a different game, but you'll need to replace my descriptions with your own.

To make sure you have everything you need and that the project created successfully, go ahead and run the program:

$ cargo run
   Compiling reentry v0.1.0 (/home/rskerr/dev/reentry)
    Finished dev [unoptimized + debuginfo] target(s) in 0.75s
     Running `target/debug/reentry`
Hello, world!

New projects created with cargo new include a simple Hello World! program so projects will compile right out of the gate. If your game doesn't compile here, stop and go sort out your Rust development environment. Here is a good place to start.

Before our closing this initial section, we're going to add two additional files - a LICENSE file and a README file. These two files are customary in open source projects and provide needed information for others who see and use the project. The LICENSE file is important because it lets others know what your intentions for sharing are. Without this file, re-use is ambiguous at best, and at worst (at least in the United States) published material should be assumed to be under copyright, which prevents re-use. By adding a LICENSE file, you make your intentions clear and let everyone know your intentions.

In our case, this is a public project and we want to encourage re-use, so we've selected the MIT license. The MIT license grants essentially unlimited rights for others and requires only that the same license is included and granted to others. Since it is a standard license, we've not included its text here.

The second file we've added is a README file. Think of the README file as a kind of starting point for new viewers of the project. README files almost always contain at least a simple description of a project. These files might also include installation and usage instructions, additional system requirements and/or caveats for use. Later, in this project we may add to the README file to provide additional instructions for anyone using the project.

Our file:

# reentry
A text adventure game built in Rust.
This is a text adventure game built to continue learning the Rust programming language.

The '.md' at the end of the README filename ('') indicates that the file is a Markdown file. Markdown is a simple formatting language that is both easy to read in text form, but can be taken as hints by display tools to provide a richer view of the file with BOLD, Headings, italics, and other formatting. Since we're pushing this project to a public repository we want viewers to know what they've got and the README file will tell them.

With the preliminaries out of the way, we've completed the first step and can commit our files.

⇂  View Source

1 - First Steps

Lets begin by doing the most simple thing we can do to get the player into the game. For our first steps, we'll show a simple welcome message and then describe the player's initial location.

fn main() {
    println!("Welcome to Reentry. A space adventure.");
    println!("You awake in darkness with a pounding headache.");
    println!("An alarm is beeping loudly. This doesn't help your headache.");

Lets review the code
1 - Rust programs start with the main() function.
2-7 - println!() function calls print messages to the console. println!() adds a new line to the end of each message
8 - No return value is given so the main() function will return ().

Running the program (with cargo run) we see:

Welcome to Reentry. A space adventure.

You awake in darkness with a pounding headache.
An alarm is beeping loudly. This doesn't help your headache.


Humble beginnings for sure, but a definite start. This simple program sets the stage for our adventure though. Hopefully you can see that descriptive text has the power to awaken the imagination and pull you into a story. This is the key element of a text adventure. Let the words drive the story and your player's imagination will provide depth.

⇂  View Source

In the next post, we'll add interactivity with a main loop and player entered input.

Enjoyed this post? Help me create more with a coffee. Never miss out on future posts by following me.


Popular posts from this blog