Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorganize physics body nodes #2184

Closed
reduz opened this issue Jan 25, 2021 · 43 comments
Closed

Reorganize physics body nodes #2184

reduz opened this issue Jan 25, 2021 · 43 comments
Milestone

Comments

@reduz
Copy link
Member

reduz commented Jan 25, 2021

Describe the project you are working on

Godot

Describe the problem or limitation you are having in your project

Physics nodes can be confusing in Godot, because some functionality overlaps and intentions are not clear. Additionally, kinematic body serves several goals at the same time, which makes it difficult to hack around for specific higher level character behaviors

Describe the feature / enhancement and how it helps to overcome the problem or limitation

The goal is to reorganize these nodes to make it easier to use and easier to hack them for specific situations.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

The new nodes will be as follows:

  • KinematicBody: Removed.
  • PhysicsBody: Existing base types for all bodies. Will acquire the move_and_collide function from KinematicBody, so all types of bodies can use it (and it's easier for users to make custom kinematic character controllers).
  • StaticBody: Will inherit "simulate_motion" from KinematicBody. If enabled, moving the node manually will cause it to adopt linear and angular velocity that will interact with actual physics bodies. I am thinking whether this property should be renamed to "infer_velocity".
  • RigidBody: Will remain as now, but in the modes (Rigid, Static, Character) Kinematic should be replaced by StaticSimulated (or another name) that acts like the simulate_motion in StaticBody. This way, except for move_and_slide you can do everything with a RigidBody.
  • CharacterBody: New node, will acquire move_and_slide, but will be exclusively dedicated to characters. This way, hacks can be piled up on it and be made easier to use for commonly requested features. Whether this class inherits PhysicsBody or RigidBody should be discussed. I tend to think for the sake of usability (you rarely want to turn this into a rigidbody, and if you do you require a lot of custom code), it should inherit PhysicsBody.

Additionally, as I believe there are too many corner use cases for characters we can't cover, we should provide versions of CharacterBody in script form, so users can tweak everything they want if they need, or even make it inherit RigidBody.

If this enhancement will not be used often, can it be worked around with a few lines of script?

No, this is core.

@Calinou
Copy link
Member

Calinou commented Jan 25, 2021

See also #1384.

@reduz
Copy link
Member Author

reduz commented Jan 25, 2021

@Calinou This proposal supersedes #1384 because the aim is to keep the good usability of having separate nodes. Many Godot users who make 2D games (if not most) don't need to deal with the extra complexity of RigidBody, which would make things a lot more confusing.

Still, having move_and_collide in PhysicsBody gets you halfway to where that proposal wants to be (the rest you can reach with some script, and we can provide this script if needs to be as mentioned in my proposal).

@aaronfranke
Copy link
Member

aaronfranke commented Jan 25, 2021

How does "you can do everything with a RigidBody" solve "because some functionality overlaps"? If PhysicsBody gets move_and_collide and StaticBody gets simulate_motion, then doesn't that mean StaticBody isn't static?

Can you give some examples of games and how they would make use of these nodes better than the existing ones? Remember, this is the purpose of the "Describe the project you are working on" section.

@LillyByte
Copy link

LillyByte commented Jan 25, 2021

StaticBodies have a very specific meaning in every physics tutorial. In that, they are static. They don't move, at all. They are environment pieces that are never supposed to move. If you start making StaticBodies that aren't always static and sometimes kinematic... you're forcing a layer of confusion you're trying to, somehow, avoid.

Godot is currently using a pretty standard and basic convention that almost all engines follow, and that can be found in generalized physics tutorials.

@Janders1800
Copy link

Janders1800 commented Jan 25, 2021

I'm also kinda confused, as a simple user what I get from this proposal is this:

PhysicsBody: This is the papa node, all tree inherit from this, so... not a node?
    |_ StaticBody: Walls and floors, 'simulate motion' is for wen its animated?
    |_ RigidBody: Bouncy balls and boxes.
    |_ CharacterBody: Isn't this just a renamed KinematicBody?

I'm sure I'm getting a lot of things wrong, but this is the best I can do with the info in the proposal.

@reduz
Copy link
Member Author

reduz commented Jan 25, 2021

@aaronfranke, @Janders1800, @LillyByte I think the misunderstanding comes from the fact of what simulate_motion (or infer_velocity, as I would like to rename) does.

A body is static when it can't be moved by other physics bodies. It doesn't mean you can't move it yourself from code, you sure can and you always could (set the position manually and it will move). It works like this in any physics engine.

So imagine you have a moving platform. A RigidBody or a CharacterBody won't do because they move by themselves. You need something that can't be affected by other nodes but that you can position yourself and that is exactly what a StaticBody is.

Now, there is a problem here which is that when you move this static body left and right, all you do is change location. Objects over it will not be moved and stay in place. At much they won't fall.

For a moving platform to work, you need this static body to kind of infer what the linear and angular velocity is based on the movement you did from your script. This would allow it to carry characters and rigid bodies with it. To do this, the ability to "infer" the velocity is required. It checks where the object was the previous frame, where it is now and the time elapsed. Based on this it computes linear and angular velocity and any body colliding against it will receive it and move along.

This solves the problem. The issue here is that doing this is kinda expensive and you don't need it for most cases of static bodies, so it needs to be switched on when you need it. This is why it is an option.

So, in Godot 3.x, KinematicBody was literally the same as StaticBody unless you turned this option on. Turning it on also did some extra magic like actually moving the node one frame later, this way it solved the sync problems (when the objects being carried were one frame delayed due to physics being processed after you moved it).

With move_and_slide out of KinematicBody, then there is not really any reason to have KinematicBody any longer. It does the same as StaticBody, so the most logical step is to just add the motion inferring option to StaticBody.

@slapin
Copy link

slapin commented Jan 25, 2021

In general physics engines do KinematicBody as variation of RigidBody with zero mass.
Static body is also RigidBody with zero mass but it can be optimized around checking motions.

I'd be pro this change if multimode RigidBody could actually merge properties of all movable bodies as modes and support all the APIs to be moved nicely as character, because that allows for nice character controllers like Uncharted one.

@slapin
Copy link

slapin commented Jan 25, 2021

Also would be nice if VehicleBody inherited that behavior.

@reduz
Copy link
Member Author

reduz commented Jan 25, 2021

@slapin thats kind of what will happen, RigidBody can do everything all the other nodes can do with the excpetion of CharacterBody (which is kept separate to avoid making it too confusing to users, as RigidBody has lots of options and properties), but you can write your own character code using move_and_collide and RigidBody rather easily if you need.

@aaronfranke
Copy link
Member

A RigidBody or a CharacterBody won't do because they move by themselves.

KinematicBody doesn't move by itself either. Are you saying that CharacterBody will, for example, have gravity by itself? Or it would be pushable by RigidBodies and other CharacterBodies out of the box?

@reduz
Copy link
Member Author

reduz commented Jan 25, 2021

Are you saying that CharacterBody will, for example, have gravity by itself?

Yes, one of the ideas in CharacterBody is either make it move by itself, or have a single function move() that you are up to call anytime in either process or physics process, and most of the arguments to move_and_slide will become properties.

@slapin
Copy link

slapin commented Jan 25, 2021

Would be nice to have interface to RootMotion for CharacterBody too. And ability to receive momentum.

@aaronfranke
Copy link
Member

aaronfranke commented Jan 25, 2021

This is my current understanding of this proposal.

  • RigidBody: Keep as is.
  • StaticBody: Delete it.
  • KinematicBody: Rename to StaticBody but don't include move_and_slide.
  • New type CharacterBody, more specialized for characters vs current KinematicBody.

@reduz
Copy link
Member Author

reduz commented Jan 25, 2021

@aaronfranke That is right

@just-georgeb
Copy link

To me I think it would be less confusing to have:

  • StaticBody: as it is now - can be moved but no velocity/moving collisions
  • KinematicBody: as it is now, but replace move_and_slide(velocity) with move(velocity). By calling move() you are asking for Godot to infer velocity and solve the moving platform problem. Keep move_and_collide() so moving platforms can interact with the environment.
  • Character body: Kinematic body with extras
  • RigidBody: as it is now

@JotaFaD
Copy link

JotaFaD commented Jan 25, 2021

Instead of having special nodes for StaticBody, why not use RigidBody's modes for everything, except characters?
Rigid mode: Has physical properties, moves using forces.
Static mode: Is not affected by collisions, if moved by code teleports to new position.
Simulated mode: If moved by code, estimates velocity and affects rigid bodies.

Also, I would name the new node just Character, it will of course extend one of the PhysicsBody, but I wouldn't call it a "body" in case it gets highly specific character properties (like mouse looking, for example).

@aaronfranke
Copy link
Member

@reduz Where does this leave concave collision shapes? Currently, they only work on StaticBody because concave-concave collisions are difficult to calculate and therefore they are intended to not move (and are only valid on StaticBody). If the new StaticBody is similar to a renamed KinematicBody but with move_and_slide removed, what happens if you put a concave collision shape on a new StaticBody and try to move it into another concave shape using move_and_collide?

@reduz
Copy link
Member Author

reduz commented Jan 26, 2021

@aaronfranke That doesn't work (it should e documented at least). You have to convex decompose that.

@aaronfranke
Copy link
Member

aaronfranke commented Jan 26, 2021

@reduz What do you mean it doesn't work? There's a resource just for it: https://docs.godotengine.org/en/stable/classes/class_concavepolygonshape.html and no decomposing is necessary to use it.

@arkology
Copy link

Why not leave two nodes: RigidBody for everything (fixing all current bugs) and CharacterBody (the same as current KinematicBody, but with corrected interaction with RigidBody)

@TokageItLab
Copy link
Member

TokageItLab commented Jan 26, 2021

I have no objection to simplification. However, for moves using CharacterBody, I would like to see the following

Strict on_floor

  • No snagging when jumping and landing repeatedly.
  • When jumping from the box's bottom to the box's corner, it should be able to land correctly without snagging.
  • Can land correctly when jumping from the static floor to the up moving floor.

Strict stop_on_slope

  • When walking on a slope, the speed in the XZ direction is slower than the speed when walking on a non-slope due to the effect of gravity.
  • No slipping when walking sideways on a slope.
  • Match the behavior of moving and non-moving slopes.

These are all things that are needed to make a character move naturally in a typical 3D platformer game, but as of Godot 3.x, it is impossible to implement all of them.

@Janders1800
Copy link

@TokageItLab I think most of them are implemented in my 3D platformer demo:
https://github.com/Janders1800/3D-Platformer

@TokageItLab
Copy link
Member

TokageItLab commented Jan 26, 2021

@Janders1800 I played your project but the player character is slipping on the slope when I put the slope in the scene. All of the things on my list must be done at the same time.

We are not all going to make a game without slopes. Also, the games with low-height steps or without the cliff catching feature, the fuzzy judgment of on_floor can be a problem. It would be silly to take a custom on_floor judgment with timer processing or judging by amount of velocity change, but in 3.x, that's the only way to do it. If it will be simplification, we should avoid implementations that require such custom on_floor judgment to be written in GDScript.

@jordo
Copy link

jordo commented Jan 27, 2021

I have to say I am pretty confused with 'simulate_motion' and 'StaticSimulated'. So kinematic types are pretty much removed? And the solver will now solve static types with velocity constraints when moved? I feel like there's benefit to separating static & kinematic.

I have to say that eventually i just gave up and am just using https://github.com/briansemrau/godot_box2d for 2D which is brutally clear about what body types do what. Has saved me a lot of hair.

@Shadowblitz16
Copy link

Shadowblitz16 commented Feb 18, 2021

So if PhysicsBody is the new KinematicBody and RigidBody derives from it.
Does that mean we will finally be able to modify the position of a rigid body without bugs like in unity?

if so I support this

@AttackButton
Copy link

Hi, is this supposed to be in the 4.0 version? Or in 4.1, etc?

@pouleyKetchoupp
Copy link

@AttackButton This is planned for 4.0.

@Zireael07
Copy link

Not too certain on naming, but having used KinematicBody as well as VehicleBody (which inherits from Rigidbody) I would love to have a way to combine the ease of use that kinematic offers with the ability to add impulses/forces that rigidbody has.

@pouleyKetchoupp
Copy link

pouleyKetchoupp commented May 11, 2021

The proposed node organization makes sense to me. There are still the same distinct modes for the physics simulation, and it will allow new use cases and features.

I'm just adding some comments on naming I had posted only in the chat before:

  1. RigidBody modes can be named this way to make things clear:
    -Dynamic: replaces the current Rigid mode (gravity and forces applied). It's more explanatory and matches the name physics engines commonly use for this use case.
    -DynamicLocked: replaces the current Character mode (dynamic with locked rotations). That would avoid confusion with the new CharacterBody node, since it's something completely different.
    -Kinematic: seems more descriptive than StaticSimulated and matches the name physics engines commonly use for this use case.
    -Static: same as before.

  2. StaticBody node: it makes sense that "static" means that it can't be pushed by another body, even if there are ways to move it around (which is already the case by changing the transform in StaticBody). But the simulate_motion property could be called kinematic_motion instead, in order to keep the naming clear and consistent.

@golddotasksquestions
Copy link

golddotasksquestions commented Jun 12, 2021

  • RigidBody: Keep as is.
  • StaticBody: Delete it.
  • KinematicBody: Rename to StaticBody but don't include move_and_slide.
  • New type CharacterBody, more specialized for characters vs current KinematicBody.

I am at least as confused by this proposal as much as I'm confused about the current implementation. Possibly more.

So far I've used KinematicBodies for moving platforms. Why? Because they are moving.

Why rename KinematicBody to StaticBody and not the other way round if the resulting node is supposed to move at least some times and check for collisions while moving?
I would like to keep a simple node for coded movement. The name "KinematicBody" seems ideal for this, while the name "StaticBody" seems like the most counter intuitive I could think of.

If a node named "CharacterBody" is supposed to fill the gap the removal of "KinematicBody" leaves behind, I already see myself having to use a CharacterBody on countless game entities that are not a character at all, all the time ... why? Why not just keep the Kinematic body?
Also, if a CharacterBody is supposed to have more specialized functionality for characters, what are those? A collection of hacks on top of the current KinemticBody functionality? Does not sound very appealing to me. It sounds like it would only solve some very specific usecases and bug out (even more?) in others. As hacks are solved properly on a lower level, this nodes becomes more and more pointless or even depreciated.

Sure the KinematicBody could use some improvement and there are a fair share of bugs. But all this time (almost 3 years) I've been using Godot, the biggest single one issue which does not seem to be included here:

A seamless transition from KinematicBody like user control, to RigidBody behavior.
The most obvious solution of using a RigidBody as a base won't work, because RigidBody misses move_and_slide() and move_and_collide() functionality. One might think setting the mode to either Kinematic or Character would solve this, but unfortunately no (both super misleading and confusing mode names btw).

#1384 Seems to go into this direction, but is not a solution either as it proposes the removal of KinematicBody all together. @Bropocalypse is absolutely correct about asking users to first disable a whole range of functionality and not touch others, is anything but user friendly and extremely counter productive if the goal is to simplify.

@pouleyKetchoupp
Copy link

pouleyKetchoupp commented Jun 12, 2021

@golddotasksquestions

  • About functionalities:

No functionality has been removed. KinematicBody was split because it was used for different unrelated reasons.

Here's how nodes work with this proposal implemented:
StaticBody: Used for anything that can be moved by script but cannot be pushed around by physics. It already had constant velocity properties before, used to induce a movement on objects standing on it, and could be moved by changing the transform. Now it also inherits moving platform functionalities from KinematicBody, by enabling kinematic_motion property, and the optional sync to physics.
RigidBody: Used for anything that can be pushed around at some point. Also useful to switch the behavior between different modes.
CharacterBody: Used only for character controllers that move using move_and_slide. The extra functionalities it will get will be additional properties, instead of adding more and more arguments to move_and_slide like it was done before. This way more variants of character behavior can be supported, since the needs can be very specific to the game you want to make. A good example is a property to control whether the speed in slopes should be constant or lower when going uphill.

Also, all nodes can now use move_and_collide, including RigidBody. It allows the advanced behavior you mentioned. You can transition between full control and physically simulated objects.

  • About naming:

It's hard to find names that are clear for everybody and match standard conventions, but if needed, things can be refined before 4.0 is out.

The new naming convention follows this pattern consistently:
Static means the object can't be pushed by other objects.
Kinematic can't be pushed by other objects and also moves following a predefined motion.
Dynamic means the object is fully simulated with applied forces and can be pushed around.
Rigid can be any type from above. It's used as opposed to soft body.

RigidBody modes have been renamed to follow this naming, so Rigid mode is now Dynamic and Character mode is now DynamicLocked.

I agree the name StaticBody for a moving platform is not the most intuitive, but it's not that uncommon. In all physics engines or game engines that I know, static bodies can actually be moved in some way or another. If we can find a better name for this node that conveys the idea it can be static and can have kinematic motion, it can still be changed for 4.0.

@Zireael07
Copy link

Static means the object can't be pushed by other objects.

Most people will assume static bodies cannot be moved, regardless of whether it's actually the case... so I would look for some synonym... Non-dynamic?

@pouleyKetchoupp
Copy link

Now I'm thinking maybe ObstacleBody instead of StaticBody could be more descriptive since it's used for walls, floor and (moving) platforms.

@slapin
Copy link

slapin commented Jun 12, 2021 via email

@golddotasksquestions
Copy link

golddotasksquestions commented Jun 12, 2021

@pouleyKetchoupp

Thank you for taking the time and trying to explain!
What you listed here makes a lot more sense to me:

The new naming convention follows this pattern consistently:
Static means the object can't be pushed by other objects.
Kinematic can't be pushed by other objects and also moves following a predefined motion.
Dynamic means the object is fully simulated with applied forces and can be pushed around.
Rigid can be any type from above. It's used as opposed to soft body.

Why can't we have these as nodes? With exactly these names and descriptions? This would clear up any confusion I can think of.
The "Character" name is really a misnomer when it won't be used for characters, which will be the case a lot.

@pouleyKetchoupp
Copy link

pouleyKetchoupp commented Jun 12, 2021

@slapin It may be an established term, but it may be dated and not the best way to describe what the node does. Currently, users are confused that a StaticBody can be used for something that's moving, so if that can be improved it will be for the best.

@golddotasksquestions Static, Kinematic, Dynamic describe the modes of functioning within the physics engine. Nodes are functionality-based and don't necessarily match these modes one-to-one. RigidBody is meant to switch between any mode, and StaticBody can be used for both Static and Kinematic behavior.

@slapin
Copy link

slapin commented Jun 12, 2021 via email

@golddotasksquestions
Copy link

golddotasksquestions commented Jun 12, 2021

Honestly I don't see a problem with these names. They seem to me a lot more clear than what is proposed and the fact that they represent the functioning within the physics engine can only be a plus. I still don't see the use for making the StaticBody something you should move. I would chose the "DynamicBody" name for as the chameleon than can do everything though. "Dynamic" as in the whole range is very common term even outside of physics engines and even outside of gamedev.

If it would be up to me we had:

StaticBody
should not be moved, ever. Has no move_and_collide(), cannot be pushed. It's a brick wall that can reflect and bounce off, but that's it. If you move this body, it's your fault because you can't read.

KinematicBody
the KinematicBody we have right now. Has move_and_slide() move_and_collide() ect. Expanded with extra functionalities and properties (those things you want to add to that "Character Body"). Should be used for anything that is supposed to move predetermined and deterministically: Retro games characters enemies and creatures, machines and mechanical devices, platforms, vehicles without dynamic physics, simple bullets ...

RigidBody DynamicBody
the RigidBody we have right now in RigidBody mode. Does not have other modes, does not have move_and _collide()
Used for simple dynamic non deterministic physics driven objects to push and kick around. Things like balls, shell casings, shards, gib ...

DynamicBody RigidBody
the RigidBody we have right now, but instead with "StaticBody", "KinematicBody", and "DynamicBody" mode. Has move_and_collide(). Can do all of the above is set to the respective mode.
Used for advanced modern character and vehicle controllers, for games that have objects than need to mix different physics behaviors as particular moments. For exampe shooting a ball along a predefined deterministic arc in a ball game during kickoff, but as soon as it reaches maximum hight it switches into RigidBody mode. It's an advanced node.

@pouleyKetchoupp
Copy link

pouleyKetchoupp commented Jun 12, 2021

@slapin Existing users will have a better description of the behavior of the nodes. New users / beginners will benefit from less confusion due to intuitive naming. This change would have to come with proper documentation and a simple migration guide.

@golddotasksquestions In your scenario, RigidBody would be used for dynamic bodies, and DynamicBody could be used for dynamic and non-dynamic bodies. This illustrates how confusing things can be when you try to match node names with internal modes. Making the node names descriptive of the usage resolves this problem.

For clarity, here's a breakdown of the different use cases:

-StaticBody: I'm proposing ObstacleBody instead. Commonly used for floor, walls, platforms and moving platforms.
Modes: Static, Kinematic.

-RigidBody: SolidBody may better describe the functionality. Standard usage for anything that is physically simulated or switches modes.
Modes: Static, Kinematic, Dynamic, DynamicLocked

-CharacterBody: Used specifically for character controllers.
Mode: Kinematic

@golddotasksquestions
Copy link

golddotasksquestions commented Jun 12, 2021

@ pouleyKetchoupp I've crossed it out and swapped the names, even though I would think the reverse would make a lot more sense to a bigger group of people who come in touch with Godot.

@pouleyKetchoupp
Copy link

Forgot to close before, implemented in godotengine/godot#48908.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests