helm-1.0.0: A functionally reactive game engine.

Safe HaskellNone
LanguageHaskell2010

Helm

Contents

Description

Contains the main functions for interfacing with the engine. This can be thought of Helm's own Prelude.

Synopsis

Types

newtype Cmd e a Source

Represents an IO-like monad with knowledge about the state of the game engine. Each command contains a collection of game actions that will be applied to your game's update function to update the game state. This is similar to a subscription in a way, with the difference being that a command does not change over time, but rather is a lazy monad and hence contains a value that from the time of the execution. A good example of the usage of a command vs. a subscription is the game window size - a command would allow you to map the current window size into an action, whereas a subscription would let you subscribe to when the window is resized and then map that event into a game action.

Just like a subscription, any function that returns a command in the Helm library will first let you map from the original contained value to a game action. It's important to note that commands are **evaluated on the main-thread** - which means they can block the rendering process. *Don't execute long-running monads under commands!*

Here the type variable e is an instance of the Engine typeclass and the variable a is the game action data type used by your game.

Constructors

Cmd (StateT e IO [a]) 

class Engine e Source

Represents a backend engine that can run a Helm game.

Helm separates the logic for running a game from the actual interaction with the user - window management, event management (key presses, mouse presses, etc.) are all handled by a specific instance of the engine typeclass. Meanwhile, the game loop and other core features are handled independently by the Helm library itself.

data GameConfig e m a Source

Represents the configuration for a Helm game.

The type variable e refers to an instance of the Engine class, m refers to a game model type and a refers to a game action type.

Constructors

GameConfig 

Fields

initialFn :: (m, Cmd e a)

Called when the game starts up. The first value in the tuple is the initial game model state and then the second value is an optional command to be run. The command allows you to execute some monads during game startup and build up some game actions before the game begins rendering. A good example would be loading a game configuration file, parsing the file contents and then mapping the parsed contents to relevant game actions.

If no initial command is required, simply pass none for the second tuple value. Alternatively, if there are a number of commands to run, call batch to combine them into one.

updateFn :: m -> a -> (m, Cmd e a)

Called whenever a game action is mapped from a command or subscription. This is where the actual implementation of a Helm game is done. The function is given a game model and the mapped action type, and should produce the new game model state based off of the action.

The first tuple value is the new model state, and then the second is a command that can be run to produce more game actions. By having this command returnable here, you can run additional IO logic based off the game action, and produce more game actions from the result.

Be very careful with what commands you run in the game update function - most importantly, don't execute long-winding commands or it will block the rendering process!. Helm will try to intelligently queue recursive commands to prevent blocking rendering. However, having a game action that returns a specific command from the update function, which in turn is executed and returns that same game action (which will then in turn return the same command, and so on) is not recommend. The best way to return commands from the update function is to to hide them behind conditionals based off your game state, so that they're not run every update function.

subscriptionsFn :: Sub e a

The subscriptions for a game. All the input sources required to make the game work should be subscribed to and mapped to the relevant game action type variant.

If no subscriptions are required (i.e. no user input is required), pass none. Alternatively, if multiple subscriptions are required use batch to combine them.

viewFn :: m -> Graphics e

Called when the engine is ready to render the game. The function is given the current state of the game model and should produce a graphics value to be rendered to the screen.

Do not rely on this function being called every game tick - the engine will figure out whether it needs to be called based off window exposure and whether or not the game model has changed since the last render.

data Graphics e Source

Represents any form of structure that produces visual graphics to the screen, e.g. 2D or 3D graphics.

The type variable e should refer to an Engine instance.

Constructors

Graphics2D (Collage e) 

data family Image e Source

Represents an image asset loaded by an engine instance.

This is a type family, where the instance types are the specific internal representations of an image for an engine. Hence the e type variable here should refer to an Engine instance, but that is not strictly required.

Having the image type be a family allows us to separate the internal representation of the image assets for each engine from the core Helm library.

Instances

data Image SDLEngine = SDLImage {} Source

Represents an Image for the SDL engine.

newtype Sub e a Source

Represents a subscription to a stream of events captured from a user's interaction with the engine. A subscription is best thought of as a collection of events over time - which is the nature of functional reactive programming (the paradigm that Helm bases it's concepts on). Although Helm uses a departed version of the traditional FRP paradigm, it still follows the concept closely and hence an understanding of FRP will allow you to understnad the library easily.

Functions throughout the Helm library that return a subscription will first let you map the data related to the event you're subscribing to into another form (specifically, a game action). These game actions are then sent to the update function of your game, i.e. the mapped subscription specifies exactly how game events will interact with your game state.

Here the type variable e is an instance of the Engine typeclass and the variable a is the game action data type used by your game.

Constructors

Sub (SignalGen e (Signal [a])) 

Engine

run :: Engine e => e -> GameConfig e m a -> IO () Source

Runs a Helm game using an engine and some configuration for a game. An engine should first be initialized separately to Helm, and then passed to this function. Helm is written this way so that library users can choose what backend engine they want to use (and hence Helm is engine-agnostic).

The best engine to get started with is the SDL implementation of Helm, which is currently bundled with the engine (although it will eventually be moved to its own package). See startup for how to startup the SDL engine, which can then be run by this function.