Flappy Bird game supporting local multiplayer of up to 2 playersGarbage collection in JavaScript multiplayer...

How much RAM could one put in a typical 80386 setup?

How to format long polynomial?

Why can't I see bouncing of a switch on an oscilloscope?

How to draw a waving flag in TikZ

How old can references or sources in a thesis be?

Why are electrically insulating heatsinks so rare? Is it just cost?

Can I make popcorn with any corn?

Unknown notation: What do three bars mean?

The Clique vs. Independent Set Problem

How to know the difference between two ciphertexts without key stream in stream ciphers

Why does Kotter return in Welcome Back Kotter?

How is the claim "I am in New York only if I am in America" the same as "If I am in New York, then I am in America?

Test whether all array elements are factors of a number

Approximately how much travel time was saved by the opening of the Suez Canal in 1869?

How to add double frame in tcolorbox?

Compress a signal by storing signal diff instead of actual samples - is there such a thing?

Is it important to consider tone, melody, and musical form while writing a song?

Writing rule stating superpower from different root cause is bad writing

What do the dots in this tr command do: tr .............A-Z A-ZA-Z <<< "JVPQBOV" (with 13 dots)

a relationship between local compactness and closure

Watching something be written to a file live with tail

Schoenfled Residua test shows proportionality hazard assumptions holds but Kaplan-Meier plots intersect

What is the offset in a seaplane's hull?

I'm planning on buying a laser printer but concerned about the life cycle of toner in the machine



Flappy Bird game supporting local multiplayer of up to 2 players


Garbage collection in JavaScript multiplayer gameGame Networking between 2 playersMultiplayer blackjack gameGame prototype with methods to manage playersYet another flappy bird cloneSimple arcade game where you just move the character aroundCard based computer gameNoughts and crosses game for 2 playersReinforcement Learning for Flappy Bird in JavaScriptSimple Flappy Bird Clone using Kivy (with very minimum physics)






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







3












$begingroup$


The game is hosted here.



GitHub repo



This is my first Phaser 3 game/project and I'm still pretty new to Javascript so I'm sure there are many things I could be doing better. The number 1 thing that I would like to improve about my code is the performance. Then code effectiveness and readability, but performance is priority.



Your feedback is valuable even if you have no experience with PhaserJS whatsoever, because a lot of things that I could probably be doing better only have to do with pure Javascript.



My JS code:



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);
}

}
}

}









share|improve this question









$endgroup$



















    3












    $begingroup$


    The game is hosted here.



    GitHub repo



    This is my first Phaser 3 game/project and I'm still pretty new to Javascript so I'm sure there are many things I could be doing better. The number 1 thing that I would like to improve about my code is the performance. Then code effectiveness and readability, but performance is priority.



    Your feedback is valuable even if you have no experience with PhaserJS whatsoever, because a lot of things that I could probably be doing better only have to do with pure Javascript.



    My JS code:



    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);
    }

    }
    }

    }









    share|improve this question









    $endgroup$















      3












      3








      3





      $begingroup$


      The game is hosted here.



      GitHub repo



      This is my first Phaser 3 game/project and I'm still pretty new to Javascript so I'm sure there are many things I could be doing better. The number 1 thing that I would like to improve about my code is the performance. Then code effectiveness and readability, but performance is priority.



      Your feedback is valuable even if you have no experience with PhaserJS whatsoever, because a lot of things that I could probably be doing better only have to do with pure Javascript.



      My JS code:



      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);
      }

      }
      }

      }









      share|improve this question









      $endgroup$




      The game is hosted here.



      GitHub repo



      This is my first Phaser 3 game/project and I'm still pretty new to Javascript so I'm sure there are many things I could be doing better. The number 1 thing that I would like to improve about my code is the performance. Then code effectiveness and readability, but performance is priority.



      Your feedback is valuable even if you have no experience with PhaserJS whatsoever, because a lot of things that I could probably be doing better only have to do with pure Javascript.



      My JS code:



      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);
      }

      }
      }

      }






      javascript game ecmascript-6 phaser.io






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Mar 29 at 9:18









      merkur0merkur0

      353




      353






















          1 Answer
          1






          active

          oldest

          votes


















          4












          $begingroup$

          What if you want to add the functionality for up to 3 players?



          You'd have to create a 'player3AnimationStage, player3SpriteSheet etc. It's also inside the 'gameState', which arguably makes sense, but still could be separated into it's own class.



          For example:



          class Player
          {
          constructor(spriteSheet, animationStage)
          {
          this.SpriteSheet = spriteSheet;
          this.AnimationStage = animationStage;
          }
          }

          const gameState = {
          player1: new Player(...);
          player2: new Player(...);


          Or better yet, have an array of Players. Try to code your game so that it does not matter how many players there are. (E.g iterate through the list of players).



          Your colours could be made into an ENUM, or a class with score, colorName, colorCode.



          I'd suggest declaring some variables at the top, to make maintenance easier.
          Such as key div elements (hiScoreTable). (Or even just the ids of the elements).
          Images.



          Try to avoid 'maigc numbers' by using named variables. For example, what is '17' here?:



          for (let i = 0; i < 17; i++) 


          Avoiding 'magicNumbers' also decreases code duplication and makes maintenance easier. For example, to increase player speed currently we'd have to change it in at least 2 places.






          share|improve this answer









          $endgroup$














            Your Answer





            StackExchange.ifUsing("editor", function () {
            return StackExchange.using("mathjaxEditing", function () {
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            });
            });
            }, "mathjax-editing");

            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "196"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: false,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216462%2fflappy-bird-game-supporting-local-multiplayer-of-up-to-2-players%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            4












            $begingroup$

            What if you want to add the functionality for up to 3 players?



            You'd have to create a 'player3AnimationStage, player3SpriteSheet etc. It's also inside the 'gameState', which arguably makes sense, but still could be separated into it's own class.



            For example:



            class Player
            {
            constructor(spriteSheet, animationStage)
            {
            this.SpriteSheet = spriteSheet;
            this.AnimationStage = animationStage;
            }
            }

            const gameState = {
            player1: new Player(...);
            player2: new Player(...);


            Or better yet, have an array of Players. Try to code your game so that it does not matter how many players there are. (E.g iterate through the list of players).



            Your colours could be made into an ENUM, or a class with score, colorName, colorCode.



            I'd suggest declaring some variables at the top, to make maintenance easier.
            Such as key div elements (hiScoreTable). (Or even just the ids of the elements).
            Images.



            Try to avoid 'maigc numbers' by using named variables. For example, what is '17' here?:



            for (let i = 0; i < 17; i++) 


            Avoiding 'magicNumbers' also decreases code duplication and makes maintenance easier. For example, to increase player speed currently we'd have to change it in at least 2 places.






            share|improve this answer









            $endgroup$


















              4












              $begingroup$

              What if you want to add the functionality for up to 3 players?



              You'd have to create a 'player3AnimationStage, player3SpriteSheet etc. It's also inside the 'gameState', which arguably makes sense, but still could be separated into it's own class.



              For example:



              class Player
              {
              constructor(spriteSheet, animationStage)
              {
              this.SpriteSheet = spriteSheet;
              this.AnimationStage = animationStage;
              }
              }

              const gameState = {
              player1: new Player(...);
              player2: new Player(...);


              Or better yet, have an array of Players. Try to code your game so that it does not matter how many players there are. (E.g iterate through the list of players).



              Your colours could be made into an ENUM, or a class with score, colorName, colorCode.



              I'd suggest declaring some variables at the top, to make maintenance easier.
              Such as key div elements (hiScoreTable). (Or even just the ids of the elements).
              Images.



              Try to avoid 'maigc numbers' by using named variables. For example, what is '17' here?:



              for (let i = 0; i < 17; i++) 


              Avoiding 'magicNumbers' also decreases code duplication and makes maintenance easier. For example, to increase player speed currently we'd have to change it in at least 2 places.






              share|improve this answer









              $endgroup$
















                4












                4








                4





                $begingroup$

                What if you want to add the functionality for up to 3 players?



                You'd have to create a 'player3AnimationStage, player3SpriteSheet etc. It's also inside the 'gameState', which arguably makes sense, but still could be separated into it's own class.



                For example:



                class Player
                {
                constructor(spriteSheet, animationStage)
                {
                this.SpriteSheet = spriteSheet;
                this.AnimationStage = animationStage;
                }
                }

                const gameState = {
                player1: new Player(...);
                player2: new Player(...);


                Or better yet, have an array of Players. Try to code your game so that it does not matter how many players there are. (E.g iterate through the list of players).



                Your colours could be made into an ENUM, or a class with score, colorName, colorCode.



                I'd suggest declaring some variables at the top, to make maintenance easier.
                Such as key div elements (hiScoreTable). (Or even just the ids of the elements).
                Images.



                Try to avoid 'maigc numbers' by using named variables. For example, what is '17' here?:



                for (let i = 0; i < 17; i++) 


                Avoiding 'magicNumbers' also decreases code duplication and makes maintenance easier. For example, to increase player speed currently we'd have to change it in at least 2 places.






                share|improve this answer









                $endgroup$



                What if you want to add the functionality for up to 3 players?



                You'd have to create a 'player3AnimationStage, player3SpriteSheet etc. It's also inside the 'gameState', which arguably makes sense, but still could be separated into it's own class.



                For example:



                class Player
                {
                constructor(spriteSheet, animationStage)
                {
                this.SpriteSheet = spriteSheet;
                this.AnimationStage = animationStage;
                }
                }

                const gameState = {
                player1: new Player(...);
                player2: new Player(...);


                Or better yet, have an array of Players. Try to code your game so that it does not matter how many players there are. (E.g iterate through the list of players).



                Your colours could be made into an ENUM, or a class with score, colorName, colorCode.



                I'd suggest declaring some variables at the top, to make maintenance easier.
                Such as key div elements (hiScoreTable). (Or even just the ids of the elements).
                Images.



                Try to avoid 'maigc numbers' by using named variables. For example, what is '17' here?:



                for (let i = 0; i < 17; i++) 


                Avoiding 'magicNumbers' also decreases code duplication and makes maintenance easier. For example, to increase player speed currently we'd have to change it in at least 2 places.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Mar 29 at 17:17









                dustytrashdustytrash

                2066




                2066






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Code Review Stack Exchange!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    Use MathJax to format equations. MathJax reference.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216462%2fflappy-bird-game-supporting-local-multiplayer-of-up-to-2-players%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    is 'sed' thread safeWhat should someone know about using Python scripts in the shell?Nexenta bash script uses...

                    How do i solve the “ No module named 'mlxtend' ” issue on Jupyter?

                    Pilgersdorf Inhaltsverzeichnis Geografie | Geschichte | Bevölkerungsentwicklung | Politik | Kultur...