Building a space shooter game with HTML5 canvas & Typescript — Part 3

André Teixeira
ITNEXT
Published in
4 min readDec 14, 2020

--

This article is the third part of a series composed by:

Part 1 — Draw stars
Part 2 — Draw a spaceship and make it rotate 🚀
Part 3 — Make the spaceship move and shoot 💨
Part 4 — Make a joystick for mobile 🕹️ 📱
Part 5 — Enemy ships and collision 💥

After implementing the steps described in part 1 and part 2 of this series, we have a starry sky and a spaceship able to rotate around/over its center. IMHO this game needs more action. Therefore, part 3 will be about making it flying around and shooting.

Acceleration and movement

This ship has a rear-engine; consequently, propulsion makes it move in the direction of its nose.

Given that the game loop invokes the draw method about 60 times per second, we can think about calculating a normal vector and moving the ship 1 step towards it in every cycle.

The following illustration shows a snapshot of one of the draw method invocations. Let's take a deeper look at how the calculations would happen on this individual execution:

TL/DR

At this point, the spaceship update function already knows positions x, y, and the rotation of the spaceship on every execution. It can be represented in the chart as:

We can now define a constant that will represent the length of the spaceship movement on each iteration. This constant, represented above as the blue vector, is the hypothenuse of the example's triangle (I will pick for this study the random value 18.0277).

Knowing that we can use the Pythagoras theorem to get the x and y values for p2. Being:

sin = opposite leg / hypothenuse;
sen = adjacent leg / hypothenuse;

We can affirm that:

x = sin(33) * hypothenuse;
y = cos(33) * hypothenuse;

Or, a generic approach using JavaScript:

const x = Math.sin(this.rotation) * this.speed;
const y = Math.cos(this.rotation) * this.speed;

Making it fly

Following are the attributes needed to make it work:

  • Speed — representing the length of the spaceship displacement over the plane;
  • Acceleration — being the resultant Vector;
  • Deceleration — representing the friction that decreases spaceship movement after the throttle is released.

The variables

The keyboard listener

The movement

And finally, in the spaceship update method, we apply the change value by adding the new accelerated position to the current spaceship position. We can do it by adding the following block to the spaceship update method:

The add and subtract operations, which will add the acceleration vectors to the current position ones, are also needed on the Vector class, in the format:

public add(vector: Vector): void {
this.x += vector.x;
this.y += vector.y;
}
public subtract(vector: Vector): void {
this.x -= vector.x;
this.y -= vector.y;
}

Important details

Since the canvas plane origin (0,0) is located on the top left, we need to invert the Y-axis calculation direction by multiplying it by -1.

Partial demo

You can see a working demo until this point at:
http://spaceship-part3-partial.s3-website.eu-central-1.amazonaws.com/

Shooting

The theory behind firing is not very different. Once the user hits the trigger (space bar), a projectile will be drawn on the top/center of the ship and follow the normal vector projection for the given draw function execution.

The idea of shooting is the same as moving, with the difference that when a bullet instance is created, it gets the spaceship angle for the given moment. In contrast, the spaceship moving method gets the latest direction for every drawing.

And as a final step, it is needed to draw and update the game class bullets. We need a list of bullets that will be rendered on their updated location on every game draw (sounds like what we did with the stars on part1, right?).

The code until this stage is tagged at:

https://github.com/ateixeira/spaceship-game/releases/tag/part3_final

The demo until this part:

http://spaceship-part3-final.s3-website-eu-west-1.amazonaws.com/

--

--