0
\$\begingroup\$

I've drawn a Health Bar before and had it drain/refill on a button press using if statements and rectangles.

First I loaded the image, then I set a new rectangle to be equal to the image's height and width.

        greenHealth = Content.Load<Texture2D>("GreenHealth");
        redHealth = Content.Load<Texture2D>("RedHealth");
        blackHealth = Content.Load<Texture2D>("BlackHealth");
        jumpGuy = Content.Load<Texture2D>("JumpGuy");
        enemyBlock = Content.Load<Texture2D>("Block");

        greenRectangle = new Rectangle(0, 0, greenHealth.Width, greenHealth.Height);
        redRectangle = new Rectangle(0, 0, redHealth.Width, redHealth.Height);
        blackRectangle = new Rectangle(0, 0, blackHealth.Width + 5, blackHealth.Height + 5);

Then I set it to drain/refill based on key presses -

  public void healthDrain()
    {

        if (Keyboard.GetState().IsKeyDown(Keys.Space))
        {
            greenRectangle.Width -= 2;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.Space))
        {
            redRectangle.Width -= 1;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.L))
        {
            redRectangle.Width = greenRectangle.Width;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.R))
        {
            greenRectangle.Width += 1;
        }

        if (greenRectangle.Width > blackRectangle.Width - 4)
        {
            greenRectangle.Width = blackRectangle.Width - 4;
        }

    }

The Result is a Health Bar that can be drained/refilled -

enter image description here

The problem arises when I want the health to drain/refill based on the Player Health, which I set to 100. I do not know how to properly implement this and attempts at it have resulted in it functioning incorrectly, like the health draining on its own, or not moving at all.

I intend to have the player take damage when in contact with the yellowish-green block in the image. I did this using rectangles and an if statement with rectangle.Intersect.

        if (jumpRect.Intersects(enemyRectangle))
        {

            playerHealth--;


        }

I tried having the health bar's width be equal to the playerHealth value but it didn't work and I'm unsure of how to make it work correctly.

I do hope I was able to make this easy for someone to help me solve.

\$\endgroup\$
  • 1
    \$\begingroup\$ This appears to be more of a "What's wrong with my code?" than a "How do I implement X?" question. \$\endgroup\$ – MichaelHouse Oct 3 '13 at 2:59
  • 1
    \$\begingroup\$ Does this mean my question is invalid? I do not know how to implement this. \$\endgroup\$ – Slateboard Oct 3 '13 at 3:16
  • \$\begingroup\$ It just means it could use some rewording. This is primarily a debugging issue, not an algorithm issue. Perhaps you can ask the question in chat instead. That's a better place for code discussions. \$\endgroup\$ – MichaelHouse Oct 3 '13 at 3:52
  • \$\begingroup\$ I suggest breaking the problem down. Make sure the visuals are working well and make sure the drain/refill values are working well. Step through with a debugger, check to ensure the values are getting set the way you expect. \$\endgroup\$ – MichaelHouse Oct 3 '13 at 4:18
2
\$\begingroup\$

I'd rather implement any rolling value (such as the health example) with two values that with with the health bars width. I'd call them something like:

int actualHealth;
int visibleHealth;

In the beginning you can set both to the same value:

public ResetHealth(int health) {
    actualHealth = visibleHealth = health;
}

And when you want to do a "hit" on the value you only change the "actual" value.

public Hit(int damage) {
    actualHealth -= damage;
}

In your update method you also should update the "visible" value to go toward the "actual" value. The effect will be that the value is decreasing over time until it hits the actual value.

// in your update code:
if (actualHealth < visibleHealth) {
    visibleHealth -= 1;
}
else if (actualHealth != visibleHealth) {
   // Make sure we don't go over
   visibleHealth = actualHealth;
}

In your render method you only need to do one thing. Draw the bar according to the visibleHealth value, while in your game logic you only look at the actualHealth. In your case the green health bar's width is based on actualHealth and the red bar's width is based on visibleHealth. In your case it'll be something like this:

int fullWidth = // the full width of the bar ;
greenHealthBar.Width = (actualHealth / 100) * fullWidth;
redHealthBar.Width = (visibleHealth / 100) * fullWidth;

If you're wondering how this calculation works, you can do the following thought experiment:

// health:   0 => (0 / 100) * fullWidth   = 0    * fullWidth = 0
// health:  25 => (25 / 100) * fullWidth  = 0.25 * fullWidth
// health:  50 => (50 / 100) * fullWidth  = 0.5  * fullWidth
// health:  75 => (75 / 100) * fullWidth  = 0.75 * fullWidth 
// health: 100 => (100 / 100) * fullWidth = 1    * fullWidth = fullWidth
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.