2025-07-16
JavaScript
ICT基礎 第14回 補助資料
本ページのサンプルファイル集
下記のどちらかからからダウンロードできます
WebClassの授業資料
Windowsの人は必ずzipファイルを展開すること!! zipファイルの中では作業できません.
恐竜ゲーム風のミニゲーム
恐竜ゲーム (目標物の元の例)
Chromeにはインターネットにつながらない時などに遊べる簡単なゲームが用意されています.

実際に, Chromeで下記
xxxxxxxxxxchrome://dino
をURL部分に入力し, Enter or Returnを押してみてください. すると, 下図のような画面が出てきます.

ここで, 実際にSpaceキーを押すと, 恐竜が横に進んでいき, サボテン等をジャンプして乗り越えるゲームが始まります.
今回は, これに似た簡単なゲームを作ることを目標にやっていきたいと思います.
htmlとjsの準備
まずは, htmlとjsの用意をします.
index.html
xxxxxxxxxx<html lang="ja"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Game</title></head><body> <canvas width="600" height="400" id="gameCanvas" style="border: solid 1px;"></canvas> <script src="./app.js"></script></body></html>
canvasタグの中にゲーム画面を描いていきますcanvasの横幅600px, 高さ400pxで固定しています. 簡単のため, レスポンシブデザインとして画面サイズにフィットさせるようにはしていません. 描画領域がわかりやすいように,
style="border: solid 1px;"で枠線を入れています後にJavaScript内で指定するために
id="gameCanvas"でidを追加しています次節以降ではこの
index.htmlを変更せずにやっていきます
app.js
xxxxxxxxxxconsole.log("hello");
ゲームの初期処理とループ処理
本節以降ではindex.html を変更しないため, app.jsの内容のみを記載します
app.js
xxxxxxxxxxlet canvas;let ctx;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); setInterval("loop()", 1000);}
function loop(){ console.log("Loop!!");}
setupという関数を用意し, 実行していることで, ここがゲームの起点 (初期処理) となります.xxxxxxxxxxcanvas = document.querySelector("#gameCanvas");index.html内のgameCanvasというidを持ったcanvasタグを取得し,canvasという名前の変数に入れています.xxxxxxxxxxctx = canvas.getContext("2d");今回は2次元の横スクロールゲームなので, canvasの中の表示形式を
2dにします (3D表示のゲーム等を作りたい場合はwebglにします)
xxxxxxxxxxsetInterval("loop()", 1000);xxxxxxxxxxfunction loop(){console.log("Loop!!");}setIntervalという関数を使って,loopという関数を1000ミリ秒ごとに実行する設定をします.実際には, 60FPS (60 frames per second. 1秒に60回描画) で実施することが多いため,
として,setInterval("loop()", 16);程度にすることが多いです.
ゲームの状態と条件分岐 (if, else)
ゲームを実行している時と, ゲームオーバーの時とで場合分けをします.
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); setInterval("loop()", 1000);}
function loop(){ if (isPlaying){ console.log("playing!!"); } else { console.log("game over!!"); }}
xxxxxxxxxxif (条件A){条件Aを満たす場合の処理}else {条件Aを満たさない場合の処理}という形で, 条件分岐を実施します.
ゲーム中 (
true), ゲームオーバー後 (false) を司る変数としてisPlayingを用意しました
背景 (水面の線)
プレイヤーが動く高さのベースとなる水面の線を描きます

app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); setInterval("loop()", 16);}
function loop(){ if (isPlaying){ //console.log("playing!!"); drawBackground(); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
プレイヤー画像の表示
プレイヤーの画像 (赤い魚. fish.png) を表示します.
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSize = 50;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ //console.log("playing!!"); drawBackground(); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
xxxxxxxxxxlet playerImg;let playerX = 100;let playerY = gndY;let playerSize = 50;プレイヤー (魚) の変数の宣言
xxxxxxxxxxplayerImg = new Image();playerImg.src = "./fish.png";fish.pngという画像を読み込む
xxxxxxxxxxctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize);画像の表示
その他
xxxxxxxxxxsetInterval("loop()", 16);60fps (16ミリ秒) に変更
xxxxxxxxxx//console.log("playing!!");コンソールがこのログで埋まってしまうのでコメントアウト
xxxxxxxxxx//console.log("game over!!");コンソールがこのログで埋まってしまうのでコメントアウト
キー入力
ジャンプの準備としてキー入力ができるようにします
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSize = 50;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; document.onkeydown = keydown; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ //console.log("playing!!"); drawBackground(); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
function keydown(e){ console.log(e.code);}
xxxxxxxxxxdocument.onkeydown = keydown;xxxxxxxxxxfunction keydown(e){console.log(e.code);}keydownという関数を作成し, キーボードが入力された場合の処理を書けるようにするe.codeで実際に入力されたキーを取得できる
プレイヤーの更新・ジャンプ
スペースキーが入力されたらジャンプするようにします.
ジャンプは, 物理の基本的な式
から, 重力下での物体の加速度, 速度, 位置の関係は
のように決まります.

これを使って, 経過時間を1とした場合の物体の速度, 位置を更新してみましょう.
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSpeed = 0;let playerAcc = 0;let playerSize = 50;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; document.onkeydown = keydown; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ //console.log("playing!!"); drawBackground(); updatePlayer(); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.fillStyle = "rgb(255,255,255)" ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
function updatePlayer(){ playerSpeed = playerSpeed + playerAcc; playerY = playerY + playerSpeed; if (playerY > gndY){ playerY = gndY; playerSpeed = 0; playerAcc = 0; }}
function keydown(e){ console.log(e.code); if (e.code == "Space"){ playerSpeed = -20; playerAcc = 1.5; }}
xxxxxxxxxxctx.fillStyle = "rgb(255,255,255)"ctx.fillRect(0, 0, canvas.width, canvas.height);毎フレームの背景を白にすることで, アニメ的な表現ができるようになる
xxxxxxxxxxif (e.code == "Space"){playerSpeed = -20;playerAcc = 1.5;}spaceキーを押したときにプレイヤーの速度 (上向き) と加速度 (下向き) を与える
xxxxxxxxxxfunction updatePlayer(){playerSpeed = playerSpeed + playerAcc;playerY = playerY + playerSpeed;::}xxxxxxxxxxupdatePlayer();プレイヤーの速度, 位置を更新
xxxxxxxxxxif (playerY > gndY){playerY = gndY;playerSpeed = 0;playerAcc = 0;}プレイヤーがジャンプで着地したら位置を固定して, 速度と加速度を止める
敵画像の表示
敵の画像 (サメ. shark.png) を表示します.
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSpeed = 0;let playerAcc = 0;let playerSize = 50;let enemyImg;let enemyX = 600;let enemyY = gndY;let enemySize = 50;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; enemyImg = new Image(); enemyImg.src = "./shark.png"; document.onkeydown = keydown; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ //console.log("playing!!"); drawBackground(); updatePlayer(); ctx.drawImage(enemyImg, enemyX - enemySize / 2, enemyY - enemySize / 2, enemySize, enemySize); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.fillStyle = "rgb(255,255,255)" ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
function updatePlayer(){ playerSpeed = playerSpeed + playerAcc; playerY = playerY + playerSpeed; if (playerY > gndY){ playerY = gndY; playerSpeed = 0; playerAcc = 0; }}
function keydown(e){ console.log(e.code); if (e.code == "Space"){ playerSpeed = -20; playerAcc = 1.5; }}
xxxxxxxxxxlet enemyImg;let enemyX = 600;let enemyY = gndY;let enemySize = 50;サメ用の変数の準備
xxxxxxxxxxenemyImg = new Image();enemyImg.src = "./shark.png";サメ画像の読み込み
xxxxxxxxxxctx.drawImage(enemyImg, enemyX - enemySize / 2, enemyY - enemySize / 2, enemySize, enemySize);サメ画像の表示
敵をランダムな速さで動かす
サメを右から左に動かします
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSpeed = 0;let playerAcc = 0;let playerSize = 50;let enemyImg;let enemyX = 600;let enemyY = gndY;let enemySpeed = -10;let enemySize = 50;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; enemyImg = new Image(); enemyImg.src = "./shark.png"; document.onkeydown = keydown; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ //console.log("playing!!"); drawBackground(); updatePlayer(); updateEnemy(); ctx.drawImage(enemyImg, enemyX - enemySize / 2, enemyY - enemySize / 2, enemySize, enemySize); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.fillStyle = "rgb(255,255,255)" ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
function updatePlayer(){ playerSpeed = playerSpeed + playerAcc; playerY = playerY + playerSpeed; if (playerY > gndY){ playerY = gndY; playerSpeed = 0; playerAcc = 0; }}
function updateEnemy(){ enemyX = enemyX + enemySpeed; if (enemyX < 0){ enemyX = canvas.width + 100; enemySpeed = - (Math.random() * 5 + 5); }}
function keydown(e){ console.log(e.code); if (e.code == "Space"){ playerSpeed = -20; playerAcc = 1.5; }}
xxxxxxxxxxlet enemySpeed = -10;サメの初期速度を定義
xxxxxxxxxxupdateEnemy();xxxxxxxxxxfunction updateEnemy(){enemyX = enemyX + enemySpeed;if (enemyX < 0){enemyX = canvas.width + 100;enemySpeed = - (Math.random() * 5 + 5);}}サメの速度によってサメの位置を更新
サメが左端に到達したら, 右端に移動するようにする
その際にサメの速さを-10から-5までの値になるように指定
Math.random()は0から1までのランダムな値を出す関数Math.random() * 5で0から5までのランダムな値を出すMath.random() * 5 + 5で5から10までのランダムな値を出す- (Math.random() * 5 + 5)で-10から-5までのランダムな値を出す
スコアの表示
経過時間をスコアとして表示するようにします
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSpeed = 0;let playerAcc = 0;let playerSize = 50;let enemyImg;let enemyX = 600;let enemyY = gndY;let enemySpeed = -10;let enemySize = 50;let initialTime;let now;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; enemyImg = new Image(); enemyImg.src = "./shark.png"; initialTime = new Date(); document.onkeydown = keydown; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ now = new Date(); //console.log("playing!!"); drawBackground(); updatePlayer(); updateEnemy(); drawScore(); ctx.drawImage(enemyImg, enemyX - enemySize / 2, enemyY - enemySize / 2, enemySize, enemySize); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.fillStyle = "rgb(255,255,255)" ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
function drawScore(){ ctx.fillStyle = "rgb(0,0,0)"; ctx.font = "20px sans-serif"; let score = now - initialTime; let scoreText = "Score: " + score; let scoreWidth = ctx.measureText(scoreText).width; ctx.fillText(scoreText, canvas.width - scoreWidth - 10, 30);}
function updatePlayer(){ playerSpeed = playerSpeed + playerAcc; playerY = playerY + playerSpeed; if (playerY > gndY){ playerY = gndY; playerSpeed = 0; playerAcc = 0; }}
function updateEnemy(){ enemyX = enemyX + enemySpeed; if (enemyX < 0){ enemyX = canvas.width + 100; enemySpeed = - (Math.random() * 5 + 5); }}
function keydown(e){ console.log(e.code); if (e.code == "Space"){ playerSpeed = -20; playerAcc = 1.5; }}
xxxxxxxxxxlet initialTime;let now;ゲームの開始時刻と現時刻を入れる変数を用意
xxxxxxxxxxinitialTime = new Date();ゲームの開始時刻を取得
xxxxxxxxxxnow = new Date();現時刻を取得
xxxxxxxxxxdrawScore();xxxxxxxxxxfunction drawScore(){ctx.fillStyle = "rgb(0,0,0)";ctx.font = "20px sans-serif";let score = now - initialTime;let scoreText = "Score: " + score;let scoreWidth = ctx.measureText(scoreText).width;ctx.fillText(scoreText, canvas.width - scoreWidth - 10, 30);}スコアを表示
xxxxxxxxxxlet score = now - initialTime;ゲームの開始時刻から現時刻までの経過時間を計算し,
scoreとする
xxxxxxxxxxlet scoreWidth = ctx.measureText(scoreText).width;スコアの文字列の横幅を取得
xxxxxxxxxxctx.fillText(scoreText, canvas.width - scoreWidth - 10, 30);スコアの文字列の横幅の分だけ位置を調整しつつ, 画面右上に表示
衝突判定
プレイヤーと敵がぶつかる (衝突する) ことを判定し, ぶつかってしまったらゲームオーバーとします.
衝突判定は
「プレイヤーと敵との距離」が「プレイヤーの半径と敵の半径の和」よりも小さくなってしまった場合
としてみます.

「プレイヤーと敵との距離」を求めるには, 直角三角形に対する三平方の定理を使って,
とします.
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSpeed = 0;let playerAcc = 0;let playerSize = 50;let playerR = playerSize / 2;let enemyImg;let enemyX = 600;let enemyY = gndY;let enemySpeed = -10;let enemySize = 50;let enemyR = enemySize / 2;let initialTime;let now;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; enemyImg = new Image(); enemyImg.src = "./shark.png"; initialTime = new Date(); document.onkeydown = keydown; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ now = new Date(); //console.log("playing!!"); drawBackground(); updatePlayer(); updateEnemy(); checkCollision(); drawScore(); ctx.drawImage(enemyImg, enemyX - enemySize / 2, enemyY - enemySize / 2, enemySize, enemySize); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.fillStyle = "rgb(255,255,255)" ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
function drawScore(){ ctx.fillStyle = "rgb(0,0,0)"; ctx.font = "20px sans-serif"; let score = now - initialTime; let scoreText = "Score: " + score; let scoreWidth = ctx.measureText(scoreText).width; ctx.fillText(scoreText, canvas.width - scoreWidth - 10, 30);}
function updatePlayer(){ playerSpeed = playerSpeed + playerAcc; playerY = playerY + playerSpeed; if (playerY > gndY){ playerY = gndY; playerSpeed = 0; playerAcc = 0; }}
function updateEnemy(){ enemyX = enemyX + enemySpeed; if (enemyX < 0){ enemyX = canvas.width + 100; enemySpeed = - (Math.random() * 5 + 5); }}
function checkCollision(){ let dx = playerX - enemyX; let dy = playerY - enemyY; let dr = Math.sqrt(dx**2 + dy**2); if (dr < playerR + enemyR){ console.log("collision!!"); playerSpeed = 0; enemySpeed = 0; isPlaying = false; }}
function keydown(e){ console.log(e.code); if (e.code == "Space"){ playerSpeed = -20; playerAcc = 1.5; }}
xxxxxxxxxxcheckCollision();xxxxxxxxxxfunction checkCollision(){let dx = playerX - enemyX;let dy = playerY - enemyY;let dr = Math.sqrt(dx**2 + dy**2);if (dr < playerR + enemyR){console.log("collision!!");playerSpeed = 0;enemySpeed = 0;isPlaying = false;}}
リスタート
ゲームオーバーになったら, Rキーを押してリスタートするようにします
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSpeed = 0;let playerAcc = 0;let playerSize = 50;let playerR = playerSize / 2;let enemyImg;let enemyX = 600;let enemyY = gndY;let enemySpeed = -10;let enemySize = 50;let enemyR = enemySize / 2;let initialTime;let now;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; enemyImg = new Image(); enemyImg.src = "./shark.png"; initialTime = new Date(); document.onkeydown = keydown; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ now = new Date(); //console.log("playing!!"); drawBackground(); updatePlayer(); updateEnemy(); checkCollision(); drawScore(); ctx.drawImage(enemyImg, enemyX - enemySize / 2, enemyY - enemySize / 2, enemySize, enemySize); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.fillStyle = "rgb(255,255,255)" ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
function drawScore(){ ctx.fillStyle = "rgb(0,0,0)"; ctx.font = "20px sans-serif"; let score = now - initialTime; let scoreText = "Score: " + score; let scoreWidth = ctx.measureText(scoreText).width; ctx.fillText(scoreText, canvas.width - scoreWidth - 10, 30);}
function updatePlayer(){ playerSpeed = playerSpeed + playerAcc; playerY = playerY + playerSpeed; if (playerY > gndY){ playerY = gndY; playerSpeed = 0; playerAcc = 0; }}
function updateEnemy(){ enemyX = enemyX + enemySpeed; if (enemyX < 0){ enemyX = canvas.width + 100; enemySpeed = - (Math.random() * 5 + 5); }}
function checkCollision(){ let dx = playerX - enemyX; let dy = playerY - enemyY; let dr = Math.sqrt(dx**2 + dy**2); if (dr < playerR + enemyR){ console.log("collision!!"); playerSpeed = 0; enemySpeed = 0; isPlaying = false; drawGameOver(); }}
function drawGameOver(){ ctx.fillStyle = "rgb(0,0,0)"; ctx.font = "20px sans-serif"; let restartText = "Game Over!! Press R to restart"; let restartWidth = ctx.measureText(restartText).width; ctx.fillText(restartText, canvas.width / 2 - restartWidth / 2, canvas.height / 2);}
function keydown(e){ console.log(e.code); if (e.code == "Space"){ playerSpeed = -20; playerAcc = 1.5; } else if (e.code == "KeyR" && isPlaying == false){ location.reload(); }}
xxxxxxxxxxdrawGameOver();xxxxxxxxxxfunction drawGameOver(){ctx.fillStyle = "rgb(0,0,0)";ctx.font = "20px sans-serif";let restartText = "Game Over!! Press R to restart";let restartWidth = ctx.measureText(restartText).width;ctx.fillText(restartText, canvas.width / 2 - restartWidth / 2, canvas.height / 2);}ゲームオーバーになったら「Rを押すと再スタートできるよ」というメッセージを表示します
xxxxxxxxxxelse if (e.code == "KeyR" && isPlaying == false){location.reload();}「ゲームオーバー後 (
isPlaying=false) 」 且つ 「キーボードでRを押した」 場合に, 今の画面を再読み込み (reload) します
プレイヤーの連続ジャンプ禁止
プレイヤーが水面に着いている場合にのみジャンプできるようにします.
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSpeed = 0;let playerAcc = 0;let playerSize = 50;let playerR = playerSize / 2;let enemyImg;let enemyX = 600;let enemyY = gndY;let enemySpeed = -10;let enemySize = 50;let enemyR = enemySize / 2;let initialTime;let now;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; enemyImg = new Image(); enemyImg.src = "./shark.png"; initialTime = new Date(); document.onkeydown = keydown; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ now = new Date(); //console.log("playing!!"); drawBackground(); updatePlayer(); updateEnemy(); checkCollision(); drawScore(); ctx.drawImage(enemyImg, enemyX - enemySize / 2, enemyY - enemySize / 2, enemySize, enemySize); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.fillStyle = "rgb(255,255,255)" ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); ctx.lineTo(canvas.width, gndY); ctx.stroke();}
function drawScore(){ ctx.fillStyle = "rgb(0,0,0)"; ctx.font = "20px sans-serif"; let score = now - initialTime; let scoreText = "Score: " + score; let scoreWidth = ctx.measureText(scoreText).width; ctx.fillText(scoreText, canvas.width - scoreWidth - 10, 30);}
function updatePlayer(){ playerSpeed = playerSpeed + playerAcc; playerY = playerY + playerSpeed; if (playerY > gndY){ playerY = gndY; playerSpeed = 0; playerAcc = 0; }}
function updateEnemy(){ enemyX = enemyX + enemySpeed; if (enemyX < 0){ enemyX = canvas.width + 100; enemySpeed = - (Math.random() * 5 + 5); }}
function checkCollision(){ let dx = playerX - enemyX; let dy = playerY - enemyY; let dr = Math.sqrt(dx**2 + dy**2); if (dr < playerR + enemyR){ console.log("collision!!"); playerSpeed = 0; enemySpeed = 0; isPlaying = false; drawGameOver(); }}
function drawGameOver(){ ctx.fillStyle = "rgb(0,0,0)"; ctx.font = "20px sans-serif"; let restartText = "Game Over!! Press R to restart"; let restartWidth = ctx.measureText(restartText).width; ctx.fillText(restartText, canvas.width / 2 - restartWidth / 2, canvas.height / 2);}
function keydown(e){ console.log(e.code); if (e.code == "Space" && playerY == gndY){ playerSpeed = -20; playerAcc = 1.5; } else if (e.code == "KeyR" && isPlaying == false){ location.reload(); }}
xxxxxxxxxxif (e.code == "Space" && playerY == gndY){playerSpeed = -20;playerAcc = 1.5;}ジャンプの箇所に
playerY == gndYという条件を追加することで, プレイヤーが地面 (水面) に着いている場合のみジャンプできるようになります.
波と繰り返し (for)
水面の波を表現します
app.js
xxxxxxxxxxlet canvas;let ctx;let isPlaying = true;let gndY = 300;let playerImg;let playerX = 100;let playerY = gndY;let playerSpeed = 0;let playerAcc = 0;let playerSize = 50;let playerR = playerSize / 2;let enemyImg;let enemyX = 600;let enemyY = gndY;let enemySpeed = -10;let enemySize = 50;let enemyR = enemySize / 2;let initialTime;let now;
console.log("hello");calcTest(10000);setup();
function calcTest(x){ console.log(123 + x);}
function setup(){ console.log("start!!"); canvas = document.querySelector("#gameCanvas"); ctx = canvas.getContext("2d"); playerImg = new Image(); playerImg.src = "./fish.png"; enemyImg = new Image(); enemyImg.src = "./shark.png"; initialTime = new Date(); document.onkeydown = keydown; setInterval("loop()", 16);}
function loop(){ if (isPlaying){ now = new Date(); //console.log("playing!!"); drawBackground(); updatePlayer(); updateEnemy(); checkCollision(); drawScore(); ctx.drawImage(enemyImg, enemyX - enemySize / 2, enemyY - enemySize / 2, enemySize, enemySize); ctx.drawImage(playerImg, playerX - playerSize / 2, playerY - playerSize / 2, playerSize, playerSize); } else { //console.log("game over!!"); }}
function drawBackground(){ ctx.fillStyle = "rgb(255,255,255)" ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(0, gndY); let dt = now - initialTime; for (let i = 0; i < canvas.width; i++){ ctx.lineTo(i, gndY + 5*Math.sin(i/10 + dt/100)); } ctx.lineTo(canvas.width, gndY); ctx.stroke();}
function drawScore(){ ctx.fillStyle = "rgb(0,0,0)"; ctx.font = "20px sans-serif"; let score = now - initialTime; let scoreText = "Score: " + score; let scoreWidth = ctx.measureText(scoreText).width; ctx.fillText(scoreText, canvas.width - scoreWidth - 10, 30);}
function updatePlayer(){ playerSpeed = playerSpeed + playerAcc; playerY = playerY + playerSpeed; if (playerY > gndY){ playerY = gndY; playerSpeed = 0; playerAcc = 0; }}
function updateEnemy(){ enemyX = enemyX + enemySpeed; if (enemyX < 0){ enemyX = canvas.width + 100; enemySpeed = - (Math.random() * 5 + 5); }}
function checkCollision(){ let dx = playerX - enemyX; let dy = playerY - enemyY; let dr = Math.sqrt(dx**2 + dy**2); if (dr < playerR + enemyR){ console.log("collision!!"); playerSpeed = 0; enemySpeed = 0; isPlaying = false; drawGameOver(); }}
function drawGameOver(){ ctx.fillStyle = "rgb(0,0,0)"; ctx.font = "20px sans-serif"; let restartText = "Game Over!! Press R to restart"; let restartWidth = ctx.measureText(restartText).width; ctx.fillText(restartText, canvas.width / 2 - restartWidth / 2, canvas.height / 2);}
function keydown(e){ console.log(e.code); if (e.code == "Space" && playerY == gndY){ playerSpeed = -20; playerAcc = 1.5; } else if (e.code == "KeyR" && isPlaying == false){ location.reload(); }}
xxxxxxxxxxlet dt = now - initialTime;for (let i = 0; i < canvas.width; i++){ctx.lineTo(i, gndY + 5*Math.sin(i/10 + dt/100));}xxxxxxxxxxfor (let 繰返しの変数名 = 繰返しの初期値; 繰返しの変数名 < 繰返しの最終値; 繰返しの増減幅){繰返しの実際の処理}という文法で, 繰返しの処理ができます.
xxxxxxxxxxfor (let i = 0; i < canvas.width; i++){繰返しの実際の処理}繰返しの変数名は
iiは0以上600未満で, 1ずつ増える (i++) ように繰返していく
xxxxxxxxxxctx.lineTo(i, gndY + 5*Math.sin(i/10 + dt/100));Math.sin()は三角関数の一種のsin関数のこと
