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

A fixed timestep.

    loop = Cauldron2D.Loop.new(60)

    {steps, loop} = Cauldron2D.Loop.advance(loop, Cauldron2D.Loop.now())
    world = Enum.reduce(1..steps//1, world, fn _, w -> World.step(w, Cauldron2D.Loop.dt(loop)) end)

`advance/2` returns how many whole steps have come due since it was last called. `dt/1` is
constant, so a simulation driven by it runs at the same speed whatever the frame rate and
replays identically given the same inputs.

Rules a caller must respect:

  * The first `advance/2` call establishes the baseline and returns no steps.
  * At most `:max_steps` are returned from one call. Time beyond that is discarded rather
    than carried, so the simulation loses that time instead of owing a backlog.
  * Time below one step is carried in the accumulator and returned by a later call.
  * A `now_ms` earlier than the previous one contributes nothing; steps are never negative.

# `t`

```elixir
@type t() :: %Cauldron2D.Loop{
  accumulator: float(),
  last: integer() | nil,
  max_steps: pos_integer(),
  step_ms: float()
}
```

# `advance`

```elixir
@spec advance(t(), integer()) :: {non_neg_integer(), t()}
```

How many whole steps are due at `now_ms`, and the loop to carry forward.

`now_ms` is a millisecond reading on a single monotonic scale, as `now/0` returns. Returns
`{steps, loop}`; pass the returned loop to the next call.

The first call on a fresh loop records `now_ms` as the baseline and returns 0 steps,
whatever the interval since `new/2`.

# `dt`

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

The duration of one step, in seconds — the `dt` a simulation should use.

# `new`

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

A loop running at `hz` steps per second. `hz` must be positive.

## Options

  * `:max_steps` — the most steps one `advance/2` call may return before the remaining time
    is discarded. Default 5

# `now`

```elixir
@spec now() :: integer()
```

The current monotonic time in milliseconds, in the form `advance/2` expects.

---

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