ExCollision (ExCollision v1.1.0)

View Source

Library for server-side collisions, physics world simulation, tilemap pathfinding, and Tiled TMX parsing.

Main features

  • TMX parsing — load Tiled maps (tile layers, objectgroup, tilesets)
  • Collision world — static and dynamic bodies (AABB), intersection checks and step simulation
  • Pathfinding — A* over tilemap with TileSource protocol support
  • TMX → World integration — build collision world from map layers (Walls, objectgroup)

Server loop

World.step(world, dt) is called every server tick (e.g. 60 times per second). Use a fixed dt = 1/60 for determinism or the actual interval between ticks.

Example

# Parse TMX
map = ExCollision.TMX.Parser.parse!("data/Dun.tmx")

# Collision world from map ("Walls" layer and objectgroup)
world = ExCollision.TMX.WorldBuilder.from_tmx(map, collision_layer: "Walls")

# Pathfinding over layer (walkability: GID=0). In Dun.tmx lines 18–28 are all zeros
layer = ExCollision.TMX.Map.layer_by_name(map, "Floor")
source = ExCollision.TMX.TileLayerTileSource.new(layer)
{:ok, path} = ExCollision.Pathfinding.AStar.find_path(source, {5, 20}, {30, 25})

# Player — Body. Every server tick: step(world, 1/60)
{world, player_id} = ExCollision.World.add_body(world, ExCollision.World.Body.from_xywh(:player, 50, 50, 16, 16, velocity: {0, 0}))
{:ok, world} = ExCollision.World.set_velocity(world, player_id, 32, 0)
world = ExCollision.World.step(world, 1/60)  # every server tick

# Interpolation for smooth rendering (alpha = time since last step / step interval)
{:ok, {x, y}} = ExCollision.World.get_interpolated_position(world, player_id, 0.5)
# Optional: clamp alpha to [0, 1]: get_interpolated_position(..., clamp: true) or get_interpolated_position_clamped/3

Summary

Functions

A* pathfinding. Options: :allow_diagonal — allow diagonal movement (8 directions)

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

List of body ids intersecting the AABB (exclude_id — body to ignore). For bullets: where it would move — who it hit.

Get object by id

Check if object with id exists in world

Interpolated body center. Pass clamp: true in opts to clamp alpha to [0, 1].

Interpolated body position for rendering. Pass clamp: true in opts to clamp alpha to [0, 1].

List of all object ids in world

Рейкастинг: ближайшее попадание луча from → to со статическими/динамическими телами. Возвращает {:hit, t, {x, y}, tag} или :miss. tag = {:static, aabb} | {:body, body_id}. t ∈ [0, 1] — где вдоль луча попало. Опции: :check_static, :check_dynamic, :exclude_body_id.

Рейкастинг: все попадания луча from → to, отсортированные от ближайшего к дальнему. Каждый элемент: {t, {x, y}, tag}. Опции: те же, что у world_raycast/4.

Remove object from world by id.

Remove static AABB by index. Returns {:ok, world} or {:error, :out_of_range}.

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

World simulation step. Call every server tick, e.g.: world_step(world, 1/60)

Functions

find_path(tile_source, start, goal, opts \\ [])

A* pathfinding. Options: :allow_diagonal — allow diagonal movement (8 directions)

parse_tmx!(path_or_xml)

See ExCollision.TMX.Parser.parse!/1.

tmx_layer_by_name(map, name)

See ExCollision.TMX.Map.layer_by_name/2.

world_add_object(world, body)

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

world_bodies_intersecting_aabb(world, aabb, exclude_id \\ nil)

List of body ids intersecting the AABB (exclude_id — body to ignore). For bullets: where it would move — who it hit.

world_from_tmx(tmx_map, opts \\ [])

world_get_object(world, id)

Get object by id

world_has_object?(world, id)

Check if object with id exists in world

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

Interpolated body center. Pass clamp: true in opts to clamp alpha to [0, 1].

world_interpolated_center_clamped(world, body_id, alpha)

Same as world_interpolated_center/4 with alpha clamped to [0, 1].

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

Interpolated body position for rendering. Pass clamp: true in opts to clamp alpha to [0, 1].

world_interpolated_position_clamped(world, body_id, alpha)

Same as world_interpolated_position/4 with alpha clamped to [0, 1].

world_object_ids(world)

List of all object ids in world

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

Рейкастинг: ближайшее попадание луча from → to со статическими/динамическими телами. Возвращает {:hit, t, {x, y}, tag} или :miss. tag = {:static, aabb} | {:body, body_id}. t ∈ [0, 1] — где вдоль луча попало. Опции: :check_static, :check_dynamic, :exclude_body_id.

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

Рейкастинг: все попадания луча from → to, отсортированные от ближайшего к дальнему. Каждый элемент: {t, {x, y}, tag}. Опции: те же, что у world_raycast/4.

world_remove_object(world, id)

Remove object from world by id.

world_remove_static_at(world, index)

Remove static AABB by index. Returns {:ok, world} or {:error, :out_of_range}.

world_set_velocity(world, body_id, vx, vy)

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

world_step(world, dt)

World simulation step. Call every server tick, e.g.: world_step(world, 1/60)