开发者控制台
感谢您的访问。此页面目前仅提供英语版本。我们正在开发中文版本。谢谢您的理解。

Drawing Sprites

Written in October 2017 by Nathan Ranney, the founder of game development studio Gutter Arcade.

A sprite is an image that is being shown on your screen and it can be a single image, or a series of images that form an animation.

First, we need to break down what draw_sprite_ext(); is, and all of the arguments it uses. Draw_sprite_ext(); is an extended version of draw_sprite(); and gives us much more control over the sprite we are drawing. This function is primarily used to draw sprites to the screen. Using this function, we can change the scale, angle, color blending, and alpha of the sprite being drawn. See the table below for all of the arguments this function requires:

Argument Description
sprite Index of the sprite you want to draw.
frame Individual frame of the sprite you are drawing.
x X position of where you are drawing the sprite.
y Y position of where you are drawing the sprite.
xscale Horizontal scaling of the sprite.
yscale Vertical scaling of the sprite.
rot Angle/rotation of the sprite.
color Color blending (c_white displays as normal).
alpha Alpha of the sprite. Range from transparent (0) to opaque (1).

There is a bit of setup required before we can really use this function effectively. We are going to define these arguments as variables, and throw all of it into a script so it can be used on any object.

Create a script and name it animation_init. Add the following lines:

Copied to clipboard.

//initialize variables for drawing, and animation.
//draw
sprite = sprite_index;
frame = 0;
xPos = x;
yPos = y;
xScale = 1;
yScale = 1;
angle = 0;
color = c_white;
alpha = 1;

//animation
frameSpeed = 1;
facing = 1;

By setting the sprite variable to sprite_index, it will use the sprite that the object has set. While we are creating scripts, we may as well create a couple of helper scripts we will need later. Create a new script called approach and add the following lines:

Copied to clipboard.

//approach(start, end, shift);

if(argument0 < argument1){
    return min(argument0 + argument2, argument1);
}else{
    return max(argument0 - argument2, argument1);
}

This script allows you to increase a value by another value, until it reaches a maximum value. I'll show you what we can do with this a little later. Next, create another script and name it player_buttons. Add the following code:

Copied to clipboard.

left = keyboard_check(vk_left);
right = keyboard_check(vk_right);
up = keyboard_check(vk_up);
down = keyboard_check(vk_down);

All we are doing here is storing our keyboard inputs into variables. These are all booleans, meaning they can either be true or false. This makes it much easier to address button presses later on.

Now that we have our animation_init script ready to go, we are ready to start drawing, that is, once we have a sprite to draw! Create a new sprite, and name it sprPlayer_Idle. Make sure this sprite has multiple frames, and each frame is different. Otherwise you won't be able to tell it's animating. Set the sprite origin to the x center, and y bottom. If you are using the sprites that I am using, that is 16 and 32 respectively.

Here is a link to all of the sprites I am using. I recommend downloading them and following along.

Next we need an object. Create a new object and name it oPlayer. Set your sprPlayer_Idle sprite as the object sprite. Add the Create, Step, End Step, and Draw events. Add the Run Code action to each event. Open up the Create event code and add the following lines:

Copied to clipboard.

//animation
animation_init();

//movement
left = false;
right = false;
up = false;
down = false;

Next we move on the to Draw event. In the Draw event, add the following lines:

Copied to clipboard.

//draw sprite
draw_sprite_ext(sprite,frame,xPos,yPos,xScale * facing,yScale,angle,color,alpha);

Now we are almost ready to run the game and see our sprite being drawn on screen. Create a room, name it whatever you want, and place your oPlayer object in the room. When you run the game you should see the sprPlayer_Idle sprite being drawn. However that sprite isn't animated, and it doesn't move. It's just sitting there being boring. Let's fix that.

Animation

Assuming that your sprite has multiple frames, we need to animate that sprite. Since we are manually drawing the sprite, we can't use built-in variables like image_speed to animate. However we did already define our own image_speed equivalent with frameSpeed. Create a new script, name it frame_counter, and add the following lines:

Copied to clipboard.

//increase frame by frameSpeed
frame += frameSpeed;

Then, create another script and name it frame_reset. Add the following lines:

Copied to clipboard.

//reset frame if it is greater than the total number of frames in the sprite
if(floor(frame) >= sprite_get_number(sprite)){
    frame = 0;
}

The first script, frame_counter, will increase the frame we are drawing by the frameSpeed. The following script is there to keep frame from counting on forever and ever. This is also useful for animation purposes later. The sprite_get_number() function returns the total number of frames in any given sprite. So if our frame is greater than or equal to that number, reset frame to 0. If you need to change the animation speed of your sprite, all you need to do is change the value of frameSpeed.

Now, let's put all of this stuff to use. Open the Step event of your oPlayer object, and add the following lines:

Copied to clipboard.

//buttons
player_buttons();

//animation
frame_counter();

Open End Step and add the following lines:

Copied to clipboard.

//animation
frame_reset();

Go ahead and run the game. You should see your sprite animating. Depending on your frameSpeed, the animation may not look correct. Try adjusting the frameSpeed value and find something that looks right to you.

The guy on the left is animating at a frameSpeed of 0.10. His hyperactive friend on the right is animating at a frameSpeed of 1. This is running at 60fps in game. The number above their heads indicate the current frame of animation they are on.

Scale

Let's move on to the x and y scaling. We will start by flipping the sprite to the left and right. This is something that I've seen a lot of folks use the image_xscale variable for, and you don't necessarily want to do that all the time. Image_xscale will flip the sprite, but it also flips the sprite mask, which can cause problems. Part of the reason we are using draw_sprite_ext(); is that we are bypassing all of these built-in variables that can cause issues. Add a couple more lines to the step event, below the code we just added:

Copied to clipboard.

//change facing
if(left){
    facing = -1;
}else if(right){
    facing = 1;
}

Run your game, and if everything was done correctly, you should be able to flip the direction your newly animated sprite is now facing by pushing the left and right arrow keys. This is because in the Draw event, we are multiplying xScale by facing. The best part about this is that your sprite mask is not changing when your sprite is flipped. Now, do you remember the Approach script we added? Using that to make your sprites squash and stretch is a great way to add some life to your animations. Add the following lines below what we just added:

Copied to clipboard.

//change scale
if(keyboard_check_pressed(vk_space)){
    xScale = 1.5;
    yScale = 1.5;
}
xScale = approach (xScale,1,0.03);
yScale = approach (yScale,1,0.03);

Run your game and hit the space bar. Your sprite should grow by 50% and then shrink back down to normal scale. Adjusting the x/y scale of your sprite can have a huge impact on the feeling of your game. Experiment with this a bit and find some values that feel right to you. I like to create a squash_stretch script because I use this trick all the time. Here is what that script looks like:

Copied to clipboard.

//adjust x and y scale
xScale = argument0;
yScale = argument1;

You can then replace the xScale and yScale lines with squash_strech(1.5, 1.5).

Angle and Rotation

Up next we have angle, which is basically just rotation. When using angle, be sure to use values between 0 and 360. I'm sure that by now you can figure out how this will work. Go ahead and try to adjust the angle using the up and down arrow keys. Did you have any luck? Check out the code below and see if your code is similar:

Copied to clipboard.

//change angle/rotation
if(up){
    angle -= 2;
}else if(down){
    angle += 2;
}

Color Blending

The next argument is color, which specifically refers to color blending. Whatever color you put in here (such as c_red) will blend your current sprite into that color. We are going to use c_white for now, which means there is no color blending, and your sprite appears as normal.

Alpha

Now, on to the last argument in draw_sprite_ext(); Alpha is the transparency of your sprite. It ranges from 0, which is totally transparent, to 1, which is totally opaque. You could use this for all kinds of stuff like making your character blink after taking damage, or turning partially invisible when they are sneaking around. Try adjusting the alpha variable and see what happens. Here is the code I used to change the alpha. This uses the A and S keys to decrease and increase the alpha.

Copied to clipboard.

//change alpha
if(keyboard_check(ord("A"))){
    alpha = approach(alpha,0,0.05);
}else if(keyboard_check(ord("S"))){
    alpha = approach(alpha,1,0.05);
}

This is another good place to use approach, as it prevents the alpha value from going below 0 or above 1.

That should cover the ins and outs of what I believe is one of the most important functions in GameMaker. Once you get the hang of draw_sprite_ext(); you'll be able to create a lot of really interesting effects, and squeeze the most juice out of your sprites. You can download this GameMaker project file here.