Why are collisions happening 1 frame late?

Godot Version

4.2

Question

I’m making a platform fighter in Godot 4 and I’m using an AnimationPlayer to toggle on or off Area3Ds which I’m using for my hitboxes. The hitbox is set to enabled on the very first frame of the animation which plays the moment the attack state is entered. Debugging shows that it’s set to enabled 1 frame late, and when a collision happens it also takes a frame before it’ll do anything. Why does this happen? Is this normal in Godot or is my code just awful? This hasn’t been a problem in any other engine.

1 Like

You could be using call deferred, which sets it to call at the end of the frame. I think that is the intended way though, so keep a lookout for any bugs which could happen.

2 Likes

AnimationPlayer has a callback process mode which I believe you want to be set to physics. The default, Idle is during process frames.

3 Likes

Area3D Documentation:

For performance reasons (collisions are all processed at the same time) this list is modified once during the physics step, not immediately after objects are moved. Consider using signals instead.

You may be using the get_overlapping_bodies() function, which will only update at the end of each frame.

P.S. Without samples of your code, we can only speculate at the cause of the issue. Consider sending more information with your next post.

3 Likes

The gif below shows the test attack I have set up. The hitbox should come out immediately, but it takes 1 frame to actually end up as enabled. It also takes an extra frame to disable. On hit it takes another frame before hitstop is applied and all that. Regardless of which callback mode is used the issue is the exact same. Not sure if any of this helps. What should happen is the exact frame that the hitbox is visible should be when it hits, and on that frame hitstop should be applied. As of right now frame 1 shows the hitbox, frame 2, enables it, frame 3 applies hitstop.

Godot_v4.2.1-stable_win64_teb8Kk8uHN

1 Like

I’m checking for hitbox collisions this way but I’m not sure if it’s the right way to go. I set the AnimationPlayer’s callback mode to immediate and the issue still happens.

1 Like

@gertkeno I’ve set it to that but the issue still happens.

@Opalion I am using get_overlapping_areas() in this function which is called right at the top of physics process:

func check_collisions():
	var hit_registered = false
	
	for hurtbox in hurtboxes:
		if not hit_registered:
			var overlapping_areas = hurtbox.get_overlapping_areas()
			for area in overlapping_areas:
				if area.name.begins_with("HITBOX") and area.has_hit[playerslot] == 0 and area.attacker != playerslot and !invincible:
					process_hit(area)
					hit_registered = true
					break

Sorry for any delays in responses, I posted a screenshot and a gif of the problem but they’ve been awaiting approval for a while

1 Like

Everything you do in the SceneTree with nodes need to synchronise with the PhysicsServer and the result back to the SceneTree.

So if you do stuff in e.g. _physics_process() that gets send to the server. There is no physics result at that point, every query you do at this point operates on the space data from the last physics step. The entire reason why you e.g. do ray queries on a get_space_state() function is to get a static copy of that physics state to query on.

After the script _physics_process() the server syncs. Then the server does its internal physics step calculation. Then the server sends the callbacks back to the SceneTree, e.g. moving physics nodes with the result from the physics server. The override functions that some physics nodes have are basically callbacks where the server asks inbetween calculations of bodies what to do to affect the result.

The Area overlap functions are always behind things because of that sync and processing order. By the time you call the area function in script nothing has synched with the server and you still query the result from the last physics space state.

If you need immediate and up-to-date overlap feedback for gameplay logic learn to use simple Rect position, overlap and ray checks and not physics. Physics is a stepped process that reacts on things and nodes will always lag behind with their node state due to the sync and processing order.

2 Likes

Is there no way to fix this with Area3Ds and such? If not would making a custom hitbox/hurtbox system be better? Alternatively I could design attacks around the delay and activate hitboxes 1 frame earlier, and then the frame after that show the visualiser or whatever to create the illusion of the attacks connecting on the frame the hitbox comes out. Which would be the better option?

1 Like

For anyone seeing this later, I recently learned with a ShapeCast3D you can use the force_shapecast_update() function to force collision checks. You can replace the Area3D with a ShapeCast3D or stack them with different collision layers.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.