06. Physics Interaction

CRYENGINE provides a powerful physics simulation system which allows objects to behave just like real world objects. Additional parameters defining how the entity should behave while moving or colliding can be added to the physicalized Entity as well.

Sydewinder uses the physics system to move the player, enemies and weapon projectiles through the game level and to detect collisions between projectiles, the environment, the player and the enemies. For further understanding we recommend that you to read the Physics Entities article.

Physicalizing an Entity

The entity function Physicalize enables physics on a specific object by using a proxy to simulate it. The proxy object is a simplified version of the geometry model used in the game. In order to allow the CRYENGINE to calculate physically correct movement and collisions, a minimal number of properties have to be set.

// Create a new Entity.
var entity = Entity.Spawn(position, rotation, scale);

// Add a geometry to the Entity.
entity.LoadGeometry(0, EnemyTypes[type].Geometry);

// Physicalize the Entity as a rigid type.
entity.Physics.Physicalize(new RigidPhysicalizeParams
{
  Density = 1,
  Mass = 0
});

Either the Density or the Mass property has to be specified. The other value is automatically computed using the relationship mass = density * volume.

Entities can be physicalized as several types by changing the type of the PhysicalizeParams, for example by changing it to StaticPhysicalizeParams or LivingPhysicalizeParams. More information about the various physics types can be found on the Physical entity types page.

Physicalized Movement

The common way for moving an Entity within CRYENGINE is to specify its physical behavior, so the engine moves the Entity accordingly. This can be done by setting the properties of the PhysicsEntity of the Entity.

// Retrieve the PhysicsEntity from the Entity.
var physics = Entity.Physics;
if(physics.PhysicsType != PhysicalizationType.None)
{
  // Assign a value to the Velocity.
  physics.Velocity = new Vector3(x, y, z);
}

Velocity only has to be set once for objects flying in a straight line. This is ideal for projectiles fired by weapons such as the default gun in Sydewinder.

However, any object with variable speed or an object that may change its direction periodically needs to be updated whenever its required.

Collision

Collision detection is an essential part of the Sydewinder game. It is used to handle projectiles hitting the player and enemy ships, or detecting if the level geometry is hit. In Sydewinder one or both objects involved in a collision will be destroyed, but objects not destroyed can move along their original path.

In order to react to collisions an Entity can override the OnCollision method to receive a message whenever a collision with that Entity occurs. If a collision occurs, the method will be called with a CollisionEvent which has more information about the collision, such as the entities involved in the collision. For example, for Sydewinder's Player class we check if a Tunnel or a DefaultAmmo Entity is hit, and handle the collision based on the type.

    protected override void OnCollision(EntitySystem.CollisionEvent collisionEvent)
    {
      // Determine wether the Player is the source or the target of the collision.
      var hitEntity = collisionEvent.PhysicsObjects[1].OwnerEntity;

      if(hitEntity != null)
      {
        var component = hitEntity.GetComponent<DestroyableBase>();

        // Handle player collision with lower tunnel by changing the player location.
        if(component is Tunnel)
        {
          // As the only colliding tunnel is a lower tunnel, always change player position.
          Vector3 playerPos = Entity.Position;
          Entity.Position = new Vector3(playerPos.x, playerPos.y, 75);
          return;
        }

        // Don't let player collide with own projectiles.
        var defaultAmmo = component as DefaultAmmo;
        if(defaultAmmo != null && !defaultAmmo.IsHostile)
        {
          return;
        }

        ProcessHit(component is Door);
      }
    }