この記事の目次
Lightning Web Components(LWC)でSnake Gameを構築する方法
Lightning Web Components(LWC)でSnake Gameを構築するための準備

SalesforceでSnake Game構築するための全体像の把握
Snake Gameはプレイヤーがキーボードの十字キーを利用して、ゲーム画面の枠内からはみ出ないようにヘビを操作してポイントを獲得していくゲームです。 Snake Gameのゲーム全体の流れを理解しておくと、現在の工程がゲームのどの部分なのか把握しやすくなるので、スムーズに作業を進められます。 今回Lightning Web Components(LWC)で構築するSnake Gameの完成形は、Salesforceの公式サイトで公開されていますので参考にしてみてください。Lightning Web Components(LWC)でSnake Gameの構築する手順

手順①ヘビが移動する領域を決める
はじめに、ヘビが移動する領域を決めます。ヘビが移動する領域は、ブロック数を計算し、ヘビが移動できる範囲をブロックサイズで除算します。 ブロックサイズで除算する方法としては、まず、HTMLのDOM要素と同じ意味のclientWidthメソッドとclientHeightメソッドを利用して高さと幅を設定します。const gameContainerEl = this.template.querySelector('.game-container');
const eWidth = gameContainerEl.clientWidth;
const eHeight = gameContainerEl.clientHeight;
for、eachの反復処理でブロックを作成
効率的にレンダリングするためには、for、eachの反復処理でブロックを作成します。gameBlocks = [];
gameRendered= false;
renderedCallback(){
if(!this.gameRendered){
const tmpBlocks = []; //forループが完了するまで一時配列を作成
for (let y = 0; y < this.yMax; y++) {
for (let x = 0; x < this.xMax; x++) {
obj = { id: `${x}:${y}`, snake: true, food: false, class: 'snake' };
}
tmpBlocks.push(obj);
}
this.gameRendered = true;
//作成した一時配列をメインの配列に割り当てる
this.gameBlocks = tmpBlocks;
}
}
コード内にあるrenderedCallback()とは、プロパティを変更したあとに、無限ループを作成するための関数です。
template要素には以下のように記述します。
< template for:each={gameBlocks} for:item=""block"" >
< div key={block.id} >
...
< /div >
< /template >
手順②ポイント(食べもの)を作成する
ポイント(食べもの)は、Snake Gameになくてはならない重要な要素です。ヘビは、このポイントを獲得することで長くなっていきます。 まず、ヘビがポイントを獲得したあとと、獲得する前とを区別するために、ポイント(食べもの)の要素に色をつける必要があります。色をつけるためには、CSSクラスを割り当てます。 ヘビの色、ポイント(食べもの)の色、何もないときの色とを区別するために真偽値を利用してsnakeはtrue、foodはfalseと設定しておきます。 ブロックのdiv要素へ色をつけるための、cssクラスを割り当るために以下のように記述しました。obj = { id: `${x}:${y}`, snake: true, food: false, class: 'snake' };
クラスにsnakeと割り当てている理由としては、if、trueタグを評価して要素を削除または追加するためです。
プロパティの追加
div要素に割り当てられたクラスの追加と削除をするプロパティを追加します。 このプロパティはポイント(食べもの)を獲得した後と、獲得する前とのif、trueの評価に応じて、割り当てるクラスを変更します。< template for:each={gameBlocks} for:item=""block"" >
< template if:true={block.snake} >
< div class={block.class} key={block.id} >< /div >
< /template >
< template if:true={block.food} >
< div class=""food"" key={block.id}>
< /template >
...
< /template >
Math.random()関数を適用させる
ポイント(食べもの)をゲームの範囲内へランダムに配置するために、div要素に対して、Math.random()関数を適用させます。const xFood = Math.floor(Math.random() * (this.xMax - 1));
const yFood = Math.floor(Math.random() * (this.yMax - 1));
const foodPosIndex = this.gameBlocks.findIndex(
(x) => x.id === `${xFood}:${yFood}`
);
this.gameBlocks[foodPosIndex].food = true;
this.gameBlocks[foodPosIndex].class = 'food';
手順③ヘビを操作するための記述
次にヘビを動かすための記述をしていきます。 ヘビの動き方を簡単に整理すると、ヘビは常に直進しながら、十字キーで左右どちらかに曲がります。ヘビは画面の上下左右いずれかに進んでいるため、ゲームの範囲はX値、Y値の座標で表すことが可能です。 たとえば、ヘビが画面の右方向に進んでいる場合はX値に+1を増加させます。xSpeed = 1;
ySpeed = 0;
xHead = 0;
yHead = 0;
move() {
this.xHead += this.xSpeed;
this.yHead += this.ySpeed;
ヘビの曲がる方向を変更する
ヘビは上下左右いずれかに進行を続けながら、キーボードの十字キーで曲がることができます。したがって十字キーの入力によって、xSpeed、ySpeedの値を増加または減少できるようにします。indow.addEventListener('keydown', (e) => {
e.preventDefault();
switch (e.key) {
case 'ArrowUp':
this.xSpeed = 0;
this.ySpeed = -1;
break;
case 'ArrowDown':
//(省略)
//キーボードの入力値ごとに入力します。
}
});
ゲームの開始時点にヘビの初期値を設定する
スタートボタンをクリックした場合など、スタートする地点を決めておくためには以下のように記述してください。setInterval(() => {
this.move();
}, 300);
手順④ヘビの長さを長くする
ここでは、ヘビの進行方向の先頭のブロックが「あたま」で、そのブロックに付随してついてくるブロックを「しっぽ」と定義します。 見た目上の違いは分かりにくいですが、プログラム上では「あたま」と「しっぽ」の記述が異なりますので注意が必要です。 ポイント(食べもの)を獲得したヘビのしっぽを長くするための記述について説明します。しっぽが増える度にブロックIDを追加する
move(){
// 「しっぽ」を移動させる記述
// ヘビがポイント(食べもの)を獲得していない場合は、最初の要素を削除する
const lastElement = this.tail[this.tail.length - 1];
if (lastElement !== `${this.xHead}:${this.yHead}`) {
this.tail.push(`${this.xHead}:${this.yHead}`);
const removedElement = this.tail.shift();
const curPosIndex = this.gameBlocks.findIndex(
(x) => x.id === removedElement
);
this.gameBlocks[curPosIndex].snake = false;
}
・・・
}
あたまと、しっぽを一緒に移動するための記述をする
あたまと、しっぽを一緒に移動させるためには、現在の「あたま(先頭のブロック)」を、「しっぽ(最後のブロック)」に追加するような記述にします。
move(){
・・・
// ヘビがポイント(食べもの)を獲得した場合は、現在の「あたま」を「しっぽ」に追加する。
// ヘビが「前段階でポイント(食べもの)を獲得していたか」を判断できるようにします。
if (this.gameBlocks[newPosIndex].food) {
this.score++;
this.tail.push(`${this.xHead}:${this.yHead}`);
・・・
}
作成したゲームをプラットフォームへ展開する方法

Git Hubでの操作
Git Hubで同期する方法としては、docsフォルダーを利用して構築したデータを同期させます。 buildDir(lwc-services.config.jsonが利用されている)を設定することで、docsフォルダーに同期していきます。module.exports = {
buildDir: './docs',
resources: [{ from: 'src/resources/', to: 'docs/resources/' }]
};
次にターミナルを開き、「npm run build」とコマンド入力してください。
Git Hubにプッシュが完了したら、メニューの「設定」から、Git Hubページの有効を指定してください。
Herokuでの操作
Herokuで同期をするには、ルートディレクトリに以下の名前でファイルを作成してください。web: npm run serve
次に以下のような記述をしてscripts/server.jsを更新します。
...
const DIST_DIR = './docs';
...
Herokuでアプリを作成します。Deployment methodはGit Hubに選択したあと、「Deployment」ボタンを押下して有効にしてください。
Snake Gameを構築する方法を確認しよう

この記事の監修者・著者

-
未経験からITエンジニアへのキャリアチェンジを支援するサイト「キャリアチェンジアカデミー」を運営。これまで4500人以上のITエンジニアを未経験から育成・排出してきました。
・AWS、salesforce、LPICの合計認定資格取得件数:2100以上(2023年6月時点)
・AWS Japan Certification Award 2020 ライジングスター of the Year 受賞