# `Cauldron2D.Body`
[🔗](https://github.com/jaman/cauldron/blob/v0.1.3/cauldron_2d/lib/cauldron_2d/body.ex#L1)

A point mass with a heading: position, velocity, and one of `headings` directions.

Positions and velocities are in tiles and tiles per second. Heading `0` points right,
and headings increase counter-clockwise on screen, so a quarter of them points up.

    body =
      Cauldron2D.Body.new(pos: {4.0, 4.0}, headings: 64)
      |> Cauldron2D.Body.turn(16)
      |> Cauldron2D.Body.thrust(20.0, dt)
      |> Cauldron2D.Body.gravitate(fields, dt)
      |> Cauldron2D.Body.drag(0.1, dt)
      |> Cauldron2D.Body.integrate(dt)

## Gravity fields

`gravitate/3` takes a list of maps:

  * `%{pos: {x, y}, strength: s, kind: :attract | :repel}` — pulls toward or pushes
    from `pos`, falling off with the square of the distance and capped within one tile
  * `%{pos: {x, y}, strength: s, kind: :clockwise | :anticlockwise}` — pushes across
    the line to `pos`, same falloff
  * `%{strength: s, kind: {:uniform, {dx, dy}}}` — a constant pull in a direction
  * `%{strength: s, kind: {:toward, {x, y}}}` — a constant pull toward a point from
    anywhere, away from it when `s` is negative

# `field`

```elixir
@type field() :: %{
  optional(:pos) =&gt; point(),
  strength: number(),
  kind:
    :attract
    | :repel
    | :clockwise
    | :anticlockwise
    | {:uniform, point()}
    | {:toward, point()}
}
```

# `point`

```elixir
@type point() :: {float(), float()}
```

# `t`

```elixir
@type t() :: %Cauldron2D.Body{
  heading: non_neg_integer(),
  headings: pos_integer(),
  mass: float(),
  pos: point(),
  radius: float(),
  vel: point()
}
```

# `accelerate`

```elixir
@spec accelerate(t(), point(), number()) :: t()
```

Add `{ax, ay}` tiles per second squared for `dt` seconds.

# `angle`

```elixir
@spec angle(t()) :: float()
```

The heading as radians, counter-clockwise from right.

# `cap_speed`

```elixir
@spec cap_speed(t(), number()) :: t()
```

Scale the velocity down to `limit` if it is faster; slower bodies are untouched.

# `direction`

```elixir
@spec direction(t()) :: point()
```

The unit vector the body faces, in screen coordinates (y grows downward).

# `drag`

```elixir
@spec drag(t(), number(), number()) :: t()
```

Slow the body by `coefficient` of its velocity per second, for `dt` seconds.

The velocity is scaled by `exp(-coefficient * dt)`, so it approaches zero without ever
reversing.

# `gravitate`

```elixir
@spec gravitate(t(), [field()], number()) :: t()
```

Apply every field in `fields` for `dt` seconds.

# `integrate`

```elixir
@spec integrate(t(), number()) :: t()
```

Move by the velocity for `dt` seconds.

# `new`

```elixir
@spec new(keyword()) :: t()
```

A body at rest.

## Options

  * `:pos` — `{x, y}` in tiles. Default `{0.0, 0.0}`
  * `:vel` — `{vx, vy}` in tiles per second. Default `{0.0, 0.0}`
  * `:heading` — index into the headings. Default `0`
  * `:headings` — how many directions the body can face. Default `64`
  * `:mass` — used by callers that trade momentum. Default `1.0`
  * `:radius` — in tiles, for collision. Default `0.5`

# `speed`

```elixir
@spec speed(t()) :: float()
```

The velocity's length in tiles per second.

# `thrust`

```elixir
@spec thrust(t(), number(), number()) :: t()
```

Accelerate along the heading by `accel` tiles per second squared for `dt` seconds.

# `turn`

```elixir
@spec turn(t(), integer()) :: t()
```

Turn by `steps` headings; negative turns clockwise. Wraps around the circle.

# `wrap`

```elixir
@spec wrap(t(), {number(), number()}) :: t()
```

Bring a body that has left a `{width, height}` world back in on the opposite side.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
