こんにちは、Yuiです。
今回はプレイヤーの行動リストを表示してみたいと思います。
今回の完成物はこちらです。
行動リストを表示する
それでは前回作ったgame.js
に「たたかう」「ぼうぎょ」「まほう」「どうぐ」の4つのコマンドを追加していきます。
まずはその4つのコマンドを配列で格納します。
GameManager
クラスの中に、コマンドを表示する部分としてshowCommand
として新しいメソッドを追加します。
showCommand() {
this.actions = [
{ name: "たたかう" },
{ name: "ぼうぎょ" },
{ name: "まほう" },
{ name: "どうぐ" },
]
this.actions.forEach((action, index) => {
this.ctx.fillText(action.name, 50, index * 30 + 350)
})
}
現時点で「たたかう」「ぼうぎょ」「まほう」「どうぐ」の4つのコマンドが画面に表示されたかと思います。それでは次に▷をそのコマンドの隣に表示するようにしましょう。
this.ctx.fillText("▷", 20, 350)
このコードを上記のshowCommand
の中に入れれば▷が「たたかう」の隣に現れたかと思います。
ただ、現時点では▷は動かしても動きませんね。
これは▷のy座標が350で固定されてしまっているからです。
そこで、y座標を矢印キーの動きに合わせて動かしていきたいと思います。
▷を動かす
さて、▷を動かすためには上述の通り現時点のy座標を流動的にする必要があります。
というわけでy座標にあたるものをthis.setAction
として、初期値を350で設定します。
初期値なので、GameManager
内のconstructor()
で設定します。
class GameManager {
constructor() {
const canvas = document.getElementById("canvas")
this.ctx = canvas.getContext("2d")
this.setAction = 350; //<=追加
this.characterList = [];
}
...
そしてchooseCommand
というメソッドを新しく作り、その中でthis.setAction
の値を変更していきたいと思います。
chooseCommand(e) {
if (e.key === "ArrowDown" && this.setAction < 440) {
this.setAction += 30;
this.ctx.clearRect(20,300, 25, 480)
this.ctx.fillText("▷", 20, this.setAction)
}
if (e.key === "ArrowUp" && this.setAction > 350) {
this.setAction -= 30;
this.ctx.clearRect(20,300, 25, 480)
this.ctx.fillText("▷", 20, this.setAction)
}
}
このへんのロジックは前回やったスライムを動かすものと同じです。
this.setActionの値で制限をつけているのは、必要以上に▷が上がりすぎたり下がりすぎたりしないためです。
clearReactで消す部分に関しては、▷が表示されている部分だけで良いので、細かく範囲を調整しています。
あとは、この部分をaddEventListener
で制御すれば動きます。以下のコードをgameManager
外の部分に書きます。
window.addEventListener("keydown", (e) => {
gameManager.chooseCommand(e);
})
そしてそれに合わせてもちろん初期値で設定していたthis.ctx.fillText("▷", 20, 350)
をthis.ctx.fillText("▷", 20, this.setAction)
に変更します。
これでgame.jsの中身は以下のようになりました。
class GameManager {
constructor() {
const canvas = document.getElementById("canvas")
this.ctx = canvas.getContext("2d")
this.setAction = 350;
this.characterList = [];
}
addCharacter(character) {
this.characterList.push(character);
}
showCharacterStatus() {
this.ctx.clearRect(0,0,640,480)
this.ctx.font = `28px serif`;
this.ctx.fillStyle = "black"
this.ctx.fillText("HP", 20, 50)
this.ctx.fillText("MP", 20, 90)
this.ctx.fillText("名前", 20, 130)
this.characterList.forEach((chara, index) => {
this.ctx.fillText(chara.hp, 190 * index + 140, 50)
this.ctx.fillText(chara.mp, 190 * index + 140, 90)
this.ctx.fillText(chara.name, 190 * index + 140, 130)
})
}
showCommand() {
this.actions = [
{ name: "たたかう" },
{ name: "ぼうぎょ" },
{ name: "まほう" },
{ name: "どうぐ" },
]
this.actions.forEach((action, index) => {
this.ctx.fillText(action.name, 50, index * 30 + 350)
})
this.ctx.fillText("▷", 20, this.setAction)
}
chooseCommand(e) {
if (e.key === "ArrowDown" && this.setAction < 440) {
this.setAction += 30;
this.ctx.clearRect(20,300, 25, 480)
this.ctx.fillText("▷", 20, this.setAction)
}
if (e.key === "ArrowUp" && this.setAction > 350) {
this.setAction -= 30;
this.ctx.clearRect(20,300, 25, 480)
this.ctx.fillText("▷", 20, this.setAction)
}
}
}
//以下のモンスター表示部分もGameManager内にメソッド追加でできますが、現状は前回のままにしておきます。
class Monster {
constructor(posX, posY, image) {
const canvas = document.getElementById("canvas")
this.ctx = canvas.getContext("2d")
const img = new Image()
img.src = image
this.img = img
this.posX = posX
this.posY = posY
this.sizeX = 100
this.sizeY = 100
img.onload = () => this.drawImage()
}
drawImage() {
this.ctx.drawImage(this.img, this.posX, this.posY, this.sizeX, this.sizeY)
}
}
new Monster(100, 200, "./img/bone.png");
new Monster(260, 200, "./img/pumpkin.png");
new Monster(420, 200, "./img/ghost.png");
class PlayerCharacter {
constructor(name, hp, mp) {
this.name = name;
this.hp = hp;
this.mp = mp;
}
}
var chara1 = new PlayerCharacter("アベル", 100, 80);
var chara2 = new PlayerCharacter("カイン", 100, 55);
var chara3 = new PlayerCharacter("プリン", 100, 45);
var gameManager = new GameManager();
gameManager.addCharacter(chara1);
gameManager.addCharacter(chara2);
gameManager.addCharacter(chara3);
gameManager.showCharacterStatus();
gameManager.showCommand();
window.addEventListener("keydown", (e) => {
gameManager.chooseCommand(e);
})
これで無事▷が動くようになったかと思います。
ただ、このままではクリックをしても何も起こりません。
そこで次回はクリック時のアクションを追加していきます。
おまけ
こちらのコードに関しては簡略的に書いているため、かなり雑な作りとなっています。
もう少しちゃんと書くのであれば、親となるクラスと子となるクラスを細かく分けて、jsファイルも分けてしまってからextendsで継承させて書いていくような書き方のほうが見やすいかと思います。
また、上述のコメントアウトでも書きましたが、モンスター表示部分(Monsterクラス)に関してはGameManager内にメソッドとして入れるなり、そもそもファイルを分けて親クラスGameManagerを継承するなり、色々書き方はありますが、現状ではこのままとしておきます。
ぜひ時間のある際にでも色々と書き換えてみて、試してみてください。