The Thrill of the Chase

I've gotten to a point in MMMbezzlement where the enemy AI does what I want almost all of the time. That's better than I thought I could do when I started this game, so I will document that minor miracle here.

Here's what I needed my fellow coworkers to do as I stole their lunches all over the office floor:

  • Walk a basic path back and forth or in a circuit depending on the route.
  • If I am caught in an enemy's vision cone while eating food, game over.
  • If I am caught in an enemy's vision cone at any other time, the enemy should chase me for three seconds.
  • If I am able to stay out of any chasing enemy's vision cone for three seconds, that enemy will return to the point where they left their path and resume it.

When you look at that short list of behaviors they seem simple. And, once implemented, the code was in fact pretty straightforward. Setting paths for enemies in GameMaker (v1.4.1772) is trivial. Even getting the enemy to chase the player isn't too bad since GML has built-in functions for that. The tricky part turned out to be combining these behaviors and building a level that allows them to work.

Walking the Path

The default state of all the NPCs in a level is to walk a handmade path. I wanted every NPC to have their own path, but I also wanted only one enemy object. Setting a path in the Drag 'n' Drop UI is easy, there's an action explicitly for it. However you can only set the path per object, not per instance. To do this I created an invisible object that executes the following code for its Create event:

// Creates enemy instances and sets their paths
// This code will break if NUMBER_OF_PATHS is higher than the number of path assets!

NUMBER_OF_PATHS = 4;

var i = 0;  
var enemy = -1;  
repeat(NUMBER_OF_PATHS)  
    {
    enemy = instance_create(0, 0, obj_enemy);
    with (enemy) 
        {
        path_start(asset_get_index("pat_enemy" + string(i)), 2, path_action_reverse, true);
        // used in obj_enemy to return an enemy to a path after they have lost the player
        path = path_index;
        }
    i++;
    }

This will spawn one enemy instance for each path resource I have created and set them on it. This does require you to change the NUMBER_OF_PATHS variable every time you create or remove another path. It also sets each path by its name, so to iterate through them you should use a naming standard that includes a number. path_start and asset_get_index are both built-in GML functions.

The last thing I do for each enemy is save their path_index to a different variable. This is necessary for the way I implement the enemies returning to their path once they have "lost" the player.

Giving Chase

Every enemy has a field of vision (fov) instance attached to them. If the player is ever caught inside that fov and is not holding food, then the enemy chases them. If they catch the player it's game over. I'm not going to cover how it works in this post, but when an enemy sees the player the fov's can_see_player variable is set to true. That triggers the following code which runs under the Step event:

if (fov.can_see_player)  
    {
    fov.image_blend = c_red;
    chase_time = room_speed * 3;
    path_end();
    mp_potential_step_object(obj_player.x, obj_player.y, 4, obj_wall);
    }

Let's go through this line-by-line.

  • fov.image_blend = c_red simply changes the fov color from white to red to make it clear to the player that an enemy is chasing them and which enemy it is.
  • chase_time = room_speed * 3; starts the timer of how long the enemy is going to chase the player. This will only count down when the player leaves the fov and will restart if they re-enter it.
  • path_end() does exactly what it sounds like. This has to be called or the next line will be ignored. This is also why I saved path_index to path in the earlier code, because calling this function clears path_index.
  • mp_potential_step_object(obj_player.x, obj_player.y, 4, obj_wall) makes the enemy follow the player. The last parameter tells the enemy to avoid all instances of the wall object in the room.

Finally, the most complex enemy code runs when the player is not within its fov. This is immediately after the previous code:

else  
    {
    chase_time--;
    // chase player if they have not been out of fov longer than chase_time
    if (chase_time > 0)
        {
        mp_potential_step_object(obj_player.x, obj_player.y, 4, obj_wall);   
        }
    // if enemy has lost player, return enemy to point where they left path and resume
    else
        {
        fov.image_blend = c_white;
        if (path_index == -1)
            {
            // The path variable is set in obj_enemypathset to ensure path is not -1. 
            if (mp_potential_step_object(path_get_x(path, prev_path_pos), path_get_y(path, prev_path_pos), 4, obj_wall))
                {
                path_start(path, 2, path_action_reverse, true);
                path_position = prev_path_pos;
                }
            }
        }
    }

Chase time begins to be decremented at every step, but until it reaches zero, the same mp_step_potential_object function is called. If the player stays out of sight long enough, the enemy's fov turns back to white and they are sent back to the spot on their path where they left to chase the player. I needed to provide x and y coordinates to mp_step_potential_object, so I used path_get_x and path_get_y. These functions require the path index which was saved to path, and the position in that path to check. Path position is a value between 0 and 1 and path_position is a variable all instances with a path have. To keep up with this, I just have a line at the top of the Step event code that says prev_path_pos = path_position.

Finally, when the enemy reaches the point where they left the path (mp_potential_step_object returns true when this happens) they are restarted on that path at that point. This is where I use the path variable that I saved back in my enemy path set object.

Result

Enemy Chase Demo

So, the player gets caught by one enemy and avoids them long enough for the chase timer to run out. That enemy returns to their path and resumes it. A second enemy catches the player and chases them for much longer because the player keeps getting caught in its fov.

This is a rough and stripped down interpretation of what happens in a lot of stealth games. It works pretty well for the simple kind of game I am making.

Issues

While this system is passable, there are definitely some problems.

  • Enemies get stuck when navigating. This is less of a problem with the current map layout. It used to be much worse. I think this is just a limitation of mp_potential_step_object.
  • Paths are predictable. This could certainly be randomized by making more paths and spawning fewer enemies than paths each time. I could also program my own pathfinding algorithm.
  • mp_potential_step_object is resource intensive. It's not a problem yet, but I could get into a situation where a lot of enemies are chasing the player at once and the function is being called every step for all of them. A way to fix this might be to make it so that mp_potential_step_object is only called every few steps.

Please let me know if you have any questions about this system or ideas for how to improve it!

Tales From the Digiverse

This past weekend a friend and I visited our local purveyor of realities, Augmentality Labs. Up until then, I had only watched others play games in VR on video. The constant refrain I heard was "This is great and it's impossible to believe it's great until you try it." After doing just that, I think I mostly agree.

First off, I should clarify the circumstances. Augmentality Labs has a pretty great set up with maybe the least possible friction for playing VR games. I booked ahead of time, walked in, and they took my friend and I to the play space. We each got a roughly 6x6 soft mat area to move around and the HTC Vive headset and pair of controllers were ready to go immediately. We got a quick tutorial from an employee and could select any game they had and freely switch within our time slot. The headset wires were held above our heads with a pulley system rigged up in the ceiling. Judging from the videos I've watched of people tripping over cords, this is probably the biggest advantage over a home set up.

Another benefit to trying this at an arcade was the possibility of local multiplayer. On the day that I write this, HTC has announced a $200 price cut to the Vive. That's great but even if more people buy one of these things, they sure aren't likely to buy a $600 spare. So for an extra $20 (the rate for a half hour of play time) my friend and I could enter these ridiculous worlds together. We had time to squeeze in three games: Trickster, Drunkn Bar Fight, and Rec Room. I knew about Drunken Bar Fight and Rec Room before hand but had no idea there were co-op modes.

Trickster - Employees told us this was the most popular co-op experience, but I found it pretty underwhelming. You're dropped into a stock standard medieval fantasy environment and some orcs come at you. You can switch between sword and shield and a bow. Since this was our first game there was some novelty to swinging the sword and drawing the bow. After that wore off, so did the fun. At one point we thought we had accidentally backtracked to the same area, but it was just an exact copy and paste of an earlier environment. This might be a good intro to VR, but it didn't do much to distinguish itself.

Drunkn Bar Fight - This was easily my favorite game we played. You're dropped into a bar with a bunch of people standing around, and you fight them. Almost everything can be used as a weapon. Bottles, chairs, gumball machines, pool cues, and walkers are all tremendously satisfying to pick up and fling around. The character models are floppy and stretchy which amplifies your hits in a hilarious way. Get hit too much by angry patrons and your body falls away from you and crumples on the floor. A friend has to bend down and drag you back to your feet, just like in a real bar! The designers of Bar Fight clearly understand what is fun to do in VR. The level and variety of interactivity won me over. That, and nailing a guy in the forehead with a dart.

Rec Room - I only saw a very small slice of Rec Room in the form of a co-op quest. The gameplay was a lot like Trickster. You're armed with a sword and bow, and you work your way through the level killing creatures. Luckily, Rec Room is about 1000 times more charming than Trickster. The premise of the game seems to be that you're in the most well-funded community center ever built. The quest takes place in hallways with lockers and water fountains. They're decorated with cardboard cut outs of castle turrets and the enemies are mop buckets on wheels painted to look like orcs. If a friend goes down, no problem. Give them a high five to revive them. Seriously. The whole aesthetic of Rec Room is fantastic and it brought back childhood memories of made up backyard adventures.

I definitely plan to go back and try more games and pay for a longer session. I thought I might be nauseous or that my eyes would be tired after a half hour but I felt like I could have easily kept going. An employee told me they plan on selling alcohol there soon which is...a choice. I think I'll stick with one escape from the real world at a time for now. At least I know that no matter how I use VR, I'll look really cool doing it.

What I Played, What I Made 2

What I Played

Solitairica - If you had told me just a few years ago that I would be into a solitaire combat game with RPG elements, I would have wondered how that game could possibly exist and also laughed at you. These days I am more open-minded when it comes to game selection...and I like stuff I can play on the couch while I watch TV.

Solitairica game board

A glance at the image above might lead you to think "Oh, Hearthstone but with Solitaire." That's not totally wrong. You are battling fantastical creatures that use a wall of cards for defense. But instead of launching attacks at them you uh, play Solitaire at them. When the card wall is gone, you win that battle. The strategy comes in with your spells. Each card you remove grants you energy points in one of four stats. This energy fuels spells that provide some advantage like healing you or destroying a card in the wall. Every time you draw a card and can't play, the enemy gets a turn to attack.

After each match you can shop for more spells and items with gold earned in battle. It's crucial to check the notes on your enemy before you challenge them so you can slot in the spells that help you counter their moves. One enemy has attacks that ignore armor, for instance. It's great getting a card streak going and then neutralizing what would have been a devastating attack with the right combination of spells.

What's that you say? RPG morsels aren't enough to satiate your trend hunger? Maybe a light sprinkling of Rogue will do the trick then. If you are ever defeated, the run ends and you are granted some amount of currency separate from gold. This allows you to buy extra item slots and power ups for certain cards to use in your next run. I have yet to make it past the first "deck" which is comprised of 18 enemies. There are 4 decks included, and another one you can buy for $0.99, at least on iOS.

While Solitairica is maybe the best take on Solitaire I've played, it suffers slightly from still being Solitaire. There are long sequences where I draw card after unplayable card while the enemy beats me down. This is boring at best but it frequently creeps into frustrating. Of course there is randomness to other CCGs, but it feels like you have much less power to plan around bad luck in Solitairica. You're not going to draw a Blue Eyes White Dragon and destroy the board. You're just praying for, like, a 7.


What I Made

Last time I mentioned I had an idea to save the mechanic where the game isn't over if you are caught without food in my 2D stealth game MMMbezzlement. The idea is that if you are seen without food, instead of enemies completely ignoring you, they walk towards you while you're in their Field of View (FOV). If they reach you game over, but if you leave their FOV for some amount of time, they go back to their path. In the context of an office, I see this as coworkers trying to talk your ear off while you've got important things to do like steal and eat their lunch.

Getting enemies to leave their path and chase the player in GameMaker was almost trivial. If the player was in an FOV without food, I just ended the path of the enemy that owned the FOV with path_end and called mp_potential_step_object. This moves them toward the x and y coordinates of the player and also tells them to avoid all instances of a certain object. In my case those objects are walls. This worked pretty well, although my level design choice of making connected cubicles (the 'H' things) really threw them off. We join the chase already in progress:

MMMbezzlement enemy chase glitch I think the angry eyes really sell the manic thrashing on the other side of the wall.

As you can see, every enemy but the bottom leftmost one is after me. While starting the chase is easy, ending it has proven to be a bit tricky. I think I'm almost there, but right now when enemies give up on the player they are not returning to their path. Instead they are returning to their spawn point and all enemies spawn at (0,0) because of the way I set paths. When the game starts they are instantly teleported to their path starting points, so that hasn't been a problem until now.

Having an enemy chase a player and then return to their patrol if they don't catch them is a common mechanic in stealth games and a lot of people online have asked how to do it in GameMaker. Once I have my method down I'll post it and include GML.

What I Played, What I Made 1

What I Played

Slime Rancher - I can't quite say that I enjoyed playing Slime Rancher, but for a few minutes, its loop had me. It is satisfying to check the plort stock market each day and make a plan for how to get those high value excretions. What keeps me hooked on these farming games is knowing that once I put in the time doing the tedious tasks, I am guaranteed a payoff. Then I can purchase upgrades that ease the tedium and increase profits forever and ever, amen. Unfortunately, Slime Rancher kept throwing wrenches in my plans. There was this one time I was keeping chickens in a pen to feed to my slimes with the most lucrative BMs. I bought higher walls for the pen, and in the description for this upgrade I was promised that they would keep out the garden-variety pink slimes. After an afternoon of foraging I returned to find that those adorable bastards had invaded the pen and devoured the hens. This and other events like it were an unwelcome dose of chaos in a game that presents itself as a peaceful farming simulator.

pink slime Look at this jerk

Super Bunnyhop has a video review that gives a much more complete analysis. Even if it doesn't quite nail the pastoral treadmill I'm looking for, it's impressive that this is Monomi Park's first game. I can't wait to see what they do next.


illi - illi has my favorite jump of any one button platformer I've played on the iPhone. I've included a GIF to sway you, so imagine you're doing that cool jump with your very own digits. It works just as you would expect. Tap for a short jump, hold for a higher, further one. When you land, there is a satisfying screen shake to indicate your impact. Nailing a landing after leaping across your whole phone screen is genuinely exciting.

jumps so ill...i Yes, you are a furry horned slug. No, I don't want to think about it.

The only thing you need to do in each level is get to the exit, but the game smartly challenges you to do more. There is always the chance to earn up to 3 badges for things like hitting collectables, getting some sweet hang time, and even speedrunning. Every once in a while there will be a badge for, I kid you not, rolling some rocks around. It's bizarre and feels super tacked on, but doesn't detract from the game.


What I Made

I am slowly cobbling together my first semi-original game. It's a weird top-down stealth game made in GameMaker. The concept is that you are a disgruntled office worker eating everyone's lunch and trying not to get caught. Right now, it looks like this:

MMMbezzlement

The hooks are hard to see in the GIF. One is that you can only be caught when you are eating food, represented by green and yellow circles. Otherwise, the enem-uh-coworkers do nothing when they see you. The other is that the "health" bar on the food only goes down when you alternate pressing the left and right arrow keys. As rudimentary as this looks, I've already learned a lot about those ideas and game making in general. Here are two of the lot.

1. An interesting twist may not translate into good gameplay. The vision cones shown in the GIF don't affect you at all unless you are holding food. If you get caught holding food, it's an instant game over. My initial thought was that this would allow for unique ways to plan routes and breathers between hectic vision cone dodging and arrow key mashing.

What actually happened was that people avoided the vision cones at all times anyway. It seems like that mechanic is ingrained so much that it's reflexive. Even worse, it made the game too easy and boring. I have some ideas to improve on this, so hopefully some form of it can survive. This brings me to my next point.

2. I have no idea when to stop. I get now why games can get drowned in mechanics. I only have like, two, and I'm still wary of adding more. At the same time it's impossible to know if something will work without just doing it. I think about the least amount of work I could do to implement an idea and do that just to find out if it's good. But if it's bad, I worry that it's only bad because I used a half measure. Maybe if I dove in and devoted a ton of time and effort it would be good, actually?

This constant inner struggle also made me realize why I've read about so many games not being fun until they're almost finished. That sounds crazy until you try to make a game yourself. You assume the developers must be doing something wrong. How could they not have known this feature really doesn't add anything, or that this mechanic kind of breaks the game? The answer is that they probably do know but maybe they found out far too late, because estimating is hard and deadlines are a thing.

I'm going to put at least a little more time into this game (working title MMMbezzlement, which might be the best thing about it so far) and see where it goes. I'll keep updating because it feels good to share progress and gives me some small amount of accountability. Til next time.

Grow Up

I was itching for a change. I think I grew tired of fighting. I didn't want to shoot, or be attacked, or fiercely compete. I needed to relax. I needed to explore without fear, and to take it slow. I needed a BUD.

This month (July 2017) the Xbox Games with Gold program brought me exactly what I needed. Grow Up, the sequel to Ubisoft's experimental 3D platformer/climber Grow Home is exquisitely easy-going. You're a robot plunked down on an exotic planet after your spacecraft blows up. Parts are scattered around said planet. You need to find those parts, along with some fun movement abilities and crystals to augment them. That's it.

The basic climbing mechanic is simple, but can get a bit fiddly. The repeated left trigger right trigger, hand over hand movement feels pretty good. But, more than once I thought I had crested a mountain, mushroom, or floating hunk of rock only to find that my uncontrollable feet did not agree. I would then tumble off and deploy my parachute. Ironically it was during one of these moments, gently floating through the sky and watching the gorgeous sunset, that I realized I wasn't bothered by imprecise climbing.

Enemies? No way. The native species mean you no harm. Some may follow you at a polite distance for a time, others ignore you completely. I once grabbed a beetle and flipped him on his back. Horrified that he could no longer move, I refused to abandon him until he was right side up and on his way. Be the change you want to see on this heap of polygons hurtling through space.

As I grew to love Grow Up, I wondered why it appealed to me so much more than a traditional 3D platformer that has you running all over a world, collecting things. I think I've narrowed it down to three great strengths:

  1. For the most part, it leaves you alone. You have a companion that lets you know when you're near a ship part or new ability. There are no other characters giving you chores to do or locking you out of part of the world.

  2. The world is truly open and fun to explore. You won't find anything to do other than collect things and look at things. But the things you collect often make it easier and more enjoyable to get around, and thanks to a day/night cycle and exotic, glowing plants, it's pretty interesting to look at too.

  3. No pressure. You can do what you want, whenever you want to do it. There are no enemies harassing you and no clocks ticking down unless you start them yourself. I tried a time trial and was instantly turned off. The controls just aren't precise enough to make quickly hitting checkpoints more satisfying than frustrating.

Grow Up has quickly become my game to pair with a podcast and a drink. At the end of a demanding day, it's a wonderfully undemanding treat.