GM:S 1.4 Diagonal Life Bars?

Discussion in 'Programming' started by MaxLos, Oct 9, 2019.

  1. MaxLos

    MaxLos Member

    Joined:
    Sep 25, 2017
    Posts:
    16
    Noob question but I could not find any topics regarding this. How do deplete a diagonal life bar properly?

    This is the code I was using for horizontal bars:
    Code:
      
    var spriteWidth = sprite_get_width(spr_healthbar); //Width of health bar sprite
    var spriteHeight = sprite_get_height(spr_healthbar); //Height of health bar sprite
    var HealthPercent = obj_player.HP/obj_player.MaxHP; //Percentage of health left
    
    draw_sprite_part(spr_healthbar, 0, 0, 0, spriteWidth*HealthPercent, spriteHeight, 0, 0);
    
    But it doesn't really properly fill/deplete bars that are tilted.


    20191009_060918.gif
     
  2. CloseRange

    CloseRange Member

    Joined:
    Jul 2, 2016
    Posts:
    836
    draw_sprite_part will always draw a sprite in this regard.
    if your origional sprite is drawn normally (horizontal or vertical like the bar on the left) then you could instead rotate the image and use draw_sprite_part_ext which allows for rotation.
    that's the best option.

    your other option is to set the image to a texture and use draw_vertex_texture.
    However then you run into the problem that your image needs to be a power of 2 and a perfect square so you'd have to scale the image down to the size you want.
    The is the less good option.

    OR if your healthbar is as simple as the image above then don't use sprites at all. Just use 2 draw triangles for the inside and 4 draw_line to get the border.
     
    ParodyKnaveBob likes this.
  3. MaxLos

    MaxLos Member

    Joined:
    Sep 25, 2017
    Posts:
    16
    Well unfortunately my health bar isnt as simple as the image, I was just using it as an example. And I know nothing about textures... But thanks for the heads up about rotating the sprite I think that might actually work so ill try that
     
  4. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,743
    This thing from one of Mike's tech blogs is GMS2-only, but it looks like exactly the use-case you want:
    https://www.yoyogames.com/blog/430/dynamic-rendering-masks

    Rotating a sprite (and then draw the partial fill with e.g. draw_sprite_general so you can draw a part AND rotate it) probably works for simple cases (e.g. Persona 5 style). If you want something really dynamic like Kingdom Hearts where the healthbar curls around in a circle, you might need to have several different sprites for different fill levels (which will use a lot of VRAM and texture page space, but will make you rip less of your hairs out in frustrating trying to get the clever solution to work).

    Another creative solution for weird shapes: use a path, step through it between 0...hp% with path_get_x/path_get_y (path position 1 is the end of the path, position 0 is the beginning), draw small segment sprites along the path from beginning to end position. Easily uses up a lot of processing power, but less memory. The age-old tradeoff between speed and space. A nice border around the path-drawn healthbar could be achieved by taking a screenshot of the filled bar, pasting it into GIMP or Photoshop (did they add copypasting into the GMS2 sprite editor yet?), and making an outline around the shape, then copying that and making a sprite outta it.
     
    MaxLos likes this.
  5. MaxLos

    MaxLos Member

    Joined:
    Sep 25, 2017
    Posts:
    16
    Welp, rotating the sprite didn't work. I thought I could just rotate a segment of the bar but doing so distorts the pixels and cause of the shape of my bar rotating it at any angle wouldn't make bar fill the outline of the curved sections of the bar anyway (picture of bar below)


    bars.PNG


    I also really want to avoid having to make multiple indexs for the sprite if i can... So ill try using paths like Yal suggested.
    Not too familiar with them, though. How would I go about drawing segments along the path? @Yal
     
  6. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,743
    Have a loop designed to loop from 0 to 1 when the bar is full (so at half health, loop to 0.5). At each such step, use path_get_x and path_get_y to get the path position for the loop value. (Subtract its value for position 0 to get a value that's independent on where the first point is located in the editor). Draw a small "segment" sprite at this position.

    Now, there's a whole bunch of kinks left to iron out in this. First of all, the shape of the segment sprite. Circles would be nice, since they have the best coverage, but this will give clear rounded edges. Let's consider a rectangle of width 1 and height equal to the bar's... uh, "acrossicord" instead, with its origin in the center right.
    upload_2019-10-10_21-13-41.png

    What's so special with this shape? It will face the direction of the path, but if we draw it with an image_xscale > 1, it will stretch backwards. We want to do exactly that: stretch it with the distance between two points on the path. Since it's 1 pixel, you can stretch it by the distance, and it will match perfectly.

    Now, we actually need to stretch it more than that sometimes, because of the outer edge of a corner being further away from the previous' point's counterpart than the center point is. This creates a gap.
    upload_2019-10-10_21-16-59.png

    This gap will be at most the square root of 2 larger than the side of the distance from the center point to the outer point of the bar (so acrossicord / 2 * sqrt(2) = acrossicord/sqrt(2) = acrossicord/1.4), if you're lazy you could just always stretch it with this value (precomputed as a constant for speed) instead of computing it based on the angle.


    Finally, the sprites might look a bit like a patchwork of rotated sprites, because that's why it is. You could solve that by have the segment sprites be pure white, and then use a shader or some blend mode trickery to project a nicer texture onto them.
     

    Attached Files:

    MaxLos likes this.
  7. flyingsaucerinvasion

    flyingsaucerinvasion Member

    Joined:
    Jun 20, 2016
    Posts:
    2,169
    If you provide a diagram explaining exactly how you created the curves in that healthbar, it could help us help you to come up with the most accurate solutions.

    I believe one of the more straightforward things to do would be to use a shader that fills the healthbar based on a gradient texture and a health value. But to do that, we'd need to be able to construct the gradient, which means we need to know how the curve was generated.
     
  8. MaxLos

    MaxLos Member

    Joined:
    Sep 25, 2017
    Posts:
    16
    Ok so.. correct me if im wrong cause I was a little bit confused but here's what I did so far:

    First I made a path (not sure if I placed it correctly?)
    path health.PNG

    Then I made a segment with a width of 1 and the height of the.. ''acrossicord", which is right here, right?
    acrossicord.PNG
    If so, that gave me a segment size of 1 x 26.

    Then I put this in the Draw Event
    Code:
    path_position = HP/100;
    draw_sprite(spr_segment,0,path_get_x(path_health,path_position),path_get_y(path_health,path_position));
    
    Is all of that right so far? @Yal

    Also, @flyingsaucerinvasion I didn't make the curves in for the healthbar with code, I just used the fill tool on the outline of the sprite, made it a separate sprite, and tried drawing it with the code in my first post. This is then when I realized it didn't work too well with curves
     
    Last edited: Oct 11, 2019
  9. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,743
    Nonono, we need rotation and scale as well... more like
    Code:
    step = 0.01
    segment_size = path_get_length(path_health)*step
    for(pp = 0; pp < hp/hp_max; pp += step){
      xx = path_get_x(path_health,pp)
      yy = path_get_y(path_health,pp)
      dir = point_direction(xx,yy,path_get_x(path_health,pp+step),path_get_y(path_health,pp+step))
      draw_sprite_ext(spr_segment,0,xx,yy,segment_size,1,dir,c_white,1)
    }
    
     
    MaxLos likes this.
  10. MaxLos

    MaxLos Member

    Joined:
    Sep 25, 2017
    Posts:
    16
    Ahhh thank you so much, its working! It does overlap the outline of the bar a little bit but I think I can fix it by myself easy. Thanks again :)
     
  11. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,743
    You could always draw the outline on top, after you draw the bar itself? Should help hiding any jagged edges as well.
     
    MaxLos likes this.
  12. MaxLos

    MaxLos Member

    Joined:
    Sep 25, 2017
    Posts:
    16
    Yeah but the entire outline is a sprite itself so it just draws the whole thing over the bar. I could make the the part that the bar is overlapping a sprite and just draw the outline --> bar--> part the bar was overlapping, i guess
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice