This site requires JavaScript, please enable it in your browser!
Greenfoot back
84mu3lC3p4C7
84mu3lC3p4C7 wrote ...

2022/12/18

Changing health bar for just one actor

84mu3lC3p4C7 84mu3lC3p4C7

2022/12/18

#
Hey, I have a code, where when Bullet object touches Enemy object, it lowers it´s health, the health bar is constucted in EnemyHealthBar class. Enemy code:
public class Enemy extends Actor
{
    static int health = 300;
    protected void addedToWorld(World world) {
        getWorld().addObject(new EnemyHealthBar(), getX(), getY());
    }
    public void hit() {
        health -= 10;
    }
Bullet code:
import java.util.List;
public class Bullet extends Actor
{
    int chance;
    int mouseDirection;
    public Bullet(){
        setRotation(Player.mouseDirection);
    }
  
    public void act()
    {
        move(10);
        if (isTouching(Enemy.class)){
            chance = Greenfoot.getRandomNumber(10);
            if (chance == 5) getWorld().addObject(new Medkit(), getX(), getY());
            List<Enemy> enemys = getIntersectingObjects(Enemy.class);
            if (enemys != null && !enemys.isEmpty()) {
                for (Enemy enemy : enemys) {
                    enemy.hit();
                }
            }
            getWorld().removeObject(this);
        }
        else {
        if (isAtEdge()) getWorld().removeObject(this);
        }
    }
}
EnemyHealthBar code:
public class EnemyHealthBar extends Actor
{
    int healthBarWidth = 300;
    int healthBarHeight = 3;
    int pixelsPerHealthPoint = healthBarWidth/Enemy.health;
   
    public void act()
    {
        update();
        setLocation(Enemy.enemyX, Enemy.enemyY);
    }
    public void update() {
        setLocation(Enemy.enemyX, Enemy.enemyY - 25);
        setImage(new GreenfootImage(healthBarWidth + 2, healthBarHeight + 2));
        getImage().setColor(Color.BLACK);
        getImage().drawRect( 0, 0,healthBarWidth + 1,healthBarHeight + 1);
        getImage().setColor(Color.YELLOW);
        getImage().fillRect( 1, 1, Enemy.health*pixelsPerHealthPoint, healthBarHeight);
        setLocation(Enemy.enemyX, Enemy.enemyY - 25);
    }
}
The problem is that it lowers health of all Enemy objects, not just one.
Super_Hippo Super_Hippo

2022/12/18

#
Your “health” variable shouldn’t be static. Static means that it’s a class variable which is shared among all its objects.
84mu3lC3p4C7 84mu3lC3p4C7

2022/12/19

#
I just don´t know how to do that exactly, I´ve tried so many things, but sometimes I get a Null Exception error, or sometimes it says that non-static variable cannot be referenced from a static context. This does noting to health variable: Bullet code:
Enemy enemy = new Enemy();
public void act()
    {
        if (isTouching(Enemy.class)){
            enemy.health -= 10;
        }
Enemy code:
public int health = 300;
This changes every healthbar: Enemy code:
static int health = 300;
(I know that I should not be using static, but I just tried it.) This gives the non-static variable cannot be referenced from a static context: Bullet code:
Enemy.health -= 10;
I really don´t understand what am I doing wrong, also, could you PLEASE quickly explain what is this Enemy enemy = new Enemy(); is that a reference, idk. Thank you very much.
Spock47 Spock47

2022/12/19

#
Change the variable to be not-static
int health = 300;
Then just stay with the Bullet code you had in the first comment:
    List<Enemy> enemys = getIntersectingObjects(Enemy.class);
    if (enemys != null && !enemys.isEmpty()) {
        for (Enemy enemy : enemys) {
            enemy.hit();
        }
    }
Now, the health of each enemy will be computed correctly. However, you also want to show the health in the health bars. Since each enemy has a different value for health, each health bar has to know to which enemy it belongs (whose health it should show). Reminder: A static attribute is a unique variable and all instances share this same value, so you can ask for it directly with the class name: "Enemy.health". But a non-static attribute is actually as many variables as there are objects of this class. So, 5 Enemies => 5 different health values. If you ask for one of these variables, the computer needs to know which of these 5 health values you want to have: You have to specify whose enemy's health you want to know: So, you first need to have a reference to one enemy. Therefore, add an enemy property to the HealthBar and add the enemy as parameter to the constructor:
public class EnemyHealthBar extends Actor
{
    private Enemy enemy;
    ...
    public EnemyHealthBar(final Enemy enemy) {
        this.enemy = enemy;
        pixelsPerHealthPoint = healthBarWidth / enemy.health;
    }
   ...
}
Then (in Enemy class) change the construction call of HealthBar to pass the enemy there:
getWorld().addObject(new EnemyHealthBar(this), getX(), getY());
Now, the health bar always "knows" to which enemy it belongs. So if it needs the health value or the x or y value, it can just ask that enemy by calling its methods/attributes, e.g.
    int rectWidth = enemy.health * pixelsPerHealthPoint
    ...
    setLocation(enemy.getX(), enemy.getY())
Spock47 Spock47

2022/12/19

#
84mu3lC3p4C7 wrote...
I really don´t understand what am I doing wrong, also, could you PLEASE quickly explain what is this Enemy enemy = new Enemy(); is that a reference, idk. Thank you very much.
Technically, the line does three things: 1.
Enemy enemy;
Creates a new empty reference/variable. You can look at it like a place in the storage is created and you put the label "enemy" on it. So, if at any later point (in this method), you reference the label "enemy", the program will look at this storage position: you can either "read" (getting what is currently at the storage position) or "write" (put something into that storage position, potentially replacing what was there before). 2.
new Enemy();
This creates a new Enemy object; a new object that has its own health value (starting at 300) and that can be put into a world. 3. The "=" is called an assignment, it puts the thing on the right side of the "=" into the variable whose label you put onto the left side of the "=", so e.g.
a = b
puts the object b into the variable/storage labeled "a". So, at any later call to the variable with label "a", the program will give this object (b) to you. =>
Enemy enemy = new Enemy();
does all these three things: 1. It creates an empty variable with label "enemy". 2. It creates a new Enemy object. 3. And then it puts this newly created Enemy object into the variable with label "enemy". Live long and prosper, Spock47
84mu3lC3p4C7 84mu3lC3p4C7

2022/12/19

#
It works! Thank you so much, now I finally understand. :D
You need to login to post a reply.