ExCollision.World (ExCollision v1.1.0)

View Source

Collision world: static and dynamic bodies (AABB). Supports collision checks and simulation (step with collision resolution). Implements Enumerable over bodies.

Summary

Functions

Add body and return {world, body_id}

Add object (dynamic body) to world. Returns {world, id}.

Add static AABB (e.g. from tiles or objectgroup)

Check if two bodies intersect (e.g. bullet and player)

List of body ids intersecting the given AABB (e.g. where a bullet would move). exclude_body_id — body to ignore (the bullet itself). Useful for bullet collision: where it would move — who it hit.

Number of bodies

List of all object (body) ids in world

Check if AABB collides with world (static or body)

Get body by id

Interpolated body center (for sprite rendering by center).

Interpolated body position for smooth rendering. alpha in [0, 1]: 0 = previous frame, 1 = current (e.g.: time_since_step / step_interval). Returns {:ok, {x, y}} — top-left corner, or {:error, :not_found}.

Get object (body) by id

Check if body/object with given id exists in world

Try to move body by (dx, dy); on collision the body does not move. If body has on_collision set, it is called with (world, body_id, [collided body ids], hit_static); callback returns updated world (e.g. remove bullet, apply damage). Returns {:ok, world, body} | {:collision, world, body} | {:error, :not_found}.

Update body in world

Update object (body) in world by its id

Рейкастинг: возвращает ближайшее попадание луча from → to или :miss.

Рейкастинг: возвращает все попадания вдоль луча from → to, отсортированные от ближайшего к дальнему.

Remove body by id

Remove object (body) from world by id. Returns updated world.

Remove static AABB by index (0 = first added). Returns {:ok, world} or {:error, :out_of_range}.

Set body velocity (vx, vy) in pixels/sec

Number of static AABBs in the world

World simulation step: for each dynamic body with velocity applies movement, stores previous_aabb for interpolation, resolves collisions (on collision movement is reverted). Returns updated world.

Types

t()

@type t() :: %ExCollision.World{
  bodies: %{required(term()) => ExCollision.World.Body.t()},
  next_id: non_neg_integer(),
  static_bodies: [ExCollision.Geometry.AABB.t()]
}

Functions

add_body(world, body)

Add body and return {world, body_id}

add_object(world, body)

Add object (dynamic body) to world. Returns {world, id}.

add_static(world, aabb)

Add static AABB (e.g. from tiles or objectgroup)

bodies_intersect?(world, body_id_a, body_id_b)

Check if two bodies intersect (e.g. bullet and player)

bodies_intersecting_aabb(world, aabb, exclude_body_id \\ nil)

List of body ids intersecting the given AABB (e.g. where a bullet would move). exclude_body_id — body to ignore (the bullet itself). Useful for bullet collision: where it would move — who it hit.

body_count(world)

Number of bodies

body_ids(world)

List of all object (body) ids in world

collides?(world, aabb, exclude_body_id \\ nil)

Check if AABB collides with world (static or body)

get_body(world, id)

Get body by id

get_interpolated_center(world, body_id, alpha, opts \\ [])

Interpolated body center (for sprite rendering by center).

Options:

  • :clamp — if true, clamps alpha to [0, 1] before interpolating (default false).

get_interpolated_center_clamped(world, body_id, alpha)

Same as get_interpolated_center/4 with clamp: true.

get_interpolated_position(world, body_id, alpha, opts \\ [])

Interpolated body position for smooth rendering. alpha in [0, 1]: 0 = previous frame, 1 = current (e.g.: time_since_step / step_interval). Returns {:ok, {x, y}} — top-left corner, or {:error, :not_found}.

Options:

  • :clamp — if true, clamps alpha to [0, 1] before interpolating (default false).

get_interpolated_position_clamped(world, body_id, alpha)

Same as get_interpolated_position/4 with clamp: true.

get_object(world, id)

Get object (body) by id

has_body?(world, id)

Check if body/object with given id exists in world

move_body(world, body_id, dx, dy)

Try to move body by (dx, dy); on collision the body does not move. If body has on_collision set, it is called with (world, body_id, [collided body ids], hit_static); callback returns updated world (e.g. remove bullet, apply damage). Returns {:ok, world, body} | {:collision, world, body} | {:error, :not_found}.

new(opts \\ [])

put_body(world, body)

Update body in world

put_object(world, body)

Update object (body) in world by its id

raycast(world, from, to, opts \\ [])

@spec raycast(t(), {number(), number()}, {number(), number()}, keyword()) ::
  {:hit, float(), {float(), float()},
   {:static, ExCollision.Geometry.AABB.t()} | {:body, term()}}
  | :miss

Рейкастинг: возвращает ближайшее попадание луча from → to или :miss.

  • from / to{x, y} начало и конец луча; задают направление и максимальную длину.
  • t ∈ [0, 1] — параметр вдоль луча: 0 = from, 1 = to.
  • Опции:
    • :check_static (default true) — проверять статические AABB
    • :check_dynamic (default true) — проверять динамические тела
    • :exclude_body_id — пропустить тело с этим id (например, стрелок)

Возвращает:

  • {:hit, t, {x, y}, tag} где tag = {:static, aabb} | {:body, body_id}

  • :miss

raycast_all(world, arg1, arg2, opts \\ [])

@spec raycast_all(t(), {number(), number()}, {number(), number()}, keyword()) :: [
  {float(), {float(), float()},
   {:static, ExCollision.Geometry.AABB.t()} | {:body, term()}}
]

Рейкастинг: возвращает все попадания вдоль луча from → to, отсортированные от ближайшего к дальнему.

Каждый элемент: {t, {x, y}, tag}. Опции: те же, что у raycast/4.

remove_body(world, id)

Remove body by id

remove_object(world, id)

Remove object (body) from world by id. Returns updated world.

remove_static_at(world, index)

Remove static AABB by index (0 = first added). Returns {:ok, world} or {:error, :out_of_range}.

set_velocity(world, body_id, vx, vy)

Set body velocity (vx, vy) in pixels/sec

static_count(world)

Number of static AABBs in the world

step(world, dt)

World simulation step: for each dynamic body with velocity applies movement, stores previous_aabb for interpolation, resolves collisions (on collision movement is reverted). Returns updated world.

Call every server tick (e.g. in GenServer or game loop): world = World.step(world, dt).

  • dt — step time in seconds. For fixed 60 ticks/sec use 1/60.
  • For deterministic simulation use fixed dt; for real-time use actual interval between ticks.

update_coordinates(world, body_id, x, y, opts \\ [])