[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 ).
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!)
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...
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
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.
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.
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.
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.
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
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.
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.
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?
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.
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 ?
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.
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 ?
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.
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.
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.
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.
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.
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.
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.
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.
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.