Physics
Physics simulation can make games much more engaging and realistic. Easel makes this easy with its built-in physics engine.
Simply give the entity a body and one or more colliders, and the physics engine will handle the rest.
pub also body = projectile
pub tangible category Category:Projectile
pub fn hero.LaunchProjectile() {
Spawn projectile {
use categories = Category:Projectile
use speed=48, radius=0.24, density=30, restitution=1, bullet=true
Body(
parent=hero,
pos=hero.Pos,
heading=hero.Heading,
speed=Direction(heading) * speed,
)
PolygonCollider(Circle)
once AfterCollide {
Expire
}
// ...
}
}
Detecting collisions
BeforeCollide is triggered when a collider is begins contact with another collider,
and AfterCollide is triggered when a collider ends contact with another collider.
You would typically use an on
block to listen for these events.
on BeforeCollide that {
if that.Category.Overlaps(Category.Unit) {
that.Health -= 10
}
}
Isolating collisions
By default, BeforeCollide
and AfterCollide
receive collision events for every collider on the entity.
Sometimes you may want to create a collider that should not trigger normal collision handling.
For example, you might want to detect when a hero gets close to an obstacle.
For this you can create a new proximity sensor collider
with the isolate
parameter of PolygonCollider set to true
.
Being close to an obstacle should not be treated the same as touching an obstacle,
and so isolate=true
is used to keep the collision handling separate.
Once a collider has been isolated, you must use BeforeCollide<Id>
and AfterCollide<Id>
to listen for its events,
as its collision events will no longer be sent to the usual BeforeCollide
and AfterCollide
handlers anymore.
This allows you to separate the handling of normal collisions from the handling of isolated collisions.
PolygonCollider<proximitySensor>(shape=Circle(10), category=Category:Proximity, isolate=true, isSensor=true)
on BeforeCollide<proximitySensor> that {
// Do something we sense something within 10 units of this entity
}
Stepping
Call the ForcefulStep to move the body to another position by applying a one-off force during the next physics simulation. Similarly, call ForcefulTurn to change the body's heading by applying a one-off torque during the next physics simulation.
This differs from just modifying Pos or Heading directly because that would simply teleport the body to its new position, whereas this applies a one-off force which can be transferred to other bodies if a collision occurs.
This technique makes a body realistically push other bodies when it is walking into them, for example a hero pushing into a boulder or into another hero.
Querying
Querying searches all colliders in the physics engine for the ones that meet certain conditions:
- QueryNearest finds the nearest collider to a point.
- QueryWithinRadius finds all colliders within a certain radius of a point.
- QueryOverlapping finds all colliders that overlap with a given collider.
- QueryNearestAlongRay finds the nearest collider along a ray.
Note that the querying is performed on colliders not bodies. That means if a body has multiple colliders, it will be returned multiple times in the results.
Querying is done using a spatial index which is only calculated on demand and cached. The cached spatial index is deleted when the physics simulation is performed, and at the end of every tick. That means if a query is performed, and then body positions are changed manually, the next query will run on a stale spatial index and so results might not be accurate. You can force the spatial index to be recalculated by calling ResetSpatialQueryIndex.