p5.js:Flappy-Bird-like-Game
プレイヤー: 遊ぶ人が操作する対象
ブロック: 迫ってくる障害物
エンティティ: プレイヤー と ブロック の総称
位置 (x, y)
速度 (x, y)
重力
ジャンプ
code:sketch.js
// ---- エンティティ関連の関数 ---------------------------------------------
// 全エンティティ共通
function updatePosition(entity) {
entity.x += entity.vx;
entity.y += entity.vy;
}
// プレイヤーエンティティ用
function createPlayer() {
return {
x: 200,
y: 300,
vx: 0,
vy: 0
};
}
function applyGravity(entity) {
entity.vy += 0.15;
}
function applyJump(entity) {
entity.vy = -5;
}
function drawPlayer(entity) {
square(entity.x, entity.y, 40);
}
function playerIsAlive(entity) {
// プレイヤーの位置が生存圏内なら true を返す。
// 600 は画面の下端
return entity.y < 600;
}
// ブロックエンティティ用
function createBlock(y) {
return {
x: 900,
y,
vx: -2,
vy: 0
};
}
function drawBlock(entity) {
rect(entity.x, entity.y, 80, 400);
}
function blockIsAlive(entity) {
// ブロックの位置が生存圏内なら true を返す。
// -100 は適当な値(ブロックが見えなくなる位置であればよい)
return -100 < entity.x;
}
// 複数のエンティティを処理する関数
/**
* 2つのエンティティが衝突しているかどうかをチェックする
*
* @param entityA 衝突しているかどうかを確認したいエンティティ
* @param entityB 同上
* @param collisionXDistance 衝突しないギリギリのx距離
* @param collisionYDistance 衝突しないギリギリのy距離
* @returns 衝突していたら true そうでなければ false を返す
*/
function entitiesAreColliding(
entityA,
entityB,
collisionXDistance,
collisionYDistance
) {
// xとy、いずれかの距離が十分開いていたら、衝突していないので false を返す
let currentXDistance = abs(entityA.x - entityB.x); // 現在のx距離
if (collisionXDistance <= currentXDistance) return false;
let currentYDistance = abs(entityA.y - entityB.y); // 現在のy距離
if (collisionYDistance <= currentYDistance) return false;
return true; // ここまで来たら、x方向でもy方向でも重なっているので true
}
code:sketch.js
// ---- ゲーム全体に関わる部分 --------------------------------------------
/** プレイヤーエンティティ */
let player;
/** ブロックエンティティの配列 */
let blocks;
/** ゲームの状態。"play" か "gameover" を入れるものとする */
let gameState;
code:sketch.js
/** ブロックを上下ペアで作成し、blocks に追加する */
function addBlockPair() {
let y = random(-100, 100);
blocks.push(createBlock(y)); // 上のブロック
blocks.push(createBlock(y + 600)); // 下のブロック
}
code:sketch.js
/** ゲームオーバー画面を表示する */
function drawGameoverScreen() {
background(0, 192); // 透明度 192 の黒
fill(255);
textSize(64);
textAlign(CENTER, CENTER); // 横に中央揃え & 縦にも中央揃え
text("GAME OVER", width / 2, height / 2); // 画面中央にテキスト表示
}
code:sketch.js
/** ゲームの初期化・リセット */
function resetGame() {
// 状態をリセット
gameState = "play";
// プレイヤーを作成
player = createPlayer();
// ブロックの配列準備
blocks = [];
}
code:sketch.js
/** ゲームの更新 */
function updateGame() {
// ゲームオーバーなら更新しない
if (gameState === "gameover") return;
// ブロックの追加と削除
if (frameCount % 120 === 1) addBlockPair(blocks); // 一定間隔で追加
blocks = blocks.filter(blockIsAlive); // 生きているブロックだけ残す
// 全エンティティの位置を更新
updatePosition(player);
for (let block of blocks) updatePosition(block);
// プレイヤーに重力を適用
applyGravity(player);
// プレイヤーが死んでいたらゲームオーバー
if (!playerIsAlive(player)) gameState = "gameover";
// 衝突判定
for (let block of blocks) {
if (entitiesAreColliding(player, block, 20 + 40, 20 + 200)) {
gameState = "gameover";
break;
}
}
}
code:sketch.js
/** ゲームの描画 */
function drawGame() {
// 全エンティティを描画
background(0);
drawPlayer(player);
for (let block of blocks) drawBlock(block);
// ゲームオーバーならそれ用の画面を表示
if (gameState === "gameover") drawGameoverScreen();
}
code:sketch.js
/** マウスボタンが押されたときのゲームへの影響 */
function onMousePress() {
switch (gameState) {
case "play":
// プレイ中の状態ならプレイヤーをジャンプさせる
applyJump(player);
break;
case "gameover":
// ゲームオーバー状態ならリセット
resetGame();
break;
}
}
code:sketch.js
// ---- setup/draw 他 ---------------------------------------------------
function setup() {
createCanvas(800, 600);
rectMode(CENTER);
resetGame();
}
function draw() {
updateGame();
drawGame();
}
function mousePressed() {
onMousePress();
}
https://img.shields.io/badge/p5.js-Flappy_Bird_like_Game-ED225D.svg?logo=p5.js&style=for-the-badge