Read the original article:Building Space Shooter with ArkTS-2
Introduction
Welcome back, everybody. In the first part, we have created the main user interface and implemented core functions for our game. Now we will add enemies and bullets. If you haven't seen part 1, check it out here.
Enemies
We will use the Ship class for enemies. Our game will have multiple enemies, thus we will store them in an array.
- Define the array:
// Game.ets
private enemies: Ship[] = []
- We will add enemies every 3 seconds, and decrease the gap as the user gains score.
// Game.ets
private lastEnemyTime = Date.now()
// iterate()
// place after clear canvas
const now = Date.now()
// add enemy
if (now - this.lastEnemyTime >= Math.max(1000, 3000 - this.score * 50)) {
this.lastEnemyTime = now
this.enemies.push(new Ship(
this.canvasWidth,
this.canvasHeight,
this.PIXELSIZE,
ShipType.ENEMY))
}
- And draw them;
// draw enemies (just before the user)
this.enemies.forEach((enemy): void => enemy.draw(this.canvasContext))
Now we have enemies, but you cannot see them yet. Because we create them just outside the top edge of the canvas, let's move them.
Since our ships are 7 PIXELSIZE long, we will move them 7 PIXELSIZE every second. Since we update our screen FRAMECOUNT times in a second, we will move the enemies PIXELSIZE / (FRAMECOUNT / 7) long in every iteration.
// Ship
private frameCount: number; // define parameter
constructor(..., frameCount: number) // update constructor
this.frameCount = frameCount
// ...
}
// define move
moveForward() {
this.leftTop.y += this.pixelSize / (this.frameCount / 7)
}
Do not forget to update user ship and enemy initializations in the Game class.
We also need a way to remove enemies from the list when they disappear from the screen.
// Ship
// define parameters
private canvasWidth: number;
private canvasHeight: number;
// modify constructor
constructor(...) {
this.canvasWidth = canvasW
this.canvasHeight = canvasH
...
}
// define function
inGame(): boolean {
return this.leftTop.y < this.canvasHeight
}
Go to iteration() and move enemies.
// move enemies (just after clearing the canvas)
this.enemies.forEach((enemy): void => enemy.moveForward())
Decrement the user's lives and remove enemies that pass the user.
// decrement lives
for (let i = 0; i < this.enemies.length; i++) {
if (!this.enemies[i].inGame()) {
this.lives--
if (this.lives === 0) {
this.end()
return
}
}
}
// remove enemies
this.enemies = this.enemies.filter((enemy) => enemy.inGame())
We will use the end() function to stop the interval, thus the game.
private end() {
clearInterval(this.intervalId)
this.intervalId = undefined
}
Let's run the app and face our enemies.
Bullet
So, the time has come. Create Bullet.ets and place under the model directory.
import Point from './Point';
export default class Bullet {
private pixelSize: number
point: Point;
hit: boolean = false
constructor(size: number, point: Point) {
this.pixelSize = size
this.point = point
}
inGame(): boolean {
return this.point.y > 0
}
move() {
this.point.y -= this.pixelSize / 2
}
draw(ctx: CanvasRenderingContext2D) {
ctx.fillStyle = '#FF0000'
ctx.fillRect(this.point.x, this.point.y, this.pixelSize, this.pixelSize)
}
clear(ctx: CanvasRenderingContext2D) {
ctx.clearRect(this.point.x, this.point.y, this.pixelSize, this.pixelSize)
}
}
Let's modify our ship to shoot.
// Ship.ets
fire(): Bullet {
return new Bullet(this.pixelSize,
{
x: this.leftTop.x + this.pixelSize * 2,
y: this.leftTop.y - this.pixelSize
})
}
Back to the Game.
private bullets: Bullet[] = []
private lastFireTime = Date.now()
Now the iterate(). We will add new bullets and move them.
- Move:
// this line already exists
this.enemies = this.enemies.filter((enemy) => enemy.inGame())
// add these
// move bullets
this.bullets.forEach((bullet): void => bullet.move())
this.bullets = this.bullets.filter((bullet) => bullet.inGame())
- Add new:
// add enemy
if (...) {...}
// fire
if (now - this.lastFireTime >= 1000) {
this.lastFireTime = now
this.bullets.push(this.userShip?.fire())
}
// draw bullets
this.bullets.forEach((bullet): void => bullet.draw(this.canvasContext))
The result should look like this.
You see that our bullets do not have any effect on the enemies. Let's change it.
- Modify the ship to make it destructible.
hit: boolean = false
checkHit(bullet: Bullet): boolean {
if (bullet.point.y <= this.leftTop.y + this.pixelSize * 3 &&
bullet.point.y >= this.leftTop.y + this.pixelSize * 2 &&
bullet.point.x >= this.leftTop.x - this.pixelSize / 2 &&
bullet.point.x <= this.leftTop.x + this.pixelSize * 4.5) {
this.hit = true
bullet.hit = true
return true
}
return false
}
- And clear it from existence.
clear(ctx: CanvasRenderingContext2D) {
ctx.clearRect(
this.leftTop.x, this.leftTop.y, this.pixelSize * 5, this.pixelSize * 6
)
}
- Now the
iterate().
// at the end of the function
for (let i = 0; i < this.enemies.length; i++) {
for (let j = 0; j < this.bullets.length; j++) {
if (this.enemies[i].checkHit(this.bullets[j])) {
this.enemies[i].clear(this.canvasContext)
this.bullets[j].clear(this.canvasContext)
this.score++
}
}
}
this.enemies = this.enemies.filter((enemy) => !enemy.hit)
this.bullets = this.bullets.filter((bullet) => !bullet.hit)
Now you can hit your enemies.
Conclusion
We have implemented enemies and bullets, but we cannot do much without moving, right? We will continue in the third part.
See you all in new adventures. :)
~ Fortuna Favet Fortibus




Top comments (0)