She's waiting...ready to tease you live - Jerkmate is free! Join Now!
x

Others [RELEASED] "Help me, Brave Sir Knight!" - A Godot dev diary (previously just "sharing my great idea")

papel

Active Member
Game Developer
Sep 2, 2018
577
794
152
Hmm, have you tried creating a timer that randomizes itself every time it ends, so the "if" checks won't be called at the same frame every time? I did that for a "fire damage" timer in my godot game, and it helped not only the performance, but also made competing sounds not play at the same time. Not sure, but maybe it could help you

View attachment 5409379
Like this: timer node's timeout signal randomizes its time, you can make it as random as you want that way, works for any timer that won't need to be 100% precise.
Like I said in the post, the cause of the problem was uncapped FPS, hitting 500, when making the scene at first, then seeing it act out in 60FPS - the math simply wouldn't work because it wasn't being called 500 times per second, only 60. To make it clearer, the function looked something like this:

Python:
var elapsedtime:float = 0
var fadein:float = 1

func _process(delta:float) -> void:
  elapsedtime += delta
  if elapsedtime > 1 and fadein > 0:
    fadein -= 0.002
    $blackrectangle.color = Color(0,0,0,fadein)
Adding random wait timers wouldn't matter because _process runs once per frame and the fade in animation (and several other things that I'm omitting here) had the math calculated per frame. That 0.002 subtraction for fadein worked fine whenever I tested that scene alone, finishing in around 2 seconds because it was running at 500 frames per second. Under 60FPS, that fade in would take 8.5 seconds or more. It's why the profilers weren't showing any significant difference in processing time

Lastly, I do need precision with the time when something starts and ends in this case, since it's animation, so AnimationPlayer was the best choice for this. I did consider using Tween, but dealing with time elapsed in code, then adding a flag to not run the tween a second time would be more work.
 

pitinar277

Newbie
Sep 27, 2025
19
27
13
Ah, its more of a precison/framerate problem, i see. But yeah, AnimationPlayer is way more precise, _process is giving me headaches, i'm currently trying to migrate stuff to AnimationPlayer, things like sound effects and stat changes, but the annoying part is i have to re-add these same calls every single time i change the animation in blender and re-import, since i duplicate them, still figuring that out.

Anyways good luck in your project, i'll keep an eye on it!
 

papel

Active Member
Game Developer
Sep 2, 2018
577
794
152
Ah, its more of a precison/framerate problem, i see. But yeah, AnimationPlayer is way more precise, _process is giving me headaches, i'm currently trying to migrate stuff to AnimationPlayer, things like sound effects and stat changes, but the annoying part is i have to re-add these same calls every single time i change the animation in blender and re-import, since i duplicate them, still figuring that out.

Anyways good luck in your project, i'll keep an eye on it!
Are tweens an option for you? Once you create a tween, you just define a node and parameter, its final value, and how long it should take to reach said value. You can also chain them together so that one will only start once the previous has finished -

Since it emits a signal when it finishes running, you can also set up a function to run when it does, like this:


Python:
@onready var sprite: Sprite2D = $Sprite

func _ready():
    var tween = get_tree().create_tween()
    tween.tween_property(sprite, "position", Vector2(600, 600), 3)
    tween.connect("finished", on_tween_finished)
    
func on_tween_finished():
    print("Tween done!")
 
  • Thinking Face
Reactions: pitinar277

pitinar277

Newbie
Sep 27, 2025
19
27
13
Are tweens an option for you? Once you create a tween, you just define a node and parameter, its final value, and how long it should take to reach said value. You can also chain them together so that one will only start once the previous has finished -
I'm starting to see how tweens may work, but i'm not sure if it will help in my case since i could just create a timer on the code instead, like this:
Code:
await get_tree().create_timer(0.06).timeout
print("hello world")
The code method i use to pinpoint a certain time in the animations is terrible, it either triggers more than twice, or never triggers, it is even worse with looping animations or animations that dynamically change speed scales.

I could put the calls directly in the creature's anims and call it a day, but the issue is that i need to always re-add it if i ever do any tweak to the creature's anims in blender, i need to re-import it, and it won't transfer the tweaked animations to the modifiable copy with old anims, its such a terrible flaw in my workflow. Quite annoying, y'know?

I will probably end up accepting having to re-do animation tracks every single time i tweak the creature animations, since i can't find a solution. I also don't feel like polluting your game's thread with my game's issues, so this will likely be the last on that regard.
 

papel

Active Member
Game Developer
Sep 2, 2018
577
794
152
Made some final adjustments and released R7! Yay!

Then I test played on the browser and noticed that a LOT of stuff wasn't working. WHY? FUCKING WHY??? Currently debugging, some signals are simply throwing C++ errors that didn't exist in previous Godot versions and that don't happen when run from the editor.

Code:
ERROR: Error calling from signal 'timeout' to callable: 'Area2D(spike-trap.gd)::_on_reload_timeout': Method expected 0 argument(s), but called with 1.
at: emit_signalp (core/object/object.cpp:1310)

ERROR: Error calling from signal 'screen_entered' to callable: 'StaticBody2D(enemy_spawner.gd)::_on_visible_on_screen_notifier_2d_screen_entered': Method expected 0 argument(s), but called with 1.
Those errors make no fucking sense because the functions were ALWAYS zero argument. These things have been working without change since R1.

To make it even weirder, if I add a dummy parameter to the problematic arguments, then the editor complains and throws debugger errors, but the exported game doesn't. What the fuck is going on here??

Code:
#This is the original function that deals with the signal. It doesn't receive parameters. It throws the error I posted above ONLY on the exported game
func _on_visible_on_screen_notifier_2d_screen_entered():
    this_visible = true

#Same function, but now receives a dummy parameter. The editor complains, but the exported game will work fine
func _on_visible_on_screen_notifier_2d_screen_entered(_dum):
    this_visible = true
#
#E 0:00:05:678   emit_signalp: Error calling from signal 'screen_entered' to callable: #'StaticBody2D(enemy_spawner.gd)::_on_visible_on_screen_notifier_2d_screen_entered': Method expected 1 argument(s), but called with 0.
# <C++ Source>  core/object/object.cpp:1310 @ emit_signalp()
This is happening to nearly every function called by a signal - bat detection, several timeouts, even the player's collision with instant death falls. I'll see if I can replicate this o a dummy project, but i'll need to start it off with an older version of godot, like 4.0, then upgrade, and see if it happens again.

I'm never updating Godot mid-project again

One of the things that I ended up forgetting to check was the proper next level, as I forgot to set up the proper scene to load. Woops
 
Last edited:
  • Like
Reactions: pitinar277