I'm trying to make a Zelda-styled health system with hearts and half hearts representing the amount of health the player has.
My initial implementation looks like this:
on load do
// set starting health and max health
hearts = 6
heartsMax = 6
heartPieces = 0
end
on draw do
// Hearts UI
if hearts==6 then
tell 0,0 to
swap "heart_full"
end
tell 1,0 to
swap "heart_full"
end
tell 2,0 to
swap "heart_full"
end
end
if hearts==5 then
tell 0,0 to
swap "heart_full"
end
tell 1,0 to
swap "heart_full"
end
tell 2,0 to
swap "heart_half"
end
end
if hearts==4 then
tell 0,0 to
swap "heart_full"
end
tell 1,0 to
swap "heart_full"
end
tell 2,0 to
swap "heart_empty"
end
end
if hearts==3 then
tell 0,0 to
swap "heart_full"
end
tell 1,0 to
swap "heart_half"
end
tell 2,0 to
swap "heart_empty"
end
end
if hearts==2 then
tell 0,0 to
swap "heart_full"
end
tell 1,0 to
swap "heart_empty"
end
tell 2,0 to
swap "heart_empty"
end
end
if hearts==1 then
tell 0,0 to
swap "heart_half"
end
tell 1,0 to
swap "heart_empty"
end
tell 2,0 to
swap "heart_empty"
end
end
end
This is working as intended, and I can gain and lose health as expected.
My question then, is how would I make this scalable to allow for increasing the max health? Is it possible without hardcoding every swap for every possible value of health? I'm trying to avoid a game where the player could theoretically gain up to 20 hearts, which means I would need to hard code 40 (because there are hearts and half hearts) blocks of swaps for every possible value of health.
If hardcoding it is my only option then just knowing that is helpful, but I was hoping there was some math solution of using variable values in the swap coordinates to sort of dynamically draw the hearts depending on any health value the character might have.
You could try using the label function with embed commands. If you set your font size to half width then you should be able to embed as many hearts as you need
Oh you could do that, but I meant using the special embed syntax, like follows:
label "{embed:heartLeft}{embed:heartRight}" at 0,0
Where heartLeft and heartRight are tiles in your room. You just need to note that when using a half width font, only the left half of the tile will be printed
Alternatively if you don't want to use a half width font project-wide, you could just make a tile that is a whole heart, and another that is just the left half, and use that with embed, as the half heart will only ever be at the end of the string
I see. would there be a way to tell it how many hearts to embed based on the value of hearts variable?
Otherwise, I would still be creating a conditional label command for every variation of possible heart values, but that does still look to be less total code if I went that route.
Well that's above my current knowledge as a "literally just started programming when Pulp released" newbie, but I will try to learn how to use modulo and implement this. Thanks!
hearts = 3
heartCounter = hearts
if hearts>0 then
heartString = "{embed:heart}"
heartCounter--
end
while heartCounter>0 do
heartString = "{heartString}{embed:heart}"
end
if heartString!=0 then
label "{heartString}" at 0,0
end
Note that this doesn't take into account the half hearts, but it should get you started!
On its own, my above post isn't very clear, so here's a working player script showing what I mean. The a button increases the heart halves and the b button decreases them.
on load do
halves = 15
heartString = ""
call "updateHearts"
end
on cancel do
if halves>0 then
halves--
call "updateHearts"
end
end
on confirm do
if halves<20 then
halves++
call "updateHearts"
end
end
on updateHearts do
log "halves: {halves}"
hearts = halves
x = hearts
y = 2
call "modulo"
heartString = ""
if mod!=0 then
hearts--
end
hearts /= 2
while hearts>0 do
heartString = "{heartString}{embed:heart}"
hearts--
end
if mod!= 0 then
heartString = "{heartString}{embed:half}"
end
end
on draw do
if heartString!="" then
label "{heartString}" at 0,0
end
end
on modulo do
mod = x
mod /= y
mod -= floor mod
mod *= y
end
Wow, that looks great! I'll have to take some time to study this since it's currently above my skill level, but it definitely seems like it solves my problem so I'll mark it as the solution.
Thanks for the help and providing a working example!
modulo in this case might be overkill, since you're always only dividing by 2. You just need to compare the value of hearts after dividing by 2 to the floor of hearts.
heartString = ""
hearts = halves
hearts /= 2
half = hearts
hearts = floor hearts
half -= hearts
while hearts > 0 do
heartString = "{heartString}{embed:heart}"
hearts--
end
if half != 0 then
heartString = "{heartString}{embed:half}"
end
edit: I realize this isn't much of a contribution to the answer, it might be just a little easier for a new programmer to follow.
I've been using your example code in a separate project to try and tweak it to my needs and it's working! Based off your example I was also able to make it draw the "empty" hearts as well so that the player always knows what their maximum health is, and it's all scalable!
Now you've essentially solved my problem, which I am grateful for, but if you're able could you offer some more insight into one part of your code that I don't quite understand?
I actually think I grasp the whole modulo function now and how it's determining whether to draw a half or whole heart, but I still don't actually understand how the while loop is working?
while hearts>0 do
heartString = "{heartString}{embed:heart}"
hearts--
end
I understand that it's decrementing hearts each loop until it reaches 0, but I'm just not understanding the syntax of how embed works. How is it drawing multiple hearts? Is the value of heartString telling it how many heart tiles to embed? Is it embeding an extra tile every loop until it reaches 0?
I guess just an overhead view of the logic would help, but again, you've already solved my problem so thank you for that!
(Here's my modified project in case anyone wants to check it out) hearts test.zip (2.7 KB)
That's awesome! Well done on extending it to support empty hearts!
Maybe simplifying the code a bit might help. Here's an example without the embedding which might make it clearer:
s = "It goes on"
num = 3
while num>0 do
s = "{s} and on"
num--
end
log "{s}" // "It goes on and on and on and on"
It's worth noting that in many other programming languages, "{s} and on" could just as easily be written as s + " and on". The idea being that the string s, in this case, has " and on" appended to it each iteration.
So, in our hearts code, each iteration of the while loop will append a new heart to the end of the current heartString variable (which starts empty) so that we end up with the number of hearts we are expecting. Also, as above, the heartString = "{heartString}{embed:heart}" code can be thought of just as equivalent to heartString = heartString + heartTile.
Regarding the embed syntax, it just replaces the {embed:heart} with a single heart tile at that point in the string.