Introduction: Generic Rooms in Twine With Sugarcube
Hello hello and welcome to my tutorial on building Wumpus Hunt in Twine with Sugarcube!
Twine is a very simple tool, designed for creating text adventure games! My favorite little cousin has chosen to make a game with Twine for her senior project, and I get to help so I'm creating this series of tutorials!
This series is intended less as a project itself, and more as a reference for game design with twine. I'm going to showcase some of Twine's features, and how you can use them as part of your game.
If you want to follow along with me as I build Hunt the Wumpus, I encourage you to change things as we go. Try adding features, or using things in new ways. That way you can make your own game, instead of just following mine.
Now, we've got a Wumpus to hunt!
Step 1: For the Sake of Brevity...
This tutorial is going to assume that you're familiar with some basics. Normally I like to make my tutorials as approachable as possible, but this time I need to get to the meat and potatoes for the sake of my adowable widdle cousin.
I'm assuming that you're passingly familiar with Twine; that you know how to download it (or use the online version), and that you know how to make new passages and link them together. I'm also assuming that you're familiar with some basic programming concepts, namely variables and functions, and how they're used in Sugarcube.
I have to assume that you're familiar with the game Hunt the Wumpus. It's a difficult concept to describe in words, and to explain in pictures would take forever. I tried to find a video or something that explained it, but I couldn't find any that were just narration-less gameplay. I guess it's one of those things that just gets passed down generationally, and everybody just assumes you know about it. I guess I'm not helping with that.
Step 2: The Idea
The idea behind this project is that we can use Twine's passages as individual rooms. The player can traverse those rooms through the links, and code will change the room's text depending on whether the Wumpus is there or not.
This concept ended up being more challenging than I anticipated, but on the whole I think it fit mostly within Twine's wheelhouse.
Step 3: Create Some Rooms
As you can see above, I started by creating a 3x3 grid of rooms. I also have an introduction passage where the player will start, and that links to one room on the grid. The code for these is very basic, just some text and links. I did a little formatting to arrange the links in each room (as you can see in the third pic), but I kept it minimal.
The key to this step is minimalism. You're going to want to re-work most of this stuff periodically, so you don't want to have to re-do a whole bunch of work. Stick to less than 10 rooms in total, keep room descriptions short, don't make things pretty just yet. They only have to be functional.
Once you get the code working, then it can be pretty.
Step 4: Add a Wumpus
To add our Wumpus, we need to create a StoryInit passage.
This passage is unique to SugarCube, and is run before the player sees the starting passage. It's used to set up variables and objects that need to be created before the game begins. It's very important that the passage be titled "StoryInit", and it's case-sensitive.
We declare our Wumpus variable as a string, and assign it a random room's title. We can use the either() function to assign it a random string from a list of strings. That way, the Wumpus will always start in a random room.
Step 5: Check for a Wumpus
To each of the room we add an "<<if>>" statement that checks whether the Wumpus is in the current room. If it is, it'll print out a short string. If it isn't, nothing shows up.
Because we're building this, we'll also add some debug information. We'd like to know ahead of time where our Wumpus is, and that it's working properly.
You'll have to copy and paste this code into each room individually for now. This is why I told you to stick to only a few rooms.
Step 6: Test
We test our code by playing it. Sure enough we can see where the Wumpus is located at the top of the screen. If we're not in that room, the "A Wumpus is here!" text does not appear.
By navigating to the correct room, we can make the text appear. This is how we'll assign our Wumpus to a random room for each game!
Step 7: Adding Generic Room Code
All that copying and pasting to get each room to check for the Wumpus is tedius. As we develop this game, we're going to want to change this code quite a lot. We'll need a better way of doing that. Let's create some generic room code.
Make a passage and title it something special. I'm just calling mine "room", with all lower-case. You might want to use special characters, or all caps, to make yours unique so it doesn't resemble any of your real room names.
We'll cut and paste our "<<if>>" statement into this generic room code. Then, in each of your real rooms, use an "<<include>>" statement. This will literally copy and paste the contents of our "room" passage into that part of each room. That way we can let the machine handle the tedious bits, while we focus on code!
You can read more about "<<include>>" and other statements in the Sugarcube 2 documentation page.
Step 8: Test
Testing this out, of course, yields the same results as before, but it's important to test frequently. Satisfying too.
It does, however, point out an unfortunate side-effect of all our coding that we can now more properly address. You may notice that as we add more code to each passage we get more and more empty space in our game. We'll take care of those next.
Step 9: Why Are There Empty Lines?
You can see above how I've added backslashes to the ends of certain lines of code. Where and when I use those is very deliberate, and to understand that you'll need to understand why we get strange linebreaks in the first place.
It's the nature of code in Twine to mingle with regular text. The angle brackets (these things: <<>>) tell Twine that what is contained is code and not text. Let me illustrate the problem with this. Let's say you have the following code:
<<code goes here>> Normal text appearing in game... <<more code goes here>> More game text...
Many text processors have an option that lets you view white-space characters; things like spaces, tabs, and linebreaks. Twine does not, but if it did, it'd look something like this:
<<code˙goes˙here>>¶ Normal˙text˙appearing˙in˙game...¶ <<more˙code˙goes˙here>>¶ More˙game˙text...
See those paragraph marks? (¶) Those aren't inside the angle brackets. That means that Twine thinks they're normal text and puts them into your game. That's why, when you play the game, it looks like this:
Normal text appearing in game... More game text...
In order to get rid of them, we can use a backslash character to tell Twine we don't want that linebreak there. In your code, it'll look something like this:
<<code˙goes˙here>>\¶ Normal˙text˙appearing˙in˙game...¶ <<more˙code˙goes˙here>>\¶ More˙game˙text...
This will appear as you'd expect in your game:
Normal text appearing in game... More game text...
Keep in mind that only linebreaks outside of angle brackets needs this. For example, if we had the following code:
We would only need the one backslash, because the first linebreak (¶) is inside the the angle brackets (<<>>).
Secondly, backslashes (\) are different from forward slashes (/), and you'll need to be careful about which one you use where, because they do different things.
Step 10: Test
Your test should reveal that you've eliminated the erroneous empty space! Splendid!
Step 11: That's All for Now
That's all the time that I have for now. So far everything is pretty basic Twine stuff. Generic room code is a useful trick to reduce the copy and paste you have to do, and those backslashes are absolutely necessary to keep your passages looking clean and your code readable.
Things are going to take off quickly from here!