Problems Animating Rolling HP / Odometer (à la Earthbound/M3)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By blue, blue

I’m new to Godot, and programming in general, but I decided to try to recreate Earthbound’s battle system. I’m stuck quite early on, I’ve a test simulating an enemy’s attack to the player’s health, and I decided to try to animate the health, just to see how it would look.

Unfortunately, I haven’t found a way to add such things without it being incredibly tedious. So I decided to ask here, see if anyone with a bit more experience could give me a bit of guidance after I failed to find an answer through searching. Attached should be the code, a screenshot of the nodes, and the sprites I’ve been trying to hook it up with. Thanks in advance! (The textureprogress node is placeholder, I was trying to mess around with it to get it to work, but that’s what lead me here.)

extends Node2D

signal health_changed
signal ko

export var max_health = 20
onready var current_health = 0
var rolling_health = 0

enum STATES {ALIVE, DEAD}
var state = STATES.ALIVE

func _ready():
    $ProgressBar.max_value = max_health
    update_health(max_health)

func update_health(new_value):
    $Tween.interpolate_property($ProgressBar, "value", rolling_health, new_value, 3, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
    if not $Tween.is_active():
	    $Tween.start()

func _process(delta):
    rolling_health = $ProgressBar.value
    $Label.text = str(rolling_health)
    $TextureProgress.value = rolling_health

func take_damage(count):
    if state == STATES.DEAD:
	    return
    current_health = rolling_health
    current_health -= count
    if current_health <= 0:
	    current_health = 0
	    state = STATES.DEAD
	    emit_signal("ko")
    
    update_health(current_health)

    #emit_signal("health_changed", rolling_health)

func _on_Button_pressed():
    take_damage(5)




:bust_in_silhouette: Reply From: Mario

As you already noticed, the game’s way of doing this with a spritesheet is actually rather tedious, too. That’s because the SNES’s PPU (Pixel Processing Unit, i.e. it’s “graphics chip”) was rather simple compared to today’s GPUs and it was lacking lots of modern features, such as repeating textures (it kind of supported those for backgrounds) and clipping (rendering only parts of a texture).

However, since Godot supports all these features I’d suggest an approach that’s a lot more simple:

First, I had to redraw a blank tile as background. Since the original sprites are a bit inconsistent (the visible white area is 12 pixels, but only 11 pixels while moving; if I didn’t miscount), I modified it slightly and added it as a Sprite2D:

Background

Second, I placed all the rolling numbers in one texture, creating one long strip, which is used by a second Sprite2D. Important detail: This texture is only the black numbers, the separating bars, and otherwise transparent background. it’s also set to be repeating!

Rolling Digits

I moved both sprites so they’d overlap each other and enabled the Region for the rolling numbers, clipping the display down to the digit “0”:

Region property

And we’re done. You see no animation? Well, yes. All you now have to do is animate the y value of the Region’s Rect and you’ll end up with a nice rolling number (once the value reaches 120 you can wrap around/reset it to 0):

The Result

(Please note that I forgot to set pixel perfect/snapped rendering before recording, so this doesn’t look as flawless as you might expect, but it will work, if you do so.)

Thanks!! I had an idea of having it scroll vertically, but didn’t know how to go about it! Seeing you actually have it laid out in a format like this is really quite nice and legible, I appreciate it!

blue, blue | 2021-04-08 20:06

1 Like