QBodyNode and Base Features - erayzesen/godot-quarkphysics GitHub Wiki

QBodyNode is the base class for all body types in QuarkPhysics. It is useful to understand the feature set shared by its derived types, such as QRigidBodyNode, QAreaBodyNode, and QSoftBodyNode. Additionally, this article provides general insights into how a QBodyNode instance functions.

How Do QBodyNode Types Work?

While knowing the internal workings may not be necessary when using the plugin, understanding the logic behind it can help you feel more comfortable with your use cases. The most crucial method that QBodyNode types must override is the QBody::Update method, which is specific to each body type. This method is called at every simulation step and governs all behaviors and constraints of derived body types through this virtual method.

The Godot extension handles things at a higher level and does not allow direct instantiation of a QBodyNode object due to the complexities of adding entirely new dynamics to the physics engine. However, you can create new body types by deriving from QBodyNode's subclasses. For instance, in the original codebase, the QPlatformerBody type is derived from QRigidBody.

Verlet Velocity Integration: Position and Rotation Properties

QuarkPhysics employs Verlet velocity integration throughout the simulation, meaning that velocities are implicit. What does this mean? In simpler terms, all moving objects in QuarkPhysics store their previous frame's position. The velocity is determined by the difference between the current and previous positions and is then applied accordingly. In other words, the new position dictates the velocity.

Thus, QBodyNode-derived objects have previousPosition and previousRotation properties alongside their position and rotation values. Similarly, QParticleObject has both position and previous position properties.

The key to manipulating velocity is modifying the previously stored positions and rotations. For example, if you set an object's position and also update previousPosition to the same value, the object’s velocity will be reset. Generally, we do not need to intervene in this way, as the simulation naturally computes velocities based on position changes. However, understanding this fundamental aspect of the physics engine is crucial.

For example, if you move an object to a different location without adjusting its previous position, the difference between the old and new positions will be interpreted as velocity. Imagine taking a box at the start of a scene and teleporting it to the other side; if done directly, the box will treat this position change as a new velocity, which is usually undesirable. The same applies to rotation.

A QBodyNode-type object’s position and rotation can be modified using the following methods:

# Methods: 
#set_body_position(value:Vector2, with_previous_position:bool)  
#set_body_rotation(angle_radian:float, with_previous_rotation:bool)
 
# Sets the body's position and previous position in a single method. This will reset the velocity to zero.
set_body_position(Vector2(512,128), true )

# Sets the body's rotation and previous rotation in a single method. This will reset the angular velocity to zero.
set_body_rotation( PI/2, true)

# Sets the body's position without affecting its velocity.
set_body_position(Vector2(125,122), false )

# Sets the body's rotation without affecting its angular velocity.
set_body_rotation( PI/180 , false )


You can also directly modify the previous position and rotation using the set_body_previous_position(value: Vector2) and set_body_previous_rotation(angle_radian: float) methods, allowing you to manipulate velocity.

Collision Layers

QBodyNode objects define two layers, functioning similarly to Godot’s physics layer system. These layers are:

  • layers : Defines which layer(s) the QBodyNode object belongs to. In other words, a QBodyNode object tells other QBodyNode objects, "I exist in these layers."

  • collidable_layers : Defines which layers the QBodyNode object can collide with. That is, a QBodyNode object expects the objects it will collide with to be in these layers.

Since this concept can sometimes be confusing for users of physics engines, an example will help clarify it. For example, let's say we have two objects named bodyA and bodyB. Before bodyA starts a collision test with bodyB, it first checks the layers defined in bodyB's layers property. If any of these layers match one of the layers listed in bodyA's collidable_layers property, the collision test is performed. Otherwise, the collision test is skipped.

Body Modes

QBodyNode objects have two modes: static and dynamic.

  • In static mode, objects do not move. They react to collisions with dynamic objects but are not affected by them. This mode is typically used for stationary platforms and walls in games.
  • In dynamic mode, objects can move, respond to and influence collisions, change position, and have forces applied to them.

Note: If you need completely static, non-moving objects, you should use rigid bodies. This is both more performant and more stable for all types of bodies.

Physics Properties

Every QBodyNode instance shares a common set of physics properties that define its behavior. These are similar to physics materials in other physics engines:

  • Mass -mass : The object's mass. Default is 1.0.

  • Friction - friction : The object's dynamic friction coefficient, ranging from 0.0 to 1.0. Default is 0.2.

  • Static Friction - static_friction: The object's static friction coefficient, ranging from 0.0 to 1.0. Default is 0.5.

  • Air Friction - air_friction : The object's air resistance coefficient, ranging from 0.0 to 1.0. Default is 0.01.

  • Restitution -restitution : Defines how much energy the object retains upon collision. This is used for elastic collisions and bouncing objects. Ranges from 0.0 to 1.0, with a default of 0.0.