Rotation of Transform2D resets in _integrate_forces

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By ggez

I have this code:

func _integrate_forces(state: Physics2DDirectBodyState) -> void:
	if reset:
		var tr = state.get_transform()
		tr.origin = some_pos
		position = some_pos
		tr.rotated(some_rot)
		state.set_transform(tr)
		reset = false

With this code, I can set the position of Rigidbody2D to some_pos. For some reason, I have to set the origin and the position itself to the pos, or else it will teleport back (why?). But it works. However setting the rotation of a Rigidbody2D does not work. It just resets itself to the last rotation. Any help?

:bust_in_silhouette: Reply From: magicalogic

To rotate tr, replace

tr.rotated(some_rot)

with

tr = tr.rotated(some_rot)

For some reason it rotates around (0, 0) instead of the objects position. Can you confirm this or have an idea why this might be? This line shouldn’t be the problem or? tr.origin = some_pos

ggez | 2020-12-01 14:28

1 Like

@ggez If you want it to rotate around the object’s position, you can use:

tr = tr.rotated_local(some_rot)

This will rotate it around the local position rather than the global origin!

1 Like

This will rotate it by that amount relative to the current rotation, right? It won’t actually set the rotation to that. Do you have to subtract the current rotation, or is there a way to reset it to zero rotation before rotating it? There’s a way to do this for Transform3D using tr.basis = Basis() and then rotating it… though it seems like there’s many strange issues with rotating transforms in general in 3d or 2d?

This suggests that you orthonormalize your transforms after every rotation to prevent them from deforming, for example.

(Deleted and reposted because I intended to reply to mesteve95… maybe I actually did it right initially… didn’t look like it was a reply lol)

1 Like

Digging into it more, I think the Transform2D equivalent to reset the rotation would be:
tr.x = Vector2(1, 0)
tr.y = Vector2(0, 1)

#Now you can directly rotate it to your target rotation with rotated_local
tr = tr.rotated_local(some_rot)

If you don’t reset the rotation to zero by directly modifying the basis with tr.x and tr.y, you’ll be rotating relative to the current rotation, instead of directly setting the rotation.

I find it odd that there’s no standard method for directly setting the rotation of transforms.

1 Like

I actually ran into this problem myself in the most recent project I’ve been working on, and I found a way of setting the rotation that has worked great!

Similar to what you’ve noted in your previous comments, it appears that you cannot directly set the rotation of the transform, so doing rotated or rotated_local will only rotate it by that amount. My way around this is similar to yours, but in one line, using:

transform = transform.rotated_local(-transform.rotation);

This resets the transforms’ rotation to zero, meaning that when you apply the next rotation using:

transform = transform.rotated_local(some_rot)

it will be set to that rotation.

I completely agree that this feels very unintuitive and certainly feels like we’re fighting against how the Transform system is designed to be used.

In the documentation you posted, I saw that it gives the advice “You must do your best to stop thinking in angles”, and to instead solve problems related to transform manipulation in terms of vectors. I’ll admit that I tend to shy away from vector math and defer to angles to avoid needing to think too hard, but it seems likely that changing our mindset to use vectors is the proper solution to this problem, and would remove our need to use these workarounds.

1 Like

That was actually my first solution. Subtract the current rotation from my target rotation.

My only concern with us is that I think it would slowly introduce floating point errors, but I’m not sure.

That’s why I preferred the method of resetting the rotation to zero by setting the transform vectors to the original basis vectors.

I.e. transform.x = Vector2(1,0) and transform.y = Vector2(0,1)

I still need to wrap my mind fully around what this does to the transform. Maybe a good idea would be to set up a test that reads out the transform2d.y, transform2d.x, and transform2d.get_rotation() and then have some key bindings mapped to doing manipulations on all of these variables… or make the script a godot editor script so you can just edit it in the godot UI.

I’m probably going to play around with that. Get my head around these matrix transforms in 2d and then 3d.

I also find it a bit odd that transform2d and transform3d have such different methods and variables exposed lol. Something else to get our heads around.

1 Like

You have some very good points, I never even considered the potential for floating point errors to creep in but it definitely could the way that I’ve been doing it, your way seems like a much safer approach.

It is very strange how different the 2D and 3D transforms are, and while they obviously represent very different things and have different needs, it would be nice if there was more consistency between them.

Good luck with the matrix math, it’s a steep learning curve but I’ve heard that it’s well worth it once you get comfortable!

1 Like