Godot-proposals: Simplify the PhysicsBodies interface and its methods

Created on 18 Aug 2020  路  18Comments  路  Source: godotengine/godot-proposals

Describe the project you are working on:
Any game that uses PhysicsBodies.

Describe the problem or limitation you are having in your project:
Currently, Godot has three types of PhysicsBody: RigidBody, KinematicBody and StaticBody. RigidBody also has four modes: Rigid, Character, Kinematic and Static. Not only is this confusing, but there are functions available in KinematicBody that are not available to a RigidBody and visa versa. Furthermore, functions like KinematicBody's move_and_slide() have lots of parameters that can be confusing and don't always do what is expected (most notably stop_on_slope).

Describe the feature / enhancement and how it helps to overcome the problem or limitation:
A KinematicBody is just a RigidBody with infinite mass (or zero inverse mass). A StaticBody is just a KinematicBody with zero (or constant) velocity. The same way a RigidBody in Character mode doesn't rotate (because it effectively has infinite rotational inertia, or zero inverse rotational inertia). Furthermore, sliding and snapping are really just PhysicsMaterial properties, and stop_on_slope can be programmed in to work as expected.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
A RigidBody already has the modes needed, so we just need to make the functions that are available to KinematicBody available to a RigidBody (in Kinematic mode). At the same time, since all of the parameters to the move_and_collide(), move_and_slide() and move_and_slide_with_snap() can be made properties of the PhysicsBody, the PhysicsMaterial, or, in the case of the up_direction and floor_max_angle, the Space or Area. These methods can then be removed, because they will no longer be needed.

If this enhancement will not be used often, can it be worked around with a few lines of script?:
No, this will actually simplify scripts.

Is there a reason why this should be core and not an add-on in the asset library?:
This is a change to how core physics works.

Finally, its worth noting that these changes should make implementing some of the other proposals (e.g. #236, #364, #628, #667 #740) easier.

physics

Most helpful comment

Merging RigidBody and StaticBody is fine, I don't think there's any real need for those to be separate.

But for KinematicBody setting linear_velocity instead of move_and_slide() is not a valid replacement. move_and_slide() et al, by nature of being functions, have some inherent functionality that isn't replicable by just setting a property. move_and_slide() calculates a new velocity for the body and returns it. This return value can be used as an event, allowing you to immediately respond to the changes that occurred, functionality otherwise missing from KinematicBody. The function move_and_collide() returns collision data, and can optionally not actually perform the movement but just test a potential movement. This is incredibly useful for precisely controlled character movement, especially when combined with the fact that since it's a method, you can call it multiple times in the same physics step. Example use cases being: doing multiple tests before choosing one to commit to or handling multiple bounces in one physics step for an extremely fast moving object.

All 18 comments

What you're proposing sounds similar to what Unity does/did, Which is to make everything a Rigidbody and let the devs deal with the pains that causes when you want custom integration.

I'd rather we rename the RigidBody modes, (since the Kinematic Mode is in fact a Kinematic__s__ mode, not a KinematicBody mode.) than to make vast changes under the hood to how these bodies are treated.

A kinematic body is NOT a rigidbody with infinite mass or similar. And it should really stay that way.

@TheDuriel I'm not suggesting that we remove any of the functionality, I'm suggesting simplifying the current implementation. For example, instead of using move_and_slide(linear_velocity) with a KinematicBody, you would just change the linear_velocity property of a RigidBody in Kinematic mode. Similarly, all the other parameters of move_and_slide() would just be properties that tend to remain constant, but can be changed when required.

That would literally not lead to the same behavior.

That would literally not lead to the same behavior.

If it's implemented correctly it would.

How would one, in this new system, implement responses to individual collision events as you are causing them?
RigidBodies by their very nature do no expose this.

I like the idea to merge RigidBody and StaticBody. I'm worrying about merging also the KinematicBody.

As I envision it, the kinematic body algorithm should be 100% customizable, and be able to just set the body velocity is really not enough.
There are games where you want to change stance, climb walls, follows paths, etc... All things that require a much bigger control over the kinematic algorithm.

If a game just needs a character that walk around, can always use a RigidBody with the mode set as Character and change the linear velocity.

For RigidBody (and 2D) it's painful for player-controlled objects that it doesn't have an API for detecting being on the ground, getting collision normal. For all that need to get PhysicsDirectSpace and do IntersectShape (for which normal is available only for closest collision) or IntersectRaycast (for which needs many casts or it doesn't detect full shapes bottom collision cases).

You actually don't. The State of the rigidbodies _integrate forces provides the necessary data without additional raycasting being needed.

You actually don't. The State of the rigid bodies _integrate forces provides the necessary data without additional raycasting being needed.

Yes, but that's the problem. Why for simple movement I need to get into another callback that works async?
I've used it plenty and it's unnecessary to use it if I don't need to change linear_velocity on the go.

If you're using a RigidBody you are already past the point of simple movement. And its one line of code to get the collision normals dot product and compare it. So its not much different from what a kinematic body offers. In fact, you could even wrap it in your own is_on_floor(state) function.

If you're using a RigidBody you are already past the point of simple movement. And its one line of code to get the collision normals dot product and compare it. So its not much different from what a kinematic body offers. In fact, you could even wrap it in your own is_on_floor(state) function.

I have gone also very not-simple roads on RigidBody and I know well how unpleasant it can be.
I already have made my own is_on_floor() methods but it shouldn't be like that. Now I have few lines in _physics_process to move rolling ball character, but to limit jumping only from the floor I need to create bigger code in _integrated_forces or parse information from direct space to know the normals of collisions. KinematicBody have direct access to KinematicCollision, why RiggidBody can't have it too? Not only normals are needed but collision force too.

Because of such lack of access from RigidBody2D I once was forced to create my own RigidKinematicBody2D.

Merging RigidBody and StaticBody is fine, I don't think there's any real need for those to be separate.

But for KinematicBody setting linear_velocity instead of move_and_slide() is not a valid replacement. move_and_slide() et al, by nature of being functions, have some inherent functionality that isn't replicable by just setting a property. move_and_slide() calculates a new velocity for the body and returns it. This return value can be used as an event, allowing you to immediately respond to the changes that occurred, functionality otherwise missing from KinematicBody. The function move_and_collide() returns collision data, and can optionally not actually perform the movement but just test a potential movement. This is incredibly useful for precisely controlled character movement, especially when combined with the fact that since it's a method, you can call it multiple times in the same physics step. Example use cases being: doing multiple tests before choosing one to commit to or handling multiple bounces in one physics step for an extremely fast moving object.

That would literally not lead to the same behavior.

If it's implemented correctly it would.

I'm somewhat bothered by this reply. Yeah, if something is implemented a certain way, it could lead to the same behavior as another way... but you could say the same about using many Sprite3D nodes to build a character model.

So... I'm kinda curious, and kinda suspicious of this answer. How much research have you done on this point? Have you actually tested that a certain implementation would lead to the same results?

It sounds like merging RigidBody and KinematicBody would remove a basic but customizable/extensible thing, and replace it with something complex, where you have to disable or work around all of its extra features if you want to make something custom. That doesn't sound like an improvement to me.

I think there is a really bad idea to merge kinematic bodies into rigidbodies.

For now, KinematicBody2D can only push RigidBody2D, and the RigidBody2D will keep the velocity.

I would like set a KinematicBody2D's linear_velocity directly(or use move_and_slide), and it will push another KinematicBody2D away that will not keep the velocity.

Can it be easily applied after this change?

@bnyu This can be integrated. Though, if you need a KinematicBody that can be pushed by one or many RigidBodies, most likely you don't want to use a KinematicBody but a RigidBody in Character mode. Probably you need to abstract some functionality on top of the RigidBody to move it as you desire and don't allow that it slides down slopes.

In order to allow a RigidBody to push a KinematicBody it's required to add a dynamic algorithm, similar to the one the physics engine already provides for RigidBody. Since we already have that, the best thing would be just do the opposite: add the feature I propose few lines above to the RigidBody.

What looks simpler for the engine developer isn't necessarily good for the game developer. Sure, merging these things would make some things easier for the former, but it would cause great confusion for the latter.
I don't think it's a good move to ask game devs to start with something complex and break it into pieces to extract what they need- Rather, it is in the spirit of Godot's node system to start with small basic parts and bring them together into something that behaves in complex ways that they can expect. Physics engines are exceedingly complex, and it can cause a lot of problems for the unwitting dev if they're asked to implement pieces that they can't tell offhand whether they are or are not relevant to the problem they're trying to solve. "Here is a physics object- Now, disable this, disable this, disable this, don't use this function because it won't affect anything even though its name makes it sound like it would, don't use this function because even though its name sounds like it does what you want it actually will _counteract_ what you want, and ignore all these things you see in the inspector. And what were you thinking even asking about THIS thing over here?" That's the kind of advice you get when trying to find out why the little pixelman isn't moving correctly on the screen.
In a perfect world that, while we cannot reach it, but can aspire to approach it, the game dev would be able to simply assemble small parts relevant to their project and then refine the micro of its behaviors into what they want.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lupoDharkael picture lupoDharkael  路  3Comments

Torguen picture Torguen  路  3Comments

SpyrexDE picture SpyrexDE  路  3Comments

arkology picture arkology  路  3Comments

Xrayez picture Xrayez  路  3Comments