code of the Ninja();

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

Showing posts with label maths. Show all posts
Showing posts with label maths. Show all posts

2012-11-24

Prepare To Be Floored (Correction)

This is a correction of a mistake in my last post.

The last section said this:

This is all very well and good for rounding, but what about flooring or ceiling a number? This trick always rounds up with a fractional part of 0.5 or above, and rounds down below that. In Game Maker, you can use the floor() function to always round down, and the ceil() function to always round up.

You're in luck, because you can do code like this:

These will still be very nearly twice as fast as their function equivalents!

The trouble is that only works if your number actually has a fractional part. If you try to floor or ceil an integer that way, you'll get the integer -1 and the integer +1, respectively.

I can still pull my fat out of the fire, though. Instead of using 0.5 as the value to be subtracted (for flooring) or added (for ceiling), you can use a constant that's just ever so slightly less than 0.5, such as:

Just set this up as a constant (call it something like MATH_CEIL) and then make a second constant that's the negative of it (e.g. MATH_FLOOR = -MATH_CEIL). Then you can do:

And everything I said still holds. You'll still get the job done twice as fast as using the function equivalents. (The use of constants doesn't slow it down at all.)

I suppose you might still technically run into a problem if you're using numbers that require a precision greater than power(2,-43), but for most purposes that'll never happen. Again, this is merely a trick to be used in code that requires optimisation at all costs, not everywhere in your program.

2012-11-05

Prepare To Be Floored

This post is nothing too special or groundbreaking, but it might be of interest to anyone who is as huge of a nerd as I am.

I noticed long ago that Game Maker automatically rounds numbers and variables when they are used as array indices. So, for example array[3.6] is precisely equivalent to array[4].

I also noticed that the same thing happens when performing binary operations:

is precisely equivalent to . The same principle holds for ^ and |.

is precisely equivalent to . The same principle holds for .

Knowing this is certainly useful; it can rid your code of unnecessary calls to the round() function.

But I got an evil thought - what would happen if I tried bit shifting a number by zero, e.g. or ? Mathematically, a bit shift of zero should leave the number unaffected, but would Game Maker go ahead and round it anyway?

The answer is yes! is equal to 32. Therefore this code:

Has the identical effect as this code:

An interesting quirk; a titbit of trivia. So what?

Well, I suspected that it might be a faster operation than the calling of the round() function, and so I tested this hypothesis. The result?

Bit shifting by zero is twice as fast as using round(). Now, that function is hardly going to break the bank, but if you have code that relies on it heavily this is definitely something to consider with regard to optimisation.

For the same effect you could also with ~1, as in this code:

It also rounds the number much faster than round(), comparable to the speed of the bit shifting method. I just don't like the readability as much; the bit shift method > 0--> looks like it's knocking off digits past zero, which is a reasonable mnemonic for rounding.

This is all very well and good for rounding, but what about flooring or ceiling a number? This trick always rounds up with a fractional part of 0.5 or above, and rounds down below that. In Game Maker, you can use the floor() function to always round down, and the ceil() function to always round up.

You're in luck, because you can do code like this:

These will still be very nearly twice as fast as their function equivalents!

(EDIT: The above about flooring and ceiling isn't perfect; be sure to read my correction!)

Okay, so maybe in practice this will make your code more confusing and less readable, but like I said: "huge nerd". =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 is your gravity, and f is the jump force, which can be set to anything. In a Genesis Sonic game, 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.

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.

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 2. Next step, times 3, then in the next, times 4, and so on, until gravity overcomes the jump force in step t minus 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 times 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 times t+1 instead).

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:

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!

2009-12-08

Sinusoidal Motion

Welcome, Code Ninjas!

This time we'll be looking at a simple script that makes certain motions look more natural.

Imagine you have a platform that you'd like to move back and forth, a common element in platformer games. You might use code something like this:

Create Event:

r = 64;//maximum distance in pixels the platform may travel from its origin before reversing direction

s = 1/32;//speed of the platforms. The divisor is how many steps you wish the platform to take to reach its maximum distance from its origin.

Step Event:

if a //moving forward...
  {
  p += s;
  if p >= 1 { p = 1; a = 0; }
  }
else //...and moving back
  {
  p -= s;
  if p <= 0 { p = 0; a = 1; }
  }

x = xstart + r*p;//update platform's position
xspeed = x-xprevious;//get platform's speed in pixels

(Note: If this code seems a little overcomplicated, it is because it had been purposefully written to be able to make platforms of any speed and range.)

This effect that this code achieves is a platform that moves away from its starting point at the specified speed, reaches its maximum distance, and then immediately reverses direction and trots back to repeat the process indefinitely. This is the sort of platform you'll often see in early 8- and 16-bit games.

The trouble with this kind of motion is the immediate reversal of motion. In one step, the platform can be moving with a speed of +5 pixels, and the in the next, with a speed of -5 pixels. This doesn't look very realistic, because in reality, most often when something reverses direction, it has to slow down to a halt, and then begin to accelerate again.

This jerky motion isn't so bad if the platform's "patrol area" is bounded by walls at its extremes - then it just looks like the platform is bouncing off of the walls, and the motion doesn't look too bad. But if the platform is floating in mid-air, as they often are, there is nothing that appears to plausibly reverse it, and the motion looks unnatural.

And it's worse than just looking unpleasant. It actually makes the game less fair, and less fun. If the player can't tell by some visual cue when the platform is going to decide to turn around, they have a much harder time getting the proper timing on their jump. They will have to use more trial and error, watching the platform make its rounds more than once before they can confidently make their move.

This is almost game-breaking if you want to keep good flow, as in a Sonic game. In the Sonic the Hedgehog games for the Mega Drive (Genesis), almost all platforms not bounded by walls move with a natural motion - decelerating as they reach their extremes, and accelerating toward their point of origin as they turn back around. This allows players to intuit exactly where the platform will be any time when they first come across it, without patient study of its entire cycle. This is one of the subtler points about the Sonic the Hedgehog game, seldom recognised, but it contributes not insignificantly to the sense of speed that made them popular.

Well then, how can we achieve the same effect so that our platforms move with a natural motion, rather than an outdated, unrealistic, and unfair jerky one? Why, with the trusty cosine function, of course!

Imagine, now, a platform that - instead of moving simply up and down, or left and right - moves in a complete circle, as many do in Sonic and Mario games. The platform's speed should be uniform, but if we were to look at just one component of its velocity - say, just the xspeed, or just the yspeed - we would notice acceleration and retardation of its speed. Simply imagine looking at the platform's circular path edge on, instead of face on. It would appear to be moving in a straight line, but slowing down at the edges and speeding up in the middle, just like those Sonic platforms we want to emulate.

So, in effect, what we want to do is make the platform move in a circle - just a really flat circle that might as well be a line. We'd use code something like this:

Create Event:

r = 64;//maximum distance in pixels the platform may travel from its origin before reversing direction (radius of the circle)

s = 180/32;//speed of the platforms. The divisor is how many steps you wish the platform to take to reach its maximum distance from its origin. (This time we use 180, not 1, because we'll be using degrees.)

Step Event:

a += s;
if a >= 360 a -= 360;
//alternatively the preceding two lines could be 'a = (a+s) mod 360;'.

//also, here we don't need to use two states, forward and back, because the circular motion takes care of that for us automatically.

x = xstart + r*cos(degtorad(a));//update platform's position
xspeed = x-xprevious;//get platform's speed in pixels

To make the platform move vertically, we can just replace all the references to x and make them y. Or, to make it actually move in a perceptible circle, we can have both sets of lines. By using a different range value for both x and y, you can squash the circle into any sort of ellipse you want - for example, a circle that is twice as wide as it is tall:

Create Event:

xr = 64;
yr = 32;

Step Event:

//...

x = xstart + xr*cos(degtorad(a)); xspeed = x-xprevious;
y = ystart - yr*sin(degtorad(a)); yspeed = y-yprevious;

Remember to subtract the sine for y, and add the cosine for x, otherwise instead of moving circularly, it'll just move in a smooth diagonal - which is actually another useful effect you might want to achieve.

Well, that about does it for platforms, but the power of sinusoidal motion goes far beyond. There are other applications, and for just such an example, I'll use the purpose for which I first I needed it myself.

In games like Phantasy Star, when you talk to townsfolk or shopkeepers, their dialogue appears on the screen inside of bordered window, or a 'text box'. In most games, the text boxes appear on the screen gradually, either opening up, dropping down, or fading in.

I wanted this animation to appear smoother, so I thought perhaps I could apply sinusoidal motion as the solution. But there was a slight hitch.

Imagine you want to fade in a window, from an alpha of 0 (invisible) to an alpha of 1 (fully opaque). You could simply add 0.1 for ten steps, but that wouldn't look very smooth. How about, instead, we use a sine function.

Code:

step = 18;

for {a=0;a<=180;a+=step}
  {
  alpha = sin(degtorad(a));
  }

Well, clearly this won't work. The value of alpha will go from 0 (the sine of angle 0), accelerate toward 1 (the sine of angle 90) and decelerate back to 0 again (the sine of angle 180). The text box wouldn't fade in, it would fade in and back out again just as quickly! This obviously isn't what we want.

But why not just use 90, instead of 180, so that alpha will stop at 1, thereby fading the text box in how we want it? Well, in that case, the fade would start smoothly, but stop abruptly. I wanted it to both start and stop smoothly.

I needed some way to have the alpha value "move" like a half-circle (slow start and stop), but only "traverse" a quarter-circle (start at 0 and end at 1).

So I made a script, called it 'sinusoidal()', and this is the function I used:

sinusoidal()

//argument0: any value between 0 and 1

return (cos(degtorad(180-(180*argument0)))+1)/2;

Now, sinusoidal motion can be employed anywhere by calling the script. The text box fade code ends up looking something like this:

Code:

step = 0.1;

for {a=0;a<=1;a+=step}
  {
  alpha = sinusoidal(a);
  }

This little script can be very versatile. You can use it to slide logos or menus onto the screen. You could use for flashing lights for smoother look. You could use it to animate a pendulum. You could even use it to make your character push a block (as Link does in the Zelda games) with a less abrupt and better looking motion. And with clever modification, who knows to what ends a Code Ninja might put it to.

For an example GMK illustrating the difference between normal and sinusoidal motion in several types of movement and animation (flashing, shrinking, swinging, sliding), click here.

Next time we'll be looking deeper into text boxes - how to make the text type out, change the text speed, and more. Until then, happy coding, Code Ninjas, and happy holidays, too!