Tutorial: Let's Learn How to Make Bullets and Sprite Animations!

About This Tutorial

In this tutorial we build a fire bullet that bounces as it flies, and along the way we explain
ACTION GAME MAKER’s “bullet” system
and how to make sprite animations.

We will use the project created in the “Jump Action Tutorial”.
ACTION GAME MAKER’s bullet system is set up in these steps:

  1. Create an object for the bullet
  2. Register it in the bullet settings of the object that fires it
  3. Fire it with the “Fire Bullet” action in the firing object’s visual script

Part 1: Let’s Make an Object for the Bullet!

First we will build the object for the bullet. This time we will explain how to make an animation from an image that is not in template format, and how to use the collision animation feature.

Part 1-1: How to Make a Sprite Animation Without a Template

A sprite animation is like a flip book: it animates by displaying images in order. Last time we loaded everything at once in template format; this time let’s learn how to build one by selecting each frame individually.

  1. Let’s prepare the image for the bullet. In the “Assets” view, click “Import official assets”.
  2. Select P_002_fire.png under “Weapon Images” and press “Import”.
  3. On the left side of the “Object” view, press “+ Create New” in the object list.
  4. Set
    Object Name: Fire Bullet
    Object Group: Player_Bullet
    Collision role: Player bullet
    then select “Bullet Base” in the lower pane and press “Create”.
  5. Switch to the Sprite Animation tab and press the “Use sprite animation” button.
  6. Press the “Add from sheet” button in the upper right.
  7. In the Add animation window, press “Add”.
  8. Name it “move” and press “OK”.
  9. The “Add frames from sheet” window opens, so press the “From Image List…” button.
  10. Choose the “P_002_fire.png” you just added and press “OK”.
  11. The image is added, but it is a little small, so let’s zoom in. Change the “Zoom” dropdown to 800%.
  12. Next, this image has 4 cells but is being treated as a single one, so let’s split it. Set Horizontal cells to “4”. Vertical lines appear on the image and it becomes 4 cells.
  13. Next, let’s match the collision size to the size of one cell. Press the “Adjust Initial Collisions” button.
  14. Both the wall collision and the attack collision look too big. Let’s adjust them.
  15. Move the wall collision handles to adjust it to roughly 8 wide and 12 high. (You can zoom the preview in and out with the mouse wheel.)
  16. Switch to the attack collision and adjust it. Make the attack collision slightly larger, about 12 wide and 16 high. When you are done, press “Confirm”.
  17. Finally, add the frames. They are loaded in the order you click them, so click 1, 2, 3, 4 in order starting from the leftmost cell, then press “Add”.
  18. The animation is now added. If the four images appear in the “Frame” field below, it worked.
  19. Try pressing the [:play_button:] button in the upper left of the window. You can preview the animation and see that the fire bullet now sparkles.

Part 1-2: Let’s Rotate the Image with Collision Animation!

  1. Change the tab to Collision Animation.
  2. Collision animation is a feature that lets you set the collisions and the image’s position, size, rotation and so on for each frame. Here we will set up the “Object image” to rotate.
    First, select the object image in the “Element (some hidden)” field.
  3. From the 5 cells in the move (4 frames) field at the very bottom, select END.
Why is there an END at cell 5 when the animation only has 4 cells?

The simple animation feature sets a key (a state) at the moment each cell starts playing. With only 4 cells, you could not set the state at the end of the 4th cell — the state at the end of the loop — so an END cell is added automatically, for the collision animation only.

  1. In the Inspector on the right, under Node2D > Transform, set the “Rotation” value to 360. That sets the “Rotation” value at the end of the animation (this is called a key). The key for the first cell is automatically set to the state at creation time = 0 degrees, and the keys for the cells in between are interpolated automatically, so this is all you need to set.
  2. Try clicking the play button in the upper left of the window — the image should spin around. If it does not work, check that you really set the END cell to 360 degrees; you may have forgotten to switch and set the first cell to 360 instead.
Why does the END cell's rotation read 359.9 after playback finishes?

It is a display-only issue. When loop playback is enabled, playing back returns automatically to the 0-second point at the 360-degree state — the true END state — so what you see is the state just before it wraps around. END does have the correct value of 360, so there is no problem.

Part 1-3: Let’s Change the Movement Speed and Gravity Settings!

Next, let’s give it movement befitting a bullet. It needs to be faster than the player, and since it bounces, it needs to be affected by gravity. (Ordinary bullets are not affected by gravity, so the template disables gravity.)

  1. Switch to the Preview tab and select “Move and jump” in the element list.

  2. In the Inspector on the right, under Movement Speed Settings, set
    Horizontal Speed: 500
    Vertical Speed: 500

  3. A little below that, the Gravity Rate value under Jump Settings is 0, so set
    Gravity Rate: 5.0
    The default gravity rate is 1.0, so this applies 5 times the normal gravity to this bullet. Normal gravity makes the movement feel floaty, so deliberately applying strong gravity gives it a snappier motion.

  4. The object setup is now complete. Let’s “Save” it just to be safe.

Part 2: Let’s Set Up the Bullet’s Visual Script!

Next, let’s set up a visual script for the bullet.

  1. Press Edit Visual Script.
  2. Press the button to create a visual script.
  3. Change State001 as follows:
    Animation to assign > Animation Category: move
    Title: Move
  4. Press “+ Add Executable Action” on the “Move” state.
    In the left pane, choose Move > TemplateMoveAction (template move settings).
    In the right pane, set the Move Template Type to Bound and turn on “Bound Bounce Gravity”.
    Bound is movement that bounces when the object hits something collidable, which makes it bounce when it hits the ground.
About the template move action

Once executed, “TemplateMoveAction” keeps performing the specified movement until another template move tells it to “stop”. In other words, it keeps the same motion even across multiple states, which makes it handy for objects that only move in simple ways. The “Enemy” left-right movement is built with it too.

  1. Next, let’s set up disappearing when it hits an enemy. Create a new state nearby, rename it to Remove, and press “+ Add Executable Action”.
  2. Add “RemoveSelf” from Disappear/Revive.
  3. Finally, set up the link. Connect a link from the “Move” state to the “Remove” state and press “+ Add Condition”.
  4. In the left pane, choose Object Control > ContactWithHitArea (contact with an object’s hit collision).
    In the right pane, enable all directions for the contact direction as seen from the object, set the target object type to Group and the target object group to “Enemy”, then add it.
  5. It now disappears when it hits an enemy, but as things stand the bullet never disappears unless it hits one. Let’s make it disappear when its wall collision hits something from the side. Press “+ Add Condition” once more.
  6. In the left pane choose “ContactWithBody”. In the right pane set
    Incoming contact direction as seen from this object: Left, Up, Right (!!not Down — if you include Down, the bullet disappears on the ground instead of bouncing!!)
    Connection With Previous Condition: “OR”
    This part is easy to get wrong, so check it carefully before adding.
  7. Look at ContactWithBody: if the icon correctly says “OR”, you are good. The bullet side is now fully set up.

Part 3: Let’s Set Up Firing the Bullet on the Player Side!

Next, let’s configure the bullet on the player side.
There are two steps: register “Fire Bullet” (the fire bullet object) in the bullet data under the “Bullet” settings, and add the “FireBullet” action.

Part 3-1: Let’s Configure the “Bullet” Settings!

  1. Go back to the Object view and switch the object to “Player”.
  2. Press “+ Add Settings” in the upper left.
  3. In the Add Settings window, add “Bullet” from Using objects.
  4. Look at the Inspector on the right, click “Array[BulletData]” in the bullet data list to expand it, then click the “BulletData” that appears to expand that too.
  5. Expand the base settings. First set the bullet name to Fire Bullet, then add “Fire Bullet” from the “List” button of the bullet object path.
  6. Next, turn on “Unlimit Shots” in the base settings (if this is off, you cannot fire while a fire bullet already exists in the scene). If the base settings look like the image, you are good.
  7. Next, expand “Initial Behavior” and set it to “Fly in the display direction of the firing object”.
  8. The bullet data side is now set. You have created data that fires the “Fire Bullet” “in the display direction of the firing object”, “no matter how many fire bullets are already in the scene”.

Part 3-2: Let’s Set Up the “FireBullet” Action!

  1. Go into “Edit Visual Script”, create a new state near the “Move” state, set the animation category name to “shoot” and name it “Ground Shot”.

  2. Press “+ Add Executable Action”. In the left pane choose “FireBullet” under “Attack/Bullet”, and in the right pane select the bullet data “Fire Bullet”, then press “Add”. If Fire Bullet is not there, check that it is correctly set in the player’s “Bullet” settings.

  3. The action side is done, so let’s make the link. Add a link from the “Move” state to “Ground Shot”, check “Trigger On Input”, and press “+ Add Input”.

  4. Set the left pane to the registered key used for input, and the right pane to Input Key: B, Input Condition: Moment Pressed, then press “Add”.

  5. As things stand you can only fire the fire bullet while moving, so let’s connect it from Idle too. The contents are exactly the same, so copy the “Move” → “Ground Shot” link, paste it onto Idle, and connect it to Ground Shot.

  6. Finally, make a link back from “Ground Shot” to “Idle” and set the state transition condition to “FINISHED_ANIMATION” (the animation has finished). Now it returns to Idle once the “shoot” animation ends.

  7. That is the setup done, but the lines may look messy. States can be moved by dragging, so this is a good chance to move them around and tidy things up a little. (In the image below, all the states have been moved down and Ground Shot has been moved up.)

  8. Now let’s test play. If everything is set up correctly, a fire bullet comes out in the direction the player is facing and travels forward while bouncing. Note that “at this point, even with correct settings, the bullet disappears but cannot defeat enemies”. Just check that the bullet comes out and that it bounces as it travels.

Checklist for when it does not work
  • No bullet comes out.
    Check that the bullet data is correctly specified in the “FireBullet” action.
  • The bullet comes out, but you cannot move afterwards.
    Check that the link back to Idle is set correctly, and that the shoot animation is correctly assigned to the Ground Shot state.
  • The bullet comes out, but not from the second shot onward.
    Check that “Unlimit Shots” is correctly turned on in the bullet data’s base settings.
  • The bullet comes out, but does not bounce.
    Check whether the template move type Bound is correctly set in the Move state,
    and whether you accidentally enabled the Down direction in “ContactWithBody”.

Part 3-3: Let’s Make Bullets Able to Defeat Enemies

At this point, even with correct settings, the bullet hits the enemy and disappears — and damage really is dealt and the HP reaches 0 — yet the enemy does not perform its damage motion.
The reason is that the transition condition to the “Damage” state is contact with the “player” group only, and contact with “player_bullet”, which the player’s bullet belongs to, is not set. Let’s fix that right away.

  1. Go back to the Object view, open “Enemy” and press “Edit Visual Script”. Copy and paste the Damage state.

  2. A state called Damage (1) is created, so change its title to “Fire Bullet Damage” and delete the “SetObjectVelocity” that is set on it. (SetObjectVelocity is the action that bounces the player up, and we do not want a bounce from a bullet.)

  3. Copy the walk → Damage link and paste it as a walk → Fire Bullet Damage link.

  4. Open “ContactWithAttackArea” in the Inspector and change the target object group to “Player_Bullet”.

  5. Next, copy the Damage → Dead condition in the same way and paste it as a Fire Bullet Damage → Dead link.

  6. That is everything. Being hit by the player’s bullet now links to Fire Bullet Damage, and once HP reaches 0 it should carry through to Dead. Let’s try it in a test play.

Checklist for when it does not work
  • The bullet does not stop at the enemy.
    Check the “ContactWithHitArea” condition on the fire bullet object.
  • The bullet disappears but the enemy does not.
    Check the conditions on the enemy’s walk → Fire Bullet Damage link and Fire Bullet Damage → Dead link.

The next tutorial is in the table of contents

Extra Challenges

You should now understand how to fire bullets and how to set up animations, so the tutorial ends here… but as a game there are probably a few things that bother you. Here are the solutions, so give them a try if you are interested.

You cannot fire in the air.

Copy Ground Shot, create an “Air Shot” state, and link to it from the “Jump” state and the “Fall” state.
From the “Air Shot” state, link only to the “Fall” state.
All the settings can be the same as Ground Shot.

  • Why not return to “Jump”?
    Because returning to Jump would make the character jump again.

  • Why separate “Ground Shot” and “Air Shot”?
    To separate where they return to. If Air Shot returned to “Idle”, the character would be able to jump in mid-air after firing.

The enemy behaves strangely when you increase its HP.

As built now, the enemy cannot return to the walk state after taking damage. (It is built on the assumption that HP is only 1.)
Let’s add links back to walk from “Damage” and “Fire Bullet Damage”.
On those links, set the condition “SwitchVariableChanged” with HP > 0, and you get a setup where the enemy returns to walk if HP is greater than 0 and moves to dead if HP is 0.

Also, since you have gone to the trouble of separating the states, you can load a new official particle (explode, for example) and use “DisplayParticle” in the Fire Bullet Damage state to show a different particle only when the enemy is hit by a fire bullet.