code of the Ninja();

// in search of swift, efficient, and invisible code

2012-03-17

Rogue Operators in GML

I've recently discovered a clutch of "rogue" operators in GML: operators that are fully functional but totally undocumented in the help file. While I wouldn't recommend using any of them (they might make your code less portable), they might be interesting to be aware of.

:=

When first n00bishly using GML, I did what I'm sure a lot of others did: I used the = operator for comparisons, e.g. if (a = b), as well as assignment, e.g. a = b. Turns out this is really bad practice if you ever plan on learning other languages (like, say, javascript), because they treat the two very differently. Assignments in javascript actually return the right-hand value, not true/false; so if you were to say if (a = 0) the conditions would never be true, just as if you'd said if (0). The solution, of course, is to use the comparison operator == for condition testing, e.g. if (a == b), and use = only for assignments.

So where does := come into all this? If GML matched other languages, it should be purely an assignment operator, e.g. a := b and not if (a := b). But since GML is special, it's merely a synonym for =. Yep, you can say if (background_color := c_blue) and it'll do the exact same thing as if (background_color = c_blue) or if (background_color == c_blue) in GML.

Dumb. Like I said, these aren't recommended.

<>

This is just a straight synonym for !=. It returns true if the left-hand and right-hand variables are not equal.

!<, !>

You would think these were cute alternatives for the <= and >= operators: whereas you might say if (a<=b) to test if a is less than or equal to b, you could also say if (a!>b) to test if a is not greater than b for the identical result. However, you would think wrong, even though there are some places around the net that suggest it's true. In GM 8.0, at least, these do not work; they throw a syntax error if used in code. (Though, oddly, they'll just be ignored if used as part of watchers in debug mode: a!>b will just return a no matter the right-hand variable is.)

|=, &=, ^=

Okay, so these are documented in the help, but not in the operators section, and there's also a confusing type where they're listed (suggesting that one of them is &\). But they are very useful if you know them; they're the bitwise brethren to the +=, -=, *=, and /= operators. For example, a |= b is equivalent to a = a|b.

2012-01-08

Simple Animation System

Hello again, Code Ninjas!

I'm afraid I have been a little too silent and invisible lately. Upheavals in personal life and multiple projects with disappointingly slow progress have kept me from posting since August, which I'm sure one needn't be told is less than ideal.

But now that the silence has been broken, I'd like to show off the animation system I'm using in my Game Maker Sonic engine, AeStHete.

You see, Game Maker has the rudiments of an animation system - all you have to do is set the animation speed for an object, and its sprite will step through all its subimages, looping when it reaches the end and even triggering an event when it does so. But there are huge drawbacks to this system, and it's not even powerful enough to be comparable to the animation system used by the original Sonic the Hedgehog, a 16-bit game that's over 20 years old.

The largest drawback by far is the fact that animations can't be frame lists; if you want to show the same subimage more than once during the animation, you're forced to store two copies of it in the sprite, potentially wasting large amounts of memory, increasing load times, and making your sprites harder to work with.

You also have no ability to vary the animation speed on a frame by frame basis, so if you desire a certain frame to be shown for longer than another, you're out of luck, unless - again - you duplicate it in your original sprite.

Alright, so there are workarounds to these problems, using timelines, or scripting, but they are bothersome and time-consuming to put together. It would be really nice if you could just tell your object to play an animation with a simple command that takes as few arguments as possible while still allowing the features that we'd really like.

Fortunately I've devised a way to do this using scripts, but before I go into it I want to complain about another problem with Game Maker's built-in animation that, while terribly obscure, bothers me no end: If you happen to be using the draw_sprite function (or one its relatives like draw_sprite_ext) instead of relying on the default draw event, and use image_index as the subimage argument, it is rounded improperly. So if your image_speed is 0.5 and you are expecting each subimage to be shown for 2 steps, you can get an unpleasant surprise: sometimes they'll be shown for 1 step, or 3... yes, on average the speed is correct but it is not stable, and it looks wrong to the eye, especially for flashing animations that require a steady framerate.

So let's avoid all these annoyances by writing scripts that handle animation a lot more like a proper video game would.

The first order of business is to set the image_speed of your object to 0, so that Game Maker will not change the image_index on its own. You want to change it manually, by calling a script which we'll name AnimUpdate.

Let's build up the script step by step.

if (animSpeed<=0) exit;

Instead of image_speed we'll be using our own variable called animSpeed. Unlike image_speed it will not be a factor (i.e. 1 changes the frame each step, 0.5 changes every other step, etc) but the literal number of steps each frame should be shown until it changes. So if you want an animation that changes frame each second, animSpeed should be equal to your room_speed.

Anyway, if animSpeed is zero or below, we'll exit the AnimUpdate script altogether; This means you can stop an animation in its tracks by setting animSpeed to 0, or even pause and unpause an animation by multiplying animSpeed by -1 (a neat trick).

animTimer -= 1;

This code simply decrements the timer; when the timer reaches zero, the frame will change:

if (animTimer<=0) {

Why use "less than or equal to" instead of just "equal to"? That way, if animTimer is already zero when the script is run, the frame will still change correctly rather than breaking the animation. In fact, this means when we start animations we can initialise animTimer at 0, which makes a little more sense than setting it to 1, and can also be used by other code to check if the animation has just been started but has not updated yet. It's just a little nicety.

animFrame += 1;

The frame number is increased. Why use animFrame and not directly increment image_index? It will become clear in time.

if (animScript) script_execute(animScript,animFrame);

Another nicety that isn't strictly necessary, this allows you to run a custom script each time a frame changes; while this will rarely be used, it is incredibly useful in complicated animations. For instance, Sonic might run a script in his walking animation that calculates the animation speed based on his actual walking speed, and sets animSpeed accordingly. The current frame is given as argument0.

if (animFrame>=animLength) {

This line checks if the animation has "finished", i.e. whether the frame number is equal to (or greater than) the length of the animation. Why check if it's greater than, also? Because if the animScript changes the current animation for some reason, and the new animation is shorter than the old, the animation won't break. This is a one character change, but it prevents the need to check for such eventualities in your animScript.

animFrame = 0; }

This line simply returns the frame number to 0, causing the animation to loop. While this is what we want in most cases, wouldn't it be nice if we had a few more options? So let's replace that line with a switch statement that checks a variable called animEnd and does different stuff.

switch (animEnd)
{
case 0: // loop
  animFrame = 0;
  break;
case -1: // stop
  animFrame -= 1;
  animSpeed = 0;
  break;
case -8192: // destroy
  instance_destroy();
  break;
default: // skip back
  animFrame += animEnd;
}

It will loop only if animEnd is zero, which is what we want most often; -1 will stop the animation; -8192 will cause the instance to destroy itself, which is convenient for simple objects like explosions or other effects which should disappear when their animation has finished; and any other value will simply be added to the frame number so you can, for instance, set use -2 to loop the final two frames (as Sonic does when tapping his foot in his boredom animation).

Onward!

animTimer = animSpeed;

Here we simply reset the timer so that it can count down until the next frame change.

if (animData=='') image_index = animOffset+animFrame;

Here, we check a variable called animData to see if it's a null string. If it is, the image_index should be the current frame number, plus an offset value. The offset value allows us to, for example, have a single sprite which contains every image of the player character. By setting the offset to the index of the subimage where the animation you want to play starts, you can have more than one animation per sprite, seriously cutting down the number of sprites needed. This is part of the reason why we didn't increment the image_index directly earlier, but used a custom variable called animFrame. The second part of the reason is in the next line:

else image_index = animOffset+real(string_char_at(animData,animFrame+1));

This line is only done if animData is not a null string but contains some data. This data should always be in the format of a string of digits, e.g. "0102030405198042". This is used as a frame list; the real(string_char_at()) is used to get a frame number from the frame list instead of using animFrame itself, which always counts up in sequence. By using a frame list, you can jump around in the sprite at will, or repeat frames as many times as you want.

Now, you'll notice that you are not allowed with this system to have a frame list that contains values greater than 9, so you can only use 10 different subimages for any animation with a frame list supplied. But this is not usually an issue in classic-style games (it never becomes an issue in Sonic, for one), and if needed you can always add an animScript which changes the offset when needed for especially complex animations.

The frame list is also our way to create variable animation speed. It's not perfect, but by repeating subimages you can achieve almost all effects ever needed, and certainly any needed by a Sonic game.

And that does it for the AnimUpdate script, except for closing the block we started way up there:

if (animTimer<=0) { ... }

Now we need to write a script called AnimPlay that will start animations running. It needs to be supplied with several arguments, most of which are optional. This is how all those variables we were using in AnimUpdate, such as animEnd, animScript, and animData get their values.

There are 5 arguments. The first is animData, which should either be a string like "3120" if you want to use a frame list, or a real number like 4 if you just want to specify the length of a sequential animation.

if (is_string(argument0)) { animData = string_digits(argument0); animLength = string_length(argument0); }

If argument0 is a string, we know you want to use a frame list, so animData is set to equal argument0 (well, only the digits of the string, anyway, to protect from errors in the real() function later on) and animLength is derived from the length of the string.

else { animData = ''; animLength = argument0; }

If argument0 is a real, however, animData is set to be a null string and the animLength is set to argument0 directly.

animSpeed = argument1;

The animSpeed (remember, the number of steps each subimage should be shown before changing) is set to argument1, the only other required argument.

animOffset = argument2;

Here, the animOffset is set. It will default to 0 if no argument2 is given, so your animation will start from the first subimage of the sprite being used.

animEnd = argument3;

The animEnd is set to argument3. Remember this value specifies the behaviour of the animation when it reaches its end. 0, the default, is loop.

animScript = argument4;

The animScript is set to argument4. If no argument4 is given, it will be 0 so no script will bother to run. (Technically, 0 is a valid script index, but chances are - since the first script you ever create in your game project has the 0 index - it won't be a useful animation script. If you wish to modify this, it's a simple enough matter to tweak this and also AnimUpdate but you're on your own with it, since I prefer the elegance of doing it this way.)

animTimer = 0; animFrame = -1;

The animTimer is set to 0 so that when AnimUpdate is called next (preferably in something like the End Step Event) the animation will initialise at the first frame. The animFrame is set to -1; it will be incremented to 0 when the animation starts.

So that's all that it takes to make a reasonably robust animation system with far more power than Game Maker's simple image_speed implementation. You may download the GML scripts from this tutorial here.

As a fun exercise, you can modify this system easily to use a delta value when decrementing the animTimer:

animTimer -= DELTA; // DELTA = 0.5

If the delta is a global value, you can slow all animations by any factor simultaneously, allowing you to create all kinds of cool slow-motion effects. Some problems will arise if the delta is greater than 1, but it wouldn't be an exercise if you didn't have to figure out how to solve something on your own. (Don't worry, it's not too difficult.)

I'd explain it all right now, anyway, but I've got to get back to coding my AeStHete engine. Until next time, happy coding!

2011-08-27

Pausing

Last time, I talked about how triggers can be used to replace traditional step events in order to solve certain esoteric problems in Game Maker. This time I want to explain how to use triggers to achieve something a lot more universally useful: pausing the game.

Game Maker, sadly, has no good built-in methods for pausing that are quite satisfactory (in fact, the documentation doesn't even mention it, except of course the references to the debugging feature). Over the years, I've experimented with the following solutions, but found each of them lacking:

Solution: Using the keyboard_wait() function
Problems: It freezes everything, preventing any sort of pause menu functionality. It also breaks the flow of games designed for controllers or the mouse, because it requires interaction with the keyboard.
Solution: Going to a dedicated Pause room
Problems: This is much better, because you can put whatever you want in the pause room to create any kind of effect you want (menus, faded image, soft music, etc). But it's kind of a pain to juggle the room_persistent status of the calling room, and if you want to show a frozen image of the game, you have to create the resource yourself using something like background_create_from_screen(). Also, if you want access to any of the objects from the calling room, you're sort of out of luck.
Solution: Using instance_deactivate_all()
Problems: This solution uses an object for controlling all pause behaviour that deactivates everything else and takes over until the game is unpaused. It has most of the same problems as the previous solution, though (no access to paused objects; the need to manually create an image resource from the screen), and introduces yet another: Unpausing requires you to call something like instance_activate_all(); if there are any objects you don't want to be reactivated, you're out of luck. Basically, this solution is incompatible with any game that has to activate/deactivate instances for any other purpose.

After all this, one starts to wonder why there isn't just some kind of built-in functionality for pausing in Game Maker. Almost all games need the feature (besides notable exceptions like Phantasy Star Online) so why not? There could be a variable called pause_object which would point to the only object which would remain active while the game was paused (much like how view_object points to the object which the view should follow). And there'd be a function called game_pause() that would take one argument - true or false - to toggle the state on and off. Would this have been so hard?

Fortunately, with a little bit of work, triggers come to our rescue in this situation, too.

Because trigger events can be set to occur before each step moment (beginning, middle, and end), it's possible to create triggers to completely replace the step events:

(If you can't see the image, the condition code for these triggers should be "return global.paused;").

If you move the actions in the step events on all your objects to the corresponding trigger events instead, you can prevent the execution of these actions merely by setting global.paused to true. Any object you don't wish to be paused should retain traditional step events, of course.

Using this method, the draw event will still be executed, preventing the need to generate an image. And all paused objects are still active in case you need to access them. Great!

One quickly notices the drawbacks to this solution, though. Beginning, middle, and end step events aren't the only things that happen for objects during each step in Game Maker. There are other events, like keyboard checking and so on, that are also performed.

This doesn't bother me personally, because I tend to ignore these events and write my own code for checking keys and stuff in the step event of some kind of control object. This isn't for everyone, though, so is there some way to get around this?

Well, yes. You can create more custom triggers that check the same conditions as the original, but also check global.paused. For example, "return global.paused and mouse_check_button_pressed(mb_left);". This is a bunch of busy work, but do it at the start of your project and it might save you some trouble down the line.

Another drawback to using triggers to pause is that Game Maker handles certain things about objects automatically. Every step, it adds hspeed to x and vspeed to y, and so on. Again, this doesn't affect me because I use all my own variables, but it can be gotten around anyway: in your code that pauses the game, you could just do this...

with (all) {
  hspeed_previous = hspeed; hspeed = 0;
  vspeed_previous = vspeed; vspeed = 0;
  image_speed_previous =image_speed; image_speed = 0;
  timeline_speed_previous = timeline_speed; timeline_speed = 0;
  alarm_previous[0] = alarm[0]; alarm[0] = -1;
  ...
}

...and of course the reverse when you unpause.

In conclusion, I admit that this solution is far from perfect also, and it requires a lot of work to get functioning flawlessly. But depending on what your game is like, and considering the issues with competing solutions, it might be useful to you.

If there are better solutions, I'd love to hear about them.

2011-08-24

Trigger Happy

When Game Maker 8.0 introduced triggers, I can't say that I was all that impressed with the feature, and I've hardly used it since. This is because, as a matter of personal preference, I tend to eschew such shortcuts in favour of handling things manually; it's far easier for me to debug code when I'm personally responsible for each line, rather than goofing around with automatic functions whose technical nature is hidden in order to make things more palatable to beginners. Sometimes I forget that Game Maker even has things like room transitions and timelines, since I habitually code custom, flexible alternatives for each of my projects.

Recently, though, I've discovered two great uses for triggers that solve problems that are otherwise either very difficult to overcome or flat-out insuperable. I'll talk about the first one of these in this post, and the second, next time.

Code Execution Order

Games (and pretty much all programs) have what's commonly called a "main program loop" which controls all the behaviour in the game. A basic platformer might have one that looks something like this:

  1. Check for press of the pause key to toggle pause on and off
  2. If paused, branch directly to (8) drawing the screen
  3. Handle player input
  4. Move all objects
  5. Check for collisions
  6. Update the camera
  7. Handle animations
  8. Draw the screen

Obviously, the above is rather simplified; for instance, there's no mention of handling the game's audio. But you get the idea.

Having started experimenting with programming long before helpful game creation suites with user-friendly GUIs like Game Maker came on the scene, I'm very used to starting a project by writing the main loop. So used to it, in fact, that when I first used Game Maker, with its event system, I found it very counter-intuitive and confusing. Buried in the help file one can find a brief explanation of the event order, but otherwise there's very little explanation given of when and how your code is being run. Without going through the effort to manually test the system and gain a detailed understanding of it, one can easily be led to make games with egregious timing issues; for example, the player juttering uncomfortably while riding moving platforms.

In the above example loop, steps 4, 5, 7, and 8 are actually loops in and of themselves. To move all objects, for instance, one must use some kind of loop (for, while, or whichever of their kin is most suitable) that moves each object in turn (perhaps by adding "speed" to "position", a popular method).

Since the code for each object must be performed sequentially in some sort order, it's natural to wonder what that order happens to be. In a classic game like Sonic the Hedghog, it is the order in which the objects are actually stored in RAM. In Game Maker, it is the order in which the objects and instances were created.

Because this, especially the object/instance distinction, can be confusing, I will explain it in greater detail.

"Object" is the natural word one wants to use when discussing "things" in a video game: the player, pickups, enemies, platforms, etc. In fact, I can't think of a single non-clumsy alternative. Game Maker, though - in one of its myriad maddening quirks - has a different, technical meaning for "object" which is much closer to something like "class" or "template". The layman's object is referred to in GM parlance as an "instance". The player never interacts with objects, only ever instances of objects.

But if you're reading this, you're probably already passingly familiar with GM's system. Anyway, every instance has an "id" as well as an "object_index". The id is a unique identifying number by which the instance can be referred to. Every time an instance is made, it is given an id number that is 1 greater than the last instance created. Barring some horrible bug in GM (or gap in my knowledge), it's impossible to have two instances with the same id, or to create an instance with an id that is lesser than an existing instance's id. (Note that objects placed in GM's room editor have fixed ids; if you restart a room their ids remain constant.)

So every instance has a unique id, creating a perfect sequence that mirrors the order in which they were created. (Yes, there will be gaps introduced when objects are destroyed, but this hardly matters.) Is this the order in which their code is executed? In short, no.

If it were, one would expect the object_index to be irrevelant, causing the following program:

control object (begin step): set string to ""

instance 1 [object A] (step): add "A" to string
instance 2 [object B] (step): add "B" to string
instance 3 [object A] (step): add "A" to string
instance 4 [object B] (step): add "B" to string

control object (end steo): output string

to output the string "ABAB". However, in reality, it will generate the string "AABB". What this means is that all instances of an object are performed in id sequence, and then all instances of the next object, and so on. The order of objects is determined by their object_index, which works much like instance ids: the first object created for a game (using the resource tree in GM itself or by using the object_add() function in a running game) will be 0, the second will be 1, and so on.

Knowing this, we can predict issues that many games will encounter. Imagine the player is object 0 and a moving platform is object 26. The player will do its motion code, during which it will align to the platform instance that it's on (if it happens to be on one) -> Then the platform will do its motion code -> Then the screen will be drawn. What will be seen when playing the game is the player always lagging one step behind the platform, because it can't catch up until the next step.

(Quick readers will notice that you can easily solve this problem by simply having the platform move the player if they're on it, as opposed to letting the player take care of their own motion, but this is not always an optimal solution depending on how you've set up your physics. For instance, if the player does take care of their own motion, it's sometimes possible to optimise by removing collision checks.)

It's certainly things like this that explain why GM has the "Begin Step" and "End Step" events. Every game creation engine I've tried out has some form of this; it gives the user the ability to make absolutely sure that certain code is done before/after other code. It works for 99% of situations, and was probably easier on the creators of the program than giving the user full control over the main loop (which might confuse beginners).

But what about that other 1% of the time? Very advanced users might be out of luck, if it weren't for triggers (you knew I had to get back to the actual subject of the post eventually, right?).

Using Triggers to Solve Order Issues

First I'll need to paint a picture of a specific order issue so that I can explain how triggers can be employed in solving it:

It's fun to be able to put cool visual effects in your game, like motion blur, lighting bloom, or ripple distortion effects when underwater. But these are incredibly difficult, if at all possible, to achieve in GM without using surfaces. By drawing the game view to a surface, and then drawing that surface to the screen, the possibilities for effects are endless. Once the view has been rendered to a surface, it can be handled like any other image resource, manipulated in a myriad of ways - even used a texture!

(Rendering to a small surface and then drawing the surface upscaled without any texture interpolation is a great way to make low-res classic-style games á la Cave Story without that nasty blur that GM normally inflicts upon you. The only other ways to do this aren't really viable - storing all graphics as 2x not only takes up more memory and CPU power, but it's only the graphics - the physics won't be "low-res" without major tweaking.)

The simplest way to convert a game to use a surface instead of drawing directly to the screen is to a) switch off automatic drawing at game start; and b) in a control object's end step event, set the drawing target to a surface, call screen_redraw(), reset the target to the screen, and draw the surface with whatever effects are desired (make sure to call screen_refresh() afterward, or the frame the player sees will always be one frame out-of-date!)

But wait... that all sounds great, but there's a hidden problem lurking amongst those otherwise reasonable instructions: "In a control object's end step event..." According to what we've learnt above, unless the control object is the last object you ever created in the game (which is almost the exact opposite of what will be the case in the vast majority of situations), some objects won't have executed their code when the screen is rendered to the surface! Normally in GM, the screen is drawn last thing, full stop. But our brilliant surface method has just borked that, pushing the drawing back to the end step event. If any object's appearance or position changes in its end step event, then it will drawn out-of-sync, which is unacceptable (to all but the development team of Sonic Genesis).

Well, what's needed (but doesn't seem to exist) is an "End End (No, really this time!) Step Event" that can be used by the control object for handling the drawing instead. If one were lucky, there might be some kind of event type (like "outside of boundary" or some such) that's handled after the end step. One might, in a hackish way, abuse it for such a purpose. However, this is not the case. This is the event order:

  • Begin step events
  • Alarm events
  • Keyboard, Key press, and Key release events
  • Mouse events
  • Normal step events
  • (now all instances are set to their new positions)
  • Collision events
  • End step events
  • Draw events

There's nothing after end step that can be conveniently repurposed.

Here (finally) is where triggers come to our rescue. Take a look at the trigger window:

When using Windows 98, one must resort to festive colour schemes in order to maintain one's sanity. =P

The magic we're about to make is all because of that little phrase toward the bottom: "moment of checking". Trigger events can be made to happen at each of GM's step events. And if "at" seems a little vague, let me amend that - it's actually directly before. (If multiple triggers are set to the same moment of checking, they'll be evaluated in the order they were created, but they'll all still happen before the associated step event.)

Well, you might be thinking, that's great - we can add new events before the end step. Good going, genius - we needed one for after.

But here's the thing: it's entirely possible to swap out the end step event of all your objects for a trigger event (let's go ahead and call it "pre-end step") - well, all except for the control object, which will use the end step to draw the surface. A large amount of clicks, surely (depending on the size of your game), but a small price to pay for full control over the order in which things happen. By the way, the pre-end step trigger should have "return true;" as its condition code, so that it happens no matter what.

And I'm sure a clever Code Ninja like you can imagine ways, through the use of many triggers, to beat GM at its own game, essentially injecting all sorts of custom step events directly into the main program loop. (Imagine a trigger whose condition was a variable called "exitStep"; you could effectively make a custom step event which could be exited at any point!) With power like that you could - dare I say it? - take over the world! =P

2011-03-19

Jump Height Calculator

Hello again, Code Ninjas!

Today is something very simple: a formula that allows you to plug in variables for "jump force" and "gravity" and get the maximum height of a jump as the result.

When designing platformers, tweaking the physics until they're just right is very important. Having a formula such as this will be useful for zeroing in on exactly what values constants like gravity should have.

Another use might be this: say you already have established physics, for instance because you're hacking a Sonic game. But you want to add a new object, such as a new kind of bumper or spring, that bounces Sonic exactly 5 times his height. Determining the force at which Sonic should be impelled by the object in order to achieve that height would be a snap using the following formula.

The simplest way to write the formula is this:

g = gravity;
f = jumpForce;
h = 0;
t = 0;
while ( f > 0 )
{
  h += f;
  f -= g;
  t += 1;
}
return h;

g is your gravity, and f is the jump force, which can be set to anything. In Sonic, for example, gravity is 0.21875pps (pixels per step) and the jump force is 6.5pps.

h is the height value we are trying to find out - the number of pixels the character will travel given the jump force f with gravity g. t is time, which is optional - it will be the number of steps it takes to reach the apex of the jump. Both h and t are initialised at 0.

Then we run a loop while f is greater than 0. In the loop, first f is added to h, then g is subtracted from f. This simulates the jump: the force acts upon the character's position, then the gravity acts upon the force. t is then incremented by 1 in order to count the time.

When the loop is finished, h will be the ultimate height of the jump.

Note that this code assumes your physics to handle similarly to Sonic's. In Sonic, because of the particulars of the original code, the jump force is added once to the character's position before gravity acts upon it. If this is not the case in your game, then the loop should be restructured accordingly; g should be subtracted from f before f is added to h.

Earlier I said "the simplest way" to write the formula. The truth is that this, while simple, is a rather brute force method. Depending on the strength of the jump force and gravity, the loop could run dozens of times. Yes, modern computers can handle this without breaking a sweat, and yes, you probably won't even be using the formula in a running game, anyway. But for the sake of mathematical beauty, we can find a better way that doesn't employ a loop.

So let's build this new formula piece by piece. First, we need to find how many steps it will take for gravity to whittle the jump force away to 0 (or less). This will be time t again.

g = gravity;
f = jumpForce;
t = ceil(f/g);

We find t by dividing f by g and rounding up to the nearest 1. Why the rounding up? Well, if the jump force isn't perfectly divisible by gravity, the remainder would still count as upward velocity and the player would still move up by a little bit during that step. Since it counts toward the total, it must be taken into account.

Now that we know how long the jump will take to reach the apex, we can easily discover the distance the character would travel during that time, without gravity, merely by multiplying f by t.

h = f*t;

Of course this seems a little silly, because we're trying to find the height covered with gravity taken into account. But knowing this value is useful; 'cos if we can also determine how much force is deducted by gravity from the jump force over t steps, we can multiply gravity by that number, subtract it from h, and have our correct result.

In the first step (t = 0), the jump force is unaffected. In the next, it is lesser by gravity. In the next, it is lesser by gravity again, i.e. it is equal to the initial jump force value minus gravity times two. Next step, times three, then in the next, times four, and so on, until gravity overcomes the jump force in step t-1.

Visually represented, you might think of the amount of force lost to gravity as a triangular stack like this:

----- (t=0)
g---- (t=1)
gg--- (t=2)
ggg-- (t=3)
gggg- (t=4)
ggggg (t=5)
...

Fortunately it is easy to find the area of a triangle such as this by finding the area of a square the size of t*t-1 and then cutting that value in half. (If, as mentioned above, your physics subtract gravity before the character moves once, the square should have a size of t*t+1 instead).

h -= t*(t-1)*0.5*g;

Et voilĂ , you have the correct height of the jump, identical to the result of the while statement method used above.

Finally, because multiplication is a commutative process, the formula can be recast in a simpler way for our final code:

g = gravity;
f = jumpForce;
t = ceil(f/g);
h = (f-((t-1)*0.5*g))*t;
return h;

You can find a small example .gmk here that lets you play with the variables to get different jump heights. Until next time, happy coding!

2011-03-02

Partially Erasing Surfaces in GM

Hey there, Code Ninjas!

One of the cool things about Game Maker 8 is the ability to export PNGs with an alpha channel for transparency. There's no separate functions for doing so, though; if you want to be sure the exported image is in PNG format, you have to make sure the extension is explicitly ".png", like so:

Code:

sprite_save("sprite.png");
screen_save_part("screenie.png",320,224);

It's especially cool to create partially transparent surfaces and export them. After creating a surface, you can use the draw_clear_alpha() function to make it completely transparent:

Code:

surface_set_target(surface);

draw_clear_alpha(c_black,0); // clear the entire surface with fully transparent colour

surface_reset_target();

One thing that's annoying, though, is the way that drawing with a partial alpha to a surface works. Instead of blending with the colour underneath, the colour is completely replaced, alpha and all. Effectively this punches "holes" in the surface image.

You'd think this could exploited to create some kind of eraser tool. Draw pixels with an alpha of 0 to the surface to erase pixels that are already there, leaving fully transparent pixels behind.

This doesn't work, though, for some reason. Very low alpha values such as 0 or 0.01 function exactly as you'd normally expect when drawing to the screen, even though higher values such as 0.7 differ when using surfaces.

So much for the ability to erase pixels from a surface using that method... But there is another way.

Set the blend mode to bm_subtract before drawing to the surface and you'll effectively be able to erase from the image:

Code:

surface_set_target(surface);

draw_set_blend_mode(bm_subtract);
draw_set_color(c_white); // color doesn't actually matter
draw_set_alpha(1); // alpha must be 1 to fully erase pixels

// erase an "X" across the surface
draw_line(0,0,surface_get_width(surface),surface_get_height(surface));
draw_line(surface_get_width(surface),0,0,surface_get_height(surface));

draw_set_blend_mode(bm_normal);

surface_reset_target();

This trick may come in handy on occasion, especially when making games where the user is allowed to paint custom textures for things - an erase tool is essential.

Until we meet again, happy coding!

2011-03-01

Looking Up and Down

Hello again, Code Ninjas!

In most 2D platformers the player has the ability to shift the camera a short way by holding up or down on the D-pad. In Sonic games, it works great but there is minor flaw that's hard to notice and really doesn't cause any problems, but I thought it would nice to show how to fix it anyway.

The problem arises when the player looks up or down near the top or bottom boundaries of the level (or whatever current boundaries the camera is limited to). In order to understand the problem, we need to look at the basic idea behind shifting the camera.

If there were no ability to look up or down, the process would be really simple. The camera would simply follow the player's position directly, with a simple check to make sure it doesn't leave the level boundaries. In order to shift the camera up and down, though, an extra step is needed. An offset is added to the player's Y position before the camera follows it. By increasing or decreasing the offset value when the up or down buttons are pressed, the camera will shift vertically relative to the player's position.

Clearly there need to be maximum and minimum values that the offset can't exceed, otherwise the player could continue to scroll the camera freely until it reached the top or bottom of the level. Normally this behaviour is not desired, so limits are set that will keep the player visible on the screen.

Imagine for a moment, though, that there aren't. Say the player is looking up - the offset decreases and decreases. It will continue to decrease even after the camera stops at the top of the level, because the offset doesn't know when to quit. The camera is limited, sure, and the player never sees beyond the boundary of the level, but the offset value is still decreasing away.

Now what would happen if the player stops pressing up? The offset value will start increasing until it returns to 0 (no shift at all). But depending on how long you've been pressing up, you'll have to wait a few moments before the camera starts to visibly scroll back to the neutral position. After all, the offset has been invisibly counting away for an undetermined amount of time, and that extra time has to be made up for when it tries to return.

This example with no upper/lower limit for the offset illustrates the problem I'm talking about, and that we're going to fix. It's less noticeable when limits are present for the offset, because the value can't continue to increase or decrease indefinitely, but it's still there. If you've got a copy of any Genesis Sonic game, try looking up or down near the top or bottom of a zone and see for yourself. Scandalous, isn't it?

It may not be the worst problem in the world, but it can be fixed, so let's give it a go.

There are actually two solutions. One would be to reduce the offset by the appropriate amount when the player lets up from pressing up or down, but that's not the solution I'll describe. Why not? Because that method would require the detection of when up or down is released, which - while certainly possible - is harder to slot right into the way the code already works in the original Sonic.

Let's look at some basic code for handling the offset, and then we'll apply the fix to it.

cam_step()

shiftMode = 0; // reset shift mode
if ( joy( UP ) ) shiftMode = -1; // player is looking up
if ( joy( DOWN ) ) shiftMode = 1; // player is looking down

switch ( shiftMode )
{
case 0: // camera is recentring
  if ( shiftOffset < 0) shiftOffset += 2; // scroll down if too high
  if ( shiftOffset > 0) shiftOffset -= 2; // scroll up if too low
  break;
case -1: // camera is shifting up
  if ( shiftOffset > -shiftLimit ) shiftOffset -= 2; // scroll up until reach negative limit
  break;
case 1: // camera is shifting down
  if ( shiftOffset < shiftLimit ) shiftOffset += 2; // scroll down until reach positive limit
  break;
}

The problem occurs in case -1 and case 1: stopping at the shiftLimit isn't good enough, because at the top and bottom of the level, we need to stop increasing or decreasing early.

How close to the top or bottom of the level must one be in order for the undesired behaviour to occur? Close enough that the distance between the top/bottom of the camera and the top/bottom of the level is less than the shiftLimit.

This suggests the solution. Instead of using the shiftLimit alone, we should use whichever happens to lesser - the shiftLimit or the difference between the view boundary and the level boundary.

cam_step()

case -1: // camera is shifting up
  r = min( shiftLimit, view_yview - shiftOffset );
  if ( shiftOffset > -r ) shiftOffset -= 2; // scroll up until reach negative limit
  break;
case 1: // camera is shifting down
  r = min( shiftLimit, levelBottom - ( ( view_yview - shiftOffset ) + view_hview ) );
  if ( shiftOffset < r ) shiftOffset += 2; // scroll down until reach positive limit
  break;

(The reason why shiftOffset has to be subtracted from view_yview is so the difference won't change once the screen starts scrolling and the offset starts to change.)

And that's all that's needed. It may not be much, but obsessive compulsives will enjoy the game more!

If you enjoyed this and the previous Code of the Ninja, be sure to come back tomorrow for one more before I slip back into the shadows. =P