A Quick Whack-A-Mole Review

I’m still working through the questions, examples, and problems you’re sending my way. I’ve got a few more things to upload too, but I’m out of time today, and can’t get back to this until Sunday early AM.

With that in mind, and hoping to reach the broadest possible audience, here is a quick video that reviews the loop I’m using in my quick Whack-A-Mole mock-up.

As I say, there are a few more things coming, but probably not until tomorrow AM.

Note: The video is still uploading to Vimeo and I don’t have an address for it yet. It should be the first video on this list, however: https://vimeo.com/user102714129. It may not be visible until 7PM on Saturday (today).

Finally: Here’s a copy of the source code for Space Gophers Something Something, the code I discuss in the 45 minute video, above.

More demo goodness

For today’s workshop, here’s a demo I just put together. It makes use of:

  • Spritesheet import;
  • Music / sound;
  • Multiple rooms / room switching;
  • Alarms / timers
  • Special effects (really just an explosion object)

You can download the demo here. Sorry for not having time to add comments — please follow along in class and annotate as useful. If I have time this weekend, I’ll revise this with full comments.

Planning Suggestions Project 2

Some ideas about how you should proceed, if you’re not yet proceed-ing.

  1. Start with a sketch of the game board and explanation of gameplay;
  2. Simplify that sketch (take as many details out as you can bear! You can put them back later!)
  3. Now describe your gameplay (your “game loop”) drawing exclusively from that sketch;
  4. Simplify and condense your game loop to its most essential elements;
  5. Add the stuff that needs to go before and after the game loop in order to make things work (e.g., “Show game board”, etc.);
  6. Now divvy that outline into phases for building (a to-do list);

In a separate phase, then, do more strategic planning.

  • Decide on immediate, mid-term, and due-date goals;
  • Decide on bonus outcomes and opportunities, etc.;
  • Map things out to a calendar (our Second Project is tentatively due on Sunday, 26 September, by Midnight);
  • Be as explicit here as you can stand to be.

Some miscellaneous suggestions: Problems you may need to solve. Keep in mind that you don’t always have to solve these problems in order — but resist the temptation (wherever possible) to skip around randomly without actually finishing any single task: That approach is a disservice to the work you’re doing, and will (usually) end up putting you in a bad position.

  • Figure out how to get a single gopher instance to appear and disappear — without making all of them do the same;
  • Figure out how to detect if you’ve clicked on a gopher at the right time;
  • Figure out how to assign points for that event;
  • Can you determine which gopher you’ve just clicked on?
  • Figure out how to record an increase in score after successful click;
  • Can you make those points appear in the place where you just clicked? Even as you remove the gopher from the screen?
  • Figure out how to vary the gopher animation;
  • Figure out how to gradually increase difficulty.

Cookie-Planets

For no particular reason, here’s a bunch of cookies orbiting around Cookie Monster.

Cookies float around Cookie Monster.

Some of the things going on in this code include:

  • Programmatic object instantiation (the Cookie Monster creates a random number of cookies) — their placement relative to the center of the screen is then calculated and saved back into each cookie instance;
  • Using instanceID handles;
  • Randomizing names using an array (and assigning the outcome to each specific instance);
  • Detecting the closest cookie instance to your mouse (and returning the instanceID);
  • Drawing text and shapes over an instance;
  • And probably some other things, too. Questions? Let me know!

Here’s the package.

More Nested Loops

for() loops are so important to understand thoroughly. This tutorial shows you how I create the side of a building by making a window out of a sprite, and then carefully calculating how to squeeze as many on the surface of the building as possible. Download the code below.

Once the windows are installed, you’ll notice that you can mouse over them to turn the inside lamps on — but they’ll go out in a random amount of time.

An unpleasant building.

The blinking blue star is my “controller object” — it builds the building, etc., but doesn’t do anything after that. Note that the building surface itself is just a sprite I’ve dragged onto an independent “Asset” layer — not the “Instances” layer itself. I can do that because the building doesn’t have any code to run. Just the windows (which are placed programmatically on the “Instances” layer, where their code can run.

If you have time, there is a tiny bit of code in the Mouse Enter event that deals with setting an Alarm — a timer — that can be useful.

Nested Loops

A for() loop lets us repeat a task a certain number of times. Put one for() loop inside another, and suddenly you’re the Mayor of Repeatsville (I dunno what that means either, just work with me on this.)

Let’s start with a quick reminder of how for() loops work when they are young, single and sassy:

for (var x = 1; x < 4; x = x + 1) {
// do everything inside those curly braces
// AKA "a code block"
}
// When that for() loop finishes, it
// will leave the code block and come here next.

As a reminder, here’s what is happening in that for() loop.

  1. We start with a temporary variable, called x, which we set to 1.
  2. Then we do everything in the code block (anything between those curly braces on lines 1 and 4).
  3. When we finish that code block, and we hit that bottom curly brace on line 4, we’re still “doing” the for() loop — so we go back to it (on line 1).
  4. It tells us to add one to x.
  5. If also tells us that if x is still less than 4, then we should do the whole code block again (this time, though, x is 2).
  6. Finished with the code block? We’re still inside the for() loop, so go back to it (on line 1).
  7. It tells us to add one to x.
  8. It also tells us that if x is still less than 4, then we should do the whole code block again (this time, while x is 3).
  9. Finished? Cool. Go back to the for() loop statement on line 1 again.
  10. It tells us to add one to x, which means x is now at 4.
  11. It then asks (just like it has before) is x < 4? This time, obviously, the answer is no. So we don’t just repeat the code block again. Instead, we make a hasty exit to the next line of code that is outside of our for() loop. In this case, we’d jump down to line 5.

The Assistant-Manager Approach to Nested Loops

So then how does a “nested for() loop” work? We’ll use them a lot — and they seem complicated, but if you break each step down, I think you’ll find that you get a lot of predictable (if tedious) steps that make sense.

First bit of advice: As before, don’t get hung up on the idea of “nested for() loops” as overly technical. Think of them instead as a way of accomplishing familiar tasks. For example, imagine we run a fancy-shmancy 5-story boutique hotel. Well, not “run” technically, as we’re Assistant Manager, not Manager. But you and I both know that the Manager leaves most of the important stuff to me, so I might as well be Manager.

Anyway, imagine that every floor of this hotel has four rooms. Five floors, four rooms each: That’s 20 rooms in total. So when I need to print out new hotel keycards — the little credit-card sized digital keys that we give to guests — I could type each one out by hand, but I could also create these keycard codes computationally.

Now imagine the keycard code looks like this: “3FL/RM4.” To us hospitality (“assistant”) management types, that means 3rd Floor, Room 4. (It isn’t as easy as it looks!) Try this one: “1FL/RM2.” That would be First Floor Room 2. (You’ll get there! Not everyone is cut out for the “assistant” manager roles). Anyway, here’s how we might think of the keycard generator in “pseudo-code” — our natural-language description of the process.

  1. Count off our hotel’s floors, one-by-one, starting with the first floor and not going past the fifth floor;
  2. For each of those floors, count off that floor’s rooms, one-by-one, starting with the first room but not going past the fourth room;
  3. Take the floor number and add the characters “FL/RM”;
  4. Now add the room number to that string;
  5. That’s the keycard code! Print it out or whatever.
  6. Keep looping through each of the rooms until you run out of them;
  7. Finished with the room loop? Now go back and do the next floor. When we do that, the first thing we come to? OH ITS THE ROOM LOOP AGAIN SO MUCH FUN. So I guess we get to do that again. In this numbered list, that means going back to step 2 again! Re-starting our room numbers from 1! Joy!

If we looked at a list of the keycards generated this way, here’s what we’d see (in the order they were created):

1FL/RM1
1FL/RM2
1FL/RM3
1FL/RM4
2FL/RM1
2FL/RM2
2FL/RM3
2FL/RM4
3FL/RM1
3FL/RM2
3FL/RM3
3FL/RM4
4FL/RM1
4FL/RM2
4FL/RM3
4FL/RM4
5FL/RM1
5FL/RM2
5FL/RM3
5FL/RM4

OK: Let’s translate that common-sense series of commands into something the computer can cope with. Here is the code above translated into GameMaker Language. In this case, I push the output to the debugger window.

for (var floor = 1; floor < 6; floor = floor + 1) {
  for (var room = 1; room < 5; room = room + 1) {
    var myKeyCode = string(floor) + "FL/RM";
    myKeyCode = myKeyCode + string(room);
    debug_message(myKeyCode);
  }
}

Some things to notice:

  • We have 5 floors, so in my code, I say (in line 1) “as long as floor is less than 6″ (which makes sure the loop only quits running AFTER it does the 5th floor). I could also have done this (less common, but just as valid):
for (var floor = 1; floor <= 5; floor = floor + 1) {
  // note that <= ("less than or equal to...") works,
  // but "equal to or less than" (floor =< 5) gives an error.
}
  • Pay attention to the indentations / tabs. While sometimes they get messed up (usually by us — the computer tries to use them wherever it can) those indentations are a good indicator of where a new block of code starts. See how everything is indented below the SECOND of the for() loops (lines 3-5)? And see how THAT for() loop and THAT code block are indented beneath the FIRST for() loop? Those indentations (which go hand-in-glove with the curly braces) help us understand how some code “fits inside” other code.
  • Because they are nested, note that the two for() loops actually do a very different amount of work. The outermost for() loop seems to do much less work, while the innermost for() loop does a lot of work.

Let’s test that idea:

Let’s say for a minute that we could somehow attach lights to each for() loop in order to see when the computer was running that code. Let’s put a Red light on the outermost loop (in the case above, the Floor counter) and a Green light on the innermost loop (in this case, the Room counter).

Here’s what we’d see (I’ve consolidated it to one line to keep it shorter!)

RGGGGRGGGGRGGGGRGGGGRGGGG

Getting Started: Project Two

Some suggestions as you get underway with this, our second project.

  • Don’t worry about art at first. That is always very tempting! But save that for later;
  • The player’s site of interaction is EVERYTHING in a game like this. Make sure it works and is predictable and satisfying before moving on to something else;
  • Make copious use of booleans (flags);
  • As you get started, don’t think about gophers, plural: Build a single working gopher and code for interaction. Relativize variables, fill the screen with instances of your Arche-Gopher, and then you’re in business.

Introducing Project Two

Whack-A-Mole

Our first effort at integrating some sense of gameplay into a project.

Whack-A-Mole was hugely popular in the 80’s and 90’s, especially at kids’ entertainment restaurant chains like Chuck E. Cheese (“Where a Kid can be a Kid!”) and even at more adult-oriented venues like Dave & Busters (“Welcome to Hell”).

In the physical version of the game, usually between 4 and 9 moles, gophers, etc., randomly emerge from fixed holes in the ground.

“I cannot cope with any of you any longer, and neither the games nor the buffalo chicken wings will suffice to numb my pain. Please let me leave.”

Physical versions of the game were extremely popular in arcades, especially with young children and guys in their mid-twenties (go figure). A large rubber mallet was typically used to strike the emerging rodents on the head, sending them back into their burrows.

Our Version

The Nature of Your Gameplay

Regardless of the options you include in your code (see below), you need to begin with a fairly basic set of questions: What kind of experience are you providing to your player? What are you requiring of her? What are you giving her in return?

My suggestion: As you are getting started, write down an answer to that question in your code comments. Keep going back to it, asking: Am I building the experience I intended?

This game offers us an opportunity to think about the kind of experience we want to build out of the generic “whack-a-mole” theme. Of course, it is important to observe that each of the gameplay suggestions (below) require increasingly complex code. Complexity doesn’t always (or even usually) mean “good.” A very simple but very solid game, with reliable interaction, is almost always preferable to a cool but utterly unplayable mess. Remember: We still play PacMan and Space Invaders because they are essentially “perfect.”

Gameplay possibilities, from simple to complex

  1. Your game is a game that emphasizes immediacy of reaction, but demands no real strategy on the part of the player;
  2. Your game is a game that demands some very simple strategic decisions from your player: She can’t hit two gophers simultaneously, for example, so she must choose the most valuable one to clobber, etc.);
  3. Throughout gameplay, your player makes choices of varying risk: For example, whacking a multicolored gopher sometimes (e.g., 25% of the time) makes all of the gophers move at 15% of their regular speed, or triples their point values, but most of the time (75% likelihood) ends up speeding up the gophers, temporarily rendering her hammer limp, or reducing point values;

Alternatively, consider more puzzle-oriented gameplay

Nota bene that in my experience, puzzle-oriented gameplay often makes for code that is more difficult to balance and harder to polish to perfection.

  1. Your game borrows some elements from puzzle-style games, but remains action/reflex oriented: E.g., your game stipulates that you cannot hit two gophers of the same color consecutively;
  2. Your game pushes further away from an action/reflex-style game into the realm of more advanced puzzle-style problem-solving.

Baseline Requirements

Requirements for our version are fairly minimal. Remember what we’ve said about working towards the “minimum viable product.”

  • 5 fixed holes and 5 independent moles/gophers;
  • Click on a gopher to send him back into his burrow and score points;
  • Choose: The game lasts either (1) n seconds or (2) however long it takes to bash n gophers;
  • The gophers should randomly appear and disappear from sight (and are only bash-able when visible);
  • When a gopher is successfully struck, there should be at least one (ideally more) indication of success;
  • The game should begin by telling the player to “get ready,” followed by a pause of (say) 3 seconds;
  • The player should always have a sense of where she is in the game. For example, the game might display time remaining; required points remaining; remaining gophers; or some combination of these (depending on the nature of gameplay in your iteration).

Some Advanced Options

If you are comfortable accomplishing the tasks above before the due date, consider adding one or more of the following characteristics to your game.

Making the Gameplay More Interesting

I strongly suggest that you engage with these options only after completing achieving “minimum viable product” (above) and that you add these one at a time.

  • Add a splash screen and a final score screen;
  • Add a theme song that plays throughout;
  • Add sound effects to gameplay
  • Animate your gophers (moles or whatever): Make the varmints react to being clicked, give them idle animation, etc.

Small-Scale Gameplay Change Suggestions

  • Incorporate false or dangerous targets (e.g., a bomb);
  • Create an animated hammer to use in lieu of a simple mouse pointer;
  • Special effects appear when hammering, missing, running out of time, scoring bonuses, etc.;
  • Increase difficulty over the length of gameplay;

Suggestions (Project One)

Persistent Problems

Using other peoples’ code

This is great! Do this more! BUT in so doing, try to take greater advantage of what they are giving you. In many cases, for example, the tutorials from which you’re borrowing are probably making things more difficult, not less: They fill up your program with lots (and lots!) of unrelated stuff, and make use of techniques that don’t quite square with ours, etc.

Again: That’s not bad — in fact, that is the single best way to learn, in my mind. However, plugging the code in and crossing your fingers is just the first step to making use of it. What you want to be able to do eventually is force the code to reveal its secrets to you — in other words, you want to keep changing things slowly over time so that you can better understand how it works, and maybe even why the developers chose to use that approach. This is a laborious and slow process at first, but you’ll get better at it as you become more familiar with more programming techniques.

Remember this, though: Your goal is always to be able to “run” your code in your head. You should be able to work through your code just like the computer will (howbeit in a slightly slower fashion). That means that you should (eventually) be able to explain what every single line of code does. (Hint: As you figure them out, add a comment or two to keep track of what is going on).

Here’s another approach to consider (and again, these are great exercises to create for yourself and work through every day). I call this UNPACKING.

Here’s some code taken directly from a tutorial on creating scrolling marquee text. I can make use of this for a project I’m working on — but I want to make time to insist that I understand how it works. We can do this by taking the code apart and breaking it down as far as we can.


Original marquee tutorial code

CREATE EVENT

my_string = "Some text for your marquee "
start_letter = 0;
marquee_length = 10; // or however many letters in your marquee
type_rate = 3/room_speed; // 3 char per second
marquee_scrolling = true;
DRAW EVENT
if marquee_scrolling{
draw_text(x, y, string_copy(my_string, start_letter, ceil(start_letter + marquee_length)));
start_letter += type_rate;
if (start_letter > string_length(my_string)) start_letter = 0;
}

With changes:

CREATE EVENT
// Text to draw to marquee on screen.
my_string = "Some text for your marquee ";
// Always (usually) count from ZERO! start_letter is a pointer
// that tells us where the marquee should begin grabbing text from
start_letter = 0;
// So this is weird. 10 characters is not the length of my marquee.
// Why doesn't this line up?
marquee_length = 10; // or however many letters in your marquee
type_rate = 3/room_speed; // 3 char per second
marquee_scrolling = true;
DRAW EVENT
if (marquee_scrolling == true) {
// how many letters total are we getting?
var totalCharacterQty = start_letter + marquee_length;
// get the ceil of that number means just "round up" in case decimal point
totalCharacterQty = ceil(totalCharacterQty);
// get a chunk of text as a string, starting with start_letter
// and running through totalCharacterQty's letter
var textChunk = string_copy(my_string, start_letter, totalCharacterQty);
 // now draw that chunk
draw_text(x, y, textChunk);
// move forward in string start based on our speed
start_letter = start_letter + type_rate;
// how big is the marquee now (why are we always recalcing this?)
var totalMarqueeLetterQty = string_length(my_string);
// Are we past the last letter?
if (start_letter > totalMarqueeLetterQty) {
// have we gotten to the end of the marquee?
// start over with the zero-position character!
start_letter = 0;
}
}

Coditionals

If() {

// code block
}

Repetition

Repeat() {

// code block
}

For() {

// code block
}