Reactor.Types
- Package
- purescript-grid-reactors
- Repository
- Eugleo/purescript-grid-reactors
This module introduces the Reactor
as a datatype.
As the Pyret documentation puts it,
a reactor is a value enabling the creation of time-based animations, simulations, and interactive programs.
During the creation of a reactor, the user supplies a function for handling clock ticks,
and functions for handling mouse and keyboard input events.
The reactor calls these event handlers whenever the respective event occurs.
From within the event handlers, the reactor's state — or, the world, as we call it —
can be updated. After each world update, the reactor renders the new world with the supplied drawing function.
#Reactor Source
type Reactor :: (Type -> Type) -> Type -> Type
type Reactor m world = { draw :: world -> Drawing, init :: world, onKey :: KeypressEvent -> Action m world DefaultBehavior, onMouse :: MouseEvent -> Action m world DefaultBehavior, onTick :: TickEvent -> Action m world Unit }
The reactor is a simple record. A reactor is is parametrized over the following type variables:
m
signifies which monad will be used to run the event handlers, which is mostly an implementation detail. Usuallym
isEffect
orAff
(i.e. asynchronousEffect
). You can safely ignore this most of the time.world
denotes what is the type of the internal state of the reactor. This is where the state of your game or simulation is saved.
The fields in the record are the following:
init
is the initial state of the reactor's worlddraw
is a function used to render the world anytime it is changedonTick
is a function called on every tick of the reactor's clock. It is called around 60 times a second, provided the reactor is not paused.onKey
is an event handler for keyboard input events. It receives the pressed key and does someAction
, which usually involves updating the world based on the received input.onMouse
is an event handler for mouse input events (button clicks, draggging, moving). Similarly to theonKey
function, it receives the details of the event and does someAction
, which usually involves updating the world based on the event.
For example, when ran, the following reactor would render a player at the initial position, and would allow the user to move the player by pressing arrow keys. The clock is paused, and mouse events are ignored.
import Reactor.Action
(executeDefaultBehavior, modify_, preventDefaultBehavior, utilities)
import Reactor.Events (KeypressEvent(..))
import Reactor.Graphics.Colors as Color
import Reactor.Graphics.CoordinateSystem
(CoordinateSystem, grid, moveDown, moveLeft, moveRight, moveUp, wrt)
import Reactor.Graphics.Drawing (fill, cell)
import Reactor.Types (Reactor)
type World =
{ player :: CoordinateSystem { x :: Number, y :: Number }
, paused :: Boolean
}
reactor :: forall m. Reactor m World
reactor =
{ init: { player: { x: 0, y: 0 } `wrt` grid, paused: true }
, draw: \{ player } -> fill Color.blue400 $ cell player
, onTick: \_ -> pure unit
, onKey: \(KeypressEvent key _) -> do
{ bound } <- utilities
case key of
"ArrowLeft" -> do
modify_ \w@{ player } ->
w { player = bound $ moveLeft player }
preventDefaultBehavior
"ArrowRight" -> do
modify_ \w@{ player } ->
w { player = bound $ moveRight player }
preventDefaultBehavior
"ArrowDown" -> do
modify_ \w@{ player } ->
w { player = bound $ moveDown player }
preventDefaultBehavior
"ArrowUp" -> do
modify_ \w@{ player } ->
w { player = bound $ moveUp player }
preventDefaultBehavior
_ -> executeDefaultBehavior
, onMouse: \_ -> executeDefaultBehavior
}
#Configuration Source
type Configuration = { height :: Int, title :: String, width :: Int }
Configuration for the Halogen component that renders the reactor. Although a reactor is a general structure, our reactors focus on grid-based games and simulations. The component thus needs a little more info than just what is in already the reactor, namely:
title
, the title of the webpage where the reactor is renderedwidth
, the width of the grid, in cellsheight
the height of the grid, in cells Notably, the size of the rendered cells isn't customizable and is set to 30pts.