xarvh / elm-gamepad / Gamepad.Simple

This is the easiest way to add gamepads to an app.

It provides four functions: sandbox, element, document, application that replace those in the elm/browser package.

These functions require an additional Config argument, which tells them what to do with gamepads.

import Gamepad
import Gamepad.Simple
import GamepadPort


type Msg
    = OnAnimationFrame Gamepad.Simple.FrameStuff


config : Gamepad.Simple.Config Msg
config =
    { onAnimationFrame = OnAnimationFrame
    , onBlob = GamepadPort.onBlob
    , saveToLocalStorage = GamepadPort.saveToLocalStorage
    , controls =
        [ ( "Move LEFT", Gamepad.LeftStickLeft )
        , ( "Move RIGHT", Gamepad.LeftStickRight )
        , ( "Move UP", Gamepad.LeftStickUp )
        , ( "Move DOWN", Gamepad.LeftStickDown )

        --
        , ( "Aim LEFT", Gamepad.RightStickLeft )
        , ( "Aim RIGHT", Gamepad.RightStickRight )
        , ( "Aim UP", Gamepad.RightStickUp )
        , ( "Aim DOWN", Gamepad.RightStickDown )

        --
        , ( "FIRE", Gamepad.RightTrigger )
        , ( "Alt FIRE", Gamepad.RightBumper )
        , ( "Transform", Gamepad.A )
        , ( "Rally", Gamepad.B )
        , ( "Menu", Gamepad.Start )
        ]
    }


main =
    Gamepad.Simple.sandbox
        config
        { init = init
        , view = view
        , update = update
        }


update msg model =
    case msg of
        OnAnimationFrame { gamepads, timestamp, dt } ->
            ...

You will need to manually add port code. See Adding Ports for how to do it.

The remapping tool can be toggled with the Escape key, but will pop up automatically when the user tries to use an unrecognized gamepad.

While the remapping tool is open, the wrapped app will continue to receive its own messages normally, but will NOT receive onAnimationFrame.

User mappings are saved to localStorage.


type alias Program flags model msg =
Platform.Program flags (Model model) (Msg msg)

A Program wrapped by this module


type alias Config msg =
{ onBlob : (Gamepad.Advanced.Blob -> Msg msg) -> Platform.Sub.Sub (Msg msg)
, saveToLocalStorage : String -> Platform.Cmd.Cmd Basics.Never
, onAnimationFrame : FrameStuff -> msg
, controls : List ( String
, Gamepad.Digital ) 
}

The additional parameters needed to create a wrapped Program


type alias FrameStuff =
{ gamepads : List Gamepad
, timestamp : Time.Posix
, dt : Basics.Float 
}

Gamepad polling should happen at every animation frame, so timing information and gamepad state information arrive together in this record.

Use the functions in the Gamepad module to make sense of the Gamepad objects.

The timestamp and dt fields are exactly what you would expect if you were using Browser.Events.onAnimationFrame and Browser.Events.onAnimationFrameDelta respectively.

sandbox : Config msg -> { init : model, view : model -> Html msg, update : msg -> model -> model } -> Program () model msg

Same as Browser.sandbox

element : Config msg -> { init : flags -> ( model, Platform.Cmd.Cmd msg ), view : model -> Html msg, update : msg -> model -> ( model, Platform.Cmd.Cmd msg ), subscriptions : model -> Platform.Sub.Sub msg } -> Program flags model msg

Same as Browser.element

document : Config msg -> { init : flags -> ( model, Platform.Cmd.Cmd msg ), view : model -> Browser.Document msg, update : msg -> model -> ( model, Platform.Cmd.Cmd msg ), subscriptions : model -> Platform.Sub.Sub msg } -> Program flags model msg

Same as Browser.document

application : Config msg -> { init : flags -> Url -> Browser.Navigation.Key -> ( model, Platform.Cmd.Cmd msg ), view : model -> Browser.Document msg, update : msg -> model -> ( model, Platform.Cmd.Cmd msg ), subscriptions : model -> Platform.Sub.Sub msg, onUrlRequest : Browser.UrlRequest -> msg, onUrlChange : Url -> msg } -> Program flags model msg

Same as Browser.application

basicControls : List ( String, Gamepad.Digital )

If you don't know yet which controls to use for your game, you can use this list: Gamepad.Simple will use the list to ask the user to configure the Left Stick and two buttons, A and B.

basicControls =
    [ ( "Up", Gamepad.LeftStickUp )
    , ( "Down", Gamepad.LeftStickDown )
    , ( "Left", Gamepad.LeftStickLeft )
    , ( "Right", Gamepad.LeftStickRight )
    , ( "A", Gamepad.A )
    , ( "B", Gamepad.B )
    ]

This means that inside your app, you will be able to use: