Hack and slash game physics and collisions

Godot Version

4.6

Question

Hi,

I need help with some information. I am implementing a hack and slash game in Godot and i need to know how to cause the animations to interpolate so that the sword swing stops when it hits a shield …

If i increase the number of physics steps will the animation start doing sub-ticks, like 0.001 or a frame for example?


You decide how the animation advances. Look at the callback mode properties in the animation player node.

So for accurate sword motion collision i would just increase the physics steps or physics frame rate and make sure the animation is set to continuous ?

How can i make sure collisions with an object like a shield are processed before the torso? At the moment i set a flag when the shield is hit and then in ``physics_process()`` i allow the damage if the shield was not hit … but i wonder if it can be done purely with signals or whether the shield will be processed after the torso…

If you want animations to update at physics tick, set callback_mode_process to “physics”.

Ah yes i think ive got that set … so is the physics priority how to ensure the shield is processed first?

Of course this could be wrong if the shield is hit last and still gets processed first.

The other way ive got involves ray casts but i prefer the idea of computing extra physics frames

Not sure I understand what you mean here.

Animations have nothing to do with physics. They are just visual representations. If your physics granularity is denser than your rendered frames granularity and you want to stop the animation as a result of a time-dense physics, then use the physics callback mode. It’ll let you stop the animation at physics tick granularity.

Yeah ill try to stop the animation on collision … i was calling get_tree().paused = true previously before i had the callback mode set.

I havent tried pausing since so maybe the result will show less penetration. I might also try raycasting forwards from the sword instead of between the last two frames, but then i dont know the ray length. So i need a way of running the animation a frame in advance then drawing a previous or interpolated frame.

You can pause and seek() backwards for a tiny amount.

1 Like

Ok, theres a shield Area3D and a torso Area3D. So if the collisions are handled with signals i have implemented two algorithms.

The first just trusts the physics system to detect the sword hitting the shield because the area sweeps through before hitting the torso.

The second collects flags for each area intersected by the sword and uses physics process to cast rays through the swords current and previous positions. This works better but im not sure why.

Ok if the first policy is used then if the shield is on the left, and the sword arrives from the left hitting the shield first and also penetrating the torso then you could hope that the shield is processed first when godot processes the signals, so that the sword can be disabled from causing damage and the animation could be paused.

If the sword arrives from the right and passes through the torso but also touches the shield near the end then of course you need the torso to be processed first.

I suppose both methods work and always benefit from higher frame rates, then the error shrinks. It would be good if the algorithm was ‘iron clad’ (pardon the pun) for lower end systems .

How would that look in code ? Is that seek() for the animation tree node?

How would I know how would it look in your code?

It’s for the animation player. For the tree, it would depend on how the tree is set up.

If two things happen inside the same physics tick, your code can always decide which one should have the priority.

The sword area has a script on it that has the method motion_active() and motion_inactive()triggered by the animation with a method call track and it also records the positions of two points that are child nodes of the sword.

I have a script on the character model that processes the signals from the collisions then in physics_process() i just check the sword rays from between the positions stored in the sword position array betweenarray.size()-2and array.size()-1

And also a point in the middle. I find the nearest position but that isnt really correct if you imagine the tip travels further in a frame than the base of the sword so the collision distance should be a percentage.

So i need to get animation time for the frames processed and then use seek() to find the position more closely matching the collision point, perhaps with lerp().

I will probably need to save the animation time of each recorded point and use that for seek … problem is that the animation calls actually come from the physics process of a parent node …

Just experiment manually how much you need to rewind until you find a value that sells the illusion. It’s a game, not a scientific simulation of sword and shield impact.

The animation needs to be rewinded on the owner of the sword … so im thinking the physics process of the reciever character calls a function on the sword owner that calls seek()

with t1 and t2 as the last and current animation times and a=nearest_col/ray_length is the percentage of the collision and the ray length. Basically seek_time=lerp(t1,t2, a)

And these are just approximations because the rays are taking a shortcut compared to the true arc of the sword between frames

The entire process woild be easier and better with an active ragdoll …