Sign in to follow this  
anthkris

How to Deduct Player Lives

Recommended Posts

I'm creating an infinite scroller and (among other things) I'm having trouble with deducting player lives. I've looked at various tutorials, but most of them seem to kill the player whenever they hit an obstacle. Ideally, I'd like to deduct a life from the player until they have no more lives.

The problem I'm experiencing is that I'm checking overlap with the player and a pool of enemies (btw, works the same way if I check for collision). In the callback, I only want to deduct a life the first time the player comes in contact with the enemy. What's happening now is that a single contact will destroy all the hearts.

I've tried using a counter, but that doesn't seem to work well as any attempt to reset it seems to be happening too quickly. I've also tried to use signals, but they seem to result in the same behavior as using the callback.

The code looks like this:

// In update
this.game.physics.arcade.overlap(this.player, this.enemiesPool, this.hurtPlayer, null, this);

// Callback
 hurtPlayer: function(player, enemy) {
    console.log(this.hitCounter);
    //do this during overlap
    this.isHit = true;
    this.canShoot = false
    enemy.play('attacking');
    player.play('hit');
    //only destroy a heart the first time you contact the enemy
    //enemy should detract 1 heart at most
    // if (this.hitCounter <= 0) {
    //   this.destroyHeart();
    // }
    // this.hitCounter++;
    this.destroyHeart();
    //enemy.kill();
  },

//Destroy heart
destroyHeart: function() {
    console.log(this.myLives);
    switch(this.myLives) {
      case 4:
        this.life4.destroy();
        break;
      case 3:
        this.life3.destroy();
        break;
      case 2:
        this.life2.destroy();
        break;
      case 1:
        this.life1.destroy();
        break;
    }
    this.myLives--;
  },

Any suggestions?

Share this post


Link to post
Share on other sites

Hi!

Try this:

Create 4 lives (three hearts and the player):

Declare variables:

this.livesCounter = 4;
this.lives = null;

On create function:

//  Lives
this.lives = this.add.group();
var x = 100; // use your values
var y = 100;

for (var i = 0; i < 3; i++) {
  var yourSprite = this.lives.create(
    x - 100 + 30 * i,
    y,
    'sprite'
  );
  yourSprite.anchor.setTo(0.5, 0.5);
}

Callback:

// Callback
hurtPlayer: function(player, enemy) {
    console.log(this.hitCounter);
//do this during overlap
    this.isHit = true;
    this.canShoot = false;
    enemy.play('attacking');
    player.play('hit');
    var live;
    live = this.lives.getFirstAlive();

    if (live) {
        live.kill();
    }
    this.livesCounter--;

    if (this.livesCounter == 0) {
        player.kill();
        this.playerDies(); // Use your custom function when the player dies
    }
},

I hope it helps!!!

 

 

Share this post


Link to post
Share on other sites

@FinalFantasyVII That still runs every collision though right? Isn't the problem actually that the collision handler fires for every collision, hence it'll fire every tick and given that the overlap is probably present for 4 ticks it takes only 4 ticks to reduce lives to 0? no?

@anthkris I think, conceptually at least, that there are a couple of potential solutions if indeed the problem is that the collision handler fires all the time:

* The simplest is probably to implement what is often called a shield, this could even be a real shield your users can see. The idea is that when your player is 'hurt' (loses a life) that they have a grace shielded period of time where they are impervious to all damage, something like a few seconds should give the user a chance to get clear of the obstacle if they can, having a visual representation of a shield can be good feedback to the user. This is pretty easy to implement, when a collision occurs keep track of the time, if another collision occurs in a set timeframe (say, a few seconds) then ignore the collision (or, at least, ignore the killing bit) and keep the time counter where it is, when a collision occurs outside of your set timeframe then reduce a life and update the time counter again. You'd have to have another mechanism for removing the shield after a set time period, a cheap simple way is to just use a timeout, this could even simplify your collision check as you just set a flag when a 'killing' collision happens and any subsequent collisions when this flag are set are ignored, after the timeout completes it flips the flag again and the death game is back on.

* Rather than a timeout you could set some sort of counter on your player object that increases each frame until a set limit, this might be useful if you plan on changing the colour of a shield or doing something else with it. When it hits a certain limit you destroy the shield.

* Keep track of the enemy you collided with and ignore any further collisions with that enemy. For stuff like bullets, which are short lived and fast moving, this is a cheap and easy solution. For long lived enemies you'll be invincible till the end of time to that enemy, which might be undesirable, which might necessitate a timer, in which case you may as well plump for either of the 2 solutions above.

* There may be a collisionEnter event of some kind, that fires the first time a collision occurs, similar to onMouseEnter vs onHover. If so this is awesome because you can use this event to perform the 'killing/hurt'. I think I'd still prefer a shield for playability reasons, but thats up to you and your game.

* Hurt the player and destroy the enemy, thus removing the collision from the next frame. Super easy to do, might not work with your gameplay though.

Share this post


Link to post
Share on other sites

Thanks so much for the suggestion @FinalFantasyVII!

@mattstyles Thanks for the list of options! I did see one tutorial where a shield, as you described it, or ghosting as the tutorial described it was implemented. That may be the best of all possible worlds. I had previously tried killing the enemy on impact and it worked, but it doesn't mesh with the game, I think. I'll also look into a collisionEnter. I'll report back if I hit another obstacle.

Share this post


Link to post
Share on other sites

I did think of another way, which is just moving the player to a safe location, to be honest I think this is actually more difficult as you'd generally want to move the player to the same location and that location might not be available right away so you might have to wait for it become available and that could take a long time if your game has many enemies swarming that part of the screen (or there is an obstacle of some sort). Again, this might work terribly with your game from a gameplay point of view anyway.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.