godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.74k stars 20.12k forks source link

AnimatableBody3D can't rotate and move at the same time #91801

Open ZenRepublic opened 4 months ago

ZenRepublic commented 4 months ago

Tested versions

reproducible in 4.2

System information

Windows 11 Godot 4.2

Issue description

AnimatableBody3D can't rotate and move at the same time

Steps to reproduce

func _physics_process(delta: float) -> void:    
  global_position.y += delta
  rotate_y(delta)

this will make the object just rotate. If you switch the rotation and movement in places, it will only move. but not both at the same time

Minimal reproduction project (MRP)

test.zip

AThousandShips commented 4 months ago

You can't update the transform that way

You should do:

func _physics_process(delta: float) -> void:    
  global_position.y += delta
  rotate_y(delta)
ZenRepublic commented 4 months ago

You can't update the transform that way

You should do:

func _physics_process(delta: float) -> void:  
  global_position.y += delta
  rotate_y(delta)

sorry, i mistyped in the original post. edited to global_position.y,

AThousandShips commented 4 months ago

Then try:

func _physics_process(delta: float) -> void:    
  position.y += delta
  rotate_y(delta)

Or

func _physics_process(delta: float) -> void:    
  global_position.y += delta
  global_rotate(Vector3(0, 1, 0), delta)
ZenRepublic commented 4 months ago

Then try:

func _physics_process(delta: float) -> void:  
  position.y += delta
  rotate_y(delta)

Or

func _physics_process(delta: float) -> void:  
  global_position.y += delta
  global_rotate(Vector3(0, 1, 0), delta)

same result with both suggestions

ZenRepublic commented 4 months ago

i have turned off "sync to physics" and it now works just fine! not sure if that's a bug at this point then

Lateasusual commented 3 months ago

Apparently AnimatableBody3D does not actually apply transforms when they're modified, since the idea is that the transform changes are propagated by the physics server and not the node itself:

https://github.com/godotengine/godot/blob/1d47561319938e10cb53d202ceaeca102511a31e/scene/3d/physics/animatable_body_3d.cpp#L103-L113

I think this is really confusing for users though, and would probably be better if the physics state-set only happened once and not during _physics_process or _integrate_forces callbacks?

This can be worked around by reading the transform, modifying it, then only writing the new value once and not reading from it again in the same frame, i.e:


func _physics_process(delta: float) -> void:
    var tf = global_transform
    tf = tf.translated(Vector3.UP * delta)
    tf = tf.rotated(Vector3.UP, delta)
    global_transform = tf

At the very least this should be clearly documented in the description for AnimatableBody3D