Invader クラス、Grid クラスを作ろう
Invader
とは?
Invader
とは敵のことです。
Grid
とは?
Grid
とはInvader
の集団のことです。
準備
- フォルダの中に
src
フォルダを作成し、その中にInvader.js
とGrid.js
ファイルを作成しましょう。
index.js
ファイルの一番上に、Grid
のimport
を追加しましょう。
- グローバル変数に
grids
を入れておく配列(Array)を作成しましょう。
- グローバル変数に
grids
にGrid
インスタンスを追加しましょう。
import { Grid } from "./src/Grid.js"
import { Player } from "./src/Player.js"
import { Projectile } from "./src/Projectile.js"
...
globalThis.player = new Player()
globalThis.projectiles = []
globalThis.grids = []
globalThis.grids.push(new Grid())
Invader.js
のポイント
constructor
の理解
constructor
はposition
だけを引数として受け取ります。
new Image()
で画像が設定されていることを確認。
- 画像の大きさを
scale
で調整しています。
update()
メソッドにProjectile
の位置を示す便利な値を設定
center
, top
, bottom
, left
, right
は後でProjectile
インスタンスに対してコードを書く時に便利になるから設定をしておきます。
export class Invader {
constructor({ position }) {
this.velocity = {
x: 0,
y: 0,
}
const image = new Image()
image.src = "./assets/invader.png"
image.onload = () => {
const scale = 0.65
this.image = image
this.width = image.width * scale
this.height = image.height * scale
this.position = {
x: position.x,
y: position.y,
}
}
}
draw() {
globalThis.ctx.drawImage(
this.image,
this.position.x,
this.position.y,
this.width,
this.height
)
}
update({ velocity }) {
if (!this.image) return
this.draw()
this.position.x += velocity.x
this.position.y += velocity.y
this.center = {
x: this.position.x + this.width / 2,
y: this.position.y + this.height / 2,
}
this.top = this.position.y
this.bottom = this.position.y + this.height
this.left = this.position.x
this.right = this.position.x + this.width
}
}
Grid.js
のポイント
constructor
の理解
constructor
は引数を受け取りません。
this.invaders
変数の中にInvader
クラスのインスタンスを格納します。
columns
とrows
はInvader
集団の列数、行数をランダムで設定するために使用します。
this.width
はInvader
集団、つまりGrid
全体の幅を計算しています。
draw()
の理解
draw()
はInvader
クラスが担当するためありません。
update()
メソッドにProjectile
の位置を示す便利な値を設定
update()
メソッドの中の以下の部分に注目する必要があります。
- 以下のコードは
Grid
が画面に右もしくは左に達した時に下に下がる、つまりy
の値をその時だけ更新するためのコードです。
- その後、横に進む方向を逆にします。
this.velocity.y = 0
if (this.right >= globalThis.canvas.width || this.position.x <= 0) {
this.velocity.x = -this.velocity.x * 1.15
this.velocity.y = 30
}
import { Invader } from "./Invader.js"
export class Grid {
constructor() {
this.position = {
x: 0,
y: 0,
}
this.velocity = {
x: 3,
y: 0,
}
this.invaders = []
const columns = Math.floor(Math.random() * 10 + 5)
const rows = Math.floor(Math.random() * 5 + 2)
this.width = columns * 40
for (let x = 0; x < columns; x++) {
for (let y = 0; y < rows; y++) {
this.invaders.push(new Invader({ position: { x: x * 40, y: y * 40 } }))
}
}
}
update() {
this.position.x += this.velocity.x
this.position.y += this.velocity.y
this.center = {
x: this.position.x + this.width / 2,
y: this.position.y + this.height / 2,
}
this.top = this.position.y
this.bottom = this.position.y + this.height
this.left = this.position.x
this.right = this.position.x + this.width
this.velocity.y = 0
if (this.right >= globalThis.canvas.width || this.position.x <= 0) {
this.velocity.x = -this.velocity.x * 1.15
this.velocity.y = 30
}
}
}
index.js
のポイント
animate()
関数の中にGrid
用のアニメーションコードを確認
- Gridを生成するアニメーション
for
ループはgrids
配列の後ろからループしています。
grids
配列の中のGrid
インスタンスを一つ受け取り、そのインスタンスの中にあるinvaders
配列の中をさらにfor
ループをしています。
Invader
インスタンスを一つ受け取り、それの.update()
メソッドを呼び出し、アニメーションを作成しています。
- Gridを生成するアニメーション
globalThis.randomInterval
(ミリ秒)間隔でGridが生成されます。
randomInterval
の数値にglobalThis.spawnBuffer
をたされます。
- 時間が進むと(
globalThis.frames
が進むと)globalThis.spawnBuffer -= 100
によってspawnBuffer
の数値が減っていきます。
- つまり、時間が経つと
randomInterval
の間隔は短くなり、Grid
が生成される間隔ば短くなります。難易度が上がっていきます。
function animate() {
...
for (let i = globalThis.grids.length - 1; i >= 0; i--) {
const grid = globalThis.grids[i]
grid.update()
for (let j = grid.invaders.length - 1; j >= 0; j--) {
const invader = grid.invaders[j]
if (!invader.position) continue
invader.update({ velocity: grid.velocity })
}
}
if (globalThis.frames % globalThis.randomInterval === 0) {
globalThis.spawnBuffer =
globalThis.spawnBuffer < 0 ? 0 : globalThis.spawnBuffer
globalThis.grids.push(new Grid())
globalThis.randomInterval = Math.floor(
Math.random() * 500 + globalThis.spawnBuffer
)
globalThis.frames = 0
globalThis.spawnBuffer -= 100
}
...
}
addEventListener("keydown", ...)
のスペースキーの挙動を確認
- スペースキーを押した時に新しい
Projectile
インスタンスを作成しましょう。(new Projectile(...)
)
globalThis.addEventListener("keydown", ({ key }) => {
switch (key) {
case "a": {
globalThis.keys.a.pressed = true
break
}
case "d": {
globalThis.keys.d.pressed = true
break
}
case " ": {
globalThis.keys.space.pressed = true
globalThis.projectiles.push(
new Projectile({
position: {
x: globalThis.player.center.x,
y: globalThis.player.top,
},
velocity: {
x: 0,
y: -10,
},
})
)
break
}
}
})
確認
- 画面上に
Invader
の集団、Grid
が飛ぶことを確認しましょう。