Sign in to follow this  
null;

Question about health bars

Recommended Posts

So I've been trying to implement a health bar recently and I wanted it to follow my player objects (I have two because one of them is controlled with arrow keys and the other is controlled with w, a, s, and d).

 

The only problem is, I heard it was more efficient to have the visuals for the health bar in a separate class. I can't do that since I can't access my player x and y variables from another class since they aren't static (they can't be, or else I wouldn't be able to have more than 1 player object).

 

The reason I need to reference my player x and y variables is because I need my health bar to essentially follow my player. How would I go about doing that?

NOTE: I don't think showing code is completely necessary, since I only need the concept of how I would go about doing it. Thanks!

Share this post


Link to post
Share on other sites

EDIT: I checked out your other thread, and now I understand what you're describing. You don't need a class to be static for it to provide information to other classes. In the same code that displays your other HUD/UI elements you can include instances of a HealthBar class (or whatever other approach you want to take). It will need to take information from your Player instances anyways, to show each player's current health, and at the same time you can pass information on the characters' onscreen locations to render the health bars in the right locations. Do you currently have a specific class for rendering things on the screen?

Edited by Khaiy

Share this post


Link to post
Share on other sites

Why can't you have the health bar as a member variable in your Player class, rendered above/around your characters? You can still have a separate HealthBar class with its own sprites and render method. I doubt that any approach you take to implementing health bars could be inefficient enough to matter.

 

EDIT: I checked out your other thread, and now I understand what you're describing. In the same code that displays your other HUD/UI elements you can include instances of a HealthBar class (or whatever other approach you want to take). It will need to take information from your Player instances anyways, to show each player's current health, and at the same time you can pass information on the characters' onscreen locations to render the health bars in the right locations. You don't need a class to be static for it to provide information to other classes.

So  I should render the health bar itself in the same class where I have the instances of my player objects? 

Share this post


Link to post
Share on other sites

 

Why can't you have the health bar as a member variable in your Player class, rendered above/around your characters? You can still have a separate HealthBar class with its own sprites and render method. I doubt that any approach you take to implementing health bars could be inefficient enough to matter.

 

EDIT: I checked out your other thread, and now I understand what you're describing. In the same code that displays your other HUD/UI elements you can include instances of a HealthBar class (or whatever other approach you want to take). It will need to take information from your Player instances anyways, to show each player's current health, and at the same time you can pass information on the characters' onscreen locations to render the health bars in the right locations. You don't need a class to be static for it to provide information to other classes.

So  I should render the health bar itself in the same class where I have the instances of my player objects? 

 

 

It depends on the structure of your code, but probably not. Your Player instances will be in some class (maybe Game, or something like that), and another class which is responsible for rendering UI/HUD elements on screen will exist elsewhere. Data does need to pass from other objects to the object that does the rendering but they don't have to both be members of the same containing class for that to happen.

Share this post


Link to post
Share on other sites

 

 

Why can't you have the health bar as a member variable in your Player class, rendered above/around your characters? You can still have a separate HealthBar class with its own sprites and render method. I doubt that any approach you take to implementing health bars could be inefficient enough to matter.

 

EDIT: I checked out your other thread, and now I understand what you're describing. In the same code that displays your other HUD/UI elements you can include instances of a HealthBar class (or whatever other approach you want to take). It will need to take information from your Player instances anyways, to show each player's current health, and at the same time you can pass information on the characters' onscreen locations to render the health bars in the right locations. You don't need a class to be static for it to provide information to other classes.

So  I should render the health bar itself in the same class where I have the instances of my player objects? 

 

 

It depends on the structure of your code, but probably not. Your Player instances will be in some class (maybe Game, or something like that), and another class which is responsible for rendering UI/HUD elements on screen will exist elsewhere. Data does need to pass from other objects to the object that does the rendering but they don't have to both be members of the same containing class for that to happen.

 

Oh so the class that actually handles the rendering elements... Lol sorry should have payed a bit more attention the first time. So I don't necessarily have to make a separate class for my healthbar? I just kind of assumed it would be inefficient not to.

 

Thank you for your help, by the way!

Share this post


Link to post
Share on other sites


Oh so the class that actually handles the rendering elements... Lol sorry should have payed a bit more attention the first time. So I don't necessarily have to make a separate class for my healthbar? I just kind of assumed it would be inefficient not to.
 

 

It may be a good idea to have a separate class define a HealthBar object, if only to define its on-screen dimensions and location and store the sprites that will be drawn. The instances of HealthBar can be instantiated anywhere that makes sense for your code, updated with player health values when your game logic updates, and then rendered along with everything else in the render loop.

 

Other design approaches exist which will work, but I think that HealthBar objects will be easier to work with both conceptually and for code maintenance. Again, efficiency (in terms of code performance) in this case will probably not matter much.

 


Thank you for your help, by the way!

 

Happy to help! I hope my suggestions are of some use to yo.

Share this post


Link to post
Share on other sites

 


Oh so the class that actually handles the rendering elements... Lol sorry should have payed a bit more attention the first time. So I don't necessarily have to make a separate class for my healthbar? I just kind of assumed it would be inefficient not to.
 

 

It may be a good idea to have a separate class define a HealthBar object, if only to define its on-screen dimensions and location and store the sprites that will be drawn. The instances of HealthBar can be instantiated anywhere that makes sense for your code, updated with player health values when your game logic updates, and then rendered along with everything else in the render loop.

 

Other design approaches exist which will work, but I think that HealthBar objects will be easier to work with both conceptually and for code maintenance. Again, efficiency (in terms of code performance) in this case will probably not matter much.

 

 


Thank you for your help, by the way!

 

Happy to help! I hope my suggestions are of some use to yo.

 

Yeah they were DEFINITELY useful. I got it working in an extremely efficient way that uses the player object's name as a parameter :D

Share this post


Link to post
Share on other sites

you should make two healthbar instances - one for player 1, one for player 2.
each only needs to worry about its own player. So, in the appropriate spot in code

healthbar1->setValue(player1->getHealthPercentage());
healthbar2->setValue(player2->getHealthPercentage());

where Player::getHealthPercentage() is essentially just { return (health * 100) / maxhealth; }

or the healthbar class can store a reference to its player and get this information itself.
or you can create a class to specifically calculate the ratio of two integers as a percentage, IE:

class PercentageOf
{
int #
int &denom;

public:
PercentageOf(int &_num, int &_denom){ num = _num; denom = _denom; }

operator int() const { return (num * 100) / denom; }
};

I'm a fan of classes like that, because it allows one complex class to perform logic using another complex class's members without any knowledge of that class at all. But making them and using them is a little awkward, so maybe not the best choice for a beginner.

Edited by nfries88

Share this post


Link to post
Share on other sites

or you can create a class to specifically calculate the ratio of two integers as a percentage, IE:

class PercentageOf
{
int #
int &denom;

public:
PercentageOf(int &_num, int &_denom){ num = _num; denom = _denom; }

operator int() const { return (num * 100) / denom; }
};

I'm a fan of classes like that, because it allows one complex class to perform logic using another complex class's members without any knowledge of that class at all. But making them and using them is a little awkward.
It's fine that you're a fan, but to a beginner this is just highly confusing. Please try to keep things as simple as possible in this forum.

Share this post


Link to post
Share on other sites

You(null;) seem to have already solved your problem but I still have some doubts about this issue ( being a beginner myself ).

 

When I experienced this problem of object references, I created a GameObject class which was the parent of all game objects. The game object class had no default constructor but one constructor which takes a string argument. The GameObject class also consisted of a std::map from string to GameObject. So, in the constructor the object created was added to the map with the string argument as its id. The GameObject class also consisted of a static method 'get' which returned a object given its id.

 

I don't know whether my approach is correct, so I'm not recommending it to anyone but instead asking for expert review since after this discussion I'm doubtful about my approach. Please review!

 

The problem in this method seems to be about downcasting to the real type of object( Since I'm using C++ not Java ). Since I never felt the need of downcasting ( I put all the usual methods in GameObject class itself ) I didn't ponder more over this issue. But now I'm looking for correcting my approach.

Share this post


Link to post
Share on other sites

Having doubts is good, it shows you aren't afraid to question your own beliefs :)

 

Maybe you can expand your explanation a bit. Some questions to help you on your way. You may not be able to answer all the questions (I added a few that can be difficult to answer). The main idea is to help you in getting insights of what you did. If you don't want to give the answer here, or only the executives summary, that's fine.

 

- What was the original reason to introduce your overall GameObject? (What problem was it supposed to solve?)

- What are you using actually using the std::map for in your game now? (Time has funny ways to change goals, it never hurts to check actual usage)

(a short code example of it is probably useful if you post about it)

- Does it do its job well?

- What are its problems?

- What do you need to fix that problem?

- Should it do other jobs too?

Share this post


Link to post
Share on other sites


It's fine that you're a fan, but to a beginner this is just highly confusing. Please try to keep things as simple as possible in this forum.

You're right, of course. I just know that the OP was having issues with domain modeling in a previous post, so I figured I'd share a relevant trick WRT to domain modeling here.
 

 

You(null;) seem to have already solved your problem but I still have some doubts about this issue ( being a beginner myself ).

 

When I experienced this problem of object references, I created a GameObject class which was the parent of all game objects. The game object class had no default constructor but one constructor which takes a string argument. The GameObject class also consisted of a std::map from string to GameObject. So, in the constructor the object created was added to the map with the string argument as its id. The GameObject class also consisted of a static method 'get' which returned a object given its id.

 

I don't know whether my approach is correct, so I'm not recommending it to anyone but instead asking for expert review since after this discussion I'm doubtful about my approach. Please review!

 

The problem in this method seems to be about downcasting to the real type of object( Since I'm using C++ not Java ). Since I never felt the need of downcasting ( I put all the usual methods in GameObject class itself ) I didn't ponder more over this issue. But now I'm looking for correcting my approach.

There's nothing wrong with having a lookup table (std::map) of all game objects. In fact, in some designs, it may be necessary. In time you'll probably learn of a better way to do this, or ways to avoid it. But if it's working fine right now, and it's making your life easier to have it, there's not really any good reason to try and eliminate it. One way you could make this better is to have integer IDs instead of strings, it will make lookup much faster because it requires only one comparison per entry.

It should be rare for downcasting to be necessary if virtual functions are provided for most cases in the base class. It's unlikely you'll run into a situation where downcasting can be avoided by eliminating the lookup table, either.

Share this post


Link to post
Share on other sites

Thank you all for the help! But as you may have doubts, I feel quite content with my method :D I'd be completely open to other suggestions if my method wasn't efficient or serving its purpose :P

 

But I really appreciate all the help!

Share this post


Link to post
Share on other sites

Having doubts is good, it shows you aren't afraid to question your own beliefs :)
 
Maybe you can expand your explanation a bit. Some questions to help you on your way. You may not be able to answer all the questions (I added a few that can be difficult to answer). The main idea is to help you in getting insights of what you did. If you don't want to give the answer here, or only the executives summary, that's fine.
 
- What was the original reason to introduce your overall GameObject? (What problem was it supposed to solve?)
- What are you using actually using the std::map for in your game now? (Time has funny ways to change goals, it never hurts to check actual usage)
(a short code example of it is probably useful if you post about it)
- Does it do its job well?
- What are its problems?
- What do you need to fix that problem?
- Should it do other jobs too?

 
First of all, thanks for trying to clear my doubts, I'll to answer all the questions in a descriptive manner this time.
I'm rewriting all the question one by one followed by their answers.
 
Q1) What was the original reason to introduce your overall GameObject? (What problem was it supposed to solve?)
Originally I had created the GameObject class as an interface for all game objects. So that I can implement Polymorphism for various general tasks related to game objects.
 
Q2) What are you using actually using the std::map for in your game now? (Time has funny ways to change goals, it never hurts to check actual usage)
(a short code example of it is probably useful if you post about it)
Here are all the snippets consisting the std::map. (I'm using namespace std)

map<string, GameObject*> GameObject::objectMap;

void GameObject::addObject(string id, GameObject* obj)
{
	objectMap[id] = obj;
}

GameObject* GameObject::get(string id)
{
	return objectMap[id];
}

Q3) Does it do its job well?
Assuming you are talking about std::map and assuming you are talking about its efficiency.
Then I think integers would have worked better. And hence I should have created a enum of object names, right?
Or is this not what you are asking?
 
Q4) What are its problems?
One: The one which I mentioned above about efficiency.
Two: It becomes more complicated if I'm not sure how objects I'm generating of each type. Since I cannot at that time use enums.
Three: Downcasting!!!
 
Q5) What do you need to fix that problem?
For fixing problem one mentioned above: Using integers for increase in performance
For Problem 2) Stick with strings, so that I can append nos to them. Or maybe I can use some other type of container...
For Problem 3) Think of some way to do the downcast, or maybe the eliminate the need of downcasting completely! (I don't think is always possible, so my doubt :( )
 
Q6) Should it do other jobs too?
Well, this one is kinda hard to understand.
But I think the map should also hold the type information about the game objects its holding!
 
(Its a wonder how a little bit of thinking and structured questioning can help us understand out problem better! Awesome help I'll remember it forever. Please tell if I've answered some questions wrongly or incompletely)
 

 

 


It's fine that you're a fan, but to a beginner this is just highly confusing. Please try to keep things as simple as possible in this forum.

You're right, of course. I just know that the OP was having issues with domain modeling in a previous post, so I figured I'd share a relevant trick WRT to domain modeling here.
 

 

You(null;) seem to have already solved your problem but I still have some doubts about this issue ( being a beginner myself ).

 

When I experienced this problem of object references, I created a GameObject class which was the parent of all game objects. The game object class had no default constructor but one constructor which takes a string argument. The GameObject class also consisted of a std::map from string to GameObject. So, in the constructor the object created was added to the map with the string argument as its id. The GameObject class also consisted of a static method 'get' which returned a object given its id.

 

I don't know whether my approach is correct, so I'm not recommending it to anyone but instead asking for expert review since after this discussion I'm doubtful about my approach. Please review!

 

The problem in this method seems to be about downcasting to the real type of object( Since I'm using C++ not Java ). Since I never felt the need of downcasting ( I put all the usual methods in GameObject class itself ) I didn't ponder more over this issue. But now I'm looking for correcting my approach.

There's nothing wrong with having a lookup table (std::map) of all game objects. In fact, in some designs, it may be necessary. In time you'll probably learn of a better way to do this, or ways to avoid it. But if it's working fine right now, and it's making your life easier to have it, there's not really any good reason to try and eliminate it. One way you could make this better is to have integer IDs instead of strings, it will make lookup much faster because it requires only one comparison per entry.

It should be rare for downcasting to be necessary if virtual functions are provided for most cases in the base class. It's unlikely you'll run into a situation where downcasting can be avoided by eliminating the lookup table, either.

 

 

Thanks for your help! I remembered about the efficiency part because of you.

Share this post


Link to post
Share on other sites

Originally I had created the GameObject class as an interface for all game objects. So that I can implement Polymorphism for various general tasks related to game objects.

Ok, this means you expected to have a lot of common properties in all objects, right?
Personally, I have some reservations, but I also see firm believers in this approach here, so let's assume here your ideas were correct.

Now that you created the game, how many methods do you have as truly common (ie fully fitting in your goal) methods? How many do not? Are there positive or negative exceptions there? Was your idea worth it, in hindsight?

 

Assuming you are talking about std::map and assuming you are talking about its efficiency.
Then I think integers would have worked better. And hence I should have created a enum of object names, right?
Or is this not what you are asking?

My question was intended much more generally. You picked GameObject because you expected it to help you in solving your problem (you said "...created the GameObject class as an interface for all game objects. So that I can implement Polymorphism for various general tasks..."). Now, looking back, is it actually doing that? Is it doing that well? (probably not, since you asked about it). So what is it not doing that you expected beforehand? Why? (can you think of reasons to explain why it didn't work out as you intended).

 

 

 

One: The one which I mentioned above about efficiency.

I would say, the first goal should be to have good global game structures. That may also be the second and third goals. If your data structures are well designed, efficiency mostly comes by itself.

In the details you can still gain a lot, but the impact is a lot less than a well designed overall structure.

 

 

 

For fixing problem one mentioned above: Using integers for increase in performance

If you can switch to integers, why do you need a map? I mean, a vector or an array would work too, right? That also holds for using enums, of course.

 

 

 

maybe the eliminate the need of downcasting completely!

I find this an interesting thought.

If you look at what you did from a distance, I think you'd see the following:

 

You wrapped all objects in a black uniform box. They are nicely stackable, and they fit exactly in the new closet that you bought. It all looks so tidy.

Now after a while, you find out that at times, you want to look inside the box, to see what it contains. Apparently, everything in the same box isn't ideal.

 

So maybe you shouldn't have coloured all boxes black? Maybe use different colours for different kinds of things? (my reservations about universal objects surfaces here!!).

 

 

As a thought experiment, what would happen if you delete the GameObject class? Would having several collections of different object types help?

 

 

 

At the end, I seem quite motivated by my dislike about universal classes, so you may want to take my comments and questions with that in mind.

Edited by Alberth

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