# timer

`import "github.com/matjam/bunyip/timer"`

Package timer schedules callbacks on game time, after a delay or on every interval. Timers run when the game calls Update, so they pause with the game and stay deterministic.

Advance a Scheduler each update with the step. After runs a function once, Every runs it repeatedly, and both return a handle to Cancel. Countdown is a simpler alternative. Start it, update it, and ask whether it is still Running. Because the time is the game's own, a paused game stops its timers by not calling Update, a replay reruns them identically, and a fast-forward advances them by a larger step. Schedulers are not goroutine-safe and fire on the goroutine that calls Update, the game loop's, so callbacks may touch game state freely.

## Types

<a id="Countdown"></a>

<a id="Countdown.Left"></a>

### Countdown

```go
type Countdown struct {
	Left float64 // seconds remaining; may become negative on the final Update
}
```

Countdown is a simple timer a game polls rather than a callback: set it and ask each frame whether it has run out.

Example:

```go
package main

import (
	"fmt"

	"github.com/matjam/bunyip/timer"
)

func main() {
	var c timer.Countdown
	c.Start(1)
	for i := 1; ; i++ {
		if c.Update(0.4) {
			fmt.Println("ran out on update", i)
			break
		}
	}
}
```

Output:

```
ran out on update 3
```

<a id="Countdown.Running"></a>

#### Countdown.Running

```go
func (c *Countdown) Running() bool
```

Running reports whether time remains.

<a id="Countdown.Start"></a>

#### Countdown.Start

```go
func (c *Countdown) Start(seconds float64)
```

Start sets the countdown.

<a id="Countdown.Update"></a>

#### Countdown.Update

```go
func (c *Countdown) Update(dt float64) bool
```

Update advances the countdown and reports whether it ran out on this update (true once).

<a id="Handle"></a>

### Handle

```go
type Handle int
```

Handle identifies a scheduled timer for Cancel.

<a id="Scheduler"></a>

### Scheduler

```go
type Scheduler struct {
	// contains filtered or unexported fields
}
```

Scheduler runs timers in game time. Its zero value is ready to use.

Example:

```go
package main

import (
	"fmt"

	"github.com/matjam/bunyip/timer"
)

func main() {
	var s timer.Scheduler
	s.After(1, func() { fmt.Println("door opens") })
	tick := s.Every(0.5, func() { fmt.Println("tick") })
	// Update from the game loop with the frame's delta; here two big
	// steps. Timers fire in time order, and at the same moment in the
	// order they were scheduled.
	s.Update(0.6)
	s.Update(0.6)
	s.Cancel(tick)
	s.Update(5)
}
```

Output:

```
tick
door opens
tick
```

<a id="Scheduler.After"></a>

#### Scheduler.After

```go
func (s *Scheduler) After(seconds float64, fn func()) Handle
```

After runs a non-nil fn once, seconds from now. A nonpositive delay becomes due on the next Update, or in the current Update if scheduled by a callback. It does not run fn during After itself.

<a id="Scheduler.Cancel"></a>

#### Scheduler.Cancel

```go
func (s *Scheduler) Cancel(h Handle)
```

Cancel stops a timer; cancelling one that already fired is harmless.

<a id="Scheduler.Every"></a>

#### Scheduler.Every

```go
func (s *Scheduler) Every(seconds float64, fn func()) Handle
```

Every runs fn every interval seconds, starting one interval from now, until cancelled. Use a positive interval for repetition; a nonpositive interval fires once on the next Update.

<a id="Scheduler.Now"></a>

#### Scheduler.Now

```go
func (s *Scheduler) Now() float64
```

Now is the scheduler's elapsed game time in seconds.

<a id="Scheduler.Pending"></a>

#### Scheduler.Pending

```go
func (s *Scheduler) Pending() int
```

Pending counts scheduled timers that have not fired or been cancelled.

<a id="Scheduler.Update"></a>

#### Scheduler.Update

```go
func (s *Scheduler) Update(dt float64)
```

Update advances time by dt seconds and fires what is due, earliest first; timers due at the same moment fire in the order they were scheduled. Callbacks may schedule or cancel timers. Use finite, nonnegative dt. Repeating timers fire once for every elapsed interval, including multiple times in a large step. Callbacks must return and must not recursively call Update.

<a id="Sequence"></a>

### Sequence

```go
type Sequence struct {
	// contains filtered or unexported fields
}
```

Sequence runs steps one after another on game time, the way a coroutine would: wait a while, do something, wait until a condition holds, run a function every update until it says it is done. It is how a cutscene, a turn's animation, a boss's attack pattern or a tutorial is written as a list rather than a state machine:

	seq := timer.NewSequence().
		Do(func() { camera.PanTo(door) }).
		Wait(1).
		Until(func() bool { return camera.Arrived() }).
		Do(func() { door.Open() }).
		Run(func(dt float32) bool { return hero.WalkTowards(door, dt) })

The game calls Update each step; Done reports when the last step has finished. Steps run on the goroutine that calls Update.

<a id="NewSequence"></a>

#### NewSequence

```go
func NewSequence() *Sequence
```

NewSequence starts an empty sequence; add steps with the builder methods, which return the sequence for chaining.

<a id="Sequence.Do"></a>

#### Sequence.Do

```go
func (s *Sequence) Do(fn func()) *Sequence
```

Do runs a function once and moves on in the same update.

<a id="Sequence.Done"></a>

#### Sequence.Done

```go
func (s *Sequence) Done() bool
```

Done reports whether every step has finished; a looping sequence is never done unless Skip was called or it has no steps.

<a id="Sequence.Loop"></a>

#### Sequence.Loop

```go
func (s *Sequence) Loop() *Sequence
```

Loop makes the sequence start over when it ends, for patrols and idle behaviours.

<a id="Sequence.Reset"></a>

#### Sequence.Reset

```go
func (s *Sequence) Reset()
```

Reset starts the sequence over from its first step.

<a id="Sequence.Run"></a>

#### Sequence.Run

```go
func (s *Sequence) Run(fn func(dt float32) bool) *Sequence
```

Run calls the function every update with the step until it returns true: a movement to carry out, an animation to play through.

<a id="Sequence.Skip"></a>

#### Sequence.Skip

```go
func (s *Sequence) Skip()
```

Skip jumps to the end, for a player who presses through a cutscene; Do steps that have not run yet do not run.

<a id="Sequence.Until"></a>

#### Sequence.Until

```go
func (s *Sequence) Until(cond func() bool) *Sequence
```

Until waits, checking each update, until the condition holds.

<a id="Sequence.Update"></a>

#### Sequence.Update

```go
func (s *Sequence) Update(dt float32) bool
```

Update advances the sequence by dt seconds, running as many steps as finish within it. It reports whether the sequence is done. Wait carries leftover time into following steps. A completed Run consumes the entire remaining step, so later Run steps in the same call receive zero dt. Use finite, nonnegative dt and do not call Update recursively from a step.

<a id="Sequence.Wait"></a>

#### Sequence.Wait

```go
func (s *Sequence) Wait(seconds float32) *Sequence
```

Wait pauses for a number of seconds.
