How to make temporarily invincible player? [Solved]

Alright so I have a game where you try to dodge obstacles and stuff. Now whenever I have my player collide I want the player to be temporarily invincible. I have the collision set up already and that works perfectly, but its in a loop and so I have no idea how to go about making a method run only once and then stopping.

Here is where I check for collision:


	// Check for collision
		for (Obstacle obstacles : obstacleList) {
			obstacles.render();
			obstacles.update();

			if (obstacles.getCollision().overlaps(player.getCollision())
					&& obstacles.getAlive() == true && player.getTimedOut() == false) {
				currentLives--;
				obstacles.setDead();
				player.revive();
			}
		}

and this is the revive method in the player class:


public void revive(){
		
		timedOut = true;
		if(timedOut == true){
			reviveTime += 1;
			
			if(reviveTime >= 500){
				timedOut = false;
				reviveTime -= reviveTime;
			}
		}

I’m sorry if this question is even too simple for this sub-forum. I’m trying my best to learn as I go. Thank you for the help! ;D

a botch way since we cant see the rest of your code is setup a boolean hasColided; and if they have collided don’t allow your character to render

Invincible not invisible ;D

To stop a loop you use the keyword [icode]break;[/icode]

xD its 2AM for me :stuck_out_tongue:

Is this what you want? If a collision is found then stop checking but take a life and heal them?

for (Obstacle obstacles : obstacleList) {
         obstacles.render();
         obstacles.update();

         if (obstacles.getCollision().overlaps(player.getCollision())
               && obstacles.getAlive() == true && player.getTimedOut() == false) {
            currentLives--;
            obstacles.setDead();
            player.revive();
++        break;
         }
      }

What I want is when the player collides with the object, it becomes inactive for a while and then comes back to life and can collide again. I found a way to do this, but the while loop makes my game lag out when I collide:


for (Obstacle obstacles : obstacleList) {
obstacles.render();
obstacles.update();

		if (obstacles.getCollision().overlaps(player.getCollision())
				&& obstacles.getAlive() == true && player.getTimedOut() == false) {
			currentLives--;
			obstacles.setDead();
			
			player.setTimedOut();
			
			while(player.getTimedOut() == true){
				player.revive();
			}
		}
	}

and the revive method in the player class:


public void revive(){
			reviveTime += 1;
			System.out.println(reviveTime);
			if(reviveTime >= 10000){
				reviveTime -= reviveTime;
				System.out.println("Revived");
				timedOut = false;
				
				
			}
		}

Any idea on how to do this more efficiently, or not make the while loop lag out the game?

So does the object become inactive or the player?

The player, that is what the revive class is for! Once the reviveTime is greater than or equal to 10000, the player becomes active again.

You could do this:


for (Obstacle obstacles : obstacleList) {
         // Should always update before rendering, or your objects will be a frame behind
         obstacles.update();
         obstacles.render();

         // If we overlap and the obstacle is alive, we want to hurt the player, kill the obstacle and start a timer
         if (obstacles.getCollision().overlaps(player.getCollision())
               && obstacles.getAlive() == true && player.getTimedOut == false) {
            // Remove life as usual
            currentLives--;
            // Kill off the obstacle, this will now stop this statement from executing next loop iteration
            obstacles.setDead();
            
            // Set the timer
            player.setTimedOut();
            
            // If the player is in timeout mode, call revive
            }else if(player.getTimedOut()){
                // There is a problem with this and I will tell you below
                player.revive();
            }
         }
      }

However…this way is quite ineffective. The reason being is that the timing mechanism is dependent on the loop. Which is bad, like so.

You have 1001 obstacles, the player collides with the first one and the revive code starts getting called for the remaining 1000 iterations of the for loop. Now because of this:


reviveTime += 1;

This is going to go from 0 to 1000 almost instantaneously. Meaning the time out is non existent. Say you have 50 obstacles instead, the timeout will last longer.

This is inconsistent.

What I suggest you do is, set a flag inside the loop to indicate the player is dead and handle the reviving outside of the loop in the players update method. This will also allow you to clean up the for loop a little as well.

Like so:


for (Obstacle obstacles : obstacleList) {
         // Should always update before rendering, or your objects will be a frame behind
         obstacles.update();
         obstacles.render();

         // We know the player is dead and can not collide, why check the rest of the block? To the next obstacle we go!
         if(player.isDead() == true) continue;

         // We can remove the extra check for the timed out, the code will never reach this statement if the player is dead anyway
         // We can also have better flow control of the program here and remove nesting another if statement
         // If we don't overlap or the obstacle is dead, we just continue to the next obstacle, removing nested if statement
         if (obstacles.getCollision().overlaps(player.getCollision()) == false || obstacles.getAlive() == false) continue;

         // Remove life as usual
         currentLives--;
         // Kill off the obstacle, this will now stop this statement from executing next loop iteration
         obstacles.setDead();

         // Set that the player is dead, we can just remove the timedOut code all together, we don't need it.
         player.setDead(true);
            
         }
      }

Now in the players update method:



public void update(float delta){

    // If the player is dead, we want to call revive
    if(isDead())
        revive();

    // Rest of your player code here

}


And the changed revive call ofc! Because we now have a proper flag

public void revive(){

         // You might want to change this to a proper time, if you are say running the game at 60fps then this
         // would take 10000/60 = 166 frames/60 = 2.77 seconds to reach 10000. If you are using LibGDX use delta time
         // if not, use nanotime for now.
         reviveTime += 1;
         if(reviveTime >= 10000){
            // We are no longer dead! Reset the flag and the timing mechanism. This will hand control back to the first
            // if statement in the loop so we can start checking for collisions again, yay!
            setDead(false);
            reviveTime = 0;
            
         }
      }

This is how I would do it, if you are not quite sure what is happening with the continue keyword you can read more about it HERE and HERE.

However I will briefly explain what is happening:

Say you are walking happily down the street and you come to a busy cross road with no pedestrian crossing, in your mind you are doing this:


for(Check check : checks){
    if(check.isLeftClear() == true && check.isRightClear() == true){
       cross();
    }
}

Now in your mind you know that if both sides are clear, you cross and if not you wait and check again. However, you also know that if the left is not clear then it is not safe to cross, same goes for the right. So why do we have to check if both conditions are true when we can just check if one is false?

The answer lies with this:


for(Check check : checks){
    if(check.isLeftClear() == false || check.isRightClear() == false) continue;

    cross();
    
}

So what we are doing here is, if left is not clear, there is no point in checking the right so just go to the next check. If left is clear we then check the right, if right is not clear we continue. If both are clear we can then ignore the continue statement and move onto the rest of the block.

What benefit does this have? Well imagine you have a whole bunch of conditions in there that we don’t want to nest together (and we are not at a crossing with a pedestrian crossing, and it’s raining :frowning: ):


for(Check check : checks){
    // Follow the green cross code!
    if(check.isGreenManOn() == true){
        // Better double check anyway, some crazy ass drivers out there
        if(check.isLeftClear() == true && check.isRightClear() == true){
            // Make sure there is not a big dirty puddle in front of you
            if(check.isThereAPuddle() == true){
                stepToTheLeft();
            }else{
                cross();
            }
        }
    }
}

Now you can see how messy it gets rather quickly, look at all those nested checks. We can easily tidy this up like so:


for(Check check : checks){
    // Follow the green cross code!
    if(check.isGreenManOn() == false) continue;

    // Better double check anyway, some crazy ass drivers out there
    if(check.isLeftClear() == false || check.isRightClear() == false) continue;

    // Make sure there is not a big dirty puddle in front of you
    if(check.isThereAPuddle() == true){
        stepToTheLeft();
        // Now we can do some more flow control here, what if by the time we stepped left the lights changed
        // or a crazed driver is coming? We can continue to the next check before crossing, or don't. Your funeral.
        continue;
    }

     cross();
}

And to neaten things up even further, when checking boolean statements you can simply just do


bool isDead = true;

if(isDead)
    // Do something

You don’t have to explicetly state == true or == false with booleans, you can can call the functions/field directly and the program knows what to do. You can do !isDead to check for false:


for(Check check : checks){
    // Follow the green cross code!
    if(!check.isGreenManOn()) continue;

    // Better double check anyway, some crazy ass drivers out there
    if(!check.isLeftClear() || !check.isRightClear()) continue;

    // Make sure there is not a big dirty puddle in front of you
    if(check.isThereAPuddle()){
        stepToTheLeft();
        // Now we can do some more flow control here, what if by the time we stepped left the lights changed
        // or a crazed driver is coming? We can continue to the next check before crossing, or don't. Your funeral.
        continue;
    }

     cross();
}

I hope this has helped, not only with your problem but with general program flow lol. I enjoyed writing it, so someone might enjoy reading it :).

EDIT: You can also apply this in your revive code if you like:

public void revive(){

         // You might want to change this to a proper time, if you are say running the game at 60fps then this
         // would take 10000/60 = 166 frames/60 = 2.77 seconds to reach 10000. If you are using LibGDX use delta time
         // if not, use nanotime for now.
         reviveTime += 1;

         // The return keyword exits out of the "outermost" block of code, in this case it is the entire method. 
         if(reviveTime <= 10000) return;

         // We are no longer dead! Reset the flag and the timing mechanism. This will hand control back to the first
         // if statement in the loop so we can start checking for collisions again, yay!
         setDead(false);
         reviveTime = 0;
      }

Or you could do it this wait, to remove an extra line lol:

public void revive(){

         // The return keyword exits out of the "outermost" block of code, in this case it is the entire method. 
         if(reviveTime += 1 <= 10000) return;

         // We are no longer dead! Reset the flag and the timing mechanism. This will hand control back to the first
         // if statement in the loop so we can start checking for collisions again, yay!
         setDead(false);
         reviveTime = 0;
      }

And that is one big ass post, sorry lol.

Perfect, just what I wanted! Thank you!