ゲームはここでホストされます 。
これは私の最初のPhaser3ゲーム/プロジェクトであり、まだかなり新しいです。 Javascriptなので、もっとうまくやれることがたくさんあると思います。私が自分のコードについて改善したい一番のことはパフォーマンスです。次に、コードの有効性と読みやすさを重視しますが、パフォーマンスが最優先事項です。
PhaserJSの経験がまったくない場合でも、フィードバックは貴重です、おそらくもっとうまくできることの多くは、純粋なJavascriptにのみ関係しているからです。
私のJSコード:
const width = window.innerWidth; const height = window.innerHeight; let hiScore = localStorage["hiScore"] || 0; const config = { width: width, height: height, backgroundColor: 0x50C875, scene: { preload, create, update, }, physics: { default: "arcade", arcade: { gravity: { y: 50 }, }, } } const gameState = { gameOver: false, score: 0, scoreText: false, player1AnimationStage: 0, player2AnimationStage: 0, player1SpriteSheet: ["upflap", "midflap", "downflap",], player2SpriteSheet: ["player2_upflap", "player2_midflap", "player2_downflap",], player1Y: (height / 2 * 0.5), player2Y: (height / 2 * 0.5), secondPlayerSpawned: false, player1Dead: false, player2Dead: false, } const game = new Phaser.Game(config, "root"); game.clearBeforeRender = false; function preload() { this.load.image("background", "assets/images/background.png"); this.load.image("ground", "assets/images/ground.png"); this.load.image("pipe", "assets/images/pipe.png"); this.load.image("upflap", "assets/images/upflap.png"); this.load.image("midflap", "assets/images/midflap.png"); this.load.image("downflap", "assets/images/downflap.png"); this.load.image("player2_upflap", "assets/images/player2_upflap.png"); this.load.image("player2_midflap", "assets/images/player2_midflap.png"); this.load.image("player2_downflap", "assets/images/player2_downflap.png"); this.load.audio("hit", "assets/audio/hit.mp3"); this.load.audio("point", "assets/audio/point.mp3"); this.load.audio("wing", "assets/audio/wing.mp3"); this.load.audio("die", "assets/audio/die.mp3"); } function create() { gameState.hitSound = this.sound.add("hit"); gameState.pointSound = this.sound.add("point"); gameState.wingSound = this.sound.add("wing"); gameState.dieSound = this.sound.add("die"); // Hide Score Table document.getElementById("hiScoreTable").style.display = "none"; const colliderTile = this.physics.add.staticGroup(); gameState.colliderTile = colliderTile.create(50, 0, "pipe").setScale(0.1, 80).refreshBody(); gameState.colliderTile2 = colliderTile.create(1, 0, "pipe").setScale(0, 80).refreshBody(); gameState.bgTile = this.add.tileSprite(0, height, width, height, "background").setScale(2); gameState.ground = this.physics.add.staticGroup(); gameState.ground.create(0, height, "ground").setScale((8.6, 1)).refreshBody(); gameState.groundTile = this.add.tileSprite(0, height, width, null, "ground").setScale(8.6, 1); gameState.gameOver = false; gameState.player1 = this.physics.add.sprite(100, gameState.player1Y, "midflap").setScale(2); gameState.player1.body.acceleration.y = 1500; gameState.pipes = this.physics.add.group(); gameState.scoreText = this.add.text((width / 2) - 100, 100, `Score: ${gameState.score}`, { fontSize: "40px", fontWeight: "bold", }); gameState.secondPlayerSpawned = false; // Layers gameState.groundTile.setDepth(1); gameState.pipes.setDepth(2); gameState.scoreText.setDepth(3); gameState.playSoundMethod = (sound) => { this.sound.play(sound); } const addRowOfPipes = () => { const hole = Math.floor(Math.random() * 7) + 3; for (let i = 0; i < 17; i++) { if (i !== hole && i !== hole + 1 && i !== hole + 2) { let pipe = gameState.pipes.create(width - 60, i * 50 + 25, "pipe"); pipe.body.setVelocityX(-200); pipe.outOfBoundsKill = true; pipe.body.allowGravity = false; pipe.body.immovable = true; this.physics.add.collider(pipe, gameState.colliderTile2, (item) => { if (i === 16) { gameState.pointSound.play(); gameState.score++; if (gameState.scoreText) gameState.scoreText.destroy(); gameState.scoreText = this.add.text((width / 2) - 100, 100, `Score: ${gameState.score}`, { fontSize: "40px", fontWeight: "bold", }); } item.destroy(); }) if (i === 16) { pipe.onWorldBounds = true; } } } } gameState.fallDown = () => { if (gameState.player1Dead) { gameState.player1.y += 5; if (gameState.player1.y > height) gameState.player1fallDownCaller.destroy(); } if (gameState.player2Dead) { gameState.player2.y += 5; if (gameState.player2.y > height) gameState.player2fallDownCaller.destroy(); } } addRowOfPipes(); gameState.gameOverMethod = () => { this.physics.pause(); gameState.scoreText.destroy(); if (gameState.score > hiScore) localStorage["hiScore"] = gameState.score; hiScore = localStorage.getItem("hiScore"); document.getElementById("hiScoreTable").style.display = "initial"; document.getElementById("score").innerHTML = gameState.score; document.getElementById("hiScore").innerHTML = hiScore; birdAnimation.destroy(); gameState.gameOver = true; this.add.text(); pipeGen.destroy(); gameState.player1.setVelocityY(150); gameState.player1.setVelocityX(0); if (gameState.secondPlayerSpawned) { gameState.player2.setVelocityY(150); gameState.player2.setVelocityX(0); } if (gameState.score > 10) { if (gameState.score > 20) { if (gameState.score > 30) { displayMedal("gold"); } displayMedal("silver"); } displayMedal("bronze"); } function displayMedal(medal) { let medalColor; document.getElementById("medalContainer").style.display = "initial"; switch (medal) { case "bronze": medalColor = "#cd7f32"; break; case "silver": medalColor = "#c0c0c0"; break; case "gold": medalColor = "#ccac00"; break; } document.getElementById("medal").style.backgroundColor = medalColor; } gameState.score = 0; } gameState.fallDownCaller = (player) => { if (player === "player1") { gameState.player1fallDownCaller = this.time.addEvent({ delay: 10, callback: gameState.fallDown, loop: true, }) } else { gameState.player2fallDownCaller = this.time.addEvent({ delay: 10, callback: gameState.fallDown, loop: true, }) } } gameState.collisionMethod = (player) => { if (player === "player1") { gameState.player1Dead = true; if ((gameState.player1Dead && gameState.player2Dead) || !gameState.secondPlayerSpawned) { gameState.gameOverMethod(); } gameState.fallDownCaller(player); } else { gameState.player2Dead = true; if (gameState.player1Dead && gameState.player2Dead) { gameState.gameOverMethod(); } gameState.fallDownCaller(player); } } // Colliders gameState.player1.setCollideWorldBounds(true); this.physics.add.collider(gameState.player1, gameState.ground, () => { gameState.dieSound.play(); gameState.collisionMethod("player1") }); this.physics.add.collider(gameState.player1, gameState.pipes, () => { gameState.hitSound.play(); gameState.collisionMethod("player1"); }); // Initialize input keys gameState.cursors = this.input.keyboard.createCursorKeys(); const pipeGen = this.time.addEvent({ callback: addRowOfPipes, delay: 1500, callbackScope: this, loop: true, }) // Animation const animateBird = () => { gameState.player1AnimationStage++; if (gameState.player1AnimationStage > 2) gameState.player1AnimationStage = 0; if (gameState.secondPlayerSpawned) { gameState.player2AnimationStage++; if (gameState.player2AnimationStage > 2) gameState.player2AnimationStage = 0; } gameState.player1.setTexture(gameState.player1SpriteSheet[gameState.player1AnimationStage]); if (gameState.secondPlayerSpawned) gameState.player2.setTexture(gameState.player2SpriteSheet[gameState.player2AnimationStage]); } const birdAnimation = this.time.addEvent({ callback: animateBird, delay: 100, callbackScope: this, loop: true, }) } function update() { if (!gameState.gameOver) { gameState.bgTile.tilePositionX += 0.1; gameState.groundTile.tilePositionX += 1; } // Press spacebar to fly up if (gameState.cursors.space.isDown) { if (gameState.gameOver) { this.scene.restart(); } else { gameState.wingSound.play(); gameState.player1.setVelocityY(-350); } } const spawnSecondPlayer = () => { gameState.secondPlayerSpawned = true; gameState.player2 = this.physics.add.sprite(100, gameState.player2Y, "player2_midflap").setScale(2); gameState.player2.body.acceleration.y = 1500; gameState.player2.setCollideWorldBounds(true); this.physics.add.collider(gameState.player2, gameState.ground, () => { gameState.dieSound.play(); gameState.collisionMethod("player2") }); this.physics.add.collider(gameState.player2, gameState.pipes, () => { gameState.hitSound.play(); gameState.collisionMethod("player2"); }); } if (!gameState.secondPlayerSpawned) { if (gameState.cursors.shift.isDown) { spawnSecondPlayer(); } } else { if (gameState.cursors.shift.isDown) { if (gameState.gameOver) { this.scene.restart(); } else { gameState.player2.setVelocityY(-350); } } } }
回答
最大3人のプレーヤーに機能を追加したい場合はどうしますか?
あなた「「player3AnimationStage、player3SpriteSheetなど」を作成する必要があります。これも「gameState」内にあります。これは間違いなく理にかなっていますが、それでも独自のクラスに分離できます。
例:
class Player { constructor(spriteSheet, animationStage) { this.SpriteSheet = spriteSheet; this.AnimationStage = animationStage; } } const gameState = { player1: new Player(...); player2: new Player(...);
さらに良いことに、プレーヤーの配列があります。プレーヤーの数が問題にならないように、ゲームをコーディングしてみてください。 (たとえば、プレーヤーのリストを繰り返し処理します。)
色をENUM、またはスコア、colorName、colorCodeのクラスにすることができます。
いくつかの変数を宣言することをお勧めします。上部にある、メンテナンスを容易にするため。キーdiv要素(hiScoreTable)(または要素のIDのみ)など。画像。
名前付き変数を使用して、「maigc番号」を回避するようにしてください。たとえば、ここでの「17」とは何ですか?:
for (let i = 0; i < 17; i++)
「magicNumbers」を回避すると、コードの重複が減り、メンテナンスが簡単になります。たとえば、プレーヤーの速度を上げるため現在、少なくとも2か所で変更する必要があります。
回答
このコードは、キーワードlet
と
。一部の関数は少し長めであるため、それらは潜在的に小さな関数に分割される可能性があります。 this.load.image
のような関数への繰り返しの呼び出しは、事前定義された配列が設定されている場合、配列のループで実行できます。
要素参照の使用を検討しましたか、前の質問に対するブラインドマンの回答純粋なJSのTipCalculator ?
メソッドgameState.collisionMethod()
には、どちらの場合も条件付きブロックの外側にプルできる行があります:gameState.fallDownCaller(player);
メソッドgameState.fallDownCaller()
で、this.time.adddEvent()
に渡されるオブジェクトは同じであり、上の1つの場所で宣言できます(または別の機能)。
displayMedal()
でswitch
ステートメントを使用する代わりに、色名を16進値にマッピングできます。利用される。
例:
const colorToHexMap = { bronze: "#cd7f32", silver: "#c0c0c0", gold: "#ccac00", };
次に、 aので使用します>演算子:
if (color in colorToHexMap) { medalColor = colorToHexMap[color]; }