見出し画像

一人で学べるWebページで簡単なゲームを作る方法(Phaser)

Webページに簡単なゲームを作りたいと思いまして、少し調べたところPhaserというゲームのフレームワークを見つけました。

今回は、このPhaserを利用して○✖︎ゲームを作っていきます。

Phaserはダウンロードして利用することもできますが、jsdeliverにもアップロードされているので、scriptのリンクを貼るだけで利用することもできます。

今回は、簡単に利用できるようにダウンロードせずに使ってみましょう。

開発環境の準備

開発環境の準備…とは言っても、Pythonがインストールされているのであれば、特に準備は必要ありません。

Phaserはhtmlファイルが1つあれば動かすことができるので、作るだけなら他に何も入りません。ただ、ローカル環境で実行してテストすることができるように、ローカルサーバーを立ち上げて動かすようにします。

Pythonを使うと簡単にローカルサーバーを立ち上げられるのでテストが簡単にできます。

まずは、ゲームを実行するhtmlファイルとして、index.htmlを作成しておきます。

# index.html

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <script src="https://cdn.jsdelivr.net/npm/phaser@3.15.1/dist/phaser-arcade-physics.min.js"></script>
</head>
<body>
   ○×ゲーム
</body>
</html>

scriptタグにあるコードでPhaserをインポートしています。そして"○✖︎ゲーム"と表示するだけのページです。次の項目からこのファイルにPhaserのゲームを作成していきます。

これだけで準備は完了です。Pythonのローカルサーバーを利用して、このWebページを表示してみましょう。

以下のコマンドを入力すればローカルサーバーが立ち上がります。

python3 -m http.server 8000

http://localhost:8000にブラウザでアクセス

"○✖︎ゲーム"と画面に表示されていれば準備は完了です!

Phaserのゲーム作成準備

まずはゲームの画面環境から設定していきます。

Phaserのコードはhtmlファイルのbodyタグ内にscriptタグを配置して、そこにコードを書いていきます。最初に少しだけconfigの設定を行い、その設定でPhaserのゲーム画面の初期化を行います。


<body>
   ○×ゲーム
 <script>

   var TicTacToeScene = new Phaser.Class({

       Extends: Phaser.Scene,

       initialize:

       function TicTacToeScene (){},

       preload: function (){},

       create: function (){},

       update: function (){},
   });

   var config = {
       type: Phaser.AUTO,
       width: 600,
       height: 600,
       scene: [ TicTacToeScene ]
   };

   var game = new Phaser.Game(config);
   
</script>


</script>
</body>

TicTacToeSceneは今回作成する○✖︎ゲームの本体です。現時点では空なので何も処理は行われませんが、これから実装していきます。

configはゲームの基本的な設定を行なっています。

typeは、Phaser.AUTOを設定しておけば問題ありません。
widthとheightはそのままゲームの画面サイズになります。
最後にsceneはゲームで使うシーンを指定します。今回使うのはTicTacToeSceneだけです。

最後に、new Phaser.Game(config)でPhaserのゲームがconfigを利用して初期化されています。

この状態で、ページを更新して、黒い画面が表示されていればOKです。

スクリーンショット 2021-06-09 8.45.09

TicTacToeSceneの初期化設定

function TicTacToeScene ()では、このクラスの初期化を行います。

具体的には、このシーンで利用する変数を定義しておきます。

function TicTacToeScene ()
{

   Phaser.Scene.call(this, { key: 'TicTacToeScene' });
   this.board; 
   this.player;
   this.turn;
   this.gameover;

},

Phaser.Scene.call()は最初に呼んでおく必要があります。シーンに合わせてkeyは変更することが可能です。

ゲーム盤の状態はboardで管理します。○✖︎ゲームの左上から右下までの9つの場所の状態を配列で保存します。初期値は0で○が入っていたら1、✖︎が入っていたら-1を設定します。

playerはゲームを遊んでいる人が'○'か'✖︎'かを設定します。プレイヤーが'○'なら1、✖︎なら-1に設定します。

turnは、現在プレイヤーの手番かコンピューターの手番かを設定します。最初は'○'からゲームが始まるので、1を設定します。

gameoverは、ゲームが終了したかを確認する変数です。

TicTacToeSceneの前処理

Phaserでは、最初にpreloadという関数が呼び出されます。シーンを始める前の処理でなにかロードしておきたい画像があれば、ここにそれらの画像を読み込むように設定しておきます。

ここでは、○の画像、×の画像、そしてゲーム盤の画像を読み込んでおくことにします。

画像は1つのフォルダにまとめておくほうが整理されていて良いので、assetというフォルダを作成してそこに画像を入れておきます。そしてload.image関数を使って、それらの画像を読み込んでいきます。

function preload (){

   this.load.image('O', 'assets/O.png');
   this.load.image('X', 'assets/X.png');
   this.load.image('board', 'assets/board.png');

}

画像2

画像3

画像4

ここで、最初の引数の'O'は、この画像のキーとなります。後で利用するときに、このキーを指定すれば必要な画像を表示できるわけです。

シンプルなゲームなので使う画像も少なくて楽ちんです。

TicTacToeSceneの作成

create関数では、ゲームが最初に始めるときの処理を記載します。

○✖︎ゲームでは、変数を初期化して、ゲーム盤を表示し、ゲーム盤をクリックした時の処理を設定したりしています。

create: function ()
{
   this.board = [0,0,0,0,0,0,0,0,0];
   
   // '○'=1, 'X'=0
   var r = Math.random();
   if (r < 0.5){
       this.player = -1
   } else {
       this.player = 1
   }

   this.turn = 1;
   this.gameover = false;

   //ゲーム盤の表示
   this.add.image(0, 0, 'board').setOrigin(0,0);

   //手番の表示
   if (this.turn != this.player){
       this.turnText = this.add.text(16, 16, 'ComputerTurn', { fontSize: '16px', fill: '#000' });
   } else{
       this.turnText = this.add.text(16, 16, 'PlayerTurn', { fontSize: '16px', fill: '#000' });
   }

   //ゲームオーバー時のイベントの作成
   this.events.once('showGameoverText', this.show_gameover_text, this);

   //画面クリック時の処理
   this.input.on('pointerdown', function (pointer) {

       if (this.gameover == false){
           if (this.turn == this.player){
               var x = Math.floor(pointer.x / 200);
               var y = Math.floor(pointer.y / 200);

               if (this.board[y*3+x] == 0) {
                   this.add.image(x*200+100,y*200+100, 'O');
                   this.board[y*3+x] = this.player;
                   this.turn_end()
               }
           }
       } else {          
           this.gameend_text.setText("");
           this.scene.restart();   
       }
   }, this);
},

this.add.image(0, 0, 'board').setOrigin(0,0)
x=0, y=0の座標にkeyが'board'の画像を表示するようにしています。setOriginをx=0, y=0に設定しているのは、Phaserがデフォルトでは座標を、画像の中央の座標として設定してしまうからです。

this.add.text(16, 16, 'ComputerTurn', { fontSize: '16px', fill: '#000' });
x=16, y=16の座標に'ComputerTurn'という文字列を表示します。fontSizeはフォントの大きさ、fillはフォントの色を設定しています。

this.events.once('showGameoverText', this.show_gameover_text, this);
ゲームオーバーになったとき、イベントを発生させて、最終的な処理を行うようにします。具体的には、勝ち負けの文字列の表示です。このshow_gameover_textは後で実装します。

this.input.on('pointerdown', function (pointer)
マウスがクリックされたときに呼ばれる関数です。ゲームオーバーでないとき、該当する場所がまだ空欄であれば、自分の値をゲーム盤に設定し、ターンが終了します。
ゲームオーバーだった場合は、新しいゲームを始めるようにしています。

show_gameover_text関数の実装

この関数は、状態を確認して、勝ったか負けたか、引き分けたかを判断して、その文字列を表示しているだけです。

show_gameover_text:function (draw)
{
   if (this.gameover == true){
       var gameover_text = ""
       if (draw == false){
           if (this.turn == this.player){
               gameover_text = "You Won"
           } else{
               gameover_text = "You Lost"
           }
       } else{
           gameover_text = "Draw"
       }
       this.gameend_text = this.add.text(270, 40, gameover_text, { font: '16px Courier', fill: '#ff0000' });
   }
           
},

turn_end関数の実装

この関数は、手が進んだときの処理を実装しています。

まず最初に、ボードの状態を確認して、ゲームが終わったかどうかを判断しています。

次に、ゲームが終わっていなければ、相手の手番に切り替えます。考えるのが面倒だったので、判定は雑な実装です( ̄▽ ̄;)

turn_end: function () {

    // check game over
   if ((Math.abs(this.board[0]+this.board[1]+this.board[2])>=3) ||
       (Math.abs(this.board[3]+this.board[4]+this.board[5])>=3) ||
       (Math.abs(this.board[6]+this.board[7]+this.board[8])>=3) ||
       (Math.abs(this.board[0]+this.board[3]+this.board[6])>=3) ||
       (Math.abs(this.board[1]+this.board[4]+this.board[7])>=3) ||
       (Math.abs(this.board[2]+this.board[5]+this.board[8])>=3) ||
       (Math.abs(this.board[0]+this.board[4]+this.board[8])>=3) ||
       (Math.abs(this.board[2]+this.board[4]+this.board[6])>=3)){
           this.gameover = true;
           this.events.emit('showGameoverText',false);
       }
   
   //check draw
   if (!this.board.includes(0)){
       this.gameover = true;
       this.events.emit('showGameoverText',true);
   }

   //change turn
   this.turn = -this.turn;
   if (this.turn == this.player){
       this.turnText.setText("PlayerTurn");
   } else{
       this.turnText.setText("ComputerTurn");
   }
}

update関数の実装

update関数では、コンピューター側の処理を実装します。

ゲームが実行されている間、update関数は継続して実行されています。なので、相手の手番になったとき、ランダムに自分の手を選んで、ゲーム盤を更新し、ターンを切り替えるようにしています。

update: function ()
       {
           if (this.turn == -this.player && this.gameover == false){
               var a = Math.floor(Math.random()*9);
               while (this.board[a] != 0){
                   a = Math.floor(Math.random()*9);
               }
               this.board[a] = -this.player

               this.add.image((a%3)*200+100,Math.floor(a/3)*200+100, 'bomb');
               
               this.turn_end()
           }
       },

○✖︎ゲームの実行

これだけでOXゲームを作成することができました。

では、早速実行して、ちゃんと動くか確認してみましょう。

python3 -m http.server 8000

http://localhost:8000にブラウザでアクセス

○✖︎ゲームが遊べるようになりました。

スクリーンショット 2021-06-09 22.46.54

実際に動かしてみる+全コード

コードはreplit.comにアップロードしておきました。

アドレスにアクセスするだけで実行できるのでやっぱり便利ですね。(初回起動には時間がかかります)

実行:

コード

まとめ

便利なフレームワークを使えば、ゲームも簡単に作ることができます。次回はこのゲームを少し改良して、コンピューター側の手をランダム選択ではなくて、強いAIにしていきたいと思います。

Phaserは作成例が非常に多いので必要なコードを見つけやすくてすぐに作れました。作成例は以下リンク先を参照してください。


ここまで読んでいただけたなら、”スキ”ボタンを押していただけると励みになります!(*´ー`*)ワクワク


この記事が気に入ったらサポートをしてみませんか?