I have no idea the full-scope of what a lot of you said, but in terms of inefficiency - using a for-loop to redraw the HUD every step can be implementationally wasteful and the use of targeted if-conditionals can allow you to make secondary logical assumptions which involve less calculation (as long as the code is commented properly, maintenance should not be too bad). I hope that does not sound argumentative.
The first point I am making is something I haven't taken advantage of until recently, but basically your health and rupees are not always constantly changing (for the most part the player avoids getting damage and is not swimming in boatloads of continuous rupees). Thus, in having a for-loop redraw everything when mostly nothing changes, means that for every step the HUD has to go through the calculations and conditionals to draw the stuff unnecessarily.
Solution: Use Surfaces. While in Game Maker 8, this was a paid feature, in Game Maker Studio Standard Edition, the surface functions are free to use. If your hearts/rupees don't change, you can just redraw the surface. When drawing sprites to the surface, always remember to clear out the surface if you are going to rebuild everything on it, and also to disable interpolation in the Game Options so that the sprites drawn to the surface aren't distorted.
Here is some sample code:
//build_hudSurface();
var i, j, k;
surface_set_target(hudSurface);
//clears/reinitializes the surface
draw_clear_alpha(c_white, 0);
if (heartsFull > 10) {
if (heartsDraw > 10) {
//draw 1st line of full hearts
draw_sprite(sprHearts, 4, 0, 0);
draw_sprite(sprHearts, 4, 8, 0);
draw_sprite(sprHearts, 4, 16, 0);
draw_sprite(sprHearts, 4, 24, 0);
draw_sprite(sprHearts, 4, 32, 0);
draw_sprite(sprHearts, 4, 40, 0);
draw_sprite(sprHearts, 4, 48, 0);
draw_sprite(sprHearts, 4, 56, 0);
draw_sprite(sprHearts, 4, 64, 0);
draw_sprite(sprHearts, 4, 72, 0);
//draw 2nd line of empty hearts
i = (heartsFull - 10) << 3;
for (j = 0; j < i; j += 8)
draw_sprite(sprHearts, 5, j, 8);
//draw 2nd line of inactive full hearts
k = ceil(heartsDraw);
i = ((k - 10) << 3);
for (j = 0; j < i; j += 8)
draw_sprite(sprHearts, 4, j, 8);
//draw 2nd line's active enlarged heart
k = (k - heartsDraw) * 4;
draw_sprite(sprHearts, k, j - 8, 8);
}
else {
//draw 1st line of empty hearts
draw_sprite(sprHearts, 5, 0, 0);
draw_sprite(sprHearts, 5, 8, 0);
draw_sprite(sprHearts, 5, 16, 0);
draw_sprite(sprHearts, 5, 24, 0);
draw_sprite(sprHearts, 5, 32, 0);
draw_sprite(sprHearts, 5, 40, 0);
draw_sprite(sprHearts, 5, 48, 0);
draw_sprite(sprHearts, 5, 56, 0);
draw_sprite(sprHearts, 5, 64, 0);
draw_sprite(sprHearts, 5, 72, 0);
//draw 2nd line of empty hearts
i = (heartsFull - 10) << 3;
for (j = 0; j < i; j += 8)
draw_sprite(sprHearts, 5, j, 8);
//draw 1st line of inactive full hearts
k = ceil(heartsDraw);
i = (k << 3);
for (j = 0; j < i; j += 8)
draw_sprite(sprHearts, 4, j, 0);
//draw 1st line's active enlarged heart
if (heartsDraw > 0) {
k = (k - heartsDraw) * 4;
draw_sprite(sprHearts, k, j - 8, 0);
}
}
}
else {
//draw 1st line of empty hearts
i = heartsFull << 3;
for (j = 0; j < i; j += 8)
draw_sprite(sprHearts, 5, j, 0);
//draw 1st line of inactive full hearts
k = ceil(heartsDraw);
i = (k << 3);
for (j = 0; j < i; j += 8)
draw_sprite(sprHearts, 4, j, 0);
//draw 1st line's active enlarged heart
if (heartsDraw > 0) {
k = (k - heartsDraw) * 4;
draw_sprite(sprHearts, k, j - 8, 0);
}
}
draw_sprite(sprRButton, 0, 198, 2);
draw_sprite(sprABButton, 0, 197, 15);
draw_sprite(sprABButton, 1, 173, 15);
surface_reset_target();
Disclaimer 1: The way I coded the demo takes advantage of a lot of "optimizations", but it is by no means completely optimized. It might be possible, for example, to rework the variable for-loops so that they both don't start from the beginning. The fixed drawn positions to the surface and starting for-loop values could be altered so that the draw_surface function used later would require no additional offset calculation.
Disclaimer 2: If I were to change around some of the code, I could have used the surfaces better. In my example demo, any time your hearts change it will rebuild the hearts entirely. Hypothetically, if I were to draw the active heart as a sprite and not a surface - to where I only was drawing empty and inactive full hearts to the surface, I could reduce the amount of surface operations. If, for example, I added a heart, I could just draw it over the empty heart and if I took away a heart, I could just redraw an empty heart over an inactive full heart. This would make it to where the majority of heart HUD building is just the manipulation of changing one heart instead of rebuilding everything on the surface. Huzzah!
Anyway, I attached .gmx demo which is in the .rar file attached to the post.