Open akien-mga opened 8 years ago
This is intended, because physics bodies manage their own transform which overwrites the ones you set. Some kind of workaround could be done eventually, but not until 3.0
Posting this here in case someone else also needs a "hack" to forcefully make scaling work on RigidBody2D.
You can use integrate forces to set the scale. For example,
func _integrate_forces(state):
set_scale(Vector2(-1, 1))
Also if you set the mode to "Kinematic" it will scale https://github.com/godotengine/godot/issues/7375 . _integrate_forces
wasn't working for me.
Edit: got _integrate_forces
working, think I copied something wrong. That's def better than changing your body type.
may do a workaround for 3.1 I am still not convinced it will work, though
Is there a way to scale rigidbodies before instantiation?
there should be a tracker with all these things, so i can work and remember everything after 3.0
@reduz The tracker for items on the 3.1 milestone is https://github.com/godotengine/godot/milestone/7
Sorry, out of time for 3.1 to create a workaround, kicking again.
Probably it needs to be at least documented in RigidBody2D class description while workaround is in progress? It took me a little while to decide that it is this issue that is screwing everything up.
I fully agree with @Houkime : A hint in the class description would have saved me almost an hour of tearing my hair out trying to figure out what's wrong with my code.
This issue is very prevalent with HeightMapShape
... Since HeightMapShape does not have any options for cell size and scaling shapes is unsupported, it is impossible to have a heightmap that isn't 1x1 cells. I hope this can be fixed in 3.2 or at least high priority in 4.0...
I'd love to see this included in 3.2 as well (a major showstopper for the project I'm working on...). Is there actually any possible work-around in 3.1?
I was trying to fix this bug, but when the scale is not (1, 1) after a physics frame the scale is changing by a small value ( 0.00001 ) because of the physics process which cause the body to flicker.
and the transform was orthonormalized intentionally which cause the scale to (1, 1). https://github.com/godotengine/godot/blob/bd61281a5f515065b05be008dd3d6b73a03f5a7c/servers/physics_2d/body_2d_sw.cpp#L293 I think the scale must be (1, 1) to make the physics work properly and we have to prevent the user from scaling it.
Any new insights on this? I'm seeing the comments on this "simply not being possible", but it pretty much makes it impossible for me to build the game I want to build with Godot (while it's not a problem in pretty much any other engine, including one I hacked together myself using Box2D).
If performance is a concern (since this would probably involve combine parent transforms and then rebuilding the physics shapes), only allowing this in _ready()
but not allowing it afterwards would be a great middle ground.
Are there any recommended workarounds (other than creating/adapting the collision polygon programmatically, which I suppose would work)?
Someone could make a collision shape scale function for 3.2. I'm not sure what the situation is for 4.0 right now
Just wanted to bump this issue. I encountered this in my very first learning project and was confused about the transform (the scale) of a Node2D
not being applied to its children (in this case, a RigidBody2D
node). This was especially baffling, because the editor rendered what I expected but playing the scene did not. I see now that this is mentioned in the documentation of RigidBody2D
, but I missed this.
Are there any thoughts, designs, or advice about how to create instanced scalable nodes that contain a RigidBody2D
? Is it possible for the scene topology below to be scaled, or is this considered an antipattern? If this topology is not ideal, what is a more ideal topology?
Are there any thoughts, designs, or advice about how to create instanced scalable nodes that contain a RigidBody2D?
The only supported option is to scale the child nodes.
The only supported option is to scale the child nodes.
Gotcha. Thanks for the help.
35614 should help alleviate this, but current quirks prevent merging it.
Awesome, that looks very helpful. 😄
I can see how applying (arbitrary) parent transforms to physics bodies could be tricky. Hopefully an intuitive solution can be found.
Using 3D, and I am not sure if this is correct, but it seems that it mostly works when scaling uniformly (the RigidBody:ies are instanced with MeshInstance and CollisionShape as children):
The other rigidbody is scaled [0.2, 0.2, 0.2]
while the longer is [0.2, 0.4, 0.2]
. Of course if it's not scaled uniformly, it results in a weird change of scale when the rigidbody rotates. (It seems to work OK if the scale is uniform.)
In any case I think this is something godot needs. For example this would be usefull when working with instanced models, but scale each instance separately.
https://github.com/godotengine/godot/pull/50637 may allow for using non-uniformly scaled PhysicsBodies, but right now, only uniform scaling is supported.
50637 may allow for using non-uniformly scaled PhysicsBodies, but right now, only uniform scaling is supported.
I see, atleast uniform scaling is working.
If it is truly supported (uniformly), should the warning message be adjusted (if it's not already) to reflect that? Or is the scaling still somewhat unsupported feature?
I'm playing around with the current 4.0 master, and was disappointed to find out that it's still not possible to scale a RigidBody2D
(I haven't tried its 3D counterpart):
As I've raised before, this makes certain use cases (like spawning asteroids of slightly randomized sizes) cumbersome to implement, as detailed in this tweet of mine and the thread following it.
I've been wondering about this issue for a long time, feeling that I must be missing something obvious, but so far I have not managed to find a solution, or at least an answer to why this is even a thing (consider that no other game engine I've used has had issues like this.)
Why does the physics engine even want to scale the body at run-time?
This is definitely one of the topics I'd like to improve for 4.0, it's just nobody had time to work on it yet.
What's needed is to check the current state for different cases, make some changes in the engine to handle more of them and adjust the warnings to be more accurate for the remaining cases.
I'll try to spend some time on this topic once the general API changes and major bug fixing are done for 4.0, but any contributor is welcome to give it a try.
FWIW, and I'm saying this as someone who knows absolutely zero about Godot's internals, I think what might also work fine is to leave RigidBody and RigidBody2D as is, but allow us to have an intermediary node between it and the collision shapes, and allow that intermediary node to apply scaling to its contained nodes (collision shapes included). (Related: @aaronfranke's proposal here: https://github.com/godotengine/godot-proposals/issues/535)
Good point! It could be a way to solve the problem in case there's any technical limitation to allow scaling the rigid body itself.
Updated MRP for 3.x
(works in master
too): RigidBody2D_scaling_bug.zip
Copying a comment by @pouleyKetchoupp on the current state of RigidBody scaling (from #35614), at least as of Feb 2021:
The current state with scaling physics objects is: Non-uniform scale: This is not supported for either bodies or collision shapes and there's no plan to support it in the future. Uniform scale: This is supported for collision shapes, not for bodies of any type. This limitation will be lifted in the future.
Parent node scaling: This is also not supported for bodies. Actually, it would be best to test global transforms rather than local ones in order to catch parent node scaling. Cases where the rigid body scale cancels the parent scale seem to work fine, so testing global transforms should be enough. edit: For collision shapes, non-uniform scale would be tested on the local transform.
apparently this problem still exists in 3d in version 4a3?? is this on the to do list??
EDIT: you CAN resize STATIC bodies and adjust size, so this wont effect levels comprised of static colliders.
for DYNAMIC rigid bodies you have to manually pair up meshes with hitboxes and resize them both every single time. this makes reusing dynamic rigid bodies limited to one size. i /think/ you can bypass this limitation with scripts?
i dont know if this isnt already planned, but this IS a problem. i know yall have your work cut out for you, but please consider it for the todo list. EDIT i understand this may be outside of your control. i'll try not to complain to much about it. ;)
apparently this problem still exists in 3d in version 4a3?? is this on the to do list??
pouleyKetchoupp is no longer available to work on the physics engine, so I can't guarantee this limitation will be lifted for 4.0. We have very few contributors who are knowledgeable with physics and have time to submit contributions to the existing physics engine implementations.
One update on this issue; it seems that on godot 3.4.2-stable the uniform scaling (like I posted on this thread earlier) works when using bullet, but not on godot physics.
(That came up when I tried to switch to godot physics for #29392 / #34596, because https://github.com/godotengine/godot/pull/56801 has not been merged.)
Just a quick ping to find out if anything has happened in the meantime. In 4.0, apparently Bullet is no longer available, only GodotPhysics3D. Scaling a scene that contains a RigidBody3D (and probably also its 2D equivalent) still yields warnings & scaling resets at scene start.
I understand this is an Open Source project and I could just take the source and fix this myself, but this is outside of my abilities. I also understand that features are usually added/fixed by people who need them, so please don't misunderstand my comment here as me demanding anything. I just can't imagine that I'm the only person on the planet who'd like to take a scene prefab and spawn smaller and larger versions of it?
(As a reminder, I am very specifically not looking for being able to change the scale at runtime; just at spawn time. And uniform scale only would be perfectly fine.)
@hmans You can work it around fairly easily by changing the size of the collision shape, instead of scaling the RigidBody.
Here's a quick example in 2D:
You'd scale the parent node, whose script takes care of setting the size of the collision shape and propagating the scale to the sprite. The RigidBody itself is not scaled and works fine.
Thanks @akien-mga, but in that example the RigidBody node will now simulate (and move) independently from its parent node, correct? So this isn't of much use as a reusable prefab scene.
I remember adding code to a Rigidbody node (the last time I actually tried building a physics game with Godot :b) that would apply the Rigidbody's scale to its children like you're doing, and then reset the Rigidbody's own scale back to 1/1/1.
Also consider that this can be a little more complex than just the children's scale. Colliders might be offset (with their origin not at 0/0/0); this would also need to be scaled accordingly.
(It would be immensely useful here if colliders didn't need to be parented directly to their rigidbodies. Then we could have an intermediate node between the two and just scale that one.)
I'm hoping for a future version where hacks like these are no longer required.
(Don't get me wrong, I fully understand that these engines also just rescale collision radii/polygons/etc. — I'm just making an argument for Godot abstracting this away so you can have a small ball and a large ball from the same prefab and not go hunting for hacks like the one above.)
I'll check again next year :-)
Woohoo:
https://user-images.githubusercontent.com/1061/218258432-299d1bd6-5d8d-4165-8c4b-80fc4135098f.mov
As a workaround for this issue, I've created a new class called ScalingRigidBody3D
in Godot 4.0 (feedback welcome):
@tool
class_name ScalingRigidBody3D
extends RigidBody3D
var _size := 1.0
@export var size : float:
get: return _size
set(v):
_size = v
_apply_size()
func _ready():
_apply_size()
func _apply_size():
for child in get_children():
if child is CollisionShape3D:
child.scale.x = size
child.scale.y = size
child.scale.z = size
This can probably be improved further.
My personal wish for Godot's (3D) physics would be to
RigidBody3D
class apply a similar logic, but out of the box (for example, it could, in _ready()
, examine its world scale, set its own scale back to 1/1/1, and scale its children accordingly. Doing this in _ready() should be enough since scaling works fine during the editing experience.)Baby steps, but we'll get there :)
Improved version of the above class — doesn't use a new property, but just applies its own scale to its children as described in the notes above:
class_name ScalingRigidBody3D
extends RigidBody3D
func _ready():
_apply_scale()
func _apply_scale():
# apply my own scale to my children
for child in get_children():
if child is Node3D:
child.scale *= scale
# reset my own scale
scale = Vector3.ONE
RigidBody3D
class itself. ;)I've polished the code, gave it some upgrades, and packaged it into a Godot Plugin. Please see this comment for details.
@hmans New to Godot and going through the tutorials wanted to try to make the 2d balls smaller and found this issue. Would your script work somehow for 2d too if just changing a few calls inside and changing to vector2? Thanks!
@hmans New to Godot and going through the tutorials wanted to try to make the 2d balls smaller and found this issue. Would your script work somehow for 2d too if just changing a few calls inside and changing to vector2? Thanks!
Yup, that should work!
If there's interest, I could wrap this into a plugin and publish it in the Asset Library (but probably for 4.0+ only.)
That could be super useful as a lot of people seem to want this but doesn't seem to be in the works anytime soon as it looks like the milestone is set to 4.1 now to fix/implement.
Hi and good morning to everyone following this issue! I've packaged my glue code into a Godot 4.0 Plugin that you can add to your project to work around this issue:
It's "fire and forget"; just add it to your project and it'll fix things up automatically. I've also given it a couple of upgrades: it now respects parent scale, also fixes child positions, and works for both 2D and 3D.
While the Asset Library listing submission is still pending, you can find it here:
https://github.com/hmans/Godot-RigidBody-Auto-Scaler
Feedback welcome! (But preferably outside of this issue thread. The plugin README is listing a bunch of ways you can get in touch with me!)
Another problematic thing when scaling rigidbodies with the workaround (eg. RigidBody is at scale 1 and CollisionShape & mesh are at your desired scale) is that automatically calculated inertia does not seem to scale.
If you use PhysicsServer3D.body_get_direct_state(get_rid()).inverse_inertia.inverse()
to check inertia, it is the same regardless of the child objects scale. This makes objects fall somewhat weirdly looking.
If I set the scale manually to something like calculated_inertia * scale
it looks slightly better. (For example if calculated inertia is about (15000,7000,15000)
on each xyz axis, and scale is 0.2
, it's about (3000,1400,3000)
respectively)
(However if I set the RigidBody3D mass to 1000, and the inertia in the editor for each axis, the model flies downwards through the floor, as if it had massive gravity. If I only set to x & z axis, it does not go through floor. When using the above function to check inertia, it reports the value set in editor for the x/z axis, and for z axis it's the autocalculated value.)
EDIT: As a workaround, it is possible to scale the inertia with script (at runtime), where ever you just have access to PhysicsDirectBodyState3D
, like _integrate_forces()
(or by getting it with PhysicsServer3D.body_get_direct_state(get_node(".").get_rid())
). Using _integrate_forces()
or _physics_process()
is usefull as inverse_inertia
is not set (inf
) at _start()
:
var has_set_inertia = false
func _integrate_forces(state):
if !has_set_inertia:
var inertia_actual = state.inverse_inertia.inverse()
if !is_inf(inertia_actual.x):
# get scale from child collider node, assuming you have already applied scale with the workaround
self.inertia = inertia_actual * collider.scale
has_set_inertia = true
Another problematic thing when scaling rigidbodies with the workaround (eg. RigidBody is at scale 1 and CollisionShape & mesh are at your desired scale) is that automatically calculated inertia does not seem to scale.
If you use
PhysicsServer3D.body_get_direct_state(get_rid()).inverse_inertia.inverse()
to check inertia, it is the same regardless of the child objects scale. This makes objects fall somewhat weirdly looking.
Good point! I'll look into this. Thanks!
Update: Using Godot Jolt physics engine, rigidbody scaling gets slightly better. (Godot Jolt is consired as physics engine, see: https://github.com/godotengine/godot-proposals/issues/7308)
var has_print_inertia = false
func _integrate_forces(state):
if !has_print_inertia && self.inertia == Vector3.ZERO:
var inertia_actual = state.inverse_inertia.inverse()
if !is_inf(inertia_actual.x):
print(name, inertia_actual)
has_print_inertia = true
outputs:
prop_physics10(0.031431, 0.031431, 0.003251)
prop_physics11(0.031437, 0.031437, 0.003251)
The prop_physics are sized the same, but with this difference:
Also tested with godot physics and expectedly above function printed different inertia for the rigidbodies.
Just wanted to add to this, as I think it's the same/similar issue: It seems the rigid bodies will attempt to invert the scaling when re-parented to something of a different scale.
When I was working on the Godot plushy for KOOK, I wanted to have the arms and legs flop around, so I had joints and rigid bodies for them. When I pick rigid bodies up, they would get reparented to a bone on the player. The first person player is actually much smaller than everything else to avoid clipping through walls, so the objects picked up got scaled down (and there's an additional scale factor as well, just to fudge things so they look right, like 0.8x). The pinned rigid bodies, which are a child of the plushie would actually get scaled UP when everything else got scaled down, so they'd be sitting at > 1.0. When I dropped the object and changed the parent back to the world, they'd still be scaled larger (possibly because it was a non-uniform scale, as stuff in first person is actually squished as well).
Here's a clip from the dev stream where this happened. The white cube is a mesh that's a child of the RigidBody3D, for visual feedback: https://clips.twitch.tv/InspiringFrozenDotterelUWot-XoUI1ECrtU8-isdX
Just wanted to add that current GodotJolt stable seems to support this out of the box. It even seems to support non-uniform scaling. That's pretty cool!
Godot 4.2 is still giving me the little exclamation mark warning that I'm doing something that I'm not supposed to be doing, but it looks like it can be safely ignored.
Just wanted to add that current GodotJolt stable seems to support this out of the box. It even seems to support non-uniform scaling. That's pretty cool!
Can confirm, here is a clip using Godot 4.2.2 and godot-jolt stable release 0.12. Each RigidBody is scaled just by their transform. IIRC this was not working on 0.11 (which was version I previously used), but not sure.
https://github.com/user-attachments/assets/6d547802-5c70-486d-98c1-b7a05915718a
The inertia also seems to be still scaled correctly, as was when using previous godot jolt version.
Operating system or device - Godot version: Mageia 6 x64, Godot 2.0.4.1 and master HEAD.
Issue description (what happened, and what was expected): RigidBody2D does not respect its scale parameter, or that of its parents. When scaling a RigidBody2D (directly or by scaling its parent), it shows properly scaled in the editor, but on runtime the scale is ignored.
Steps to reproduce:
Link to minimal example project (optional but very welcome):
3.x
MRP (works inmaster
too): RigidBody2D_scaling_bug.zip(Old 2.1 project: RigidBody2D_scaling_bug.zip)
The project has a root Node2D scaled by (0.2, 0.2), and RigidBody2D, StaticBody2D and KinematicBody2D children. When running the scene, you'll see that only the RigidBody2D does not respect its parent's scale.