Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impact Attribute Damage #109

Merged
merged 7 commits into from
Mar 18, 2024
Merged

Impact Attribute Damage #109

merged 7 commits into from
Mar 18, 2024

Conversation

ac-arcana
Copy link
Collaborator

Deal damage to an attribute when a rigid body impacts something.
There is a minimum velocity setting to prevent weak hits from damaging the attribute.

I made this so that I can have a potion that shatters when dropped.

Deal damage to an attribute when a rigid body impacts something else
@ac-arcana
Copy link
Collaborator Author

Comment on lines 13 to 15
@export var next_impact_time : float = 0.3

var time_passed : float
Copy link
Contributor

@FailSpy FailSpy Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe you can replace time_passed with Godot's Timer functionality so this class doesn't need to track time. Can create and store a oneshot Timer dynamically in code on the _ready, and you can then reuse the single reference to the timer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I basically copy pasted that from the impact sounds component. Is there an advantage to creating a whole new node for such a simple timer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use SceneTreeTimer
It does not create a new node.

The advantage is really that there's not a duplication of time tracking in the backend. Godot pools timers together and ticks them together, as well it also standardizes timer tracking to make it easier to hook with other scripts. So it saves a cycle or so on _physics_process

Copy link
Collaborator Author

@ac-arcana ac-arcana Mar 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware of SceneTreeTimer and I am just taking a look at it. I see that it does not create a node. However, it does still create a timer which is automatically freed once the time is elapsed. On top of this, I would probably need to store a boolean to track whether the timer has completed or not.
Isn't the timer still going to result in GC when it is freed? I'm used to thinking in C# terms, so this might not be the case for gdscript?
Maybe I'm missing a way to keep a reference to it once it has timed out?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, I don't think you're thinking of it wrong. I originally had a Timer node/resource in mind, so if you're using SceneTreeTimer, scratch the reusing reference thing.
The main thing that strikes me as making it worthwhile to add a SceneTreeTimer is that currently every ImpactAttribute component in a scene will be running cycles on _physics_process at all times to check if it should decrease its timer.

With using SceneTreeTimer, only ImpactAttribute components that have recently made an impact (and thusly, a timer is actually relevant) will be tracking time in an already existing section of Godot's backend that tracks time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an extremely minor performance optimization BTW, I don't think that this is a necessary change at all, nor will really be felt by anyone. I was just throwing in this tidbit as a thing to be aware of overall.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm starting to get what you're suggesting now. If there is no physics process function at all checking a timer it will save a little bit of performance on these objects every frame.
So do you think it would be better to use SceneTreeTimer? Or would making and keeping a Timer node be better as it would prevent allocating a new timer and resulting GC for each collision?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a SceneTreeTimer is just neater if it's purely code based, given that the Timer node requires some configuration to make it one shot etc.

@ac-arcana
Copy link
Collaborator Author

I do have a performance concern with using length on every impact.
Potentially I can change it to length_squared. Also if I can check the timer first and fail out of the check it might save some performance.

@FailSpy
Copy link
Contributor

FailSpy commented Mar 12, 2024

I do have a performance concern with using length on every impact. Potentially I can change it to length_squared. Also if I can check the timer first and fail out of the check it might save some performance.

For this sort of thing length_squared is all you need. length doesn't majorly affect performance, but can only help to do length_squared instead

The post-timer check would also be nice as you say

Made the timer check first, and switched to length_squared to improve performance.
@ac-arcana
Copy link
Collaborator Author

I have updated to use length_squared and to check the timer first. I still would like to discuss SceneTreeTimer more as I feel like I still may be missing something about it. See my comment above.

@Phazorknight
Copy link
Owner

Hey y'all, just wanted to say I'm not ignoring this PR, just saw that there were still changes happening and was looking into other stuff.

I see the issue with checking a float in the _physics_process on every object like this (especially since I think components like this will be used a lot), so I'll look into improving this on the ImpactSounds component and see what I can come up with.

@Phazorknight
Copy link
Owner

Okay, so I just pushed an update to ImpactSounds.gd in 52612a4

This changes it to use SceneTree timer instead of the _physics_process.
@ac-arcana , @FailSpy , would love to see if y'all think perfomance is better.

@FailSpy
Copy link
Contributor

FailSpy commented Mar 15, 2024

Okay, so I just pushed an update to ImpactSounds.gd in 52612a4

This changes it to use SceneTree timer instead of the _physics_process. @ac-arcana , @FailSpy , would love to see if y'all think perfomance is better.

Okay, well... I added 680+ health potions to one scene all colliding with each other. I then tried old and new methods in the profiler as fairly as I could

OLD profiled, peaked script function time:
image

NEW profiled, peaked script function time:
image

New technique I would say is more efficient. Though lots of SceneTreeTimer initializations at once will slow things down -- see _on_parent_node_collision_new taking longer despite being fewer calls; in theory, you won't have 450+ ImpactSounds hitting each other all at once initializing that many SceneTreeTimers

Basically, if you do have lots of things constantly colliding, then it might be worth considering the old way, but for MOST immersive sims, the new way probably makes the most sense. :P

Ultimately it's not really saving that much as you can see, considering what it took to get here, but hey, fun to experiment 😆

@ac-arcana
Copy link
Collaborator Author

Thanks for doing the analytics like that. It's nice to see the data. I appreciate getting to learn from each other in this way. I also find it super interesting to see how much _on_parent_node_collision_new jumped up in time.
I definitely see the performance improvement. I agree that both should be done this way. Thanks for the discourse!

@ac-arcana
Copy link
Collaborator Author

Updated with the new timing method. I think this is ready now :)

Copy link
Contributor

@FailSpy FailSpy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

Copy link
Owner

@Phazorknight Phazorknight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, this is awesome. Thank you so much!

Only have a minor note:
line 11: @export var damage : int

attribute values are usually floats, so converting this to a float would probably be recommended. Though it still seems to work fine in my tests overall.

@ac-arcana
Copy link
Collaborator Author

ac-arcana commented Mar 16, 2024

Good catch, I didn't realize the attribute is a float. This will prevent potential conversion errors. Damage is a float now.

Copy link
Owner

@Phazorknight Phazorknight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@Phazorknight Phazorknight merged commit e841b91 into Phazorknight:main Mar 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants