Current section
Files
Jump to
Current section
Files
src/rcade/inputs.gleam
import lustre/effect.{type Effect}
import rcade/inputs/controls.{type Controls, type SystemButtons}
import rcade/inputs/spinner.{type Spinner}
import rcade/player.{type Player, Player1, Player2}
/// Combined input state for a player.
pub type Player1Inputs {
Player1Inputs(controls: Controls, spinner: Spinner)
}
/// Combined input state for a player.
pub type Player2Inputs {
Player2Inputs(controls: Controls, spinner: Spinner)
}
/// Poll all input states at a given interval (in milliseconds).
///
/// Returns an effect that builds a msg from the states of both players'
/// controls and spinners, as well as the state of the system buttons.
pub fn poll(
every interval: Int,
with to_msg: fn(Player1Inputs, Player2Inputs, SystemButtons) -> msg,
) -> Effect(msg) {
effect.from(fn(dispatch) {
let _stop =
start_polling(interval, fn() {
let player1 =
Player1Inputs(
controls: controls.read_player(Player1),
spinner: spinner.read(Player1),
)
let player2 =
Player2Inputs(
controls: controls.read_player(Player2),
spinner: spinner.read(Player2),
)
let system = controls.read_system()
dispatch(to_msg(player1, player2, system))
})
Nil
})
}
@external(javascript, "./inputs_ffi.mjs", "start_polling")
fn start_polling(interval: Int, callback: fn() -> Nil) -> fn() -> Nil
/// A button press event from the classic controls.
pub type ButtonPress {
PlayerButton(player: Player, button: String)
SystemButton(String)
}
/// Subscribe to "classic" control press events.
///
/// Each press dispatches a `ButtonPress` with the provided msg constructor.
pub fn on_press(with to_msg: fn(ButtonPress) -> msg) -> Effect(msg) {
effect.from(fn(dispatch) {
let _unsubscribe =
controls.subscribe(fn(player_int, button, is_system) {
let event = case is_system {
False -> {
let player = case player_int {
1 -> Player1
_ -> Player2
}
PlayerButton(player:, button:)
}
True -> SystemButton(button)
}
dispatch(to_msg(event))
})
Nil
})
}