DC HUD Notes

DCurrent

Site Owner, OpenBOR Project Leader
Staff member

Preface​

These are mostly development notes for my own use so I have them in one spot. Feel free to ignore. I will provide some bit of context for anyone interested though.

Background​

All, I don't know if you noticed in some of my example videos, but I'm a big fan of dynamic HUDs. At minimum, I require the following:
  • Have segments that drain individually, with visual indication through clipping, color, or a combination of both.
  • Sine wave color cycling, working in conjunction with (i.e. not overriding) existing colors and drawmethods.
  • Fully support animation at each level (meter, segment, etc.), separate from above features.
  • Support dynamic text and vector graphics, again without interfering with other features.
  • Change background and other elements in response to player status.
  • Optionally display all active enemies' statuses on screen.
    • Row and column breaks must be automatic, adjust to screen size, and avoid overlapping other items like the timer.
    • As enemies are defeated, their status must stay momentarily on screen, then fade away using dynamic transparency.
    • When an enemy HUD expires and occupies an area preceding other HUDs, the remaining HUDs move smoothly to fill the gap left behind. Rows and columns rearrange themselves accordingly. Time between movements must be constant regardless of distance.

Additionally, a personal requirement right off the bat is to never use models. No offense to @Bloodbane and @maxman, I think using models for any part of the HUD is a very clunky and sub-optimal way to go about things. Unfortunately, getting all that stuff to work required a LOT of hard coding. Every project had its own unique setup, and that's a big reason I've never managed a full release. Recently I devised a two part system to eliminate much of the hard code.

Part 1​

Modelless animations. I'll cover this in detail later. Basically, I use the file-stream system to read a custom sheet of my own, styled similar to native model sheets. The parser creates a series of nested arrays with sprites, delays, drawmethods, etc. to build animation objects I can reference and play back with other scripts.

Part 2​

Text based HUD. Similar to the above. I've built a HUD system that assembles meters by reading from text sheets. See notes below.
 
Last edited:

HUD Meter Notes​

Meters are subdivided to allow a dynamic representation of values. The names of each subdivision are roughly based on the design of an electrical meter, albeit with some additions. To illustrate we will use the classic Zelda heart meter.

1670433657942.png

Meter – Meter is the primary container. It houses all the other units to indicate a status on screen.

Register – Registers are the first level of a meter. In our Zelda example, it is the row of hearts. One meter may have multiple registers, and each register can measure one value. Although this arrangement allows a meter to handle disparate status values (i.e., HP and MP), this is not the intent nor recommended. Rather, it should be more analogous to the multiple hands of a clock. In gaming terms an example would be one register indicating current hit points, while a second register also indicates hit points, but with a much slower rolling effect to convey received damage, as is common in modern fighting games. Registers are also used to add “back fill”. For example, a static row of black hearts to provide backdrop as the register indicating hit points with red hearts depletes.

Unit – Units are the segments of a meter and act as containers for dials. In a register of hearts, one unit houses the dials that represent an individual heart. For instance, in a register of four hearts, the fourth unit is indicative of 75% - 100% hit points, and its dials will represent hearts for that value range.

Dial – Dials are range triggered sub-divisions of a unit. Dials are only active if a sub-percentage the parent unit represents falls with the dial’s range setting. In the four-heart example, if the hit points are at 75%, then the first three hearts sub percentages are 100%, while the fourth is 25%. In turn we might set up four dials to represent sub percentages up to 25%, 50%, 75%, and 100% respectively. This allows us to give each unit dynamic behavior based on the status value. Again, using the Zelda model, this is how we would replicate the half heart behavior.

Pointer – Pointers are containers within a dial. Each pointer houses one animation, drawmethod settings, and other support adjustments. This allows each dial to have multiple graphical elements active at once. An example would be a "back" and "front" pointer, with the front pointer tied to meter's value and the back pointer acting as a static backdrop for the meter unit.

Code:
meter player_hp
  
    offset 29 24
    register fill
  
        value_key fill_fraction      
        # offset 0 0

        unit 0  
          
            # offset 0 0
            dial 0
              
                range 1.0
                # offset 0 0
                # container back
              
                pointer fill

                    # offset 0 0

                    animation hp_horizontal_front      
                    clip_config vertical_down unit
                  
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 0 100 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
          
            dial 1
          
                range 0.75 1.0
                # offset 0 0
              
                pointer back
                  
                    # offset 0 0
                    animation hp_horizontal_front
              
                pointer fill
              
                    # offset 0 0
                    animation hp_horizontal_front
      
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 170 170 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
          
            dial 2
          
                range 0.5 0.75              
                # offset 0 0

                pointer back

                    # offset 0 0
                    animation hp_horizontal_front
              
                pointer fill

                    # offset 0 0
                    animation hp_horizontal_front
                  
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 150 100 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
          
            dial 3
          
                range 0.0 0.5
                # offset 0 0

                pointer back

                    # offset 0 0
                    animation hp_horizontal_front
              
                pointer fill

                    # offset 0 0
                    animation hp_horizontal_front
      
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 200 0 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
      
        unit 1  
          
            offset 13 0
            dial 0
              
                range 1.0
                # offset 0 0
                # container back
              
                pointer fill

                    # offset 0 0
                    animation hp_horizontal_front      
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 0 100 0  
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
          
            dial 1
          
                range 0.75 1.0
                # offset 0 0
              
                pointer back
                  
                    # offset 0 0
                    animation hp_horizontal_front
              
                pointer fill
              
                    # offset 0 0
                    animation hp_horizontal_front
      
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 170 170 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
          
            dial 2
          
                range 0.5 0.75              
                # offset 0 0

                pointer back

                    # offset 0 0
                    animation hp_horizontal_front
              
                pointer fill

                    # offset 0 0
                    animation hp_horizontal_front
                  
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 150 100 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
          
            dial 3
          
                range 0.0 0.5
                # offset 0 0

                pointer back

                    # offset 0 0
                    animation hp_horizontal_front
              
                pointer fill

                    # offset 0 0
                    animation hp_horizontal_front
      
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 200 0 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0

        unit 2  
          
            offset 26 0
            dial 0
              
                range 1.0
                # offset 0 0
                # container back
              
                pointer fill

                    # offset 0 0
                    animation hp_horizontal_front      
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 0 100 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
          
            dial 1
          
                range 0.75 1.0
                # offset 0 0
              
                pointer back
                  
                    # offset 0 0
                    animation hp_horizontal_front
              
                pointer fill
              
                    # offset 0 0
                    animation hp_horizontal_front
      
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 170 170 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
          
            dial 2
          
                range 0.5 0.75              
                # offset 0 0

                pointer back

                    # offset 0 0
                    animation hp_horizontal_front
              
                pointer fill

                    # offset 0 0
                    animation hp_horizontal_front
                  
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 1
                    dm_tint_color 150 100 0
                    dm_tint_cycle_amplitude 25 25 25
                    dm_tint_cycle_wavelength 3.0
          
            dial 3
          
                range 0.0 0.5
                # offset 0 0

                pointer back

                    # offset 0 0
                    animation hp_horizontal_front
              
                pointer fill

                    # offset 0 0
                    animation hp_horizontal_front
      
                    clip_config vertical_down unit
                    dm_config active reset_pre reset_post
                    dm_enabled 1
                    dm_tint_mode 4
                    dm_tint_color 200 0 0
                    dm_tint_cycle_amplitude 35 35 35
                    dm_tint_cycle_wavelength 3.0
 
Last edited:
Meant to post this here instead of my World Heroes thread. Testing a pie depletion style meter using the HUD system. The meter operates as follows.
  • 1 Register - Contains 10 units, each representing 10% of the total HP value.
    • 10 Units - Each unit contains 13 dials. Each dial's activation range is roughly 0.08% percent of the unit's 10% share.
      • Dial 0: 100%
        • Pointer 0 - hp_front_0 with green tint and sine wave brightness cycle.
      • Dial 1 through 12: 1% to 99.99%.
        • Pointer 0 - hp_front_0 with no drawmthods. Serves as dark grey background as unit empties.
        • Pointer 1 - hp_front_0 with yellow/amber/red tint and sine wave brightness cycle.
      • Dial 13: 0%
        • Pointer 0 - hp_front_0 with no drawmthods. Serves as dark grey background to indicate completely empty unit.
 
Last edited:
Whoa! The MP looks animated! How do you ever make that animated instead of using models for animation? You don't seem to use animated BG layers, do you? I believe not. It's astonishing!
 
Whoa! The MP looks animated! How do you ever make that animated instead of using models for animation? You don't seem to use animated BG layers, do you? I believe not. It's astonishing!

Thanks @maxman.

An often forgotten capability of OpenBOR is it can read and write text files. I took advantage of that to build a modeless animation system that allows you to create scripted animations by filling out an animation sheet with a format similar to native model texts. Each animation is identified by a name, which other scripts (like the HUD) can then call and play back.

It does a lot of things native animations don't, like belt scrolling or drawing text. These are my own notes at the top of the sheet that show the things you can add. It's made in such a way I can very quickly expand it to support more effects and properties. Ex: Right now, the only drawmethod available is tinting, but I could add all the others in just a couple of minutes.

Code:
####################################
###### Commands and Attributes #####
####################################
#
# animation <name> - Name of animation. This might be used by a hard
#    coded script draw in an animation set.
#
#    belt_loop <string args> - What to do when scroll reaches defined min or max. Accepts one or more of the following:
#        x_return - Move to the opposite X boundary.
#        x_reverse - Reverse current belt_notch_x.
#        x_stop - Stop auto scroll on X axis.
#        y_return - Move to the opposite Y boundary.
#        y_reverse - Reverse current belt_notch_y.
#        y_stop - Stop auto scroll on Y axis.
#
#    belt_delay <int centiseconds> - Belt auto scroll delay.
#
#    belt_notch_x <int> - Pixels to auto scroll frame on horizontal axis.
#
#    belt_notch_y <int> - Pixels to auto scroll frame on vertical axis.
#
#    belt_pos_x_min <int> - Minimum horizontal scroll position.
#
#    belt_pos_x_max <int> - Maximum horizontal scroll position.
#
#    belt_pos_y_min <int> - Minimum vertical scroll position.
#
#    belt_pos_y_max <int> - Maximum vertical scroll position.
#
#    dm_alpha <int> - Drawmethod alpha mode.
#
#    dm_config <string args> - Drawmethod config. This is not a native drawmethod property. Accepts one or more of the following:
#            active - Use animation frame drawmthods. If not present, drawmethods are not applied at all.
#            reset_pre - Reset drawmethods before drawing frame.
#            reset_post - Reset drawmethods after drawing frame.
#
#    dm_enabled <int> - Drawmethod on (1) or off (0).
#
#    dm_tintcolor <int red> <int green> <int blue> - Drawmethod tint color.
#    dm_tintmode    <int> - Drawmethod tint mode.
#
#    delay <int centiseconds> - Delay time.
#
#    frame <path sprite> <path alpha mask (optional)> - Animation frame. Use "none" to add a frame with no sprite.
#
#    loop <string args> - Looping behavior for animation. Accepts one or more of the following:
#        enable - Animation loops to frame 0 after last frame plays.
#
#    next <int frame> - Move to <next> frame index instead of subsequent index when the frame delay expires.
#
#    offset <int x> <int y> - Position of frame.
#
#    position <int x> <int y> - Position of animation.
#
#    text_config <string args> - text behavior for string output. Accepts one or more of the following:
#        enable - Enable drawing the string. String does not draw otherwise.
#        center_x - Place horizontal center of string at frame position.
#        center_y - Place vertical center of string at frame position (i.e. in a three line string, position is vertical center of second line).
#
#    text_string <string> - Text to draw into frame. Use @~<variable name>~@ to insert value from a
#        local variable in the parent code.
#
#    text_line_break <string> - Discard each instance of <string> in the text_string and start a new line.
#
#    text_font <int font#> - Font to draw text.
#
# END - Immediately stop parsing of the animation list at this point.
#

This is what the MP animation entries look like.

Code:
animation hero_h_frame    

    frame data/sprites/hud/player_mp_unit_empty_h_0.png

animation hero_h_fill

    loop enable

    delay 15

    frame data/sprites/hud/player_mp_unit_fill_h_0.png
    frame data/sprites/hud/player_mp_unit_fill_h_1.png
    frame data/sprites/hud/player_mp_unit_fill_h_2.png
    frame data/sprites/hud/player_mp_unit_fill_h_3.png

animation hero_e_frame    

    frame data/sprites/hud/player_mp_unit_empty_e_0.png

animation hero_e_fill

    loop enable

    delay 12

    frame data/sprites/hud/player_mp_unit_fill_e_0.png
    frame data/sprites/hud/player_mp_unit_fill_e_1.png
    frame data/sprites/hud/player_mp_unit_fill_e_2.png
    frame data/sprites/hud/player_mp_unit_fill_e_3.png

animation hero_r_frame    

    frame data/sprites/hud/player_mp_unit_empty_r_0.png

animation hero_r_fill

    loop enable

    delay 12

    frame data/sprites/hud/player_mp_unit_fill_r_0.png
    frame data/sprites/hud/player_mp_unit_fill_r_1.png
    frame data/sprites/hud/player_mp_unit_fill_r_2.png
    frame data/sprites/hud/player_mp_unit_fill_r_3.png

animation hero_o_frame    

    frame data/sprites/hud/player_mp_unit_empty_o_0.png

animation hero_o_fill

    loop enable

    delay 12

    frame data/sprites/hud/player_mp_unit_fill_o_0.png
    frame data/sprites/hud/player_mp_unit_fill_o_1.png
    frame data/sprites/hud/player_mp_unit_fill_o_2.png
    frame data/sprites/hud/player_mp_unit_fill_o_3.png

The animations themselves are constructed using multidimensional arrays. The parent script supplies the animation playback function with the desired animation object, and it draws the appropriate sprite with any drawmethods or other effects specified. Here's the whole MP entry from the HUD system. Note the animation names. That tells the HUD system what animation to play depending on ranges and sub ranges. The HUD system then adds its own effects and adjustments, and that's your end result on screen.

Rich (BB code):
meter player_mp
 
    offset 29 24
 
    register full
        offset 2 -1
        value_key fill_fraction_mp
        range 1.0 1.0
     
        unit 0                     
            dial 0             
                range 0.0 1.0
                pointer full
                    animation hero_full 
 
    register fill
        value_key fill_fraction_mp
        range 0.0 0.999999
     
        unit 0         
            dial 0         
                range 0.0 1.0

                pointer frame
                    animation hero_h_frame

                pointer fill
                    offset                        1 1
                    animation                    hero_h_fill
                    clip_config                    vertical_down unit
                    dm_config                    active reset_pre reset_post
                    dm_enabled                    1
                    dm_tint_mode                3
                    dm_tint_color                200 0 0
                    dm_tint_cycle_amplitude        25 25 25
                    dm_tint_cycle_wavelength    3.0
                     
        unit 1
            offset 13 0

            dial 0             
                range 0.0 1.0

                pointer frame
                    animation hero_e_frame

                pointer fill
                    offset                        1 1
                    animation                    hero_e_fill
                    clip_config                    vertical_down unit
                    dm_config                    active reset_pre reset_post
                    dm_enabled                    1
                    dm_tint_mode                3
                    dm_tint_color                200 0 0
                    dm_tint_cycle_amplitude        25 25 25
                    dm_tint_cycle_wavelength    3.0

        unit 2
            offset 26 0

            dial 0             
                range 0.0 1.0

                pointer frame
                    animation hero_r_frame
                pointer fill
                    offset                        1 1
                    animation                    hero_r_fill
                    clip_config                    vertical_down unit
                    dm_config                    active reset_pre reset_post
                    dm_enabled                    1
                    dm_tint_mode                3
                    dm_tint_color                200 0 0
                    dm_tint_cycle_amplitude        25 25 25
                    dm_tint_cycle_wavelength    3.0

        unit 3
            offset 39 0

            dial 0             
                range 0.0 1.0

                pointer frame
                    animation hero_o_frame
                pointer fill
                    offset                        1 1
                    animation                    hero_o_fill
                    clip_config                    vertical_down unit
                    dm_config                    active reset_pre reset_post
                    dm_enabled                    1
                    dm_tint_mode                3
                    dm_tint_color                200 0 0
                    dm_tint_cycle_amplitude        25 25 25
                    dm_tint_cycle_wavelength    3.0


HTH,
DC
 
Last edited:
Back
Top Bottom