Retro Platformer tutorial part 2 – Shooting bullets!

In part 1 of this series, we went through:

  • Setting up a new project
  • Creating a hero character
  • Coding her running and jumping behavior
  • Adding some animations

In part 2, we will create a bullet object, write the code to shoot bullets on a button press and add some shooting animations for the hero character.

Creating a bullet object

  • Take the “spr_bullet_buster.png” file from Mega Woman’s asset pack and drop it into you Game Maker project
  • Set the origin to “middle center”
  • Create a new Object and call it “o_bullet_blaster”
  • Set its sprite to “spr_bullet_buster”
  • Set its Parent to “o_projectile”
  • Open the Object’s Variable Definitions and turn off “flag_hurt_hero” (see below)

While you’re there, you can also customize the bullet’s speed by changing the spd value. Make it 3 for now. You can change it to your liking later.


Shooting bullets

Open the Mega Woman object’s Step event and add this code under the jumping part:

if(input.B_pressed && instance_number(o_bullet_blaster) < 3)
{
    instance_create_depth(x+6*hdir,y,depth,o_bullet_blaster,{hdir:hdir});
}

What this does is when the “B” key is pressed (the gamepad’s B key is linked to the “X” key on the keyboard ) and there’s less than three blaster bullets on screen, it will create a new blaster bullet. Note: the “o_projectile” objects destroys themselves when they get out of the current View. Check the Outside View 0 event for details.

The {hdir:hdir} part at the end of the instance_create_depth passes the horizontal direction of the hero object to the bullet so that the bullet moves in the same direction the hero is facing.

Setting a minimum delay between bullet shots

Let’s say we want to implement a minimum delay between each shot to prevent the player from spamming the shoot button too quickly.

Add these variables to the Create event:

shoot = 0;
shoot_delay = 10;

Next go the the Step event and add the bold parts to the shooting code:

if(input.B_pressed && shoot == 0 && instance_number(o_bullet_blaster) < 3)
{
    shoot = shoot_delay;
    instance_create_depth(x+6*hdir,y,depth,o_bullet_blaster,{hdir:hdir});
}

if(shoot > 0)		shoot--;

This adds a condition to shooting the bullet (shoot == 0) and set the shoot variable to the shoot_delay value when the button is pressed. This value is decreased by 1 with each step until it reaches 0.

This essentially create a 10 steps minimum delay between each fired shot. You can customize this by changing the value of shoot_delay.

Shooting animations

Open Mega Woman’s Create event and add these lines to set up the animations we need:

create_anim("idle_shoot",6);
create_anim("walk_shoot",16,21);
create_anim("jump_shoot",15);

We also need a few variables to manage how long the animations are used. Add this too to the Create event:

shoot_posture = 0;
shoot_posture_delay = 30;

Now let’s implement these variables into the shooting code by adding the parts in bold:

if(input.B_pressed && shoot == 0 && instance_number(o_bullet_blaster) < 3)
{
    shoot = shoot_delay;
    shoot_posture = shoot_posture_delay;
    instance_create_depth(x+6*hdir,y,depth,o_bullet_blaster,{hdir:hdir});
}

if(shoot > 0)		shoot--;
if(shoot_posture > 0)	shoot_posture--;

Just like with shoot and shoot_delay, the new code above set shoot_posture to the shoot_posture_delay when the fire button is pressed and the value of shoot_posture is then decreased by 1 every step until it reaches 0.

But how do we use this to manage our animations? Let’s change the animation management part in the Step event (inside the STATES.NORMAL state):

// MANAGE ANIMATIONS
if(blocked_down)
{
    if(shoot_posture > 0)
    {
        if(hsp == 0) play("idle_shoot");
        else         play("walk_shoot");
    }
    else
    {
        if(hsp == 0) play("idle");
        else         play("walk");
    }
}
else
{
    if(shoot_posture > 0)    play("jump_shoot");
    else                     play("jump");
}

Again the animations are divided between “walk” and “idle” when the hero is on the ground (blocked_down) and “jump” when he is not.

On top of that we check if the shoot_posture is above 0 or not to decide if we should use the shooting animations or the regular ones. This will cause our hero to display her shooting animations (with her arm outstretched) for 30 steps after pressing the shoot button. You can customize the delay by changing the value of shoot_posture_delay in the Create event.

Summary: Mega Woman’s code so far

Create event

event_inherited();

create_anim("idle",0,5);
create_anim("slide",7);
create_anim("walk",8,13);
create_anim("jump",14);
create_anim("hurt",44);

create_anim("idle_shoot",6);
create_anim("walk_shoot",16,21);
create_anim("jump_shoot",15);

shoot = 0;
shoot_delay = 10;

shoot_posture = 0;
shoot_posture_delay = 30;

Step event

event_inherited();

if(do_step)
{
    switch state
    {
	case STATES.NORMAL:
	    hsp = (input.right - input.left) * spd;
	    if(hsp != 0)
	        hdir = sign(hsp);

	    // CONTROLS JUMP
	    if((blocked_down || coyote > 0) && input.A_pressed)
		vsp = -jump_spd;

	    // INTERUPT JUMP
	    if(vsp < 0 && !input.A)
		vsp = 0;

	    if(input.B_pressed && shoot == 0 && instance_number(o_bullet_blaster) < 3)
	    {
		shoot = shoot_delay;
		shoot_posture = shoot_posture_delay;
	        instance_create_depth(x+6*hdir, y, depth, o_bullet_blaster, {hdir:hdir});
	    }

	    if(shoot > 0)		shoot--;
	    if(shoot_posture > 0)	shoot_posture--;


	    // MANAGE ANIMATIONS
	    if(blocked_down)
	    {
		if(shoot_posture > 0)
		{
	    	   if(hsp == 0)	play("idle_shoot");
		   else		play("walk_shoot");
		}
		else
		{
		   if(hsp == 0)	play("idle");
		   else		play("walk");
		}
	    }
	    else
	    {
		if(shoot_posture > 0)	play("jump_shoot");
		else			play("jump");
	    }
			
	    break;
    }
}

Conclusion

So now Mega Woman can run, jump and shoot bullets! In this part we’ve built a very basic projectile. You can see that the o_projectile object took care of everything without us having to code any behavior.

The o_projectile object has many customizable variables to change the way it behaves including its speed, damage, piercing through enemies, making it persistent (not destroyed by colliding with a target), adding an effect when it hits or is destroyed and making it affected by gravity. All of that can be done just by changing the settings in the Variable Definitions of your child objects. Check the Super State Engine documentation to learn more.

We can also code different or more complex behaviors for our projectiles by writing in the their Step events. There are not limits to the possibilities! This will be covered in a future post.

Next up! Getting hurt and dying

In part 3 of this series, we’ll make our hero object get hurt by enemies and handle dying.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *