Legacy GM [SOLVED] Problem with Zelda style hearts divided in 4 quarters

G

Grimbel

Guest
Hello everyone,

I am very new in Game Maker: Studio and my programming skills are still very limited, but I am working very hard in my project and I hope to see it finished some day. It is first time I ask for help, and I hope this community can help me. My problem is the one below:

I have followed a YouTube tutorial in order to make a Zelda style hearts system. The video is designed in a way that every heart is divided in 2 halves, but I want to divide it in 4 quarters instead. I thought it would be easy to adapt, but not at all! Here it is the exact minute (14:40) where the author of the tutorial explains the code:

I think the problem could be easily solved if the code in two small sections below was the right one, but I don't know what to write or how to do it, so I ask for your help.

Code:
// draw two quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_two_quarters == 26 * 10) {
        y_two_quarters = 26;
        x_two_quarters = 0;
    }
    draw_sprite(spr_heart_life_2, 0, xx + x_two_quarters, yy + y_two_quarters);
    x_two_quarters += 26;
}

// draw three quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_three_quarters == 26 * 10) {
        y_three_quarters = 26;
        x_three_quarters = 0;
    }
Here is the complete page:

Code:
/// Draw the stats

var width = display_get_gui_width();
var xx = width - 26 * 6;
var yy = 32;
var x_zero_quarters = 0;
var y_zero_quarters = 0;
var x_one_quarters = 0;
var y_one_quarters = 0;
var x_two_quarters = 0;
var y_two_quarters = 0;
var x_three_quarters = 0;
var y_three_quarters = 0;
var x_four_quarters = 0;
var y_four_quarters = 0;

obj_player_stats.maxhp = clamp(obj_player_stats.maxhp, 12, 24);
obj_player_stats.hp = clamp(obj_player_stats.hp, 0, obj_player_stats.maxhp);

//draw text
draw_set_colour(c_white);
draw_text(width - 26 * 10 / 2, 0, "-Life-");
draw_set_halign(fa_center);

// draw empty heart
repeat(obj_player_stats.maxhp/4) {
    if(x_zero_quarters == 26 * 10) {
        y_zero_quarters = 26;
        x_zero_quarters = 0;
    }
    draw_sprite(spr_heart_life_0, 0, xx + x_zero_quarters, yy + y_zero_quarters);
    x_zero_quarters += 26;
}

// draw one quarter heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/4) * 4) {
    if(x_one_quarters == 26 * 10) {
        y_one_quarters = 26;
        x_one_quarters = 0;
    }
    draw_sprite(spr_heart_life_1, 0, xx + x_one_quarters, yy + y_one_quarters);
    x_one_quarters += 26;
}

// draw two quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_two_quarters == 26 * 10) {
        y_two_quarters = 26;
        x_two_quarters = 0;
    }
    draw_sprite(spr_heart_life_2, 0, xx + x_two_quarters, yy + y_two_quarters);
    x_two_quarters += 26;
}

// draw three quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_three_quarters == 26 * 10) {
        y_three_quarters = 26;
        x_three_quarters = 0;
    }
    draw_sprite(spr_heart_life_3, 0, xx + x_three_quarters, yy + y_three_quarters);
    x_three_quarters += 26;
}

// draw four quarters heart
repeat(floor(obj_player_stats.hp/4)) {
    if(x_four_quarters >= 26 * 10) {
        y_four_quarters = 26;
        x_four_quarters = 0;
    }
    draw_sprite(spr_heart_life_4, 0, xx + x_four_quarters, yy + y_four_quarters);
    x_four_quarters += 26;
}
Thank you very much in advance for helping, and I hope I can learn something from this.
 
Last edited by a moderator:

TheSnidr

Heavy metal viking dentist
GMC Elder
That looks like an extremely inconvenient way of drawing hearts!!! I'd much rather suggest using a for-loop. Put the heart images in a single sprite so that image index 0 is a full heart, index 1 is three quarters, and so on. Put the following code in draw gui:
Code:
max_health = 3;
posX = 26;
posY = 26;
heartSize = 32;
rows = 10;
for (var i = 0; i < max_health; i ++)
{
    draw_sprite(spr_heart, 4 * median(0, 1, i + 1 - health), posX + heartSize * (i mod rows), posY + heartSize * (i div rows));
}
If health is 2, this will draw two full hearts. If health is 1.25, it will draw one and one quarter heart.
 

NicoDT

Member
Hello everyone,

I am very new in Game Maker: Studio and my programming skills are still very limited, but I am working very hard in my project and I hope to see it finished some day. It is first time I ask for help, and I hope this community can help me. My problem is the one below:

I have followed a YouTube tutorial in order to make a Zelda style hearts system. The video is designed in a way that every heart is divided in 2 halves, but I want to divide it in 4 quarters instead. I thought it would be easy to adapt, but not at all! Here it is the exact minute where the author of the tutorial explains the code:

I think the problem could be easily solved if the code in two small sections below was the right one, but I don't know what to write or how to do it, so I ask for your help.

Code:
// draw two quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_two_quarters == 26 * 10) {
        y_two_quarters = 26;
        x_two_quarters = 0;
    }
    draw_sprite(spr_heart_life_2, 0, xx + x_two_quarters, yy + y_two_quarters);
    x_two_quarters += 26;
}

// draw three quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_three_quarters == 26 * 10) {
        y_three_quarters = 26;
        x_three_quarters = 0;
    }
Here is the complete page:

Code:
/// Draw the stats

var width = display_get_gui_width();
var xx = width - 26 * 6;
var yy = 32;
var x_zero_quarters = 0;
var y_zero_quarters = 0;
var x_one_quarters = 0;
var y_one_quarters = 0;
var x_two_quarters = 0;
var y_two_quarters = 0;
var x_three_quarters = 0;
var y_three_quarters = 0;
var x_four_quarters = 0;
var y_four_quarters = 0;

obj_player_stats.maxhp = clamp(obj_player_stats.maxhp, 12, 24);
obj_player_stats.hp = clamp(obj_player_stats.hp, 0, obj_player_stats.maxhp);

//draw text
draw_set_colour(c_white);
draw_text(width - 26 * 10 / 2, 0, "-Life-");
draw_set_halign(fa_center);

// draw empty heart
repeat(obj_player_stats.maxhp/4) {
    if(x_zero_quarters == 26 * 10) {
        y_zero_quarters = 26;
        x_zero_quarters = 0;
    }
    draw_sprite(spr_heart_life_0, 0, xx + x_zero_quarters, yy + y_zero_quarters);
    x_zero_quarters += 26;
}

// draw one quarter heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/4) * 4) {
    if(x_one_quarters == 26 * 10) {
        y_one_quarters = 26;
        x_one_quarters = 0;
    }
    draw_sprite(spr_heart_life_1, 0, xx + x_one_quarters, yy + y_one_quarters);
    x_one_quarters += 26;
}

// draw two quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_two_quarters == 26 * 10) {
        y_two_quarters = 26;
        x_two_quarters = 0;
    }
    draw_sprite(spr_heart_life_2, 0, xx + x_two_quarters, yy + y_two_quarters);
    x_two_quarters += 26;
}

// draw three quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_three_quarters == 26 * 10) {
        y_three_quarters = 26;
        x_three_quarters = 0;
    }
    draw_sprite(spr_heart_life_3, 0, xx + x_three_quarters, yy + y_three_quarters);
    x_three_quarters += 26;
}

// draw four quarters heart
repeat(floor(obj_player_stats.hp/4)) {
    if(x_four_quarters >= 26 * 10) {
        y_four_quarters = 26;
        x_four_quarters = 0;
    }
    draw_sprite(spr_heart_life_4, 0, xx + x_four_quarters, yy + y_four_quarters);
    x_four_quarters += 26;
}
Thank you very much in advance for helping, and I hope I can learn something from this.
Hi! I can´t look the video right now (I´m at work), but this is how I´d do it.

The sprite would have 4 subimages (each showing a quarter of the heart)

Code:
//create event
separation = 30            //separation between hearts
times =                        //variable to check if needs to be separated (after each heart is complete)
x_pos = 25     //position of first heart´s centre
y_pos = 25
MaxHP = 4*4
HP = MaxHP
i=0
frame_number = 0
Code:
//drawevent
for (i=0; i<MaxHP ; i++) {
  frame_number = i mod 4       
  times = i div 4 
  if (HP>= i+1)   draw_sprite(spr_heart, frame_number, x_pos + times*separation, y_pos);
}
Be aware that the sprite should be something like this
Sin título.png
So if you overlap them you get the full heart, and the origin of the sprite is in the centre (touching the corner of the heart).
 

jo-thijs

Member
Hello everyone,

I am very new in Game Maker: Studio and my programming skills are still very limited, but I am working very hard in my project and I hope to see it finished some day. It is first time I ask for help, and I hope this community can help me. My problem is the one below:

I have followed a YouTube tutorial in order to make a Zelda style hearts system. The video is designed in a way that every heart is divided in 2 halves, but I want to divide it in 4 quarters instead. I thought it would be easy to adapt, but not at all! Here it is the exact minute where the author of the tutorial explains the code:

I think the problem could be easily solved if the code in two small sections below was the right one, but I don't know what to write or how to do it, so I ask for your help.

Code:
// draw two quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_two_quarters == 26 * 10) {
        y_two_quarters = 26;
        x_two_quarters = 0;
    }
    draw_sprite(spr_heart_life_2, 0, xx + x_two_quarters, yy + y_two_quarters);
    x_two_quarters += 26;
}

// draw three quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_three_quarters == 26 * 10) {
        y_three_quarters = 26;
        x_three_quarters = 0;
    }
Here is the complete page:

Code:
/// Draw the stats

var width = display_get_gui_width();
var xx = width - 26 * 6;
var yy = 32;
var x_zero_quarters = 0;
var y_zero_quarters = 0;
var x_one_quarters = 0;
var y_one_quarters = 0;
var x_two_quarters = 0;
var y_two_quarters = 0;
var x_three_quarters = 0;
var y_three_quarters = 0;
var x_four_quarters = 0;
var y_four_quarters = 0;

obj_player_stats.maxhp = clamp(obj_player_stats.maxhp, 12, 24);
obj_player_stats.hp = clamp(obj_player_stats.hp, 0, obj_player_stats.maxhp);

//draw text
draw_set_colour(c_white);
draw_text(width - 26 * 10 / 2, 0, "-Life-");
draw_set_halign(fa_center);

// draw empty heart
repeat(obj_player_stats.maxhp/4) {
    if(x_zero_quarters == 26 * 10) {
        y_zero_quarters = 26;
        x_zero_quarters = 0;
    }
    draw_sprite(spr_heart_life_0, 0, xx + x_zero_quarters, yy + y_zero_quarters);
    x_zero_quarters += 26;
}

// draw one quarter heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/4) * 4) {
    if(x_one_quarters == 26 * 10) {
        y_one_quarters = 26;
        x_one_quarters = 0;
    }
    draw_sprite(spr_heart_life_1, 0, xx + x_one_quarters, yy + y_one_quarters);
    x_one_quarters += 26;
}

// draw two quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_two_quarters == 26 * 10) {
        y_two_quarters = 26;
        x_two_quarters = 0;
    }
    draw_sprite(spr_heart_life_2, 0, xx + x_two_quarters, yy + y_two_quarters);
    x_two_quarters += 26;
}

// draw three quarters heart
repeat(floor(obj_player_stats.hp/4) + frac(obj_player_stats.hp/1) * 1) {
    if(x_three_quarters == 26 * 10) {
        y_three_quarters = 26;
        x_three_quarters = 0;
    }
    draw_sprite(spr_heart_life_3, 0, xx + x_three_quarters, yy + y_three_quarters);
    x_three_quarters += 26;
}

// draw four quarters heart
repeat(floor(obj_player_stats.hp/4)) {
    if(x_four_quarters >= 26 * 10) {
        y_four_quarters = 26;
        x_four_quarters = 0;
    }
    draw_sprite(spr_heart_life_4, 0, xx + x_four_quarters, yy + y_four_quarters);
    x_four_quarters += 26;
}
Thank you very much in advance for helping, and I hope I can learn something from this.
Hi and welcome to the GMC!

I can't see the exact minute in the tutorial for some reason and 38 minutes is pretty long to go through.

However, I can see how the code you've provided is built.
It looks overly complicated though.

Try this instead:
Code:
/// Draw the stats

var gui_width = display_get_gui_width();
var heart_width = 26;
var heart_height = 26;
var row_amount = 10;
var xoffset = width - heart_width * row_amount;
var yoffset = 32;
var heart_sprite;

/* This should be executed in the end step event, not in the draw event
obj_player_stats.maxhp = clamp(obj_player_stats.maxhp, 12, 24);
obj_player_stats.hp = clamp(obj_player_stats.hp, 0, obj_player_stats.maxhp);
*/

//draw text
draw_set_colour(c_white);
draw_set_halign(fa_center);
draw_set_valign(fa_top);
draw_text(gui_width - xoffset * 0.5, 0, "-Life-");

// draw empty heart
var amount = obj_player_stats.maxhp * 0.25;
var remaining = obj_player_stats.hp;
for(var i = 0; i < amount; ++i) {
    if remaining <= 0
        heart_sprite = spr_heart_life_0;
    else
        switch remaining {
        case 1:
            heart_sprite = spr_heart_life_1;
            break;
        case 2:
            heart_sprite = spr_heart_life_2;
            break;
        case 3:
            heart_sprite = spr_heart_life_3;
            break;
        default:
            heart_sprite = spr_heart_life_4;
        }
    remaining -= 4;
    draw_sprite(heart_sprite, 0, xoffset + (i % row_amount) * heart_width, yoffset + (i div row_amount) * heart_height);
}
If you don't need your hearts to be animated, you can also have 1 single heart sprite with as first image an empty heart, as second image a quarter of a heart and so on.
You can then further simplify my code to:
Code:
/// Draw the stats

var gui_width = display_get_gui_width();
var heart_width = 26;
var heart_height = 26;
var row_amount = 10;
var xoffset = width - heart_width * row_amount;
var yoffset = 32;
var heart_sprite;

/* This should be executed in the end step event, not in the draw event
obj_player_stats.maxhp = clamp(obj_player_stats.maxhp, 12, 24);
obj_player_stats.hp = clamp(obj_player_stats.hp, 0, obj_player_stats.maxhp);
*/

//draw text
draw_set_colour(c_white);
draw_set_halign(fa_center);
draw_set_valign(fa_top);
draw_text(gui_width - xoffset * 0.5, 0, "-Life-");

// draw empty heart
var amount = obj_player_stats.maxhp * 0.25;
var remaining = obj_player_stats.hp;
for(var i = 0; i < amount; ++i) {
    draw_sprite(spr_heart_life, clamp(remaining, 0, 4), xoffset + (i % row_amount) * heart_width, yoffset + (i div row_amount) * heart_height);
    remaining -= 4;
}
I've been typing so slow that you've got 2 responses now already, all of them pretty much like my response.
I still felt like posting this reply though.

EDIT:
If you have any questions, feel free to ask them!
 
G

Grimbel

Guest
Guys, thank you all very much for answering so fast and with such a level of detail. I will try to use your solutions and see if I can make them work. If for whatever reason and need your help again, I will ask.
 

Dagolard

Member
Hi! I can´t look the video right now (I´m at work), but this is how I´d do it.

The sprite would have 4 subimages (each showing a quarter of the heart)

Code:
//create event
separation = 30            //separation between hearts
times =                        //variable to check if needs to be separated (after each heart is complete)
x_pos = 25     //position of first heart´s centre
y_pos = 25
MaxHP = 4*4
HP = MaxHP
i=0
frame_number = 0
Code:
//drawevent
for (i=0; i<MaxHP ; i++) {
  frame_number = i mod 4      
  times = i div 4
  if (HP>= i+1)   draw_sprite(spr_heart, frame_number, x_pos + times*separation, y_pos);
}
Be aware that the sprite should be something like this
View attachment 9802
So if you overlap them you get the full heart, and the origin of the sprite is in the centre (touching the corner of the heart).

This is actually an pretty easy and interesting way of doing this, thanks a lot
 
Top