Gamedev Grievances #11: The Power of One (Using Objects Wisely)

One of the mechanics of Ambience I’ve been working on lately is the idea of “prison liberations”. Essentially, it works like this: When you’re traversing an area and you’re defeated by one of Foss’s Henchmen, you’ll be captured and sent to a prison. (If you’re defeated in a prison, then you’re just thrown back into your cell.)

capture-in-prison-a

Once you’re captured, you have to escape from the prison before you can progress any further through the game. However, once you progress far enough through the story, you have two options: you can either escape from the prison, or liberate it.

escape-liberate-options

An escape involves just that – you escape from the prison, disappear into the darkness, and continue your journey. The other option is to liberate the prison – which means you have to sneak into the depths of the prison and shut down the security systems, effectively liberating all the (unseen) prisoners from the dungeons. This option, however, is more difficult than a simple escape. The route is longer, prison guards are tougher, and items, while powerful, are scarce. And once you reach the end and disable the security systems, there’s a boss fight to be won as well.

Of course, there are significant rewards for completing such a task, which I won’t talk about in detail here. What I did want to focus on was the “disabling security systems” part of the liberation, which is basically a “match-the-colours” style minigame. (High-tech security systems, indeed.)

match-colours-short

Of course, for every game (or minigame) there has to be a strategy for putting it into action. In this case, there were two main ways I could have done this.

Option 1: Use multiple objects (or “classes”, if you’re not using GM:S) that are all interfaced and work together. In this example, I would probably need at least three objects. Firstly, a button object which changes colour when selected and when there’s a match. Secondly, a selector object which moves between buttons and selects them. And thirdly, a controller object which creates the buttons and selector, registers player input, keeps track of the number of tries remaining, and checks for matches.

Of course, there’s room for some variation to this scheme of operation. For example, you could have the selector object pick up the player input and move between buttons, while the controller does everything else. Or you could scrap the controller entirely and get the selector object to do everything, including creating and destroying the button objects.

Option 2: Alternatively, you could go full minimalist and just create a single controller object which deals with everything: buttons and selector, player input, tries remaining, matches, and so on. A consequence of this is that all the buttons and the selector have to be drawn manually – in other words, the player doesn’t really manipulate any “real” buttons or selectors, but just pictures of buttons and selectors instead. The way it plays out is exactly the same, but under the hood it’s very different.

So, which one did I pick?

Years ago, when I first started making games and playing around with GameMaker, I would have gone for the first option almost every time. In the world of object-oriented programming, it just seems simpler to think of buttons and selectors as real objects that do things, rather than just deal with drawings that give the same result.

However, one thing I’ve found with this option is that the limiting factor on functionality is always the interactions between objects, which for more complex systems can get disgustingly messy. Once you reach that stage and you find a bug, it can take ages to track it down – often because you have to mentally juggle and deal with so many objects that are all interacting with each other.

Of course, in the end systems do get complex and dealing with lots of interactions does become unavoidable, along with the messy consequences. But if there’s an easy way and a (potentially) complex way of doing something, I’ve learned to just pick the easy option. Which is, I judged, the second option. In that case, when everything’s done using a single object, the thing that gets complex is the code – which means you have to be very careful, and very efficient, about how you choose to implement your system.

The Game Plan

Here’s how I made the minigame using option 2…

  • First, I created two square-shaped grid data structures: one grid contained the colour values, while the other one contained integer values for the “status” of each cell.
  • I then filled each cell in the colour grid with one of four colour values (integers). Keep in mind that I couldn’t just fill the by randomly choosing a value for each cell – that would potentially give me an odd number of one type of colour, making the puzzle impossible to solve! Instead, I made a list of values to choose from, then filled each row with the same value. I then called a handy built-in function to scramble the grid values and create a random array of colours for the player to match.
    var numlist = ds_list_create();
    ds_list_add(numlist, 1,2,3,4); // colour values
    for(var j=0; j<4; j++) {
        for(var i=0; i<4; i++) { // the colour grid is 4x4
            colourGrid[# i,j] = numlist[| i];
        }
    }
    ds_grid_shuffle(colourGrid);
    ds_list_destroy(numlist);
  • I also defined the number of tries to give the player (this took some trial and error to balance!), as well as the selector’s current position in the grid, and some other things.
  • When the player selects a cell, it changes the corresponding value in the “status grid” from 0 (not selected) to 1 (selected). If that’s the only cell selected, it then lets the player choose another cell. Once a second cell is selected, the colour values of the selected cells are compared. If there’s a match, then it changes both the selected cell statuses to 2 (matched) so they remain revealed and the player can’t select them again. If it’s not a match, it briefly shows the colours and then resets the selected cells to 0.
  • Finally, I set up the object’s Draw event to draw the buttons and selector. The button appearances are dealt with by using different subimages in the button sprite for each state (not selected, selected and matched). I also used a shader to colour the button sprite when it was selected or matched, so I didn’t have to make four different sets of sprites for the four colours.

After that, things were easy – I just needed to create the controller object to start the game, and destroy it when the game was over.

I’m not too familiar with how one would best implement something like this in a different language or system, but for me in my little GM:S world, the single-object method worked really well. It’s also especially useful for minigames where you don’t want it to interfere with other stuff in the larger game – you just put everything in a single isolated object and let it do its work. Also, it was very satisfying to see how I could just drop a single instance in the room and BAM! – the minigame would do its thing.

(One final note about the game: I originally gave the player the option to select a cell and then deselect it to change the player’s choice, but then realized this would be a very bad idea. See if you can work out why…)

Be the first to comment

Leave a Reply