# Topdown Tank Battle: Part 10

###### Tags: godotgamedevtutorial

In this tutorial series, we’ll walk through the steps of building a 2D top-down tank game using Godot 3.0. The goal of the series is to introduce you to Godot’s workflow and show you various techniques that you can apply to your own projects.

This is Part 10: Homing missiles

You can watch a video version of this lesson here:

## Introduction

This time, we’re going to build on the existing bullet object to create a heat- seeking missile. We’ll also adjust the shooting code to allow for multiple shots in a spread.

We’re going to start by adding the homing functionality to the existing bullet script. First, we’ll adding some new variables:

``````export (float) var steer_force = 0

var acceleration = Vector2()
var target = null``````

`steer_force` represents the missile’s agility - how quickly it can turn and chase its target. A value of `0` will be a regular bullet that travels in a straight line.

When the missile spawns, we can pass it a target, but we want to be able to ignore that when spawning “dumb” bullets, so adjust the `start()` function like so:

``````func start(_position, _direction, _target=null):
position = _position
rotation = _direction.angle()
velocity = _direction * speed
target = _target``````

Next, in the `_process()` function, we need to apply a seeking behavior if there is a target assigned:

``````func _process(delta):
if target:
acceleration += seek()
velocity += acceleration * delta
velocity = velocity.clamped(speed)
rotation = velocity.angle()
position += velocity * delta``````

We’ll find our needed acceleration via the `seek()` function (more about that in a moment), and apply that to the current velocity. We also need to clamp the velocity so that when heading straight for the target, the missile doesn’t continue to accelerate above the maxiumum speed. Finally, we set the `rotation` so that the missile will point in the direction of motion.

### Seeking behavior

“Steering behaviors” is the collective name for a number of algorithms that produce movement such as seeking, following, flocking, etc. If you’re not familiar with the topic, I highly recommend reading The Nature of Code, which has a fantastic chapter on the subject, along with interactive demos.

For our missile, we will be using the “seek” behavior:

``````func seek():
var desired = (target.position - position).normalized() * speed
var steer = (desired - velocity).normalized() * steer_force
return steer``````

This works by first finding the `desired` movement vector, which is straight towards the target at maximum speed. However, to avoid “instant” turning, we then calculate the `steer` vector by finding the difference between the current velocity and the desired one. The “amount” we move our velocity (i.e. accelerate) is that difference scaled by the `steer_force`. The result: the bigger the `steer_force`, the faster the object turns to move towards its target.

## Missile scene

The missile scene is an inherited scene created from `Bullet.tscn`. I’ve chosen the following image from the spritesheet for the missile:

Set its `speed` to `400` and `steer_force` to `25` in the Inspector and save the scene. Drop it in to the `Bullet` property of one of the enemy tanks in your map scene.

### Launching missiles

If you ran it now, your missiles would still travel in a straight line, because they’re not getting the `target` value from the enemy. Update the shooting line in `EnemyTank.gd` to pass this data (the enemy already has the player set as its target):

``shoot(target)``

Now update the base `Tank.gd` script to pass this data along to the missile when it spawns:

``````func shoot(target=null):
if can_shoot:
can_shoot = false
\$GunTimer.start()
var dir = Vector2(1, 0).rotated(\$Turret.global_rotation)
emit_signal('shoot', Bullet, \$Turret/Muzzle.global_position, dir, target)
\$AnimationPlayer.play('muzzle_flash')``````

Finally, the `Map.gd` script, when it receives the signal, needs to pass the target to the missile:

``````func _on_Tank_shoot(bullet, _position, _direction, _target=null):
var b = bullet.instance()
b.start(_position, _direction, _target)``````

Try running the scene and testing that the missiles seek the player. Try changing the `steer_force` and `speed` (and the missile’s `lifetime`) properties to see how they affect the missile’s behavior.

## Missile trail

To make the missile look more appealing, we’re going to add a smoke trail. Add a `Particles2D` node to the missile scene. Particles nodes have a large number of properties, so I’ll list the adjustments in the table below:

Property Value
Amount `35`
Lifetime `0.4`
Visibility/Show Behind Parent `On`
RayCastUp `(0, -32)`

For the texture, I found the following smoke animation on Open Game Art:

Add this to the Texture property and set the HFrames to `24`.

Now add a new `ParticlesMaterial` in the Process Material property and set its values like so:

Property Value
Gravity `(0, 0, 0)`
Initial Velocity `0`
Animation/Speed `1`

Finally, in the Scale section, add a new Scale Curve and set its endpoints like the picture below:

This will make the smoke grow gradually larger as it dissipates.

The missiles should now have a pleasing smoke trail:

## Multi-shot

One more improvement we can make to shooting: multi-shot. This will allow us to have an enemy (or player) shoot multiple shots at once in a spread.

Start by adding two more new properties to `Tank.gd`:

``````export (int) var gun_shots = 1 # number of projectiles per shot
export (float, 0, 1.5) var gun_spread = 0.2 # angle between them``````

Once more, we need to update the `shoot()` function:

``````func shoot(num, spread, target=null):
if can_shoot:
can_shoot = false
\$GunTimer.start()
var dir = Vector2(1, 0).rotated(\$Turret.global_rotation)
if num > 1:
for i in range(num):
emit_signal('shoot', Bullet, \$Turret/Muzzle.global_position, dir.rotated(a), target)
else:
emit_signal('shoot', Bullet, \$Turret/Muzzle.global_position, dir, target)
\$AnimationPlayer.play('muzzle_flash')``````

If the number of shots is 1, we can just do as we already are doing. However, if the number is greater, we need a counting loop to generate each one and set its angle based on the `spread`. Calculating that angle (`a`) is complicated by the fact that `num` may be even or odd. If it’s odd, we want the center shot to go forward, and the others to its left and right. Howevef, if `num` is even, there is no center bullet, so we need an equal number to the left and right. The `a` formula will calculate that for us.

Now our player and enemy tanks need to pass these properties when they call shoot:

`EnemyTank.gd`:

``````if target_dir.dot(current_dir) > 0.9:

`Player.gd`:

``````if Input.is_action_just_pressed('click'):