gloop

package module
v0.0.0-...-95f0d49 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 10, 2019 License: MIT Imports: 4 Imported by: 0

README

gloop

Go Report Card Travis CI GoDoc

Real-ish time Go simulation loop with support for simultaneous fixed step (simulation) and elastic step (rendering) functions. Includes a heartbeat channel to monitor loop health and performance metrics.

Example

A full example using Vulkan and metrics publishing is availabe in _examples/gloopex folder.

render := func(step time.Duration) error {
    // Do elastic-step work here.
    // The step param will be larger than RenderLatency
    // if we start to fall behind. 
    return nil
}
simulate := func(step time.Duration) error {
    // Do fixed-step work here.
    // The step param will always be SimulationLatency,
    // and we'll invoke the function more often if
    // we start to fall behind.
    return nil
}
// Set up the loop here.
loop, err := gloop.NewLoop(render, simulate, gloop.Hz60Delay, gloop.Hz60Delay)
// Start up the loop. This is not blocking.
loop.Start()
// Wait some period of time...
<-time.NewTimer(time.Minute).C
// At some point, call Stop.
// It's safe to do this from inside render() or simulate().
// The loop will also stop if render() or simulate() return an error.
loop.Stop(nil)
// Wait for the loop to finish.
// Once this chan is closed, it is guaranteed that
// neither render() nor simulate() will be called again.
<-loop.Done()

Quick Tutorial

loop.Start(...) starts the loop in a different goroutine.

loop.Stop(...) will halt the loop. This is thread safe, and can be called from within loop.Render(...) or loop.Simulate(...).

If loop.Render(...) or loop.Simulate(...) return an error, the loop will halt and the loop's loop.Err() will be set to non-nil.

Pull performance metrics out of the loop with sample <- loop.Heartbeat().

Wait for the loop to finish with <- loop.Done(). Once this closes, loop.Render(...) and loop.Simulate(...) will not be called again. The chan will also not close until any currently-executing calls to either of those functions finish.

There is no need to use synchronization objects; only one call to loop.Render(...) or loop.Simulate(...) will run at a time.

Install

go get -u github.com/erinpentecost/gloop

Testing

# You can use normal go tooling...
go test ./...
# Or the makefile...
make test

Documentation

Overview

Package gloop implements a game loop.

Index

Constants

View Source
const Hz60Delay time.Duration = time.Duration(int64(time.Second) / 60)

Hz60Delay is 1/60th of a second.

Variables

This section is empty.

Functions

This section is empty.

Types

type LatencySample

type LatencySample struct {
	RenderLatency   time.Duration
	SimulateLatency time.Duration
}

LatencySample is a measure of how far behind simulate() or render() are.

type Loop

type Loop struct {
	// Render is an elastic-step function.
	Render LoopFn
	// Simulate is a fixed-step function.
	Simulate LoopFn
	// RenderRate controls how often Render will be called.
	// This is the time delay between calls.
	RenderLatency time.Duration
	// SimulationRate controls how often Simulate will be called.
	// This is the time delay between calls.
	SimulationLatency time.Duration
	// contains filtered or unexported fields
}

Loop is a game loop.

func NewLoop

func NewLoop(Render, Simulate LoopFn, RenderLatency, SimulationLatency time.Duration) (*Loop, error)

NewLoop creates a new game loop.

func (*Loop) Done

func (l *Loop) Done() <-chan interface{}

Done returns a chan that indicates when the loop is stopped. When this finishes, you should do cleanup.

func (*Loop) Err

func (l *Loop) Err() error

Err returns the the reason why the loop closed if there was an error. Err will return nil if the loop has not yet run, is currently running, or closed without an error.

func (*Loop) Heartbeat

func (l *Loop) Heartbeat() <-chan LatencySample

Heartbeat returns the heartbeat channel which can be used to monitor the health of the game loop. A pulse will be sent every second with current simulation and render latency.

func (*Loop) Start

func (l *Loop) Start() error

Start initiates a game loop. This call does not block. To stop the loop, close the done chan. To get notified before Simulate or Render are called, pull items from the heartbeat channel. If either Render or Simulate throw an error, the error will be made available on the output error channel and the loop will stop.

func (*Loop) Stop

func (l *Loop) Stop(err error)

Stop halts the loop and sets Err(). You probably want to make a call to this somewhere in Simulate().

type LoopError

type LoopError struct {
	Inner       error
	Message     string
	StackTrace  string
	ErrorSource TokenSource
	Misc        map[string]interface{}
}

LoopError is thrown when a gogameloop function returns an error.

func (LoopError) Error

func (e LoopError) Error() string

type LoopFn

type LoopFn func(step time.Duration) error

LoopFn is a function that is called inside the game loop. step should be treated as if it was the amount of time that elapsed since the last call.

type TokenSource

type TokenSource int

TokenSource is the creator for the token (metrics or errors).

const (
	// TokenLoop is something generated by the game loop package directly.
	TokenLoop TokenSource = iota
	// TokenRender concerns Render().
	TokenRender TokenSource = iota
	// TokenSimulate concerns Simulate().
	TokenSimulate TokenSource = iota
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL