前回まででネット対戦型スネークゲームの大枠の部分を完成させましたが、今回はもうすこしフィールドを大きくして自機(自蛇?)を画面中央に表示させます。
フィールドの大きさを設定する
まずフィールドの大きさの設定ですが、SnakeGame_Playerクラスの静的変数で設定していました。この値を変えます。
app.js
1 2 3 4 5 6 7 |
class SnakeGame_Player { // 初期のフィールドの大きさ static MinPosX = -2000; static MinPosY = -2000; static MaxPosX = 2000; static MaxPosY = 2000; } |
クライアントに描画用のデータを送信するときにフィールドの大きさも伝えます。そのためのクラスをつくります。
app.js
1 2 3 4 5 6 7 8 |
class SnakeGame_Field { constructor(minPosX, minPosY, maxPosX, maxPosY){ this.MinPosX = minPosX; this.MinPosY = minPosY; this.MaxPosX = maxPosX; this.MaxPosY = maxPosY; } } |
1 2 3 4 5 6 7 8 9 |
class SnakeGame_Data{ constructor(){ this.Players = []; this.Foods = []; this.Field = new SnakeGame_Field( SnakeGame_Player.MinPosX, SnakeGame_Player.MinPosY, SnakeGame_Player.MaxPosX, SnakeGame_Player.MaxPosY); } } |
クライアント側の処理
クライアント側の処理ですが、クライアントは自分のIDがわからないと自機を中央に表示させることができません。そこでユーザーがページにアクセスしてIDが決定したらそれをクライアントに伝えます。
ClientToServerFirst関数が実行されたら取得されたIDをクライアントに送信します。
クライアントにIDを送信する
app.js
1 2 3 4 5 6 7 8 9 10 11 |
class SnakeGame { static ClientToServerFirst(snakeGame, socket, data){ let id = socket.id; let player = new SnakeGame_Player(0, 0); player.ID = id; SnakeGame.Players.push(player); // クライアントにIDを送信する snakeGame.to(id).emit('server_to_client_id', {value : id}); } } |
ここからはクライアントの処理です。接続したらserver_to_client_idイベントによってIDが送られてくるので、これを保存しておきます。
snake-game/snake-game.js
1 2 3 4 |
let id = ''; // ここにIDを保存する snake_game.on("server_to_client_id", function(data){ id = data.value; }); |
クライアントによる描画処理
画面の中央に自機を表示させるためには、描画するものを画面の幅と高さの半分だけ平行移動させて描画すればよいので、それを格納する変数としてtranslationXとtranslationYを用意します。
snake-game/snake-game.js
1 2 |
let translationX = 0; let translationY = 0; |
server_to_client_objectsイベントでデータを受信したら画面全体を深い緑色で塗りつぶし、どれだけ平行移動させて描画するかを求めたのちにフィールドの内側を黒で塗りつぶします。そのあと各プレイヤーと餌をtranslationXとtranslationY分だけずらして描画します。
snake-game/snake-game.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
snake_game.on("server_to_client_objects", function(data){ let dataFromServer = data.value; // canvas全体を塗りつぶす con.fillStyle = "#008000"; // 深い緑色 con.fillRect(0, 0, can.width, can.height); let player = dataFromServer.Players.find(player => player.ID == id); if(player != null){ translationX = can.width/2 - player.PosX; translationY = can.height/2 - player.PosY; } // フィールド内を塗りつぶす con.fillStyle = "#000000"; con.fillRect( dataFromServer.Field.MinPosX + translationX, dataFromServer.Field.MinPosY + translationY, dataFromServer.Field.MaxPosX - dataFromServer.Field.MinPosX, dataFromServer.Field.MaxPosY - dataFromServer.Field.MinPosY); // 各プレイヤーと餌を描画する dataFromServer.Players.forEach(snake => { DrawSnake(snake); }); dataFromServer.Foods.forEach(food => { DrawFood(food); }); // プレイヤーの座標と長さを表示する DrawPlayerStatus(player); }); |
DrawSnake関数を修正して各プレイヤーをtranslationXとtranslationY分だけずらして描画します。
snake-game/snake-game.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
function DrawSnake(snake){ let len = snake.TrajectoryX.length; for (let i = 0; i < len - 1; i++) { if (i % 4 == 0){ con.fillStyle = snake.ColorString1; con.strokeStyle = snake.ColorString1; } else if (i % 4 == 2){ con.fillStyle = snake.ColorString2; con.strokeStyle = snake.ColorString2; } else continue; con.beginPath(); con.arc( snake.TrajectoryX[i] + translationX, snake.TrajectoryY[i] + translationY, snake.Radius, 0, 2 * Math.PI, false); con.fill(); con.stroke(); } let last = len - 1; con.fillStyle = snake.ColorString1; con.strokeStyle = snake.ColorString1; con.beginPath(); con.arc( snake.TrajectoryX[last] + translationX, snake.TrajectoryY[last] + translationY, snake.Radius, 0, 2 * Math.PI, false); con.fill(); con.stroke(); } |
snake-game/snake-game.js
DrawFood関数を修正して餌をtranslationXとtranslationY分だけずらして描画します。
1 2 3 4 5 6 7 8 |
function DrawFood(food){ con.fillStyle = food.ColorString; con.strokeStyle = food.ColorString; con.beginPath(); con.arc(food.X + translationX, food.Y + translationY, food.Radius, 0, 2 * Math.PI, false); con.fill(); con.stroke(); } |
プレイヤーの座標と長さを表示する関数です。
snake-game/snake-game.js
1 2 3 4 5 6 7 |
function DrawPlayerStatus(player){ if(player != null){ con.fillStyle = "#ffffff"; con.font = 'bold 16px "MS ゴシック"'; con.fillText(`X = ${Math.round(player.PosX)} Y = ${Math.round(player.PosY)} Length = ${player.Length}`, 10, 40); } } |