ASP.NET coreで対戦型『殺しの七並べ』をつくる(3)の続きです。今回はクライアントサイドの処理を定義します。
Contents
cshtml部分
cshtml部分を示します。PC用とスマホ用を同じページで作ろうとしたのですが、それだとカードが小さくなりすぎるので、PC用はカードが大きめに表示されるようにしました。
Pages\kill-seven\pc.cshtml
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
@page @{ Layout = null; } <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>鳩でもわかる殺しの7並べ(PC用)</title> <meta name="viewport" content="width=device-width, initial-scale = 1.0"> <link rel="stylesheet" href="./style.css" type="text/css" media="all"> <style> <!-- スマホ用のページはこの部分をはずす --> #container { width: 800px; } </style> </head> <body> <div id="container"> @Html.Raw(adText) <div id = "field"> <canvas id="canvas"></canvas><!-- ここに出されたカードを描画する --> <div id="game-result"></div><!-- ゲーム終了時に順位を表示する --> </div> <p id="result"></p><!-- 現在の状態を表示する --> <button id="entry">参加する(割り込み参加できます)</button> <p id="player-name-outer"><label for="player-name">プレーヤー名:</label><input type="text" id="player-name" maxlength="24"></p> <div id="cards"></div><!-- プレイヤーが持っているカードを表示する --> <div id="players-info"></div><!-- 各プレイヤーの状態(残り枚数と殺されたカードの枚数)を表示する --> <p> 効果音: <input type="range" id="volume-range" min="0" max="1" step="0.01"> <span id="volume-value"></span> <button id="volume-test">効果音のテスト</button> </p> <p>ゲームの説明</p> <p> 普通の7並べとちがって縦や斜めにつながっているカードでも出すことができます。 単数または複数のカードを四角く囲まれるとそのカードは殺されてしまうので気をつけてください。 ゲームが終了したときに殺されたカードが少ないほうが上位、 枚数が同じ場合は先に上がったプレイヤーが上位です。 ジョーカーは使いません。またトンネルルールはありません。 </p> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script> <script> const connection = new signalR.HubConnectionBuilder().withUrl("/kill-seven-hub").build(); </script> <script> const CANVAS_WIDTH = 730; const CANVAS_HEIGHT = 330; const PC = true; // スマホ用のページは値を変える CANVAS_WIDTH = 360; CANVAS_HEIGHT = 200; PC = false; </script> <script src="./app.js"></script> </body> </html> |
wwwroot\kill-seven\style.css
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 35 36 37 38 39 40 41 42 43 44 45 46 |
body { background-color: #000; color: #fff; } #container { width: 360px; } #field { position: relative; } #canvas { display: block; } .card-button { border-color: white; background-color: transparent; width: 50px; height: 75px; } #game-result { position: absolute; left: 0px; top: 30px; background-color: rgba(0, 0, 0, 0.5); width: 360px; display: none; } #entry { width: 250px; height: 60px; margin-top: 20px; } #cards { margin-top: 20px; } #volume-range { vertical-align: middle; } |
グローバル変数と定数
つぎにJavaScript部分を示します。最初にグローバル変数と定数を示します。
wwwroot\kill-seven\app.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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
// カードのサイズ const CARD_WIDTH = 50; const CARD_HEIGHT = CARD_WIDTH * 1.5; // プレイヤーの名前の表示色 const colors = ['#f0f', '#0f0', '#0ff', '#ff0', '#f50', ]; // canvasとコンテキスト const $canvas = document.getElementById('canvas'); const ctx = $canvas.getContext('2d'); // 要素 const $entry = document.getElementById('entry'); const $playerName = document.getElementById('player-name'); const $result = document.getElementById('result'); const $playersInfo = document.getElementById('players-info'); const $gameResult = document.getElementById('game-result'); const $playerNameOuter = document.getElementById('player-name-outer'); // 効果音 const startSound = new Audio('./sounds/start.mp3'); const putSound = new Audio('./sounds/put.mp3'); const ngSound = new Audio('./sounds/ng.mp3'); const otherPutSound = new Audio('./sounds/other-put.mp3'); const passSound = new Audio('./sounds/pass.wav'); const deadSound = new Audio('./sounds/dead.mp3'); const othersDeadSound = new Audio('./sounds/others-dead.mp3'); const timeupSound = new Audio('./sounds/timeup.mp3'); const oneSound = new Audio('./sounds/1.mp3'); const twoSound = new Audio('./sounds/2.mp3'); const threeSound = new Audio('./sounds/3.mp3'); const fourSound = new Audio('./sounds/4.mp3'); const fiveSound = new Audio('./sounds/5.mp3'); const sixSound = new Audio('./sounds/6.mp3'); const sevenSound = new Audio('./sounds/7.mp3'); const eightSound = new Audio('./sounds/8.mp3'); const nineSound = new Audio('./sounds/9.mp3'); const tenSound = new Audio('./sounds/10.mp3'); const ranking1Sound = new Audio('./sounds/ranking1.mp3'); const ranking2Sound = new Audio('./sounds/ranking2.mp3'); const ranking3Sound = new Audio('./sounds/ranking3.mp3'); const ranking4Sound = new Audio('./sounds/ranking4.mp3'); const ranking5Sound = new Audio('./sounds/ranking5.mp3'); // ボリューム調整用のレンジスライダーなど const $volumeRange = document.getElementById('volume-range'); const $volumeValue = document.getElementById('volume-value'); const $volumeTest = document.getElementById('volume-test'); let connectionID = ''; // ASP.NET SignalRでサーバーと接続時に発行される一意の値 let playerNumber = -1; // ゲームに参加しているときに付与されるNumber let volume = 0.5; // 効果音のボリューム let cardImages = [[], [], [], []]; // カードのイメージを格納する配列 let cardButtons = []; // 手持ちのカードはボタンとして表示される |
ページが読み込まれたときの処理
ページが読み込まれたときの処理を示します。canvasのサイズを調整して背景を緑で塗りつぶします。そのあと各カードのイメージを配列に格納し、レンジスライダーでボリュームの調整ができるようにします。ASP.NET SignalR ハブへ接続を試みます。
1 2 3 4 5 6 7 8 9 10 11 12 |
window.addEventListener('load', async() => { $canvas.width = CANVAS_WIDTH; $canvas.height = CANVAS_HEIGHT; ctx.fillStyle = '#080'; ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); cardImages = await getCardImages(); initVolume(); connection.start(); // ハブに接続を試みる }); |
カードの絵柄は素材サイトからダウンロードした1枚の画像ファイルにすべてのカードのデザインが描かれているものを使います。ここから必要な部分をきりとってイメージを配列cardImagesのなかに格納します。
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 |
async function getCardImages(){ const cardImages = [[], [], [], []]; const fileImage = await new Promise(resolve => { const image = new Image(); image.src = "./images/cardimage.png"; image.onload = () => { resolve(image); } }); for(let suit = 0; suit < 4; suit++){ for(let number = 1; number <= 13; number++){ // どの部分を切り取るかは素材によって適切に変える const canvas = document.createElement('canvas'); canvas.width = CARD_WIDTH; canvas.height = CARD_HEIGHT; const ctx2 = canvas.getContext('2d'); ctx2.drawImage(fileImage, 380 * (number - 1) + number, suit * 600, 355, 500, 0, 0, CARD_WIDTH, CARD_HEIGHT); const dataUrl = canvas.toDataURL(); const cardsImage = await new Promise(resolve => { const image = new Image(); image.src = dataUrl; image.onload = () => { resolve(image); } }); cardImages[suit][number] = cardsImage; } } return cardImages; } |
レンジスライダーでボリュームの調整ができるようにするための処理を示します。
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 35 36 37 38 39 40 |
function initVolume(){ $volumeRange?.addEventListener('input', () => { volume = Number($volumeRange.value); $volumeValue.innerHTML = volume; setVolume(); }); $volumeRange.value = volume; $volumeValue.innerHTML = volume; setVolume(); function setVolume(){ startSound.volume = volume; putSound.volume = volume; ngSound.volume = volume; otherPutSound.volume = volume; deadSound.volume = volume; othersDeadSound.volume = volume; timeupSound.volume = volume; oneSound.volume = volume; twoSound.volume = volume; threeSound.volume = volume; fourSound.volume = volume; fiveSound.volume = volume; sixSound.volume = volume; sevenSound.volume = volume; eightSound.volume = volume; nineSound.volume = volume; tenSound.volume = volume; ranking1Sound.volume = volume; ranking2Sound.volume = volume; ranking3Sound.volume = volume; ranking4Sound.volume = volume; ranking5Sound.volume = volume; passSound.volume = volume; } $volumeTest?.addEventListener('click', () => { startSound.play(); }); } |
ASP.NET SignalRで接続したときの処理
ASP.NET SignalRでサーバーと接続できたときにおこなわれる処理を示します。この場合はASP.NET SignalRでサーバーと接続時に発行される一意の値をグローバル変数に格納します。
1 2 3 4 |
connection.on('SucceedConnectionToClient', (id) => { connectionID = id; $result.innerHTML = '接続完了'; }); |
もし途中で通信が切れてしまったら切れてしまった旨を表示します。
1 2 3 4 |
connection.onclose(async () => { connectionID = ''; $result.innerHTML = 'エラー:通信が切断されました'; }); |
エントリー時の処理
ユーザーがエントリーをしようとした時の処理を示します。
プレイヤー名を入力しないでエントリーボタンを押下したときはプレイヤー名を設定するようにアラートを表示させます。それ以外の時はエントリーの処理をおこないます。
1 2 3 4 5 6 7 8 9 10 |
$entry?.addEventListener('click', () => { if (connectionID != '') { let playerName = $playerName.value; if(playerName == ''){ alert('プレイヤー名を設定してください'); return; } connection.invoke("Entry", playerName); } }); |
エントリーの処理が正常におこなわれたときはサーバーサイドから’SucceedEntryToClient’が送信されるので、この場合はエントリーの処理が完了した旨を表示します。そして割り当てられたプレイヤーとしてのNumberをグローバル変数に格納し、エントリーボタンやプレイヤー名設定用のテキストボックスなどを非表示にします。
1 2 3 4 5 6 7 8 9 10 11 |
connection.on('SucceedEntryToClient', (playerNum) => { $entry.style.display = 'none'; $result.innerHTML = 'エントリー完了'; playerNumber = playerNum; $gameResult.style.display = 'none'; putSound.play(); const $playerNameOuter = document.getElementById('player-name-outer'); $playerNameOuter.style.display = 'none'; }); |
エントリーの処理が正常におこなわれなかったときはサーバーサイドから’FailuredEntryToClient’が送信されます。この場合はエントリーの処理がおこなわれなかった旨を表示します。
1 2 3 4 |
connection.on('FailuredEntryToClient', () => { $result.innerHTML = 'エントリーに失敗しました'; playerNumber = -1; }); |
ゲーム開始時の処理
ゲームが開始されたときは’GameStartedToClient’が送信されるので、この場合はゲーム開始の効果音を再生します。
1 2 3 |
connection.on('GameStartedToClient', () => { startSound.play(); }); |
ゲーム中の処理
ゲーム開始までのカウントダウンやプレイヤーが手番のときのカウントダウン、プレイヤーがもつカードの状態が変化した場合はサーバーサイドから’CardsToClient’が送信されます。この場合は送られてきたjsonから適切な表示と描画をおこないます。
1 2 3 4 5 6 7 8 |
connection.on('CardsToClient', (json1, json2, isPlayerTurn) => { const obj = JSON.parse(json1); showNavi(obj); // ナビゲーションの表示(後述) drawCardOnTable(obj); // 卓上に出されたカードの描画(後述) showPlayersInfo(obj); // プレイヤーの状態の表示(後述) showPlayerCards(json2, isPlayerTurn); // ユーザーがプレイヤーのときは所持するカードの表示(後述) }); |
ナビゲーション表示
ゲーム開始前とゲーム時にナビゲーションを表示する処理を示します。
ゲーム開始前は開始までの時間の表示と秒読みの音声の再生、ゲーム中はユーザーの手番のときは残り時間の表示と秒読み音声の再生をおこないます。他のプレイヤーの手番のときは誰の手番なのかを表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
function showNavi(obj){ const secondsToStart = obj.SecondsToStart; if(secondsToStart > 0){ // ゲーム開始前 $result.innerHTML = '開始まで あと ' + secondsToStart + ' 秒です'; const sounds = [oneSound, twoSound, threeSound, fourSound, fiveSound]; if(secondsToStart >= 1 && secondsToStart <= 5) sounds[secondsToStart - 1].play(); } else { // ゲーム中 if(playerNumber == obj.CurPlayerNumber){ const time = obj.Players[playerNumber].SecondsToHand; $result.innerHTML = 'あなたの手番です。残り ' + time + ' 秒'; const sounds = [oneSound, twoSound, threeSound, fourSound, fiveSound, sixSound, sevenSound, eightSound, nineSound, tenSound]; if(time >= 1 && time <= 10) sounds[time - 1].play(); } else{ let name = obj.Players[obj.CurPlayerNumber].Name.split('<').join('<'); name = name.split('>').join('>'); $result.innerHTML = `他のプレイヤー(${name})の手番です`; } } } |
卓上のカードを描画する処理
卓上に出されたカードを描画する処理を示します。殺されたカードにはそのうえに×も描画します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
function drawCardOnTable(obj){ ctx.fillStyle = '#080'; ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); // 卓上に置かれたカード for(let cardsIndex = 0; cardsIndex < obj.Cards.length; cardsIndex++){ const card = obj.Cards[cardsIndex]; // どのカードを描画するのか? const position = getCardPositionOnTable(card.Suit, card.Number); // どこに描画するのか? const image = cardImages[card.Suit][card.Number]; // どのイメージを描画するのか? ctx.drawImage(image, position.x, position.y, position.w, position.h); } // 殺されたカード for(let cardsIndex = 0; cardsIndex < obj.DeadCards.length; cardsIndex++){ const card = obj.DeadCards[cardsIndex]; // どのカードを描画するのか? const position = getCardPositionOnTable(card.Suit, card.Number); // どこに描画するのか? const image = cardImages[card.Suit][card.Number]; // どのイメージを描画するのか? ctx.drawImage(image, position.x, position.y, position.w, position.h); drawX(card); // ×を描画する } } |
カードのスートと番号からそのカードをどの座標に描画するのかを取得する処理を示します。PC用のページとスマホ用のページでは座標が異なるので処理を分けています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function getCardPositionOnTable(suit, number){ if(PC){ return { x: (CARD_WIDTH + 5) * (number-1) + 10, y: (CARD_HEIGHT + 5) * suit + 10, w: CARD_WIDTH, h: CARD_HEIGHT, } } else { return { x: (CARD_WIDTH * 0.42 + 5) * (number-1) + 10, y: (CARD_HEIGHT * 0.42 + 5) * suit + 10, w: CARD_WIDTH * 0.42, h: CARD_HEIGHT * 0.42, } } } |
カードの上に×印を描画する処理を示します。これもPC用のページとスマホ用のページでは描画する座標が異なるので処理を分けています。
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
function drawX(card){ const position = getCardPositionOnTable(card.Suit, card.Number); ctx.strokeStyle = '#000'; if(PC) ctx.lineWidth = 8; else ctx.lineWidth = 4; ctx.beginPath(); ctx.moveTo(position.x, position.y); if(PC) ctx.lineTo(position.x + CARD_WIDTH, position.y + CARD_HEIGHT); else ctx.lineTo(position.x + CARD_WIDTH * 0.42, position.y + CARD_HEIGHT * 0.42); ctx.stroke(); ctx.beginPath(); if(PC){ ctx.moveTo(position.x + CARD_WIDTH, position.y); ctx.lineTo(position.x, position.y + CARD_HEIGHT); } else { ctx.moveTo(position.x + CARD_WIDTH * 0.42, position.y); ctx.lineTo(position.x, position.y + CARD_HEIGHT * 0.42); } ctx.stroke(); if(PC) ctx.lineWidth = 6; else ctx.lineWidth = 3; ctx.beginPath(); ctx.moveTo(position.x, position.y); if(PC) ctx.lineTo(position.x + CARD_WIDTH, position.y + CARD_HEIGHT); else ctx.lineTo(position.x + CARD_WIDTH * 0.42, position.y + CARD_HEIGHT * 0.42); ctx.strokeStyle = colors[card.PlayerNumber]; ctx.stroke(); ctx.beginPath(); if(PC){ ctx.moveTo(position.x + CARD_WIDTH, position.y); ctx.lineTo(position.x, position.y + CARD_HEIGHT); } else{ ctx.moveTo(position.x + CARD_WIDTH * 0.42, position.y); ctx.lineTo(position.x, position.y + CARD_HEIGHT * 0.42); } ctx.strokeStyle = colors[card.PlayerNumber]; ctx.stroke(); } |
プレイヤー情報の表示
canvasの下にプレイヤー名、残り枚数、殺されたカードの枚数を表示する処理をしめします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function showPlayersInfo(obj){ let text = ''; text += '<table style = "font-weight:bold;">'; text += '<tr>'; text += '<td style = "width:240px;">プレイヤー</td>'; text += '<td style = "width:50px;">残り</td>'; text += '<td style = "width:50px;">Dead</td>'; text += '</tr>'; for(let i = 0; i < obj.Players.length; i++){ let name = obj.Players[i].Name.split('&').join('&').split('<').join('<').split('>').join('>'); text += '<tr style = "color:' + colors[i] + '">'; text += '<td>' + name + '</td>'; text += '<td>' + obj.Players[i].CardsCount + '</td>'; text += '<td>' + obj.Players[i].DeadCardsCount + '</td>'; text += '</tr>'; } text += '</table>'; $playersInfo.innerHTML = text; } |
プレイヤーが所持するカードの表示
プレイヤーが所持するカードをcanvasの下に表示する処理を示します。カードはbutton要素で表示します。手番のときはクリックするとサーバーサイドに”PutOutCard”を送信(=そのカードを出す処理が)できるようにします。showPlayerCards関数はほぼ1秒おきに実行されますが、表示するカードが前回の処理時と同じ場合はなにもしないようにしています。
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 35 |
let _json2 = ''; let _isPlayerTurn = false; function showPlayerCards(json2, isPlayerTurn){ // 第一引数が空文字列の場合はなにも表示しない if(json2 == ''){ _json2 = ''; cardButtons.forEach(button => button.remove() ); cardButtons = []; } // 表示するカードが前回の処理時と同じ場合はなにもしない if(_json2 == json2 && _isPlayerTurn == isPlayerTurn) return; _json2 = json2; _isPlayerTurn = isPlayerTurn; cardButtons.forEach(button => button.remove() ); cardButtons = []; const obj2 = JSON.parse(json2); for(let cardsIndex = 0; cardsIndex < obj2.length; cardsIndex++){ const card = obj2[cardsIndex]; cardButtons.push(createCardButton(card.Suit, card.Number)); // createCardButton関数は後述 } if(isPlayerTurn){ // 手番のときはクリックに反応するようにする cardButtons.forEach(button => { button.onclick = () => { const arr = button.id.split('-'); connection.invoke("PutOutCard", Number(arr[0]), Number(arr[1])); }; }); } } |
手持ちのカードをボタンとして表示する処理を示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function createCardButton(suit, number){ const button = document.createElement('button'); button.style.padding = '0px'; button.style.marginRight = '15px'; button.style.marginBottom = '20px'; button.style.backgroundColor = 'transparent'; button.style.borderColor = 'transparent'; const image = cardImages[suit][number]; button.innerHTML = image.outerHTML; button.id = suit + '-' + number; document.getElementById('cards')?.appendChild(button); return button; } |
着手完了時の処理
カードを出す処理がおこなわれたときは、それが自分が出したカードの場合は’PutCardToClient’が、それ以外のプレイヤーが出したときは’OthersPutCardToClient’が送信されます。
この場合はどちらも効果音を鳴らします。自分の手番でカードを出す処理が正常におこなわれたときは、それ以上クリックしてもカードを出す処理がおこなわれないように表示されているカードはいったん消去します。
1 2 3 4 5 6 7 8 9 10 11 |
connection.on('PutCardToClient', () => { cardButtons.forEach(button => button.remove() ); cardButtons = []; putSound.currentTime = 0; putSound.play(); }); connection.on('OthersPutCardToClient', () => { otherPutSound.currentTime = 0; otherPutSound.play(); }); |
着手拒否時の処理
出せないカードを出そうとした場合は拒否されたことがわかるように効果音を鳴らします。
1 2 3 4 |
connection.on('DenyCardToClient', () => { ngSound.currentTime = 0; ngSound.play(); }); |
パス成立時の処理
パスした場合も効果音を鳴らします。またこの場合もそれ以降はクリックしてもカードを出す処理がおこなわれないように表示されているカードはいったん消去します。
1 2 3 4 5 6 7 |
connection.on('PlayerPassedToClient', () => { _json2 = ''; cardButtons.forEach(button => button.remove() ); cardButtons = []; passSound.currentTime = 0; passSound.play(); }); |
カードが殺されたときの処理
カードが殺されたときも効果音を鳴らします。ユーザー自身のカードが含まれている場合とそうでない場合で効果音を変えます。
1 2 3 4 5 6 7 8 9 10 11 |
// 殺されたカードのなかにユーザーがもつカードがある場合 connection.on('KilledOwnToClient', () => { deadSound.currentTime = 0; deadSound.play(); }); // ない場合 connection.on('KilledOthersToClient', () => { othersDeadSound.currentTime = 0; othersDeadSound.play(); }); |
ゲームが終了したときの処理
ゲームが終了したら’GameFinishedToClient’とともに順位にかんする情報がjsonで送られてくるのでそれを表示します。またユーザーの順位に応じて効果音を鳴らします。
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 35 36 37 38 39 40 41 42 43 |
connection.on('GameFinishedToClient', (json) => { const obj = JSON.parse(json); let ranking = 0; // ユーザーの順位(ゲームに参加していた場合は1~5のいずれかが代入される) let text = ""; text += '<table style = "font-weight:bold;">'; text += '<tr>'; text += '<td style = "width:50px;">順位</td>'; text += '<td style = "width:180px;">プレイヤー</td>'; text += '<td style = "width:50px;">Dead</td>'; text += '<td style = "width:50px;">Finish</td>'; text += '</tr>'; for(let i = 0; i < obj.length; i++){ const player = obj[i]; if(player.Number == playerNumber) ranking = player.TrueRanking; let name = player.Name.split('<').join('<'); name = name.split('>').join('>'); text += '<tr>'; text += `<td>${player.TrueRanking}</td>`; text += `<td>${name}</td>`; text += `<td>${player.DeadCardsCount}</td>`; text += `<td>${player.Ranking}</td>`; text += '</tr>'; } text += '</table>'; playerNumber = -1; setTimeout(() => { $gameResult.innerHTML = text; $gameResult.style.height = CANVAS_HEIGHT + 'px'; $gameResult.style.display = 'block'; $result.innerHTML = 'ゲーム終了'; $entry.style.display = 'block'; $playerNameOuter.style.display = 'block'; const sounds = [ranking1Sound, ranking2Sound, ranking3Sound, ranking4Sound, ranking5Sound]; if(ranking >= 1 && ranking <= 5) sounds[ranking - 1].play(); }, 2500); }); |
プレイヤー全員離脱時の処理
プレイしていた人が全員離脱してしまった場合は表示されていたカードをすべてリセットします。
1 2 3 4 |
connection.on('GameAbandonedByAll', () => { ctx.fillStyle = '#080'; ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); }); |