javascriptphaser-framework

Creating A Bullet Sprite At Players Sprite Location In Phaser But The Sprite Wont Be Created / Added To The Game


This is a game where the monkey moves around the platforms collecting coins. I want to have the monkey shoot a banana when the down arrow and left arrow are pressed.

How would I create the bullet?

I have the keypress for the shooting and it calls shootR or shootL depending on which arrow is pressed. What I need is to create the projectile and have it move to the right or left(not affected by gravity). Can I get some help creating this projectile as var proj = projs.create(x, y, 'proj'); is not working.

var config = {
  type: Phaser.AUTO,
  width: 1900,
  height: 1000,
  physics: {
    default: 'arcade',
    arcade: {
      gravity: { y: 300 },
      debug: false
    }
  },
  scene: {
    preload: preload,
    create: create,
    update: update
  }
};
var main = document.getElementById("startBtn")
var heading = document.getElementById("header")
var gameOver
var platforms;
var score = 0;
var scoreText;
var leafAm = 0
var leafText
var gunAm = 0
var ammoAm = 0
var ammoText
var monkeyType = "monkey"
var delay = 0


function start() {
  game = new Phaser.Game(config);
  main.innerHTML = ''
  heading.innerHTML += '<h1 class="header2" onclick="shop()"><u>Click To Access Shop</u></h1>'
}

function preload() {
  this.load.image('Background', 'assets/Background.jpg');
  this.load.image('ground', 'assets/platform.png');
  this.load.image('coin', 'assets/coin.png');
  this.load.image('redCoin', 'assets/redCoin.png');
  this.load.spritesheet('monkey', 'assets/monkey.png', { frameWidth: 600, frameHeight: 720 });
  this.load.spritesheet('proj', 'assets/bullet.png', { frameWidth: 200, frameHeight: 200 });
}

function create() {
  this.add.image(500, 275, 'Background').setScale(3);
  platforms = this.physics.add.staticGroup();
  platforms.create(200, 650, 'ground').setScale(0.15).refreshBody();
  platforms.create(600, 400, 'ground').setScale(0.15).refreshBody();
  platforms.create(1600, 650, 'ground').setScale(0.15).refreshBody();
  platforms.create(750, 100, 'ground').setScale(0.15).refreshBody();
  platforms.create(850, 750, 'ground').setScale(0.15).refreshBody();
  platforms.create(100, 950, 'ground').setScale(0.15).refreshBody();
  platforms.create(400, 950, 'ground').setScale(0.15).refreshBody();
  platforms.create(700, 950, 'ground').setScale(0.15).refreshBody();
  platforms.create(1000, 950, 'ground').setScale(0.15).refreshBody();
  platforms.create(1300, 950, 'ground').setScale(0.15).refreshBody();
  platforms.create(1600, 950, 'ground').setScale(0.15).refreshBody();
  platforms.create(1900, 950, 'ground').setScale(0.15).refreshBody();
  platforms.create(1800, 800, 'ground').setScale(0.15).refreshBody();
  platforms.create(250, 250, 'ground').setScale(0.15).refreshBody();
  platforms.create(1000, 500, 'ground').setScale(0.15).refreshBody();
  platforms.create(1150, 220, 'ground').setScale(0.15).refreshBody();
  player = this.physics.add.sprite(100, 450, 'monkey').setScale(0.075);
  this.physics.add.collider(player, platforms);
  player.setBounce(0.2);
  player.setCollideWorldBounds(true);
  this.anims.create({
    key: 'left',
    frames: this.anims.generateFrameNumbers('monkey', { start: 0, end: 3 }),
    frameRate: 10,
    repeat: -1
  });
  this.anims.create({
    key: 'turn',
    frames: [{ key: 'monkey', frame: 4 }],
    frameRate: 20
  });
  this.anims.create({
    key: 'right',
    frames: this.anims.generateFrameNumbers('monkey', { start: 5, end: 8 }),
    frameRate: 10,
    repeat: -1
  });
  this.anims.create({
    key: 'shoot',
    frames: this.anims.generateFrameNumbers('proj', { start: 0, end: 3 }),
    framerate: 15,
    repeat: -1
  })
  coins = this.physics.add.group({
    key: 'coin',
    repeat: 10,
    setXY: { x: 12, y: 0, stepX: 150 }
  });
  coins.children.iterate(function (child) {
    child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
    child.setScale(0.05)
  });
  this.physics.add.collider(coins, platforms);
  this.physics.add.overlap(player, coins, collectCoin, null, this);
  redCoins = this.physics.add.group();
  this.physics.add.collider(redCoins, platforms);
  this.physics.add.collider(player, redCoins, hitredCoin, null, this);
  projs = this.physics.add.group()
  this.physics.add.collider(projs, platforms)
  this.physics.add.collider(projs, redCoins, shootredCoin, null, this)
  scoreText = this.add.text(16, 16, 'Score: 0₴', { fontSize: '40px', fill: 'rgb(85, 1, 1)' });
  ammoText = this.add.text(16, 66, 'Ammo: 0🍌', { fontSize: '40px', fill: 'rgb(85, 1, 1)' });
  leafText = this.add.text(16, 116, 'Shields: 0🍃', { fontSize: '40px', fill: 'rgb(85, 1, 1)' });
}

function update() {
  cursors = this.input.keyboard.createCursorKeys();
  if (cursors.down.isDown && cursors.left.isDown && delay == 0) {
    shootL()
  } else if (cursors.down.isDown && cursors.right.isDown && delay == 0) {
    shootR()
  }
  if (cursors.left.isDown) {
    player.setVelocityX(-240);
    player.anims.play('left', true);
  }
  else if (cursors.right.isDown) {
    player.setVelocityX(240);
    player.anims.play('right', true);
  }
  else {
    player.setVelocityX(0);
    player.anims.play('turn');
  }
  if (cursors.up.isDown && player.body.touching.down) {
    player.setVelocityY(-330);
  }
}

function collectCoin(player, coin) {
  coin.disableBody(true, true);
  score += 1;
  scoreText.setText('Score: ' + score + '₴');
  if (coins.countActive(true) === 0) {
    coins.children.iterate(function (child) {
      child.enableBody(true, child.x, 0, true, true);
    });
    var x = Phaser.Math.Between(0, 800);
    var redCoin = redCoins.create(x, 16, 'redCoin').setScale(0.05);
    redCoin.setBounce(1);
    redCoin.setCollideWorldBounds(true);
    redCoin.setVelocity(Phaser.Math.Between(-300, 300), 20);
  }
}

function shootR(player, redCoin, proj) {
  var x = player.x
  var y = player.y
  
  var proj = projs.create(x, y, 'proj');

  // proj.setVelocityX(-240);
  // player.anims.play('shoot', true);
  ammoAm -= 1
  ammoText.setText('Ammo: ' + ammoAm + '🍌');
  delay = 1
  this.time.delayedCall(3000, delayer, null, this);
}

function shootL(player, redCoin, proj) {
  var x = player.x
  var y = player.y

  var proj = projs.create(x, y, 'proj');

  ammoAm -= 1
  ammoText.setText('Ammo: ' + ammoAm + '🍌');
  delay = 1
  this.time.delayedCall(3000, delayer, null, this);
}

function hitredCoin(player, redCoin) {
  if (leafAm > 0) {
    leafAm -= 1
    leafText.setText('Shields: ' + leafAm + '🍃');
    redCoin.disableBody(true, true);
    var x = Phaser.Math.Between(0, 800);
    var redCoin = redCoins.create(x, 16, 'redCoin').setScale(0.05);
    redCoin.setBounce(1);
    redCoin.setCollideWorldBounds(true);
    redCoin.setVelocity(Phaser.Math.Between(-300, 300), 20);
  } else {
    this.physics.pause();
    player.setTint(0xff0000);
    player.anims.play('turn');
    gameOver = true;
    this.time.delayedCall(3000, restart, null, this);
  }
}

function shootredCoin(projs, redCoin) {
  redCoin.disableBody(true, true);
  projs.disableBody(true, true);
}

function restart() {
  score = 0
  var leafAm = 0
  var gunAm = 0
  var ammoAm = 0
  this.scene.stop();
  this.scene.start();
}

function shop() {
  main.innerHTML = `<button class="shopBackground"></button>`
  main.innerHTML += `<button class="shop1">Shop</button>`
  main.innerHTML += `<button class="shop2">Warning: Shop Fast, you can still die</button>`
  main.innerHTML += `<button class="shop3" onclick = "buy1()">Banana Gun...₴100.00<br>(Ability to shoot bananas)<br>click here to buy</button>`
  main.innerHTML += `<button class="shop4" onclick = "buy2()">Leaf Shield...₴30.00<br>(Protection from 1 hit)<br>click here to buy</button>`
  main.innerHTML += `<button class="shop5" onclick = "buy3()">Bananas...₴10.00<br>(Extra ammo, gun comes with 1)<br>click here to buy</button>`
  main.innerHTML += `<button class="shop6">₴ is score</button>`
  main.innerHTML += `<button class="shop7" onclick="main.innerHTML = ''">Back To Game</button>`
  main.innerHTML += `<img src="/assets/banana1.png" class="banana1">`
  main.innerHTML += `<img src="/assets/banana2.png" class="banana2">`
  main.innerHTML += `<img src="/assets/leaf.png" class="leaf">`
}

function buy1() {
  if (score > 99 && gunAm < 1) {
    gunAm += 1
    ammoAm += 1
    score -= 100
    scoreText.setText('Score: ' + score + '₴');
    alert("You have bought a gun \nClick the down arrow and either left or right to shoot\nShooting costs ammo but bullets detroy the red orbs\nEnjoy and good luck")
  } else if (gunAm > 0) {
    alert("You already have one")
  } else {
    alert("Not enough score")
  }
}

function buy2() {
  if (score > 29) {
    leafAm += 1
    score -= 30
    scoreText.setText('Score: ' + score + '₴');
    leafText.setText('Shields: ' + leafAm + '🍃');
  } else {
    alert("Not enough score")
  }
}

function buy3() {
  if (score > 9) {
    ammoAm += 1
    score -= 10
    scoreText.setText('Score: ' + score + '₴');
    ammoText.setText('Ammo: ' + ammoAm + '🍌');
    ;
  } else {
    alert("Not enough score")
  }
}

function delayer() {
  delay = 0
}

There is also some HTML and CSS but those parts aren't affecting it or at least they shouldn't be


Solution

  • There are somethings to unpack here,

    function definitions:

        function shootR(player, redCoin, proj) 
        ...
    

    functions being called:

        ...
        if (cursors.down.isDown && cursors.left.isDown && delay == 0) {
            shootL()
        } else if (cursors.down.isDown && cursors.right.isDown && delay == 0) {
            shootR()
        }
        ...
    

    Quick fix: pass the player parameter, example: shootR(player)

    Quick fix: Pass the scene to the function, example: shootR(this, player) and alter the functions to:

    function shootL(scene, player,  redCoin, proj) {
        var x = player.x
        var y = player.y
    
        var proj = projs.create(x, y, 'proj');
    
        ammoAm -= 1
        ammoText.setText('Ammo: ' + ammoAm + '🍌');
        delay = 1
        scene.time.delayedCall(3000, delayer, null, scene);
    }
    

    btw.: the code could be improved using classes and their properties, I would suggest looking at the phaser examples https://phaser.io/examples/v3/view/scenes/scene-from-class and/or https://phaser.io/examples/v3/view/scenes/scene-from-es6-class on how to use classes for scene, this could remove many problems. And you would not need to use global varibales or pass so many parameters.