DIV ARENA FORUMS

Accurate health bar

BreadCaster - 3-7-2016 at 06:29 PM

[Cross-posted this with the Bennu forums, as I don't know who from here actually goes there aside from Mikey. Hope that's okay!]

So, as you may or may not of seen in the screenshots forum, there's a trailer for CyberCrisis now, and it's coming along really well. There's just a few more bugs to be fixed and the FMV to be recorded and put in, and it's done.

The largest remaining game bug I can find is that the health bars do not always accurately depict the health of the units they are floating over - including the one for the player. As this is the only indicator for the players health, this is a pretty major issue.

The reason for this bug, as far as I can tell, is because the system of updating it is so weird - at present, the healthbar(); process is updated by a local variable called "wounded" in the father of the process that called it - which is how processes communicate that they're doing damage to each other in CyberCrisis (via "wounded"). So in the context of the healthbar - "if (father.wounded<>0)" is how the health bar process knows to update itself, taking drawing the red box further to the left of its map. This has an issue when the gameplay gets as frantic as you see in the trailer, so another solution is required.

Other variables used in the game are health and maxhealth - these should be self explanatory, but essentially maxhealth is the maximum amount of health the player can have, and health is how much health the player currently has. What I thought would be a better idea than using the if (father.wounded<>0) method would be to just update the healthbar(); process every frame, using a calculation between the width of the health bar graphic (50 - 50 pixels wide and 3 pixels high), health and maxhealth - regardless of if the player has taken any damage or not (I would need to somehow adjust this for the enemy units, destructible objects and buildings, as their health variables are private - this could be done with a local variable for health, let's say notplayer_health :lol: ).

So, the solution I came up with, was firstly to declare some private variables - health_unit and h_unittoremove. health_unit=(50/maxhealth) to come up with the amount of pixels to remove for each health point lost, and h_unittoremove=(health_unit*health), to come up with the total number of pixels to redraw as red (with the red box). Then draw_box(0, 3, h_unittoremove, 3); frame; in the main loop of the process. Now, this works just fine in theory. Maxhealth and health start as the same amount - 300. (you can upgrade the amount of maxhealth you can have later on in the game, through the use of the ingame shop :) )

So, 50/300 (maxhealth) =0.166666666666667 - so 0.166666666666667*300 (health) = 50. Lower the health (the second 300), let's say to halfway - 150 - and you get 0.166666666666667*150 = 25. Perfect. Except, not. Because neither DIV nor Bennu supports floating point maths/decimal points. So what you actually get from 0.166666666666667*300, or 0.166666666666667*150, or 0.166666666666667*anything, is a big fat 0. Doh!

Is there a way around this that anyone can think of? It's a real head scratcher.

Thanks to everyone who's suggested help/fixes so far, you've really helped and this game is going so so well - I think we're only a month or so away from release (with the FMV to shoot and all, that is!)

- BreadyTits

MikeDX - 3-7-2016 at 08:57 PM

real_unit = 50000/maxhealth

health_unit = real_unit / 1000;


[Edited on 3-7-2016 by MikeDX]

BreadCaster - 4-7-2016 at 01:43 AM

Quote: Originally posted by MikeDX  
real_unit = 50000/maxhealth

health_unit = real_unit / 1000;


[Edited on 3-7-2016 by MikeDX]


aha, and then having h_unittoremove=(real_unit*health) and then draw_box(bla bla, h_unittoremove, bla) to draw the health bar, as in my aforementioned idea? :)

This does make rather a lot of sense but for some reason I got it into my head that there'd be some kind of issue with rounding and it wouldn't work, so I wanted to see if someone else would hit upon the same idea. I think I may of been getting myself confused with the disparity between the 50000 and 1000...

[Edited on 4-7-2016 by BreadCaster]

BreadCaster - 5-7-2016 at 05:03 PM

Wonderful, got this working now. Thanks so much Mikey, glad someone more technically minded is around :) there's only one bug left in the game that I know of to date, aside from the occasional terminal crash for seemingly no reason (hard to trace and fix non-replicatable bugs). I'll try to sort that out by myself before I come looking around for any more assistance :)

Dani_Karmann - 14-8-2016 at 07:53 AM

Quote: Originally posted by MikeDX  


real_unit = 50000/maxhealth

health_unit = real_unit / 1000;



Perhaps I look like a complete stupid, but I don't understand. Why 50000? Can you explain it, Mike? How to make this in a process in Div2, using the define_region function with a healt bar of 100 pixels wide? I want to make a health bar using a 100 pixels graphic, that works like in Pokémon Red/Blue. But I don't know how to make it and your method looks confusing to me.


BreadCaster - 14-8-2016 at 07:51 PM

Quote: Originally posted by Dani_Karmann  
Quote: Originally posted by MikeDX  


real_unit = 50000/maxhealth

health_unit = real_unit / 1000;



Perhaps I look like a complete stupid, but I don't understand. Why 50000? Can you explain it, Mike? How to make this in a process in Div2, using the define_region function with a healt bar of 100 pixels wide? I want to make a health bar using a 100 pixels graphic, that works like in Pokémon Red/Blue. But I don't know how to make it and your method looks confusing to me.



This piece of code was for a health bar that was 50 pixels long, but we didn't use the define region command. Instead, I was using a graphic which was 50 pixels wide and I think 3 or 4 pixels tall - it was created in code using map_new (but keep in mind, I was using Bennu to make this game, not DIV - Bennu is a windows port which is based off of DIV but with a few other functions as well, plus 32 bit colour. map_new is not a command in DIV, I don't think!).

The divided by 1000 bit is done because floating point math (decimals) can't be done in DIV, so it's basically a crafty workaround, haha.

Don't feel bad if you don't understand it, I genuinely struggled for a little while with this and it took a while for me to get it right.

[Edited on 14-8-2016 by BreadCaster]

MikeDX - 14-8-2016 at 09:22 PM

Bennu isn't a port of DIV, it's a fork of fenix, which is a clone written from the ground up.

I'll try to get some demo code together tomorrow to demonstrate this health bar, as I think it will make sense. I immediately thought a region would be good for this, and just slide a graphic forward / back.


BreadCaster - 14-8-2016 at 10:04 PM

I thought that initially it was pretty much exactly the same, and then they started adding in extra things? I don't know my Bennu history :p

MikeDX - 15-8-2016 at 03:24 PM

I know fenix used to be close to the DIV2 syntax, but I don't know if it was ever 100% compatible like gemix was - but gemix started from the DIV2 sourcecode and was then rewritten (mostly).

Possible fenix started even before DIV2, I don't have exact dates, but I dont think it was ever a case where you could just run any DIV2 prg in fenix.

BreadCaster - 18-8-2016 at 11:09 AM

Quote: Originally posted by MikeDX  
Bennu isn't a port of DIV, it's a fork of fenix, which is a clone written from the ground up.

I'll try to get some demo code together tomorrow to demonstrate this health bar, as I think it will make sense. I immediately thought a region would be good for this, and just slide a graphic forward / back.



how many regions can you define? because in Cybercrisis there's often up to 10 or 11 health bars on the screen at once in the later stages xD

Dani_Karmann - 21-11-2016 at 05:58 PM

I just tried to use this method in Div 2 with the healt bar of my game, but it does not work, the energy bar looks ok, but it does not change its wide. I tried to combine the "health_unit/100000" (because the health bar of my game is 100 pixels wide) with the "define region" function, but I don't know how to calculate the region to show. Can you help me? Remember that I want an energy bar that works like in "Pokémon Red/Blue". The graphic of my energy bar measures 100x10 pixels. The above method is ok for a plain box, but I want to show a graphic.

[Edited on 21-11-2016 by Dani_Karmann]

CicTec - 21-11-2016 at 06:11 PM

Quote: Originally posted by BreadCaster  
Quote: Originally posted by MikeDX  
Bennu isn't a port of DIV, it's a fork of fenix, which is a clone written from the ground up.

I'll try to get some demo code together tomorrow to demonstrate this health bar, as I think it will make sense. I immediately thought a region would be good for this, and just slide a graphic forward / back.



how many regions can you define? because in Cybercrisis there's often up to 10 or 11 health bars on the screen at once in the later stages xD

DIV currently can define up to 32 regions, the new graphics engine can define now up to 65536, however it is no longer necessary to use it to create similar effects to the life bar, there are new graphics features to do this more directly.

CicTec - 21-11-2016 at 06:16 PM

Quote: Originally posted by Dani_Karmann  
I just tried to use this method in Div 2 with the healt bar of my game, but it does not work, the energy bar looks ok, but it does not change its wide. I tried to combine the "health_unit/100000" (because the health bar of my game is 100 pixels wide) with the "define region" function, but I don't know how to calculate the region to show. Can you help me? Remember that I want an energy bar that works like in "Pokémon Red/Blue". The graphic of my energy bar measures 100x10 pixels. The above method is ok for a plain box, but I want to show a graphic.

[Edited on 21-11-2016 by Dani_Karmann]

Hi Dani_Karmann,

Could you please provide more details?, For example the bar is decreased by constant or variable magnitude?

Dani_Karmann - 21-11-2016 at 08:00 PM

I' ve defined two variables, energy and max_energy. When you start the game, the two variables are set to 25. Every time you gain a level or pick a red potion, your max health increases. As you can see in the first example image, my idea is to make a life bar represented by 10 hearts. I'm using two heart bars, one for the actual energy (normal hearts) and another one behind for the max_energy (dark hearts). It works like in the Pokémon games, the max width of the energy bar is always the same, 100 pixels.
Actually I'm using an energy bar that increases every time your max_energy does, until you arrive to the top (600 energy points).
I'm using this:

define_region(10,2,3,energy/2,10); Where 10 is the region, 2 and 3 the x and y positions, "energy/2" is because the max energy is 600 but the actual bar measures 300 pixels, and 10 is the height of the graphic.

But there is a problem: a 300 pixels-wide bar hides part of the screen, looks very big, as you can see in the second image. My idea is to make a smaller energy bar, with only 100 pixels, as the third image shows. My problem is that I do not know how to make this type of energy bar.

Note: energy and max_energy are global variables.


EXAMPLE.png - 302kB dos4gw_002.png - 302kB TEST2.png - 302kB

CicTec - 21-11-2016 at 08:22 PM

Well, it is not complicated:
- Create an energy bar of 100 pixels with blacks hearts (1)
- Create an energy bar of 100 pixels with red hearts (2)
- Define a region initial width of 100 pixels to be assigned to the graph (2).
- It decreases the width of the region based on the strength of the damage.

The strength of the damage is constant? for example, the bar contains 10 hearts, any damage received, decreased by a heart?, half, two hearts?, is constant or variable ?

Dani_Karmann - 21-11-2016 at 09:24 PM

It is determined by your defense status. Of course, it's not the same when you are touched by an enemy at level 1 or at level 50. Every time you gain levels, your defense status increases. For example, when you are touched by the enemy "little crab" at level 1, you lose 6 health points; but when your defense status is at the maximum level, you only lose 1 point.
It's defined this way:

id2=collision(TYPE little_crab);
IF(id2)
SWITCH(defense);
CASE 1..10:energy-=6;END
CASE 11..25:energy-=5;END
CASE 26..50:energy-=3;END
CASE 51..75:energy-=2;END
CASE 76..100:energy--;END END
END

It's an easy way to calculate the amount of damage you receive depending on your defense status. It's different for every enemy in the game.

For now, the hearts are only decorative, in fact the energy bar is considered as it was a solid rectangle.

The energy bars are already done, but the question is: how to calculate the bar width like I show in the first example image. Although your max energy is 25 hp, or 30,55,72,100 or any number, the maximum width of the bar ALWAYS has to be 100 pixels. Like the Pokémon energy bar. When your energy is at 50% it will show 5 hearts, etc. The first energy bar (red) will always change its width depending on your health, the second bar (dark) is not a problem, it's just a static graphic, it will never change in any way. "Defense" is a global variable, too.

This is the big problem, how to make your health points always "fit" into the 100 pixels wide bar, considering that you begin with 25 points and you gain, for example, 3 health points with every new level or 5 points with every red potion.





[Edited on 21-11-2016 by Dani_Karmann]

CicTec - 21-11-2016 at 09:55 PM

Well, need other informations, for example we are at level 1 with 25 ponts, we are touched then the energy is decreased of 6 points, the red hearts displayed those who ought to be ?

Dani_Karmann - 22-11-2016 at 04:43 PM

In the case that you begin the game with 24 points, instead of 25, and you are touched 2 times by a little crab, then you receive 12 damage points (6+6), then your energy will become 12/24, that is, 50% of 100%, so the energy bar will show 5 red hearts and 5 dark hearts. If you are touched one time, then it will show 7 red hearts and a half and 2 and a half dark hearts. In the case that you have a maximum of 100 health points and you receive 10 damage points, then your energy levels will be 90/100, so the energy bar will show 9 red hearts and one dark. It changes every time your energy increase or decrease. I want to know how to calculate the proportion of the red bar.

Have you ever played Pokémon Red/Blue? My idea of the energy bar is exactly as it works in the Pokémon games.


hqdefault.jpg - 24kB

CicTec - 22-11-2016 at 05:34 PM

I see, I asked a lot of information to understand how you want to implement the bar.

I never played the Pokemon, but I see from the screenshot that the reduction can be variable, the problem is the difference of the bar, here is just a rectangle, in your game have 10 hearts, we may have cases where, for example, is displayed only 1/6 of a red heart, or the reduction of at least half a heart ?

Until we have all the information you can not get a suitable formula.

Dani_Karmann - 22-11-2016 at 05:54 PM

As I said before, the hearts are only decorative, so the energy bar works exactly as it was a solid rectangle, so of course it can show a full heart, 1/2 heart, or any fraction of a heart. So, don't worry about the hearts to show, I want to calculate the total width of the life bar.

If you look at the Pokémon screenshot, you can see that my idea is an energy bar that changes its proportion depending on your health points, but always being 100 pixels maximum, although your life is 34/34, or 128/128, or 300/300. For example, if your energy values are 17/34, 25/50, 100/200, etc., it always shows 5 red hearts of 10. If your health level is 10/100 or 20/200 it shows 1 red heart, etc.

The red hearts are like the grey bar in the screenshot, and the dark hearts are like the white box that contains the energy bar.

CicTec - 22-11-2016 at 06:42 PM

Ok, so is variable,

The formula should be:
Code:
if(energy_damage > 1) energy_bar = energy_max / energy_damage; if(energy_bar <= 0) energy_bar = 1; // to avoid division by 0 or other errors for (100 / energy_bar) end define_region(N, 0, 0, 100 - (100 / energy_bar)), 10); else define_region(N, 0, 0, 100, 10); end


- energy_damage initially be 0, then it is expected to increase by level (+6 per level 1, +4 per level 2, etc ...).
- energy_max varies according to the level (24, 30, 50, 100, etc ...).
- 100 is constant in the number of pixels of the bar.


It should be what you needed.


[Edited on 22-11-2016 by CicTec]

[Edited on 22-11-2016 by CicTec]

Dani_Karmann - 22-11-2016 at 08:27 PM

The code seems to work, but there is something I don't understand. Can you explain why you are making a division between max_energy and energy_damage? Should the "energy_damage" be declared as a global variable at the beginning of the game?
And then, every time my character touch an enemy, I have to write "damage=X" and then "energy-=damage"? Your code seems ok, but I'm a bit confused with the "energy_damage" variable.

Now I have to try this method with the magic bar.

[Edited on 22-11-2016 by Dani_Karmann]

Dani_Karmann - 22-11-2016 at 09:25 PM

I found a little problem: your method works ok when you are touched one time by an enemy; but if you are touched a second time then the life bar don't shows correctly. The problem seems to be solved if you add the variable "damage" every time you are touched. So, if you are touched 1 time, "energy_damage" will be 6, a second time will be 12, etc.
Other thing: you have to decrease the value of "energy_damage" every time you restore your life. The two things seem solved, I'm testing.

CicTec - 22-11-2016 at 09:35 PM

Creo que eres español, asi que lo escribo tambien en este idioma para que te resulte mas claro.

Estas usando una unidad de misuracion diferente respecto a la barra de energia, por ejemplo tenendo:
- energy_max a 24.
- cada golpe resta 6 a energy_max (sumando energy_damage).

De esta forma tu codigo deberia cambiar asi:
Code:
id2=collision(TYPE little_crab); IF(id2) SWITCH(defense); CASE 1..10:energy_damage+=6;END .... END

Ponendo el ejemplo que energy_damage pasa de 0 a 6 por el golpe recibido, hay:
Code:
energy_bar = energy_max / energy_damage;

Que seria tener energy_bar = 24 / 6 (= 4), el numero de golpes maximos que puedes recibir en base a los valores del nivel actual.

Despues hay que dividir 100 (que seria el 100% de energia total) por el valor anterior:
Code:
(100 / energy_bar)

Obtenendo asi la porcentaje que se va a restar (100 / 4 = 25), y por acabar se resta este valor con 100, que es el ancho de la barra de enercia en pixels (100 - 25 = 75), asi se obtiene el valor final de la barra.

No he podido probar todos los casos, si usas valores muy grandes para energy_max y valores muy pequeños para energy_damage, obtendras un valor float (tipo 0.16) que redondeado a INT seria 0, por ende necesitas encontrar valores adecuados por cada nivel o modificar la formula segun las necesidades.

Espero que el codigo te sea util.

------------------------------------------------------------------------------------------------------------------------------------------------------ --

I believe that you are Spanish, then I write in this language in order for you to be more clear.

you are using a different unit of measurement for the energy bar, for example taking:
- energy_max 24.
- each shot subtracts 6 to energy_max (by adding 6 to energy_damage).

In this way the code should change as follows:
Code:
id2=collision(TYPE little_crab); IF(id2) SWITCH(defense); CASE 1..10:energy_damage+=6;END .... END

Then energy_damage goes from 0 to 6 after the blow received, having:
Code:
energy_bar = energy_max / energy_damage;

Resulting energy_bar = 24/6 (= 4), the maximum number of shots that can receive based on the values ​​of the current level.

Then you divide seve 100 (which would be the 100% of total energy) to the previous value:
Code:
(100 / energy_bar)

Thus you are obtained the percentage to be subtracted (100/4 = 25), and to finish it subtracts this value by 100, which is the width of the energy bar in pixels (100-25 = 75), so as to obtain the final value of the bar.

I could not test all cases, if you use too large values ​​for energy_max and too small to energy_damage, you will get a float value (type 0:16) which will be rounded to INT 0, then you need to find suitable values ​​for each level or change the the formula according to need.

I hope that the code will be useful.

Dani_Karmann - 23-11-2016 at 04:17 PM

Don't worry about the language, I'm spanish but I understand, speak and write English very well.
Yes, the code seems to work, now I'm adapting the .prg to the new code. Now it's time to apply it to the magic bar, I think it will be easier because there are only two variables, "magic" and "max_magic". I'm making some tests.

Thanks for the code, your efforts, and above all, your patience. If I finish the game some day, you will appear in the credits, in the "special thanks" section. :)

CicTec - 23-11-2016 at 05:01 PM

It has been a pleasure for me, I hope that you can finish the game, and I hope to see soon a new demo. :)

Dani_Karmann - 23-11-2016 at 06:37 PM

Uh-oh, there is a problem: I wrote your code, it works fine when your energy is at 100%, at 75%, etc.; but when your energy is at 50% or less the energy bar disappears, and it reappears when your life is bigger than 50%. I have adapted the same code for the magic bar, and the same problem occurs. The bar does not show any graphic when your health is less than a half.


CicTec - 23-11-2016 at 06:48 PM

Mmmm yes, need another formula than, wait please.

[Edited on 23-11-2016 by CicTec]

Dani_Karmann - 23-11-2016 at 07:20 PM

I used your code changing only the words "energy_damage" to "daño"("damage" in spanish), the rest is the same, I think.

PROCESS barra_vida(x,y);

BEGIN graph=22;
z=-503;region=10;
LOOP

IF(daño>1)energy_bar=max_energy/daño;

IF(energy_bar<=0)energy_bar=1;END

define_region(10,2,3,100-(100/energy_bar),10);

ELSE

define_region(10,2,3,100,10);END

FRAME;END END

In the player process I wrote a line to control the "damage" variable, so it increases every time you are touched by an enemy, an it decreases when you touch a recovery heart or a Red Flower and you recover part of your life. (the Recovery Heart refills your health and a Red Flower recovers 10 health points). As I said, the only problem is that the energy bar disappears when your life is under 50%, the rest of the time it works well.

CicTec - 23-11-2016 at 07:31 PM

You can use the formula of Mike, adapted for your 100 pixels bar:
Code:
real_unit = 100000 / max_health; health_unit = real_unit / 1000; if(health_unit <= 0) healt_unit = 1; end define_region(1, 0, 0, 100 - (health_unit * damage), 10);

But you'll have some inaccurate values, because the formula would require floating point currently not supported by DIV.

100000 is the value of your bar width (100 pixels) * 1000 (the decimal floating point conversion to INT).

Dani_Karmann - 24-11-2016 at 08:14 PM

It works, but it seems that when your energy/magic reaches 0, the bar still shows a little part of itself. I've used your second code for the health and the magic bar, and this is the only problem, I recorded a video to show how it looks.

https://www.youtube.com/watch?v=TFH9HGZPgts

CicTec - 24-11-2016 at 08:25 PM

in which the minute video is shown?

It should be easy to solve, try:
Code:
if(damage < max_health) real_unit = 100000 / max_health; health_unit = real_unit / 1000; if(health_unit <= 0) healt_unit = 1; end define_region(1, 0, 0, 100 - (health_unit * damage), 10); else region = -1; end

if damage> = max_health simply the graph does not appear in any region.

[Edited on 24-11-2016 by CicTec]

Dani_Karmann - 24-11-2016 at 08:41 PM

No, it is not showed in the video. (Well, in second 0:23 the magic reaches 1 point). The video has been recorded to show how the new life and magic bars work.

CicTec - 24-11-2016 at 08:49 PM

From the video it seems to work well, the issue of when it reaches 0 should be corrected with the above code, try please.

Dani_Karmann - 24-11-2016 at 08:54 PM

I' ve tried and when the health/magic reaches 0, the bar shows the full width.

Now this is the process "life bar" from my game:

PROCESS barra_vida(x,y);
PRIVATE real_unit;health_unit;
BEGIN graph=22;
z=-503;region=10;
LOOP

IF(daño<1)daño=1;END
IF(daño<max_energy)real_unit=100000/max_energy;

health_unit=real_unit/1000;

IF(health_unit<=0)health_unit=1;END

define_region(10,2,3,100-(health_unit*daño),10);

ELSE region=-1;END

FRAME;END END

CicTec - 24-11-2016 at 09:15 PM

I can't test for now with a really example, try:
Code:
if(damage < max_health) real_unit = 100000 / max_health; health_unit = real_unit / 1000; if(health_unit <= 0) healt_unit = 1; end define_region(1, 0, 0, 100 - (health_unit * damage), 10); else define_region(1, 0, 0, 0, 0); end

Dani_Karmann - 25-11-2016 at 10:02 PM

The bar is not accurate, but don't worry. At least, it works. In fact, perhaps the game is not going to be finished anyway.

BreadCaster - 25-11-2016 at 11:12 PM

Quote: Originally posted by Dani_Karmann  
The bar is not accurate, but don't worry. At least, it works. In fact, perhaps the game is not going to be finished anyway.


:(

We'd all like to see the game finished, Dani!!

If you're really struggling with it, would you like me to send the source code for the health bar from Cybercrisis? :)

CicTec - 25-11-2016 at 11:31 PM

Quote: Originally posted by Dani_Karmann  
The bar is not accurate, but don't worry. At least, it works. In fact, perhaps the game is not going to be finished anyway.

Unfortunately it is a loss of accuracy problem for INT, when the floating point support will be added to the formula will be accurate.

I hope you can finish the game. :)

Dani_Karmann - 26-11-2016 at 09:54 PM

I will continue this in the "WIPS" section. Breadcaster, this is the energy bar process:

PROCESS barra_vida(x,y);
PRIVATE real_unit;health_unit;
BEGIN graph=22;
z=-503;region=10;
LOOP

IF(daño<1)daño=1;END
IF(daño<max_energy)real_unit=100000/max_energy;

health_unit=real_unit/1000;

IF(health_unit<=0)health_unit=1;END

define_region(10,2,3,100-(health_unit*daño),10);
ELSE define_region(10,2,26,0,0);END

FRAME;END END
//---

(Note: "daño" means "damage" in Spanish)