게임은 여기 에서 호스팅됩니다. .

GitHub 저장소

이것은 저의 첫 Phaser 3 게임 / 프로젝트이며 아직 Javascript이므로 더 잘할 수있는 일이 많이있을 것입니다. 내 코드에서 가장 개선하고 싶은 것은 성능입니다. 그렇다면 코드의 효율성과 가독성이 가장 중요하지만 성능이 최우선입니다.

PhaserJS에 대한 경험이 없더라도 귀하의 의견은 소중합니다. , 내가 더 잘할 수있는 많은 일들이 순수 자바 스크립트와 관련이 있기 때문입니다.

내 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”내부에 있습니다. “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”를 피하면 코드 중복이 감소하고 유지 관리가 쉬워집니다. 예를 들어 플레이어 속도를 높이기 위해 현재 우리는 적어도 두 곳에서 그것을 변경해야합니다.

답변

이 코드는 키워드 letconst. 일부 기능은 약간 긴 편이므로 잠재적으로 더 작은 기능으로 분할 될 수 있습니다. this.load.image와 같은 함수에 대한 반복적 인 호출은 사전 정의 된 배열이 설정된 경우 배열에 대한 루프에서 수행 될 수 있습니다.


요소 참조 사용을 고려 했습니까? , 이전 질문에 대한 블라인드 맨의 답변 순수 JS의 팁 계산기 ?


gameState.collisionMethod() 메소드에는 두 경우 모두 조건부 블록 외부에서 가져올 수있는 행이 있습니다. gameState.fallDownCaller(player);


gameState.fallDownCaller() 메소드에서 this.time.adddEvent()에 전달 된 객체는 동일하며 위의 한 지점 (또는 별도의 기능).


displayMedal()에서 switch 문을 사용하는 대신 색상 이름을 16 진수 값으로 매핑하면 사용됩니다.

예 :

const colorToHexMap = { bronze: "#cd7f32", silver: "#c0c0c0", gold: "#ccac00", }; 

그런 다음 in 연산자 :

if (color in colorToHexMap) { medalColor = colorToHexMap[color]; } 

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다