Hey,
I'm trying to add a health and a mana bar to my game. The healthbar and manabar supposed to change their lengths when the $health and $mana values change. I have a "stowable" right side bar that uses the Sugarcube 2 style to open and close. Now, I simply add the HTML code as is:
<div class="health-bar" data-total="1000" data-value="1000">
<div class="bar">
<div class="hit"></div>
</div>
</div>
to the story passage that is tasked to display status related data to the player. At this point I became to suspect that the structure of the HTML code (more precisely the class hierarchy) was not respected by SugarCube 2. This is because the result ended up being all over the place. Meanig that the elements did not line up on eachother rather got scattered.
Here's the CSS code:
health-bar {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 200px;
height: 20px;
padding: 5px;
background: #ddd;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
position: relative;
}
.bar {
background: #c54;
width: 100%;
height: 10px;
position: relative;
transition: width .5s linear;
}
.hit {
background: rgba(255,255,255,0.6);
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 0px;
transition: width .5s linear;
}
This was obviously added to the stylesheet of the story. It addresses all 3 html elements that were declared above. We are creating a healthbar that plays a transition (we could call animation) that decreases the health bar over time leaving a lower opacity (shadow) of the health bar behind, which then aligns with the health bar that overlays it as it decreases.
Now the JavaCode is a macro that I simply add to a link and use it to decrease the health bar using a fixed value.
/% Main passage %/
<<decrease_HP>>
JS code:
// Reference the elements of the health bar
$(document).ready(function()
{
var hitBtn = hBar = $('.health-bar'),
bar = hBar.find('.bar'),
hit = hBar.find('.hit');
}
// Define macro to test the health bar:
Macro.add( "decrease_HP",
{
handler : function(){
// grab HTML defined data values
var total = hBar.data('total'),
value = hBar.data('value');
if (value < 0) {
// we are dead transition to game end
return;
}
// max damage is essentially quarter of max life
damage = 100;
var newValue = value - damage;
// calculate the percentage of the total width
var barWidth = (newValue / total) * 100;
var hitWidth = (damage / value) * 100 + "%";
// show hit bar and set the width
hit.css('width', hitWidth);
hBar.data('value', newValue);
setTimeout(function(){
hit.css({'width': '0'});
bar.css('width', barWidth + "%");
}, 500);
if( value < 0){
// dead, dead and dead, go to Game End
}
}
});
Now, the code will most likely not work, because I've just written it on my phone without syntax check or linting. I only wanted to provide as much info as I could out of the top of my head until I get back to my computer.
Anyways, I have two problems with my solution:
1. The health bar HTML elements are not aligned as they are supposed (on top of eachother overlaying one another) instead they are rendered below eachother. I suspect there's a better way to define HTML in sugarcube passages, but no idea how.
2. The health bar does not react to value change, meaning the transition can't be seen nor the result of the transition (a lower health value presented on the health bar). Now, the transition part is not that important to me, but I at least want to see the results of a decreased health bar in my RightSideBar passage.
Any help would be welcome!
Thank you!
Comments
re: your CSS
Some care is needed when adding Line-break in your passage code because by default they are converted into br elements and these elements can effect how CSS works. If you inspect the HTML generated for the example you gave you will see it looks like the following: ... you can suppress those br elements by adding Line Continuation markup to your StoryRightSidebar example.
re: everything else
All your other issues are a result of timing.
A. The assignment of variables on document ready.
This code wont work for three reasons
1. That event occurs before the contents of your Story Javascript passage is processed so you can't use it to do something, but even if that was not the case...
2. Those elements don't exist until after the first passage and the StoryRightSidebar are rendered, but even if this was not the case...
3. Those elements are destroyed and recreated each time the Reader traverses from one passage to another.
note: Moving the declaration of those variable into the body of the decrease_HP macro won't help for the reasons described in the next point.
B. Calling your decrease_HP macro
1. Within the first passage of your story:
Again the elements you are trying to reference won't exist yet because the contents of the StoryRightSidebar passage is not processed until after the contents of the first passage is rendered thus your code gets run too early.
2. Within any passage other than the first passage of your story:
In this case the elements will exist so your code will work on them BUT those modified elements will be destroyed and replaced with new ones when the contents of the StoryRightSidebar passage is processed and rendered.
The following solution uses variables to track the current state of health and damage.
a. StoryInit passage
b. StoryRightSidebar passage
c. Story Javascript area
d. To test add the following to a passage, it can be the first passage of your story.
That said, when HP drops to the same value as the damage or below, the bar disappears, which is a bit odd. Might also be interesting if there was a darker section behind the healthbar indicating the total HP size compared to your current HP once it starts dropping.
Your example showed: When it should have been the following:
That said, you'd probably be better of using an ID for the health bar element itself, rather than a class since it's a unique element.
I did notice that fact and corrected it in my own test-case but I forgot to remark on it during my write-up. (I blame this oversight on the wife, who started tapping her foot with impatient about 2/3 the way through the construction of my previous comment, she wanted to go out for lunch. lol)
Also thinking about duplicating this code and using it for a mana bar.
About the code (missing "."): as mentioned before, I wrote this down on my phone without checks. I just needed to communicate a detailed idea.
Yes, your assumption about the right side bar is correct! I'm using that code indeed.
I assume this healthbar implementation that you presented here is scalable. Meaning that I can place more items like these on my side bar and assign them to different values. In order to do that I simply need to specify the structure of the new healthbar and use the same CSS styling (maybe even grab some element using JS to color the bar to blue) and then implement the Update Mana Bar postrender task.
Anyways, I'll definitely try it out, but more importantly read the reasons and understand why my solution never would've worked and try and build on the newly gained knowledge.
Thanks again for the help, all of your help. I really appreciate it!
Btw.: Does anyone know how to accept answers on the forum? I don't see any prompt popping up about accepting the answer on my phone or tablet.
Also, did you notice when you retract or expand the right sidebar, it makes the text 'jump' instead of the smooth push the left sidebar traditionally gives the body text? I was wondering if there was a way to fix that.
Also looking for a way to make sure the right sidebar starts the game hidden instead of visible. Currently I use Config.ui.stowBarInitially = true; for the left one, but no idea how to do it for the right.
Is there a way to instantiate this healthbar and have and assign a new current value and value to subtract from the bar length?
var HealthBar = new Bar(health_bar, health_value, health_decrease);
var StaminaBar = new Bar(stamina_bar, stamina_value, stamina_decrease);
var Mana = new Bar(mana_bar, mana_value, mana_decrease);
where mana_bar would be name of the bar: #mana-bar, mana_value would be the current mana value being displayed on by the Bar object, mana_decrease is the value that needs to be decreased from the mana_value (for the animation thingie, see code posts above.)
I need to say, I have not looked up the instantiation of DOM stuff and how to apply this to already existing HTML and CSS, but I guess that is what I need to do here, but no idea how.