0 votes

Hello Godot World!

OS - Windows 10 64 bit
Godot version - 3.2.2 (C#/Mono)

I hope everybody is having a fantastic day and that the sun light shines forever on your path!! Good will to all!

Now, after grinding my teeth for the past few hours racking my brains over this problem, I've come to a head and decided to post this issue on the forums, as no searches I have done have helped, and even after having a go at diving in to the Godot source code (sucessfully, obviously...) I'm none the wiser.

So the scene setup is this:

Node2D at the scene root

KinematicBody2D (name: MovingBody)
--Sprite
--Area2D (name: InteractArea)
----CollisionShape2D (shape: RectangleShape2D)

Area2D (name: InteractableArea)
--Sprite
--CollisionShape2D (shape: RectangleShape2D)

On the "InteractArea" on the "MovingBody" I have the signals like so:

areaentered: MovingBody->OnAreaEnteredInteractArea (Area2D area)
area
exited: MovingBody-> OnAreaExitedInteractArea (Area2D area)
bodyentered: MovingBody->OnBodyEnteredInteractArea(PhysicsBody2D body)
body
exited: MovingBody->OnBodyExitedInteractArea(PhysicsBody2D body)

On the "InteractableArea" have the signals like so:

areaentered: InteractableArea->OnAreaEntered (Area2D area)
area
exited: InteractableArea-> OnAreaExited (Area2D area)
bodyentered: InteractableArea->OnBodyEntered(PhysicsBody2D body)
body
exited: InteractableArea->OnBodyExited(PhysicsBody2D body)

The idea being that the KinematicBody2D is used for solid collision while the InteractArea is used to scan for InteractableAreas.

I've got this set up so that whenever one of those signals are fired a GD.Print() is ran with details like:

(name of self): (name of signal) -> (name of other)
InteractableArea: OnAreaEntered -> InteractArea
MovingBody: OnAreaEnteredInteractArea -> InteractableArea

So I can see the flow of operations/signals being fired. From doing several experiments I've found that the area signals seem to be prioritised over the body signals in general; if the MovingBody and the InteractableArea are overlapping when the scene starts then the body signals are fired first, otherwise all other times it seems that the area signals are fired first.

The problem I am having is that when I move the MovingBody (by using MoveAnd-Slide/SlideWithSnap/Collide inside of the _PhysicsProcess method) towards the InteractableArea the OnBodyEntered signal is not fired until the following frame. Let me try to explain that a little better:

MovingBody is on the right, InteractableArea is on the left:
[ ] [ ]

When the MovingBody moves, it gets closer to the InteractableArea:
[ ] [ ]

And when the MovingBody overlaps the InteractableArea:
[[ ]]

I expect the OnAreaEntered signal to fire on the InteractableArea (which it does) then I also expect the OnBodyEntered signal to fire on the InteractableArea (which it doesn't). It isn't until the very next frame that the OnBodyEntered is fired, making me suspect that the actual physics body is not actually "moved" until the very beginning of the _PhysicsProcess method (well, before this method is called), then when the MovingBody is moved (MoveAnd-etc) then the Area is moved/updated and detects the overlap with the other area, but the body is not "recalculated?" until the next frame.

I've tried putting ForceUpdateTransform() everywhere (before and after everything) and this hasn't helped. The only thing I have found that has given me the most accurate result is by moving the MovingBody manually (Translate(Velocity * delta)) and ticking "Sync To Physics"on the MovingBody; doing this results in both signals (OnArea and OnBody) being called on the same frame, but it seems that they are now BOTH fired on the following frame, whereas before the OnArea signal was fired on the same frame of movement that caused the overlap.

I have set up a manual time stepper to tick through the steps and it is showing me the same as I have said above.

So..... I am unsure if this is a bug within Godot, or if I am not using something right, or something else completely. I have looked through the Godot documentation and I cannot find a mention of this behaviour anywhere, only that the signals available and that they are fired when that action happens (OnBodyEntered is fired when the body enteres the area, OnAreaEntered is fired when the area enteres the area etc).

If anybody would like to see the code I can put it here but it is literally

public override void _OnPhysicsProcess (float delta)
{
Velocity = MoveAndSlide(Velocity, Vecotr2.Up);
}

Any help would be appreciated!!! And have a lovely day! stops grinding teeth

Edit:

I thought I'd add a paste of the output console.

Frame: 1
Frame: 2
Frame: 3
Frame: 4
Frame: 5
InteractableArea1: OnAreaEntered -> InteractArea (IsQueuedFree=False)
MovingBody: OnAreaEnteredInteractArea -> InteractableArea1 (IsQueuedFree=False)
Frame: 6
InteractableArea1: OnAreaContinue -> InteractArea (IsQueuedFree=False)
InteractableArea1: OnBodyEntered -> MovingBody (IsQueuedFree=False)
Frame: 7
InteractableArea1: OnAreaContinue -> InteractArea (IsQueuedFree=False)
InteractableArea1: OnBodyContinue -> MovingBody (IsQueuedFree=False)
Frame: 8
InteractableArea1: OnAreaContinue -> InteractArea (IsQueuedFree=False)
InteractableArea1: OnBodyContinue -> MovingBody (IsQueuedFree=False)
Frame: 9
InteractableArea1: OnAreaContinue -> InteractArea (IsQueuedFree=False)
InteractableArea1: OnBodyContinue -> MovingBody (IsQueuedFree=False)
InteractableArea1: OnAreaExited -> InteractArea (IsQueuedFree=False)
MovingBody: OnAreaExitedInteractArea -> InteractableArea1 (IsQueuedFree=False)
Frame: 10
InteractableArea1: OnBodyContinue -> MovingBody (IsQueuedFree=False)
InteractableArea1: OnBodyExited -> MovingBody (IsQueuedFree=False)

Frame 1 to 4 are when the MovingBody is heading towards to InteractableArea, frame 5 you can see it detects the Area2D overlap, then frame 6 it detects the Body2D overlap, then frame 9 is when it leaves the InteractableArea but the body leaving is not detected until frame 10.

Edit2:

If I move the MovingBody towards and through the InteractableArea then the above behaviour is shown, but if I reverse this and move the InteractableArea towards and through the MovingBody then both signals (OnAreaEntered and OnBodyEntered) are fired at the expected time, but no matter what I try, if I move the MovingBody (which is what I'm after, the MovingBody is just a small placeholder for an Actor) then the OnBodyEntered signal is not fired until the next frame.

Any ideas guys? I've read that it only moves/updates a list internally once every physics tick, but isn't ForceUpdateTransform() supposed to override this?

in Engine by (14 points)
edited by

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.