8-Bit Warrior Games + Design + Tutorials + Random

7Sep/150

[GameMaker] YYC Optimisation – Direct Value Access

(This does not benefit standard VM exports or HTML5/JS exports but will make them perform slower)

Recently, I stumbled across a nifty optimisation for GameMaker's YYC (C++) compiler. In my tweening engine, I had noticed that some "simpler" easing scripts were performing much slower than more complicated ones.

For example...

/// EaseLinear()
return argument2 * argument0 / argument3 + argument1;

...was performing much slower than...

/// EaseInOutQuad()
var _arg0 = argument0/(argument3 * 0.5);
if (_arg0 < 1){ return argument2 * 0.5 * _arg0 * _arg0 + argument1; }
return argument2 * -0.5 * (--_arg0 * (_arg0 - 2) - 1) + argument1;

This had me baffled. So, I tweaked various parameters, attempting to find what was driving the non-sensical performance difference. Eventually, I noticed the unique thing EaseInOutQuad had which EaseLinear didn't:

operations involving a numerical constant

What I learned is that, under the hood, GameMaker seems to handle variables as a general data type which can be safely passed around to various expressions, functions, and scripts. I assume that these general types will then fetch and return their actual data type when needed, which may be a real number, string, array, or some other type. Apparently, this can lead to extra overhead when checking for a variable's data type at runtime.

Now, what does this have to do with numerical constants helping speed things up? Well!

When you write an operation explicitly involving a numerical constant, it can be assumed that other variables interacting with the numerical constant are (should be) real numbers, or at least know how to deal with them. In the right places, this can enable GameMaker to optimise things by directly accessing a variable's real value instead of accessing its general "packaged" data type first.

For example, in the most simplest form:

x = a;      // What is 'a'?

x = 0+a; // Compiler can assume 'a' is a real number

In the example above, GameMaker will first access (a) as a general type before assigning its actual value to (x). With (0+a), however, the real value from (a) will be directly accessed since the numerical constant (0) makes it safe to assume the intention of the operation. This can lead to speed gains, even with the (possible) slight overhead from the "+0" operation. Stripped down, the compiled C++ output would basically look like this (but much messier)...

x = a; // Access 'a' and find which type to assign x

x = 0 + a.val; // Directly assign the real value of 'a' to x

Despite appearing more complex, the second line is faster as its real value is being directly accessed by the C++ code. The operation involving a numerical constant allows this to occur.

Now! To get the most out of this technique, we need to utilize the Order of Precedence.

x = a + 0 + b * c; // We can do better!

In the above example, I have attempted to directly access the real values of all variables in the expression by adding (+ 0). However! Because (b * c) has a higher predence and will be executed first, b and c will fail to get the intended optimsation of having their values directly accessed. Instead, we need to wrap brackets around the first executed variable and add a constant zero to it.

x = a + (0+b) * c; // That's better!

Now, (0 + b) will be executed first, with (b) directly accessing its value. Because (b) is now assumed to be a real value, (c) can also assume it is real. And because ( (0+b) * c ) is assumed to be real, (a) can ALSO assume it is real when it is accessed last. As a result, all values will be directly accessed by the C++ code:

x = a.val + (0 + b.val) * c.val; // YAY!

Note that this trick also works when multiplying or dividing by constant values:

x = a + 0.5 * b * c; // Divide and conquer!

Note that using this technique directly with script/function parameters can sometimes do more harm than good. Script and function parameters may require general data types to be passed as arguments. Remember that the general type is safer to pass around?

x = AddValues(a+0, b+0, c+0); // Probably BAD

x = ShowNumber (a + (0+b) / c); // Probably GOOD

In the first example above, because of how the YYC works, the numerical constant (+0) would force all 3 parameter values to first be pre-calculated and assigned to 3 temporary "general" variables. This creates extra overhead and can slow things down. However, with the second example, the optimsation benefits for the single argument would likely speed things up, as the single parameter involves a more complex calculation, allowing direct access to 'a', 'b', and 'c' in a single expression. The cost of the "extra overhead" would likely be outweighed.

In regards to the easing algorithms I had mentioned at the start, placing ( 0 + argument0) at the start of EaseLinear was all that was needed to greatly boost its speed!

return (0+argument2) * argument0 / argument3 + argument1; // Huzzah!

Anyhow! There's no sure way to know how this could help speed up your own code until you try. Check to see where it helps and where it doesn't. Experiment and benchmark the results!

Also, be sure to check out the outputed C++  code for your project in the Asset Cache Directory. You can find the directory by going to File -> Preferences.

19Sep/130

[GameMaker Studio] Blurry Surfaces… Why??

If you use interpolation for your game's graphic settings, drawing surfaces can appear blurrier than expected. This is due to graphics being interpolated (smoothed out) when they are drawn to a surface, then being interpolated a second time when the surface is drawn to the main view. There is a simple way to resolve this.

When drawing to a surface, interpolation can be temporarily turned off with texture_set_interpolation() and turned back on when you are finished drawing to the surface. The result is a sharper image when drawing the surface to the main view.

/*** DRAW EVENT ***/
// Set the surface for drawing
surface_set_target(mySurface);

// Turn off interpolation
texture_set_interpolation(false);

// Draw stuff to the surface
draw_sprite(spr_StrongBad, 0, 0);
draw_sprite(spr_HomeStar, 32, 100);

// Turn on interpolation
texture_set_interpolation(true);

// Route drawing back to main view
surface_reset_target();

// Draw the surface to the main view
draw_surface(0, 0);

There!
You should now have a much crisper image when drawing with surfaces!

null

8Aug/130

[GameMaker] Utilizing script_execute();

null

Syntax : script_execute(scr, arg0, arg1, arg2, ...);

I can't help but feel that script_execute() is one of the most overlooked functions in GameMaker. The official docs describe it as a way to "pass a script to an instance in a dynamic way". Lets take a look at a simple way it can be utilized.

Lets say you wanted to make a "Play" button for your game. You go ahead and create a new object called obj_ButtonPlay. You give it a sprite and put some code in the Mouse Left Pressed event. You've also added some extra code to make it switch images when the button is highlighted. It works as you expect.

But now, you need an "Options" button. So, again, you make another button, naming it obj_ButtonOptions. You give it a sprite, and put some code in the Mouse Left Pressed event. You also add some more of that fancy code to make it highlight. But now you realise that you need more buttons; MANY MORE! You continue to make a new object for each and every button in your game.

Using script_execute, I like to avoid needing a different object for each button.
We can create ourselves a single button object and, using script_execute, make it do (virtually) whatever we want it to.

This time, we create an object called obj_UIButton and initialize a variable in its Create Event:

// Create Event
onTouchUp = -1;

Secondly, we add some code to the Mouse Left Released event:

// Mouse Left Released Event
if (onTouchUp != -1)
{
script_execute(onTouchUp);
}

Now, we go ahead and create ourselves a new script called "GameStart" and write the code we need to start the game:

// GameStart()
audio_play_music(bgmAwesomeSong, true);
room_goto(rmBattleZone);

Then create another script called "GameQuit":

// GameQuit()
GameSave();
audio_stop_music();
room_goto(rmMainMenu);

We can now dynamically create both required buttons and attach these scripts.

buttonPlay = instance_create(320, 250, obj_UIButton);
buttonPlay.onTouchUp = GameStart;
buttonPlay.sprite_index = spr_ButtonPlay;

buttonQuit = instance_create(320, 350, obj_UIButton);
buttonQuit.onTouchUp = GameQuit;
buttonQuit.sprite_index = spr_ButtonQuit;

Now, both of these buttons, created from the same object, will do two totally different things by using script_execute to call the attached script. The base obj_UIButton object can be extended to include the "fancy" selection highlight and other features. Each instance created from the root object will instantly receive these new features without having to make a new object and repeat code.

This is just one simple example. Its not my goal to show you an extensive way to use it but, rather, to simply get you thinking about how it might help you at some point in your development journey. It is one more tool waiting to be used when you need an elegant solution.

null

3May/1214

[Game Maker] Grid Movement -PART 3- Character Animation

If you find this tutorial helpful, please consider showing support by trying my latest game
Insane Number Run
Insane Number Run***

In the case of being too ADD, you can download the completed project for this lesson here:

[Windows]
Part 3 Editable Project Download

[Mac]
Part 3 Editable Project Download (Slightly outdated)

If you have not already done so, I highly suggest going through parts 1 and 2 of this series first, as this lesson will be based upon their existing code.

Part 1: The Basics
Part 2: Collision Detection

Welcome to part 3 of my series on Grid Based Movement for Game Maker!
In this lesson, we are going to look at implementing character animation for our player object. There are a few ways to go about doing this with Game Maker, but today I will teach one of the techniques which I prefer and continue to use myself.

The result of this lesson should look like this: Grid Animation Example

Alright, onto the Lesson!
First, lets get ourselves some sprite strips to work with. Go ahead and download the following files to use for our lesson. You can use your own if you like, but note that you will likely need to make minor adjustments to the example code if you do so.

Sprite Strip 1
Sprite Strip 2
(Big thanks to Cody Penner for the sprites! )

For this lesson, we are going to continue where we left off from Part 2: Collision Detection. You can download the completed editable project for that lesson here: Part 2 Project Download

With our existing project from Part 2, add the new sprite strips to the Sprites folder.
The first 4 images of the sprite strip are for the standing "animations", one for each direction. Following them are the walking frames for all 4 directions containing 4 images for each animation.

Noting the placement, order and length of our images/animations within the sprite strip is important. We will be using this information to properly set up our animations for our player object. Be aware that the numerical values of the images in the strip are zero-based. This means that 0 refers to the first image, 1 to the second, 2 to the third, and so on. We can explicitly change an instance's displayed image at runtime by modifying its built in image_index variable, setting it to the appropriate offset we want, relevant to the current sprite strip. Soon, you will see how this is used to create smooth walking/standing animations for our grid based movement system.

Before doing anything else, open up the properties for obj_player and change Sprite to one of the sprites we just imported.

Within obj_player, highlight the Create Event and open the existing Execute Code action.
Below the already existing code in our action, insert the new variables we will use to support our animation system.

// ...PREVIOUS OLDER CODE

    // We will now keep track of our direction
direction = 270;
    // Used to help set standing animations
justStoppedMoving = true;

    // Initialize animation properties
animIndex = 0;         // first frame in current animation
animLength = 0;        // current animation length in frames
animSpeed = 0;         // current animation speed
animIndexRelative = 0; // relative from first frame of animation

    // Set animation length properties
animLengthStanding = 1;
animLengthWalking  = 4;

// Set animation speed properties
animSpeedStanding  = 0.0;
animSpeedWalking   = 0.2;

    // Standing animation index offsets
animIndexStandRight = 0;
animIndexStandUp    = 1;
animIndexStandLeft  = 2;
animIndexStandDown  = 3;

    // Walking animation index offsets
animIndexWalkRight = 4;
animIndexWalkUp    = 8;
animIndexWalkLeft  = 12;
animIndexWalkDown  = 16;

 

Because we want our character facing downward at the start, we will set direction to 270
As a refresher: right = 0, up = 90, left = 180, down = 270
We have also created a new variable justStoppedMoving which will enable us to easily manage code for when our player stops walking. This can be helpful for setting standing animations.

Following that, we have initialized some required properties to make our animation system work. animIndex, animLength, animSpeed and animIndexRelative hold the status of the active animation.
animIndex receives the value of the first frame in the animation we want to use. We can easily assign it one of the animation indexes we have created, such as animIndexWalkRight.
animLength holds the length of the current animation in frames. We will assign in the value from either animLengthStanding or animLengthWalking.
animSpeed is simply how fast our animation will animate. Make sure to keep the value relatively small. We will assign it the value held by animLengthStanding or animLengthWalking.
Finally, we initialized animIndexRelative. This variables holds the current animation's frame value relative to its starting animIndex frame. It will allows us to repeatedly cycle through and select the appropriate frames needed for each animation.

With that set up, we are now going to set up a script so that we can comfortably change the required properties needed to set up the appropriate animations we want.

In GameMaker's 'Scripts' folder, create a new script called 'SetAnimation'
Inside this script, go ahead and input the following code:

animIndex = argument0;
animLength = argument1;
animSpeed = argument2;

 

This script takes 3 arguments. It will be used to change our animation Index, Length, and Speed.
With that inputted, close it up and once again open the properties for obj_player.

We are now going to add the code which will make our animation system work. But we are not going to add it to the Normal Step Event. Instead, we will add an End Step Event, and place our code inside there. By placing our animation system here, we separate it from our Normal Step Event code, ensuring the intended animations are drawn after all our other updates are finished.

Inside the End Step event, add a new action -> Execute Code. Inside this code action, place the following:

image_index = animIndex + animIndexRelative;
animIndexRelative += animSpeed;

if  (animIndexRelative >= animLength)
{
    image_index = animIndex;
    animIndexRelative = 0;
}

 

With that code in place, the animation will always be within our set boundaries.
As long as we use the SetAnimation script, we can be certain that our animation system will function properly.

We are now going to return to the Normal Step event for obj_player and edit the existing code action.
We will start by adding a new line at the bottom of our existing code for when our character has just stopped moving.
Add the line of code where it is commented: // *** NEW CODE ***

//... OTHER CODE

if (isMoving == true)
{
    x += speedX;
    y += speedY

    moveTimer -= moveSpeed;
    if (moveTimer)
    {
        isMoving = false;
        justStoppedMoving = true; // *** NEW CODE ***
    }
}

 

We can now return to the top of the code action and utilize the justStoppedMoving variable to set standing animations when our player finishes walking.

    
    // Set standing animations if just stopped
if (justStoppedMoving == true)
{
    justStoppedMoving = false;

        // Set appropriate standing animations
    if (direction == 0)
        SetAnimation(animIndexStandRight, animLengthStanding, animSpeedStanding);
    else
    if (direction == 90)
        SetAnimation(animIndexStandUp, animLengthStanding, animSpeedStanding);
    else
    if (direction == 180)
        SetAnimation(animIndexStandLeft, animLengthStanding, animSpeedStanding);
    else
    if (direction == 270)
        SetAnimation(animIndexStandDown, animLengthStanding, animSpeedStanding);
}

    // ... Other Code

 

Based upon the character's current direction, we have effectively set the appropriate standing animation. But up until this point, we haven't written any code to change the character's direction or set a walking animation.

Just below the code we wrote, we will modify the existing code within the keyboard_key() check statements to include an updated direction. We will also set the appropriate walking animation when our player is able to move.
Go ahead and modify our existing code to include keeping track of our current direction, as well as setting the appropriate animations. Note that this code will also set an appropriate standing animation if the player is blocked and unable to move. This allows the player to allows face the direction they intend to.

if (isMoving == false)
{
         // Perform 4 direction keyboard and grid checks
         // for setting appropriate movement and animation
    if (keyboard_check(vk_right))
    {
        direction = 0; // Keep track of new direction

        if (obj_grid.cells[(x div 32) + 1, y div 32] == 0)
        {
            isMoving = true;      // Lets start moving
            moveTimer = gridSize; // Ready moveTimer for countdown
            speedX = moveSpeed;   // Set horizontal speed
            speedY = 0;           // Set vertical speed
            SetAnimation(animIndexWalkRight, animLengthWalking, animSpeedWalking);
        }
        else
        {       // Set standing anim for new direction
            SetAnimation(animIndexStandRight, animLengthStanding, animSpeedStanding);
        }
    }
    else
    if (keyboard_check(vk_up))
    {
        direction = 90;

        if (obj_grid.cells[x div 32, (y div 32) - 1] == 0)
        {
            isMoving = true;
            moveTimer = gridSize;
            speedX = 0;
            speedY = -moveSpeed;
            SetAnimation(animIndexWalkUp, animLengthWalking, animSpeedWalking);
        }
        else
        {
            SetAnimation(animIndexStandUp, animLengthStanding, animSpeedStanding);
        }
    }
    else
    if (keyboard_check(vk_left))
    {
        direction = 180;

        if (obj_grid.cells[(x div 32) -1, y div 32] == 0)
        {
            isMoving = true;
            moveTimer = gridSize;
            speedX = -moveSpeed;
            speedY = 0;
            SetAnimation(animIndexWalkLeft, animLengthWalking, animSpeedWalking);
        }
        else
        {
            SetAnimation(animIndexStandLeft, animLengthStanding, animSpeedStanding);
        }
    }
    else
    if (keyboard_check(vk_down))
    {
        direction = 270;

        if (obj_grid.cells[x div 32, (y div 32) + 1] == 0)
        {
            isMoving = true;
            moveTimer = gridSize;
            speedX = 0;
            speedY = moveSpeed;
            SetAnimation(animIndexWalkDown, animLengthWalking, animSpeedWalking);
        }
        else
        {
            SetAnimation(animIndexStandDown, animLengthStanding, animSpeedStanding);
        }
    }
    // ... OTHER CODE
}

 

With that code in place, we now have a functioning animation system where the character will animate according to our set parameters determined by the sprite strip.
A benefit to this animation system is that sprite strips, which share the same animation parameters, can be swapped at any time with ease! Simply change the character's sprite_index and the change will be immediately reflected, no matter what state the character is in!

If you want to have your standing animations the same as your walking animations (think Dragon Warrior/Quest), then simply change the standing properties to be the same as the walking animation properties, and you're good to go!

If you have any questions or suggestions, I would love to hear from you!
And if you're on Twitter, find me at @Nehemius

null

15Feb/121

[Game Maker] Grid Movement -PART 2- Collision Detection

If you find this tutorial helpful, please consider showing support by trying my latest game
Insane Number Run
Insane Number Run***

Accompanying video tutorial. Suggested to watch in fullscreen at quality of 480p or higher:

NOTES
***
If you have not already done so, I highly suggest going through Part 1 of this tutorial series as what follows will be based upon its existing code. Links to other lessons can be found here:
Part 1: The Basics
Part 3: Character Animation

An editable gmk for this lesson can be downloaded here: Part 2 Download
***

1) Create a new object, naming it obj_grid

2) Create a new object, naming it obj_block

3) Assign obj_block a 32x32 sprite

Our obj_grid instance is going to manage our grid's collision information. It will initialize and hold a 2-dimensional array for storing locational information in our rooms. We will use the number 0 to represent an empty location, and the number 1 to represent a wall

4) Inside obj_grid, Add Event -> Create create, then add a piece of code code containing:

var i, j; // Not required but helps speed up 'for loop'

// Use the room's height and width divided by grid size (32) to
// initialize grid with 0
for (i = 0; i <= (room_width div 32); i += 1)
{
   for (j = 0; j <= (room_height div 32); j += 1)
   {
      cells[i,j] = 0;
   }
}

// This 'with()' statement will cycle through all obj_block instances
// within our rooms and use their relative x/y properties
with(obj_block)
{
   // Use block's x/y divided by grid size to set relative location
   // in cells[x,y] array to 1
   other.cells[x div 32, y div 32] = 1; // 'other' refers to obj_grid

   // For performance, we can remove the instance
   instance_destroy();
}

 

Now we are going to add some conditionals to our keyboard_check() blocks from part 1 to see if the corresponding direction next to our player is free. The code to be added will be marked by the comments '// <- ADD'

5) Inside obj_player -> Step step -> piece of code code, modify to match:


if (isMoving == false)
{
    if (keyboard_check(vk_right))
    {
        if (obj_grid.cells[(x div 32) + 1, y div 32] == 0) // 

 

With this work done, we can now set up our room with walls to run into. Before doing so, make sure you have a 32x32 background tile to represent as a wall.

6) Go ahead and add the wall tiles to our test room, anywhere you like, making sure to use a 32x32 grid size in the room editor's settings.

7) Place obj_block instances on top of the tiles you just placed

8) After selecting the room's 'Settings' tab near the top, find and click the button titled 'Creation code'. Once doing so, add this code:

instance_create(0,0,obj_grid);

There! Making sure you have obj_player in the room, go ahead and run your level. Your player should now properly detect the walls you have set out. Notice that the actual wall instances are removed, and only the more efficient background tiles remain.

Again, feel free to contact me with any comments or questions.
Happy coding!

null