First thing, maybe this is how it's supposed to work, but I find this very weird. So I'm simulating firearm code at the moment and realized that my time to empty a mag was consistent, but not accurate. I kept thinking it was due to some recursion that I was using for the weapon, but I changed that and still was having the same results. I then changed the FPS and realized my results changed by .5 seconds. This is a huge difference.

I played around with the locked FPS and results are in the video that's attached. For 1200RPM/30rds there was a difference of 1.461 to 1.933 seconds (280fps vs 60fps) to empty a mag. For 300RPM/30rds there was a difference of 5.811 to 6.234 (280fps vs 60fps). At higher fps, the results were more "accurate". Even then, only @ 1200rpm is the 280fps results accurate. It was off by 2 tenths when I tried it @ 300RPM.

What could this be and how can I make these timings more consistent throughout different frame rates and also provide more accurate results? I've also tried handling the input through other than _input() (what I'm using atm), but process()/physics_process() resulted in the same thing.

Video:

  • xyz replied to this.
  • jruiz I'm guessing here since you didn't post any code. Don't reset bullet time counter to zero. Instead start counting from leftover time, i.e. the frame delta time minus its fraction used to complete the last bullet time.

    Have you tried comparing the Timer node? I have found that in Godot the Timer node seems to be really accurate compared to anything else you can do in code but mind you I'm not planning on making games as accurately measured as this.

      jruiz I'm guessing here since you didn't post any code. Don't reset bullet time counter to zero. Instead start counting from leftover time, i.e. the frame delta time minus its fraction used to complete the last bullet time.

        Lethn Yea, I gave that a go previously. Same issue.

        xyz This is makes sense. Implemented this really quickly and started getting consistent timings between frame rates, now it's a matter of getting the right results. I'm getting ~3.8s at 600rpm (expecting 3s), going to dive into it a bit more. Appreciate the help!

        You need to post some code. We have no idea what you are calculating. Another angle is floating point inaccuracy with small numbers. Also, everything in Godot runs at a fixed rate (either the physics tick or frame rate) so you cannot accurately get number between frames. On a 60Hz monitor that would be 16.7 ms, but the loose change could accumulate over frames if your math logic is incorrect.

          cybereality Yea, I should've posted some code, you're not wrong. I have this cluster of messy code for prototyping though and I figured not to, but will in the future. I got it working consistently across different frame rates. I was using delta time to add time from the moment the first bullet was shot and when mag was emptied to get the final time. That wasn't really the issue though, it was more about getting the RPM consistent as I was using a timer resetting at zero and that's when xyz's comment made a lot of sense to me. I made the adjustments they mentioned by letting time run and fixed a few other issues with my shoot method using recursion for full-auto and it's all working as intended. The math doesn't exactly add up to the real thing, but it's close enough, and most importantly consistent.

          • xyz replied to this.

            jruiz It should actually be quite exact and framerate independent if you implement it properly. The delta time numbers here, although quite small, are still not small enough to start making significant float precision problems. I suggest you make a dummy project that just counts time and use that to figure out how to approach it. That way you'll also be able to post your code without rest of the clutter and get better help with it.

              xyz Maybe I didn't explain this the best as I was in a hurry, but I mean that the results for the time it takes to empty a mag are the same every time now, thanks to your solution. I was mainly talking about the math behind it. So at 600RPM we'd empty a 30rd mag in 3s, but I get like 2.889s which is not a big deal, and I'm fine with this since it's always the same duration now. The only real issue that I've encountered is that the first few seconds of the scene loading, the mag takes 3.2s to empty instead of the 2.889s that occur for the rest of the duration. Since it's only for the first few 1-3s anyways, I don't really mind it all that much.

                jruiz Oh, I thought the time you were getting was 3.8 instead of 3.0 which would make a considerable difference. But looks like you just made a typo in the post before. If you can live with 2.889 that's fine then. Personally I'd still want to hunt down where that .111 is lost, out of pure curiosity 🙂

                  xyz I'm def still thinking about hunting that little difference down in the future 😃 I think for the sake of development, the consistent 2.889s is fine for now. If I find the reason for that gap I'll make sure to add to the post and possibly include a stripped down project here as well. I appreciate the help!

                  jruiz

                  The only real issue that I've encountered is that the first few seconds of the scene loading, the mag takes 3.2s to empty instead of the 2.889s that occur for the rest of the duration. Since it's only for the first few 1-3s anyways, I don't really mind it all that much.

                  This might be a Godot 4 issue (_physics_process() specifically). I've recreated a minimal project on Godot 3 and I'm not having these inconsistencies. This also happens randomly when playing, not something that only happens when the game is first launched.

                  Going to upload minimal recreations on here for both GD4 and GD3 so people can take a look.

                  Recreations of the prototype can be found here: https://github.com/jar-wtf/firearm-testing-recreation

                  I would start with the Godot 4 version and run it. First run will be around 3.2s and will produce around 2.889s after that for a good while. I would leave that running in the background while testing the Godot 3 version. After trying the Godot 3 version, Godot 4 version might start having the inconsistency of 3.2s again, if not it might take some more time. On the other hand, the Godot 3 version should be producing super consistent results.

                  You shouldn't use timers for this. Make an accumulator variable (like current_time) that starts at 0 and then adds delta_time every frame (in _process()) and is never reset.

                  Then you can record the start time of the bullet shot (shot_time = current_time) and bullet end and subtract to get the exact difference (duration = current_time - shot_time).

                    cybereality I'm not using a timer for this and I'm letting time run, as you mentioned.

                    • xyz replied to this.

                      jruiz It works but looking at your code you're doing it in a kind of convoluted way - with recursive calls and yields/awaits in the input callback. This makes execution hard to follow and can cause nasty bugs down the line. Consider rewriting it in a simple way.

                      Btw 2.9s time is correct since you only measure gaps between shots. There's 29 of them for 30 bullets, each lasting .1s at 600 rpm.

                        xyz That makes so much sense lol ty. Also, I was planning on removing the recursive shoot() call since it had some certain issue I wanted to fix, but got a bit invested in this issue and forgot about it. I'll be changing that soon.

                        Do you have any idea why there might be an inconsistent results for the Godot 4 version? The random 3.2s results on the Godot 4 version are a bit concerning at the moment. This is not something that occurs in the Godot 3 version.

                        Edit: Updated GitHub to remove recursion.

                        • xyz replied to this.

                          jruiz Nice! Haven't put my hands on v4 yet at all. There was a recent discussion on latency issues I think. @cybereality may have some insight on that.