Knowledgebase / Pow! Shooting projectiles (missiles, bullets, lasers)
We’re going to make projectiles that shoot from our player character. Pew pew!
This tutorial follows on from previous material covered in the Programming section of the Gamefroot Help page. The tank controls are built from How to make controls for a top-down player (RPG style). You can adapt the concepts from this tutorial to create a projectile system for any kind of game.
Step 1: The original projectile
Find an object to use as your projectile — this could be a bullet, missile, laser beam, ball, rock, or whatever you’d like. Place this projectile somewhere out of the way. In this example, the original projectile is hidden inside a group of trees. It’s important that the original projectile object is placed in a blocked off area, so that it can’t be accidentally touched by anything. If it touches anything, it will be destroyed, and if the original is destroyed, then we won’t be able to make copies of it.
Right-click on the projectile, and Add a new script. When it’s created, it first needs to add tag to itself so it can be identified by other game objects. Grab the “When created” block from Events, and drag into it the “add tag on myself” block from Sensing. In this example, we’ll give it the tag “bullet”.
When it hits anything, it needs to be destroyed. Grab “When I am touched get toucher” from Physics, and also “destroy myself” from Control Flow.
Remember that the original projectile needs to be placed somewhere in your level where it won’t touch anything. If it touches anything it will be destroyed, and if the original is destroyed, then we won’t be able to make copies of it.
Step 2: The shooter
For the bullets to be shot from our player object, we need to edit the script on that object.
First we need an event block that we can use as the trigger to shoot a bullet. In this example, we’ll use “When the player presses key spacebar” — grab that block from Events, and change backspace to spacebar (or whatever key you’d prefer to use).
To shoot a bullet, we’ll create a new instance of the original bullet, and position this copy where the player is. Grab the “create new instance” block from Draw. Click on “instance” and change its name to “bullet”.
We can target the original bullet by detecting its tag, so also grab the “first instance by tag” block from Sensing, and get rid of the “class class” block to make way for this block.
This block won’t go inside the gap! That’s because the “create new instance” block can target a class of objects, but not a single instance of an object. To deal with this we’ll grab the “class of myself” block from Sensing, and replace “myself” with “first instance by tag”. Make sure you type in the tag that your projectile has.
Now we’ll position the new bullet. Grab two “set x position of myself” blocks from Transform, and drag them under the previous block. Change one “x position” to “y position”, and drag both “myself” blocks into the trash can. Replace them with “instance bullet” local variables from Variables.
And lastly, set its x and y positions to the x and y positions of the player (“x postion of myself” from Transform).
Play the game and test out your bullets by hitting spacebar. Not very bullet-like are they?
Step 3: Giving the bullet a direction and velocity
We want the bullets to shoot off in the direction that the player is facing. Go back to editing the player script, and grab “Set rotation of myself” from Transform. Drag this block to the bottom of the “When the player presses key spacebar” event. Also grab “instance bullet” from Variables, and drag it into where myself is (and drag myself into the trash). Then grab “rotation of myself” from Transform and drag it into where the 0 is.
To tell the bullet what x velocity and y velocity it should have, we could send it messages, or we could use a global variable. The value of a global variable can be retrieved and changed from any script in your game. It will be easier to keep a global variable updated, so we’ll create a new global variable for the bullet’s direction. Since we want this global variable to keep updating, grab the “Constantly” block from Events, and then from the Global section of the Variables category, grab “set true/false i to” and drag it into the “Constantly” block.
Change “true/false” to “number”, and click on “i” and rename it to “bullet direction”. Then grab “rotation of myself” from Transform, and place it in the end of the global variable block.
Now whenever the player object changes it’s rotation, this global variable will update with that number, and any other object can retrieve that value. The rotations will be 0 degrees, 90 degrees, 180 degrees, or 270 degrees.
Lastly, close the player script, and edit the bullet script. We want the bullet to set its velocity based on our global variable bullet directon, so we’ll start with if-statements. Grab four “if” blocks from Control Flow, and drag them into the bottom of the “When created” block.
The if blocks should each check one of these conditions:
- Does bullet direction = 0?
- Does bullet direction = 90?
- Does bullet direction = 180?
- Does bullet direction = 270?
To check if a number equals another number, grab the “_=_” block from Operators.
0 degrees means the tank is facing up, so the bullet should move upwards. 90 degrees means the tank is facing right, so the bullet should move to the right. 180 degrees means the tank is facing down, so the bullet should move down. 270 degrees means the tank is facing left, so the bullet should move to the left.
Grab “set x velocity” blocks from Physics, and drag them into the if blocks to set the correct velocities. For example, to make the bullet shoot to the left if the bullet direction = 270, set x velocity to -1000.
Play your game to test your bullets. They should now shoot off in the correct direction. You can alter the velocities to make the bullet faster or slower (x velocity 1000 feels about right, but you can try 2000 or 500). Note: If you’re using a different game object for your player character, then your rotations may be different. Keep tweaking the velocities until it looks good.
Step 4: Better bullet positions
We need to adjust the position of the bullet for each direction so that the bullet shoots from the right location. When the player creates a new bullet, we’ll use if-statements just like we did before, and we’ll have to figure out how far away we want our bullet to shoot from. We’ll create an “x offset” property variable, and a “y offset” property variable, and change these for each direction. Then we’ll adjust the x and y position of the bullet by adding those offsets to its position.
Open the Player script, and drag four “if” blocks into the bottom of the “When player presses key spacebar” block. Then grab “_=_” blocks from Operators, and “number bullet direction” blocks from Variables.
Then create two new number property variables, bullet x offset and bullet y offset. Make sure you put the bullet x and y offset blocks in each “if” block.
Before we set the bullet x and y offsets, we need to make sure that those values will be added to the bullet’s original position. Grab two “set x position of myself” blocks, drag them underneath the “if” blocks, and change one “x position” to “y position”. Replace “myself” with “instance bullet”, then grab “_+_” from Operators, and put “x position of myself” in the left side of the addition block, and “number bullet x offset” in the right side. Do the same for the y position using y blocks.
Finally, grab number blocks (0) from Operators, and place them in the bullet x and y offset blocks. Try a bunch of different values for the offsets, and play your game to check if the offsets work well. Here are the offsets that work well with the tank:
Step 5: Shootable objects
You’ll need to add collision detection blocks to any object that you want to be able to be shot by the bullet. In this example I’ll use these metal barrels. They need to destroy themselves when they are touched by any object with the tag “bullet”. Remember that specific collision detection blocks need to do two things:
- Detect the collision: “When I am touched get toucher”
- Check the collider: “if instance toucher has tag”
Here’s an example script for a shootable barrel obstacle:
See if you can create a maze, or an obstacle course. Good luck!