A Critique of Brothers: A Tale of Two Sons

I recently got around to playing Brothers: A Tale of Two Sons. It’s one of those games I picked up forever ago, and it just sat around. I got it because it has to be one of the most critically acclaimed games I’ve ever seen. Giant Bomb and many, many other gaming sites gave it a 5/5 or very near such a perfect score.

I’m going to take a contrarian view, and I’m going to back up my claims with hard facts. Anyone paying attention and who knows about games should know better. I’m very confused as to how “experts” could have thought this game was good. I’m confused how “experts” could have even liked the game.

First, the game suffered from genre confusion. I’m all for experimenting with new, cross-genre ideas, but there has to be some content there at the end of the day. Was it a puzzle game? No. It fails on this front, because I never once had to “solve” something. From start to finish, the solution of how to progress was immediately obvious. Moreover, many of the puzzles repeated … several times … like, way too many times for a game this short.

Was it a platformer? No. The platforming aspects were too easy, and the stakes were too low. I think I died at one point because I accidentally let go of a trigger. That was my only death, and basically it happened because I itched my face or something. I got to repeat the task immediately with no penalty.

There is no platforming difficulty at all. In fact, many elements were downright bad on this front:

screenshot-brothers-a-tale-of-two-sons-climb-1024x592

brothers

The number of places where you must edge around a cliff or cross a narrow bridge got on my nerves. Not because I had to execute something challenging, but because the game designers clearly have no idea why other games use these elements. There is no risk of falling. The game won’t let you—I tried. So what’s the point other than to slow the player down? It’s more than an annoyance; it’s bad game design.

Basically, the game must be a story-driven walking simulator, because we’ve now determined it isn’t any of the other genres it’s crossed with. So how is the story? Oh, boy. Don’t get me started. It’s terrible.

First, it starts with a MacGuffin. This is already bad, mostly because we don’t even know what we’re setting off on our adventure to find. We only know it will magically save our father. That’s convenient. Where are we going? How do we know this cure will work? Don’t the writer’s know that MacGuffins are considered a cliche trope indicative of bad storytelling?

Then we haven’t even left our town and a kid is trying to stop us. Why? Our father is dying, and this kid doesn’t want to let us through. I get it. They needed an excuse to set up some “platforming puzzles” (that, recall, require no platforming or puzzle-solving skills). But you can’t have such a disgusting character with no motivation. I hate the term “ludonarrative dissonance,” because I’ve never consciously experienced it. But here I did. This conflict between gameplay and story already ruined the mood of the game in the first five minutes.

Another act of ludonarrative dissonance was when I got to this big castle that I couldn’t enter, but it had these perfectly placed pegs to grab on to (not quite the picture I wanted, but you get the point):

638766-brothers-a-tale-of-two-sons-windows-screenshot-brothers-tied

Really? This highly fortified castle has this convenient other way to scale it with perfectly placed pegs, just the right distance so that the rope randomly tied between the two brothers barely reaches. Is this a story game or a puzzle platformer? If it’s a platformer, we could overlook these huge narrative flaws. But it doesn’t work as a game in that genre. It’s a story game, but these scenarios wreck the suspension of disbelief for the story.

More succinctly, in the language of game design, these sections involve “environmental puzzles,” but the puzzles don’t occur naturally in the environment at all. This is bad game design.

And let’s not even go there with the deus ex machinas. Are you stuck and can’t actually progress? Yes? Oh, well, good thing a giant appears out of nowhere and just throws you across the ravine. Did you get to the top of the castle only to be at a dead end? Good thing there is a bird trapped in a cage that will fly you to the next area.

It gets worse. How is that bird still alive? It’s been trapped in a cage for who-knows-how-long, bleeding, without any food, and all the people that could feed it are dead. Are we really supposed to believe the bird is still alive?

Lastly, people claim the ending is really sad. They claim they were moved to tears. I couldn’t get past the shrieking woman singing that shrill song at the climax. It ruined the mood. Ending Spoiler:

On a more serious note, I’ve already mentioned all the reasons I never got into the story: ludonarrative dissonance, tropes/cliches, unmotivated characters, ruined suspension of disbelief, plot holes, etc. I just didn’t feel anything except relief the game was over.

On positive note, the concept could have been amazing. Part of what made the game easy was that the core concept was never executed to its fullest. You have to move one of the brothers with one hand and the other with the other hand.

The potential for some truly interesting and difficult gameplay is there. All they had to do was design parts where you have to move both at the same time in fairly precise and independent ways. Instead, they stuck to having you move both in parallel or one at a time. That was the main downfall of the game: It didn’t even deliver on its core innovative mechanic.

Overall, each element has much better games. For puzzle platforming, there are dozens of examples: Braid, Thomas Was Alone, Teslagrad, Super Meat Boy, Trine, and on and on. For story, there are dozens of examples: Gone Home, Bastion, To the Moon, and on and on. For atmosphere: Limbo, Dear Esther, Kentucky Route Zero, The Long Dark, and on and on. I see no reason why anyone should play this game under any circumstance. There’s just much better games on every front.

I know. The whole is better than the sum of its parts for some games. In this case, that is not true. In fact, many parts messed up other parts. What the critics and people who liked this game were thinking is beyond me.

Reviewing Sirlin’s Codex

I’m travelling, so this might not be the most thorough or polished review Codex deserves. Don’t take this as a reflection on the game.

The game can be learned in one or two playthroughs, but it will probably sound way more complicated when describing it in words. I’ll refer to Magic: The Gathering (MtG), Hearthstone, and Dominion. If you have absolutely no familiarity with any of these games, you may want to skip the post. But, you don’t have to have played any of them. If you’ve heard of MtG and vaguely know what a deckbuilding game is (Dominion), you’ll probably be fine.

Codex takes the core of MtG as it’s starting point. Each player has their own deck built from various colors. The colors tend to have themes that loosely follow MtG. Red focuses on haste and burn spells. Green is creature and growth spell based. Black uses skeletons and killing off creatures to get effects. And so on.

But that’s about where the comparisons stop. One of the most annoying aspects of MtG for me is that you can only attack the other player with your creatures. The opposing player has all these creatures on the battlefield and can even block with them, but the attacker can’t have their creatures attack them. It makes no sense, and forces really weird play to avoid bad trades. Also, after being damaged, creatures heal for the next turn. This makes healing a totally nonviable type of spell to design around.

Hearthstone basically fixes these two oddities by allowing creatures to attack each other, and damage persists across turns. This is also how Codex works. It opens up so many interesting decisions. Do I heal myself or do I heal my creatures? (It’s actually not that interesting. Answer: Always heal the creatures because your health isn’t as important as board presence).

In all these games, one must pay a cost to cast a spell or summon a creature. MtG builds these costs into the deck by forcing you to have “dead” cards (land). This means you can randomly get flooded by too much or screwed by too little. The ideal would be to play a land every turn to keep ramping up to better creatures until you hit an ideal amount, and then you never want to draw land again.

Since this is the ideal, Hearthstone just forces this to happen by giving you one extra mana per turn. It fixes these two MtG issues in one swoop. You never draw dead cards, and you can focus on strategically playing on curve without being at the mercy of random draw.

In a sense, this goes too far, because it eliminates some of the decision space. Codex draws on RTS games and hits a very interesting middle ground. You pay for cards with gold, and you always have the choice to increase the amount of gold each turn to play on curve. But unlike Hearthstone, there’s a cost to do it. You must convert a card in hand to a “worker.” This removes the card from the game and costs 1 gold, a startlingly high cost that after a few games becomes clear to always be worth it.

The more decisions that have to be made, the higher the skill cap. This one choice each turn is very interesting. Do you forego making a worker to have better card advantage, and 1 extra gold this turn; or is this too risky because the next turn your opponent will have more gold if they make a worker?

Another RTS innovation that increases the decision space is building tech buildings. Each turn you get to add two cards to your deck from a pool determined by your starting factions. This is the Dominion deck building idea. The point of this is that you can try to predict your opponents strategy and then add in cards to your deck to counter them. But maybe they were only feigning a strategy and you teched in a counter which they already countered. The mind games are real.

If you haven’t built any buildings, you can only use cards coming from Tech 0. If you spend money to build a building, you get to use Tech 1 cards and so on. This is often the hardest decision in the game for me. Tech 2 cards are really, really powerful. If one player starts playing them significantly earlier than another, they will probably spiral out of control to victory.

But building the structure to play these powerful cards pretty much wrecks a whole turn. In other words, if you build these too early, you might incur a cost so severe you fall behind and can’t catch up, even with the powerful new cards. If you build it too late, your opponent might just win with their powerful cards. It’s a super interesting and critical decision that has to be made by comparing economies, board state, card advantage, your current strategy, your opponent’s strategy and so on.

The last interesting innovation I’ll talk about is the fact that you have to have a “hero” in play to cast spells. This opens up a huge range of possible targets for attack. Do you kill the hero and cripple their ability play spells? Do you attack creatures for board advantage? Do you attack tech buildings so they can’t play their more powerful cards? Do you all-in and only attack the base in hopes of rushing a victory?

And this is only the half of it. There’s a board, so creatures can take up strategic positions. Heroes have abilities they get from levelling up. Some of the innovative card keywords are really clever, like Purple being about time manipulation. And I’m sure I’m missing dozens of cool ideas they’ve packed into this.

I’ll admit it is quite expensive to get the full thing, but it’s not a collectible or trading card game. The set is complete as is (and considering it’s priced at about 2 booster boxes of MtG cards, i.e. 1/(10,000+) of the cards in MtG, it’s hard to complain). Once you have all the cards (which come in the Deluxe version), you’re done buying cards for the game forever. The Core Set is priced at a standard board game price and gets you the complete Green and Red sets, and if this is interesting to you, you’ll get more than enough hours of play to make it worth it.

Overall, I couldn’t be happier. It’s like this game was designed specifically with me in mind. The game is really fun at a casual level, but really deep. I could see the game becoming quite competitive with how high the skill ceiling seems to be.

Basic Game Programming Part 3

Here’s an experiment to try purely in C++ (or the language of your choice). Print any character you want on a blank terminal screen at a specific location (say 10 characters over and on the 4th line). This is a crucial idea in game programming, because even something as simple as using the arrow keys to move something around a screen requires you to do this.

You’ll find it gets tedious quickly. Let me guess what you came up with. You have two auxiliary functions. One of them prints “\n” an appropriate number of times to move you to the correct line. The other prints a bunch of ” ” to move you over. It works.

Now suppose you want more information on the screen like health remaining or an inventory list. You can’t use that method anymore, because it depends on where the cursor ended during the last thing you drew. This, in turn, depends on information that could be changing (Health: 9 vs Health: 10 places the cursor one more space over).

Matters get even worse if you want to draw something on the right edge of the screen, because you have no idea what the player is looking at. One could use a standard terminal size, another could have maximized it to fullscreen. This changes the number of spaces on a line.

Until you actually try to do these things, or at least seriously attempt a thought-experiment doing it, you will never appreciate why adding an external library to handle this stuff is important. There are tons of these in existence, but probably the most common and universal ones are built from SDL (we will definitely not get into that today).

The simplest for C++ is probably ncurses. It stands for “new curses” and has a pretty interesting history (the name implies there was a curses). It effectively emulates a terminal, which sounds ridiculous at first (why not just use the terminal!) until you think through all the problems above. Today, we’ll make an “@” symbol move around the screen using the arrow keys.

For our purposes, the two most useful functions in the library will be clear() and mvaddch(). As we saw last time, clear() was annoying because it was OS and terminal dependent. Since ncurses emulates a terminal, there is one function that clears the screen independent of OS. The function mvaddch takes 3 arguments, the first two are ints and give the y-coordinate and x-coordinate where you want to place a character, and the third argument is a character that gets placed in that location.

Even though I want to think in terms of x and y coordinates, mvaddch actually takes the row then the column number. This means you put in y first and x second and the y-coordinate counts down from the top of the screen which can be confusing to new users of ncurses.

At this point, we understand the structure of the game loop, so you should basically be able to fill in the rest of the program. There are quite a few subtleties, though, so I’ll go slowly through it.

The only variables I need this time are the x-coordinate and y-coordinate, so I’ll make these global. I started it at (5,5) randomly. We get input using getch(). This returns an integer, but we don’t need to worry about what that integer is. Since we are using the arrow keys we can use KEY_UP, KEY_DOWN, etc which are integers corresponding to the correct arrow directions. Also, using integers is nice rather than characters, because in C++ we can more cleanly write a bunch of “else if” statements with a “switch.”

This lets us make the whole Update() function by changing the x and y coordinates depending on which arrow direction was pressed.

void Update() {
	switch(userInput) {
		case KEY_LEFT:
			XPOS = XPOS - 1;
			break;
		case KEY_RIGHT:
			XPOS = XPOS + 1;
			break;
		case KEY_UP:
			YPOS = YPOS - 1;
			break;
		case KEY_DOWN:
			YPOS = YPOS + 1;
			break;
	}
}

As before, our draw function clears the whole screen and then draws everything. Because of how ncurses works, nothing will be drawn to the terminal until refresh() is called. This is basically so you can store a whole bunch information about what is going to be displayed, and then it can work out how to display it separately:

void Draw() {
	clear();
	mvaddch(YPOS, XPOS, PLAYER);
	refresh();
}

The only thing left is to initialize a bunch of stuff, but the content of the program is really that simple. I commented the initialization lines so you can see what they do, but for the most part, you’ll just copy and paste that whole chunk in every use of ncurses.

#include <ncurses.h>

int XPOS = 5;
int YPOS = 5;
char PLAYER = '@';
int userInput;

void Update() {
	switch(userInput) {
		case KEY_LEFT:
			XPOS = XPOS - 1;
			break;
		case KEY_RIGHT:
			XPOS = XPOS + 1;
			break;
		case KEY_UP:
			YPOS = YPOS - 1;
			break;
		case KEY_DOWN:
			YPOS = YPOS + 1;
			break;
	}
}

void Draw() {
	clear();
	mvaddch(YPOS, XPOS, PLAYER);
	refresh();
}

int main() {

	//Initialize ncurses

	initscr(); //Tells it to make a terminal screen.
  	clear();   //Clears the screen.
  	noecho();  //When user types input, it doesn't appear on the screen.
  	cbreak();  //Typed character is immediately available.
  	keypad(stdscr, TRUE);  //Standard screen.
  	curs_set(0);  //Starts the cursor at (0,0).
  	mvaddch(YPOS, XPOS, PLAYER); //Draw '@' in the initial location.
  	refresh();  //Updates the screen to display the '@'.

	while(true) {

		//Input()
		userInput = getch();

		Update();
		Draw();

		if (userInput == 'q') {
			break;
		}
	}

	endwin();  //Closes the terminal screen.

	return 0;
}

This will probably be the last post in this series. I have one more topic I could do (decoupling the draw loop from the game logic loop). For the most part, you should now be in a position to look up tutorials on using fancier stuff like Unity or Monogame.

The problem I found with those tutorials is that they focus solely on how to use their engine and not on what these underlying components of the engine are (and why they exist). Hopefully after these posts, these concepts make more sense allowing you to more easily jump in.

(For the record, these posts keep getting the C# tag even though I type C++. It autocorrects it upon hitting the publish button.)

Basic Game Programming Part 2

So here’s a video of the finished product for today. If you haven’t read the last post, you should do that and try the exercises. Better yet, watch the finished product and try to create it without reading the excercises:

We’ll go through all the changes I made, but we’ll start with the most important one. Last week I gave the suggestion “Feature 6: Figure out where to clear the screen to not be so cluttered.” This is a crucial concept in drawing the graphics when making a game.

This toy example gives us the fundamental idea, but if you actually try it in C++, you’ll find it somewhat difficult. I used Linux, so I could use system(“clear”) to clear the terminal screen. You’ll need different commands depending on the operating system. Fighting with drawing things in the proper place will give you a huge appreciation for tools that aid in doing this (we’ll talk about one next week called “ncurses”).

If you watch the video, I programmed it to give the illusion that certain things were static on the screen and don’t get redrawn. In reality, on every iteration of the game loop, I cleared the entire screen and redrew the whole screen with the updated information. This makes it look like “Your Health:” stays the same while the number clicks down as you lose health.

You obviously don’t have to do it this way, but experience has taught me you can get some nasty display bugs if you don’t fully clear and redraw. As I said before, this merely amounted to adding a simple system(“clear”) at the beginning of the Draw() function. I also added a few lines of information.

void Draw() {
  system("clear");
  cout << "Your Health: " << PLYRHLTH << "\n";
  cout << "Enemy Health: " << ENMYHLTH << "\n";
  cout << "a. Attack \n";
  cout << "b. Run \n";
  cout << PLYRDMG;
  cout << ENMYDMG;
}

The other major change was to rescope the variables (you might have noticed they changed names and are all caps, my convention for global variables). Since I wanted many of the functions to be able to access and change the PlayerHealth, EnemyHealth, and so on, I made them all global. This also cleaned up having to pass all of them to each function and allowed me to refactor Update() into its own function.

At the top of the program I list them and initialize them. PLYRDMG is the message “You hit for 2 damage” and so on (see Draw() and compare to the video). It is initialized to be blank so everything writes in the same place:

int PLYRHLTH = 10;
int ENMYHLTH = 10;
string PLYRDMG = "\n";
string ENMYDMG = "\n";

The only thing that changed in the Update() function is an added if statement in a few places so that half the time you miss and half the time the enemy misses. I also had to come up with a way tell the game loop whether the player chose to “Run” and exit the game. This was easy before, because we could write if (PlayerInput == “b”) { break; } to break out of the game loop.

Now the function isn’t in the game loop, so calling “break;” doesn’t work. The way around this was something people came up with in Operating Systems programming a long time ago. I made Update() return an integer rather than be a void. This way I could always return 0 if the player wanted it to keep going. Otherwise it returns 1 and I know they want to break out of the game. This why in C and C++ main() is an int rather than a void. Returning 0 tells the OS that everything went well in the execution of the program.

int Update(string playerinput) {
  if (playerinput == "a") {
    if (rand() % 2 == 0) {
      int r1 = rand() % 4;
      ENMYHLTH -= r1;
      stringstream ss;
      ss << "You hit for " << r1 << " damage.\n";
      PLYRDMG = ss.str();
    } else {
      PLYRDMG = "You miss.\n";
    }
  }

  else if (playerinput == "b") {
    return 1;
  }

  else {
    PLYRDMG = "This is not a valid option.\n";
  }

  //Enemy attacks.
  if (rand() %2 == 0) {
    int r2 = rand() % 4;
    PLYRHLTH -= r2;
    stringstream ss;
    ss << "Enemy hits for " << r2 << " damage.\n";
    ENMYDMG = ss.str();
  } else {
    ENMYDMG = "Enemy Misses!\n";
  }

  return 0;
}

Lastly, I added a “Start Screen” to get into the game. I return to this when the game ends and ask if the player wants to play again. This was done simply by putting the whole game in a second while loop. As long as the player keeps entering “y” for “do you want to play” I keep the boolean variable WantToPlay = true. Otherwise I switch it to false and the game ends. This is also something a prebuilt engine will do for you in a much more elegant way.

Here’s the whole thing:

#include <iostream>
#include <sstream>
#include <stdlib.h>

using namespace std;

int PLYRHLTH = 10;
int ENMYHLTH = 10;
string PLYRDMG = "\n";
string ENMYDMG = "\n";

void ResetVariables() {
  PLYRHLTH = 10;
  ENMYHLTH = 10;
  PLYRDMG = "\n";
  ENMYDMG = "\n";
}

void Draw() {
  system("clear");
  cout << "Your Health: " << PLYRHLTH << "\n";
  cout << "Enemy Health: " << ENMYHLTH << "\n";
  cout << "a. Attack \n";
  cout << "b. Run \n";
  cout << PLYRDMG;
  cout << ENMYDMG;
}

string Input() {
  string tmp;
  cin >> tmp;
  return tmp;
}

int Update(string playerinput) {
  if (playerinput == "a") {
    if (rand() % 2 == 0) {
      int r1 = rand() % 4;
      ENMYHLTH -= r1;
      stringstream ss;
      ss << "You hit for " << r1 << " damage.\n";
      PLYRDMG = ss.str();
    } else {
      PLYRDMG = "You miss.\n";
    }
  }

  else if (playerinput == "b") {
    return 1;
  }

  else {
    PLYRDMG = "This is not a valid option.\n";
  }

  //Enemy attacks.
  if (rand() %2 == 0) {
    int r2 = rand() % 4;
    PLYRHLTH -= r2;
    stringstream ss;
    ss << "Enemy hits for " << r2 << " damage.\n";
    ENMYDMG = ss.str();
  } else {
    ENMYDMG = "Enemy Misses!\n";
  }

  return 0;
}

int main() {
  int State;
  string PlayerInput;
  bool WantToPlay = true;

  while(WantToPlay) {

    //Reset the Initial Information
    ResetVariables();
    srand(time(NULL));
    system("clear");
    cout << "An enemy approaches. Do you fight (y/n)?\n";
    PlayerInput = Input();
    if (PlayerInput == "n") {
      WantToPlay = false;
    }
    Draw();

    //Game Loop
    while(true) {

      PlayerInput = Input();
      State = Update(PlayerInput);

      if (State == 1)
        break;

      //Break out of the game looop if won or lost.
      if (ENMYHLTH <= 0) {
        system("clear");
        cout << "You Win.\n";
        break;
      }
      else if (PLYRHLTH <= 0) {
        system("clear");
        cout << "You Lose.\n";
        break;
      }

      Draw();
    }

    cout << "Game Over.\n";
    cout << "Want to play again (y/n)?\n";
    PlayerInput = Input();
    if (PlayerInput == "n") {
      WantToPlay = false;
    }
  }

  return 0;
}

Next time we’ll work on improving the graphics by using outside tools and getting something moving around the screen so it feels more game-like.

Basic Game Programming Part 1

A lot of people think the best way to get young people into programming is through making games. I agree. Unfortunately, it is kind of hard to find the basics, so I want to do a series on it (Pygame is your best bet for a tutorial, but I’ve personally had bad experiences with it). This is definitely not meant to be some comprehensive tutorial. It is only meant to introduce some basic ideas.

There’s a lot of tools out there to make this easy (RPG Maker comes to mind). These tools allow you to make a fairly complicated and polished game without having any idea about how it is coded. Drag and drop images on a screen, and voila, a game is born. This defeats the whole point!

Other tools like game engines (Pygame, Unreal Engine, Unity, Monogame, Cocos, etc) are important to not have to deal with complicated graphics rendering or other hassles. These should be used in real life. For the purpose of this series, we will look at rudimentary simplifications of some of the things going on underneath these engines.

I will not assume you are comfortable with programming, but I also won’t explain the code much. I’ll assume you can look at the code and are able to figure out with some prompting what it does. The most important part of learning to program is learning the ability to look things up.

I’m going to use C++ even though I know most people learn Python or Java these days as their first language. But if you want to write cross-platform games, you’ll want to use C++ (Cocos) or C# (Unity and Monogame) or whatever Unreal uses. If you want a refresher, this game will only use cin, cout, variables, if/else. This should take less than 2 hours to learn from a reasonable tutorial.

If you have a little programming experience, there is a fundamental concept you’ll have to get used to called the game loop. It essentially looks like this:

while(true) {
    //Insert entire game here.
}

The game will infinitely loop through the instructions. For most simple games, this is overkill and uses a ton of unnecessary processing power. Also, without a professional game engine underneath, you don’t have a way to limit the speed at which it loops (30 times per second or 60 times per second). Don’t worry about any of this. Just know that you will eventually want this constant loop, so it is good to get used to it.

Let’s add a touch more detail now. The game loop roughly consists of three parts: Getting input from the player, Updating the game state based on that input, and Drawing to the screen whatever has changed from the update step. This is called the engine, because it keeps churning and puts the game in motion. If you use Unity or some pre-built engine, each of these parts will exist already (and will loop independently in parallel, but that is for another time).

Our game now looks like this:

while(true) {
   GetInput();
   Update();
   Draw();
}

Again, this is needlessly complicated for the game we will make, but it is worth getting used to this flow with something basic so you aren’t learning a whole new framework with something more complicated.

Now let’s describe the game. The game will display your health and the enemy’s health. The player will have 2 choices: Attack or Run. If you attack, you hit the enemy, in which case the enemy’s health decreases by some amount (we’ll make it random between 0 and 3). If you run, you leave the game (effectively a “quit” choice). The enemy always hits you.

If the enemy’s health reaches 0, the player wins. If the player’s health reaches 0, the player loses.

A part of the engine I didn’t describe is the initialization that come before entering the game loop. In this case, we might want to describe the setup and get the initial variables set up and call the Draw() function to get something on the screen.

There will be 2 variables: PlayerHealth and EnemyHealth. Let’s set them both to 10 to start. At this point I think we can write the first form of the Draw() function, which right now will just print out and label these variables and give the two options for action. Eventually, we’ll probably want to say who got hit, too.

void Draw(int playerhealth, int enemyhealth) {
  cout << "Your Health: " << playerhealth << "\n";
  cout << "Enemy Health: " << enemyhealth << "\n";
  cout << "a. Attack \n";
  cout << "b. Run \n";
}

This might look a bit confusing, but “cout” just means “print to the screen.” So each line of that is printing “Your Health: 10” (and the \n means “new line”).

Now let’s get the input. We’ll do something a little bad, but we’re just trying to get the flow down here. We’ll worry about “good coding practices” some other time. Let’s make the function Input() return the string the user inputs, so we can store it rather than modifying some global variable.

string Input() {
  string tmp;
  cin >> tmp;
  return tmp;
}

Again, “cin” just asks for the player input. The input is stored in the variable “tmp” and then gets returned.

The most complicated part of this is going to be the Update() function, but it isn’t so bad. Update() needs to say: if the player typed “a” we subtract the attack amount from EnemyHealth. If the player typed “b” we exit the loop. If anything else was typed, we don’t do anything and notify them it is not an option.

if (PlayerInput == "a") {
      int r1 = rand() % 4;
      EnemyHealth -= r1;
    }
    else if (PlayerInput == "b") {
      break;
    }
    else {
      cout << "This is not a valid option.\n";
    }

I used here a random number between 0 and 3 (inclusive) for how much damage the attack does. (Look up rand() for how it works. It is part of the standard library.) There isn’t much left, so I’ll give the whole thing now with some comments:

#include <iostream>
#include <stdlib.h>

using namespace std;

void Draw(int playerhealth, int enemyhealth) {
  cout << "Your Health: " << playerhealth << "\n";
  cout << "Enemy Health: " << enemyhealth << "\n";
  cout << "a. Attack \n";
  cout << "b. Run \n";
}

string Input() {
  string tmp;
  cin >> tmp;
  return tmp;
}

int main() {
  //Initialize the variables
  int PlayerHealth = 10;
  int EnemyHealth = 10;
  string PlayerInput;

  //Initial Information Drawn
  cout << "An enemy approaches... \n";
  Draw(PlayerHealth, EnemyHealth);

  //Game Loop
  while(true) {
    PlayerInput = Input();

    //Update Information based on input.
    if (PlayerInput == "a") {
      int r1 = rand() % 4;
      EnemyHealth -= r1;
    }
    else if (PlayerInput == "b") {
      break;
    }
    else {
      cout << "This is not a valid option.\n";
    }

    //Enemy attacks.
    int r2 = rand() % 4;
    PlayerHealth -= r2;

    //Break out of the game looop if won or lost.
    if (EnemyHealth <= 0) {
      cout << "You Win.\n";
      break;
    }
    else if (PlayerHealth <= 0) {
      cout << "You Lose.\n";
      break;
    }

    //Print out the Updated Info
    Draw(PlayerHealth, EnemyHealth);
  }

  cout << "Game Over.\n";

  return 0;
}

Here’s some features to add as homework. Now that the core is there, if you think of one thing and add it each day (15 minutes tops?), in 2 weeks you’ll have a pretty interesting and complicated text-based game. They don’t have to be these or even in this order. These are what popped into my head.

Excercise 0: Try cleaning up the current code so that Update() is its own function like Input() and Draw(). Don’t try too hard, because it is more complicated than it’s worth. You will encounter your first struggle with how to scope variables that all your functions want to know about. Also, breaking out of the while loop will become tricky.

Feature 1: Look up how to do random numbers. Make it so that you only hit the enemy 50% (or whatever you want) of the time. Make it so the enemy only hits you sometimes. This might be a 2 day feature if you are totally new to programming in C++.

Feature 2: Tell the Player that they hit the enemy and how much damage they did.

Feature 3: Make a “Title Screen” that tells you the game you are about to play.

Feature 4: Add some backstory to the introductory text.

Feature 5: Add more options for player input (different types of attacks that do different damage amounts).

Feature 6: Figure out where to clear the screen to not be so cluttered.

Feature 7: Ask if the player wants to play again rather than automatically closing the program when it is over.

That’s a whole week’s worth of exercises, and you’ll have a basic working game at the end. Next week, I’ll go through implementing these changes and maybe make a quick video to show that end result can look like a real-life, old-school text game.

Thoughts on ToME’s Adventure Mode

I’ve done several posts explaining why I think roguelikes are a great genre of game to play. It is probable that the most important feature of a roguelike for me is permadeath. For example, see this post for reasons why.

If you aren’t up on roguelikes, there are only a handful of games that standout as the “giants” that most people have heard of. One of these is called ToME (aka ToME 4; aka Tales of Maj’Eyal). There are more interesting features in ToME than could fit in a single blog post. Someday I may come back and post about these.

I’ll fully admit that my views on permadeath have evolved a bit, possibly due to my age. I think the older someone gets, the more likely they are to view losing all progress in a game as too punishing to be worth it. You tend to grow out liking the more extreme and hardcore elements of certain games.

Anyway, I stand by my original post. I’ll recall some key points. Permadeath is a great game mechanic, because it forces you to contemplate the consequences of your actions. It gives weight to the game. It makes you become better at it in order to win. You can’t just “save scum” until you get through a particularly difficult section.

Before you take this the wrong way, ToME is possibly the most well-balanced roguelike I’ve played. Every death feels like my own fault and not me getting screwed by the randomness. But when a game involves as much randomness as any of the great classic roguelikes, you are bound to get the occassional unavoidable death that is not your fault.

This becomes more and more pronounced as a game’s design is less thoroughly vetted for imbalances. Part of ToME’s excellent balance comes from people who have put in thousands of hours of play who can spot these things. The developer takes their opinions seriously which makes the game more fair.

ToME has three modes of play: roguelike, adventure, and explore. Roguelike has traditional permadeath. Once your die, you must start the entire game over. Adventure gives you five lives. Once those five are gone, you start the game over. Explore is deathless.

The main point I’ve been contemplating is whether Adventure mode ruins the permadeath experience of a roguelike. This will be a highly controversial statement, but I think it keeps all the original greatness of the mechanic and eliminates the negative aspects.

If you only have five lives, then each one is still precious. You’ll play the early game as if you only have one life, because if you waste one early, you will probably restart anyway. This makes the beginning just as intense as if you only had one life.

Let’s put it this way. If you don’t play as if you only have one life, then you will probably quickly lose them all anyway and revert to roguelike mode. So nothing really changes. In the middle and late game, if you are really good and don’t lose any lives, then it didn’t matter anyway. If you’re like me, you’ll probably be back to one life by that point and get all the benefits of roguelike mode.

It seems to me that Adventure mode merely serves to alleviate the annoyance and waste of time that comes from getting killed in one hit by some out of depth enemy that randomly appeared due to no fault of your own. It keeps all the intensity and pressure of permadeath, but gives some much needed buffer for the extreme amount of randomness of roguelikes.

I’d be quite happy to see some other roguelikes incorporate this as an option, but I’d also be totally understanding if they saw it as a compromise on the quality of the play experience.

7DRL Takeaway Lessons

I promise this will be my last 7DRL post, but I thought I should record some thoughts I’ve had about it now that it is over.

This post could alternately be called “Why I Will Not Use MonoGame in the Foreseeable Future.”

First, the motto of MonoGame is “Write Once, Play Everywhere.” This sounded promising to me, because my first game had issues deploying almost anywhere. Of course, what they mean is that you can play anywhere supported by Windows.

There are ways to get builds onto other platforms so that Mac and Linux users can play, but I only had 7 days, and I’m not a trained computer scientist, so that wasn’t going to happen. This was a little frustrating, and also one Windows user already complained they couldn’t get it installed.

Second, MonoGame is effectively a re-implementation of XNA 4. Unfortunately, some of the pipelines (especially with an up to date Visual Studio) are broken and require hacks to work. This caused major problems with sound. So much so that I scratched all sound from the game.

I know that with enough time, I probably could have gotten this working (because lots of games made with it have sound), but I couldn’t waste the time in those 7 days to fight with it. This was frustrating, because one of the main reasons to use MonoGame was to make all of that streamlined and easy.

I also felt trapped into using Visual Studio as an IDE. This is certainly a fine IDE, but I’m most comfortable with Sublime Text 2. Switching editors wastes a lot of time, especially when you “downgrade.”

By this I mean VS doesn’t have half the great features of ST2 (including my most used feature: multiple cursors). In retrospect, I should have edited in ST2 and built in VS.

All this being said, MonoGame was a good enough framework to produce a full working game in 7 days, so I can’t complain too much. Also, if I were part of a larger team with a longer time frame, many of these issues would disappear. So I admit these complaints come specifically from the 7 day issue.

If I do this again, I will almost certainly try Cocos2d-x. It looks like this will fix all the complaints I had. First, Cocos2d-x is open source. This means I can actually see what the engine is doing if I need to! What a concept.

Second, it is C++, so it will deploy across platforms much easier. Lastly, it isn’t in some transition period like MonoGame where content management seems to use outdated, unsupported pipelines. I’m also more familiar with C++ than C# which would have solved a few headaches.

Theseus: a 7DRL 2015 Completed!

Final Stats:

One week.
About 90 hand drawn 64×64 pixel tiles.
Over 2000 lines of code.
A completed one-hp strategy roguelike.

Proof that it can be beaten happened during my stream where I tested for bugs (quality isn’t the best):

Actually, I think I’ve finally gotten it balanced so that you should be able to win if you know what you are doing every time except for extraordinarily rare scenarios dictated by the randomness.

7DRL 2015 Success.

[Edit:] I’ve set up an itch page: http://hilbert90.itch.io/theseus
Download the game to play for free here: https://www.dropbox.com/sh/1ywjy7s3y72bq5k/AABOZWsPOFBYs0qgcxW5Ccqxa?dl=0

7DRL: Theseus, Alpha Testing Phase

Alright. I have to leave for the day. I’ve thrown a few more things in this morning at the last minute, and then built the whole game.

If anyone wants to test it and give feedback, that would be much appreciated. I’ll still do a lot of polishing tomorrow.

Sorry, as of right now I have a build that I’m 99% positive will work on any Windows 7 or 8 machine. Earlier probably works, but hasn’t been tested. I haven’t made any others (the opposite of my first game which people could only get to work on Linux).

I’ve learned my lesson. If I do this again, I’ll probably switch to Cocos2d-x, which is open source, and easily builds into any machine.

Types of things I’m looking for:

1. The whole thing crashes. If this happens, try to remember exactly what happened and leave a comment.

2. The setup doesn’t install it on your computer, but you are using Windows. Let me know something about your computer if this happens.

3. The game is too easy (for example, you consistently scale up too quickly and bash your way to victory with no thought).

4. You can let me know if it is too hard, but I probably won’t change that.

5. Anything else that seems reasonable to need a fix for being on Day 6 of developing a game (you can say the art is not polished, but that will just hurt my feelings … it’s Day 6 and I had a lot of other things to do for goodness sake).

6. The Readme didn’t have enough information.

Tonight or tomorrow, I’ll probably add 2 more items for reference of what will be added before the final release.

Thanks. Have fun.

I’ll think of a better way of distributing this later. For now, go here: https://github.com/wardm4/Theseus

Press Download Zip (button to right). Ignore all the files except the one called “Theseus.zip” Right click on that and save it somewhere (your Downloads folder or whatever). Unzip it and then double click on setup.exe. That will prompt a standard install.

Better yet. I’ve added just the zip to a Dropbox here if you don’t want to get the source code too: https://www.dropbox.com/sh/1ywjy7s3y72bq5k/AABOZWsPOFBYs0qgcxW5Ccqxa?dl=0

7DRL Dev Log Day 5

Today turned out well. I didn’t get trapped trying to fix some problematic C# syntax like in the past two days. The main improvements were to draw the final boss, get him animated, program his AI, and get the final room set up (which has different design structure than the rest of the labyrinth).

I did some balancing with the boss to figure out how much HP seemed reasonable for what level I thought an average person would be at. I also drew, animated, and designed an AI for a new NPC that will make an appearance later in the game. They are pretty tricky, so I imagine a bunch of deaths for people who dare to make an attempt at them.

The game feels reasonably complete at this point. There is a nice progression leading up to the final boss, and you win the game if you kill it. I made a push to get it to this point before today, because it turns out that tomorrow I’ll have almost no time to work on it at all.

I have two more significant additions I want to make, and then tons of polishing I can do (tons of extra animations, sound, balancing, bug finding and fixing, etc). Overall, I’m finding the game a bit too easy, but my alpha tester hasn’t beaten it yet, so who knows. If you know all the enemy patterns (like I do), then I think it is beatable pretty much every time with caution. I never came across an impossible situation today.

Tomorrow I’ll give a download of the most up-to-date version in case any readers want to volunteer a few playthroughs to give some feedback before the end of the last day.