02.creating-a-turret-that-shoots-rockets

Creating a turret that shoots rockets

In the first part of this series, we created a chest with an area that detects when a body enters or leaves it. The chest’s only reaction was to open and close.

In this lesson and the next, we will use the same technique to create a turret that shoots rockets!

The turret will shoot every second, using a Timer. It will also rotate to aim at the last mob that enters its range.

Note: a “mob” is a common shorthand for “mobile.” We use it to designate enemies or critters that move. In this project, the mobs are cars.

We need four scenes to make this work:

  1. The turret.
  2. The rocket. This is what the turret will shoot.
  3. The mob. It will have the same structure as the Gem from the previous lesson but look like a toy car.
  4. The scene that holds it all.

You will only create the turret. We prepared the rocket and the mob for you.

We will take look at them, though, to understand what they do and how they work.

Then, we’ll start creating the turret.

Studying the premade scenes

Let’s start by studying the structure and code of the scenes we provide you.

The Rocket

Open the file TowerDefense/common/Rocket.tscn.

The rocket has a structure similar to the chest you created before. It should start to be familiar now, with its Area2D, CollisionShape2D, and Sprite.

The rocket also has a Timer to make it explode if it flies for too long without hitting a target. This prevents the rocket from flying forever.

Finally, the rocket has a Particles2D that leaves a smoke trail on its path.

Notice how we aligned the rocket’s reactor with the scene’s origin point (where the green and red axes cross). This allows us to rotate the rocket around this point.

Let’s have a look at the script.

We check for bodies entering the rocket’s area. We also check for the Timer running out.

extends Area2D

onready var timer := $Timer

func _ready() -> void:
    connect("body_entered", self, "_on_body_entered")
    timer.connect("timeout", self, "explode")

Let’s look at the _on_body_entered() function:

export var damage := 10.0

func _on_body_entered(body: PhysicsBody2D) -> void:
    if body.has_method("take_damage"):
        body.take_damage(damage)
    explode()

The _on_body_entered() function calls the take_damage() function on a colliding body if the colliding body has that function. It also calls explode(), which destroys the rocket.

We move the rocket by updating its position in the _physics_process() function.

export var speed := 350.0

func _physics_process(delta: float) -> void:
    # The transform.x holds the direction in which the rocket is facing. We
    # multiply that direction by `speed` to calculate the rocket's velocity.
    position += transform.x * speed * delta

The transform property is of type Transform2D. It bundles position, rotation, and scale in one place.

In 2D games, we often use the position, rotation, and scale properties individually. Under the hood, game engines work with these transform types to boost performance and productivity.

Transforms rely on a mathematical concept called matrices. They are small grids of numbers.

Finally, the explode() function deletes the rocket and instantiates an explosion scene at the point of impact.

func explode() -> void:
    # We load the explosion scene and instantiate it.
    var explosion := preload("Explosion.tscn").instance()
    # Then, we place the explosion where the rocket is.
    explosion.global_position = global_position
    # We append the explosion to the main scene's children.
    get_tree().root.add_child(explosion)
    # And delete the rocket itself.
    queue_free()

The Car

Open the scene TowerDefense/common/DraggableCar.tscn, which is our mob.

The DraggableCar is similar to the gems we created in the previous project. It has the following nodes:

It has no unique script attached to it.

Creating the turret’s scene

Let’s now create our turret, to have a base to aim and shoot!

The turret will once again use an Area2D, CollisionShape2D, and a Sprite. However, there are a few additions:

Also, in this scene, the collision shape will control the turret’s range.

Create a new scene with an Area2D named Turret at its root. Add a CollisionShape2D, a Sprite, and a Timer as children.

Then, save the scene in the TowerDefense/ directory.

Find the image cannon.png and set it as a texture.

Add a Position2D as a child of the Sprite and align it with the cannon’s mouth.

We use the Position2D node to represent spawning points or to create pivot points.

Like Node2D, which it extends, it stores a position, rotation, and scale. On top of that, it draws a reticle in the viewport only.

To snap it to the horizontal axis, you can either press the left and right arrow keys to nudge the node or hold down the Shift key as you move it with the mouse.

Turn on the Timer’s Autostart property in the Inspector. You can also change the Wait Time for the turret to shoot more or less frequently.

Finally, select the CollisionShape2D node and assign a CircleShape2D to its Shape property.

The collision shape controls the turret’s targeting range. Mobs that enter the area will become potential targets.

Click and drag the shape’s resize handle and increase its radius to your liking. We made ours 256 pixels large.

The exact size doesn’t matter too much, though. It’s something you typically adjust when testing your complete game.

Final Scene

Let’s bring the turret and mobs together into a new scene to later test our turret.

Create a new scene and instantiate the turret and a few mobs (DraggableCar). The scene should look something like this:

Like before, save it in the TowerDefense/ directory.

We’re now ready to write the turret’s code. We’ll do that in the next lesson.