Cauldron2D.Input.Pad (Cauldron2D v0.2.2)

Copy Markdown View Source

Turns game-controller events into the set of actions a player is holding.

A game declares a padmap from action to controls, in the Xbox layout whatever the hardware, as Gamepad.Wire names them:

padmap = %{left: [:dpad_left, {:axis, :left_x, :neg}], fire: [:a, :right_bumper]}
pad = Cauldron2D.Input.Pad.new(padmap, deadzone: 0.3)

Feed it every {:controller, event} map with handle/2; held/1 is the set of actions held and strength/1 how hard each axis-driven one is pushed. Hand both to Cauldron2D.Input.merge/3.

A control is a button name (:a, :b, :x, :y, :left_bumper, :right_bumper, :back, :start, :guide, :left_stick, :right_stick, :dpad_up, :dpad_down, :dpad_left, :dpad_right) or {:axis, name, :neg | :pos} for one direction of :left_x, :left_y, :right_x, :right_y, :left_trigger or :right_trigger. Axis values run -1.0..1.0, up and left negative; a trigger runs 0.0..1.0.

A button holds its action in full. An axis holds it at its magnitude once past :deadzone. An action held by both is held in full. Every controller's controls count, and a controller that goes away releases what it held.

A stick may aim instead of holding actions: the padmap's :aim bound to {:stick, :left} or {:stick, :right} makes aim/1 the direction that stick is pushed in, {dx, dy} of length one (up and left negative), or nil inside the deadzone, measured radially; a client turns it into an aim point a fixed way from the focus, as an on-screen thumbstick does. :aim holds no action of its own, but the stick may push one: {:stick, :left, push: [action: :thrust, beyond: 0.6, least: 0.3, gain: 1.4]} holds :thrust while the stick is past beyond of its travel, at a strength that starts at least and grows by gain over the rest of the travel to 1.0 — the rule an on-screen thumbstick's push follows. Defaults: beyond: 0.5, least: 0.25, gain: 1.6.

Summary

Functions

Where the aim stick points: a direction of length one, or nil with no aim stick or inside the deadzone.

The stick bound to :aim, or nil.

Where axis stands now, -1.0..1.0 (0.0..1.0 for a trigger): the reading furthest from centre over every controller, or 0.0 while none is past the deadzone.

Whether the padmap binds either direction of axis to an action.

The padmap for actions that steers with the d-pad and the left stick.

Apply one controller event.

The actions held by any controller.

A pad reading padmap.

What the aim stick pushes when pushed far, or nil.

How hard each action held only through an axis is pushed, 0.0..1.0.

Types

control()

@type control() ::
  atom()
  | {:axis, atom(), :neg | :pos}
  | {:stick, :left | :right}
  | {:stick, :left | :right, [{:push, keyword()}]}

event()

@type event() :: %{:type => atom(), optional(atom()) => term()}

padmap()

@type padmap() :: %{required(Cauldron2D.Input.action()) => [control()]}

push()

@type push() :: %{
  action: Cauldron2D.Input.action(),
  beyond: float(),
  least: float(),
  gain: float()
}

t()

@type t() :: %Cauldron2D.Input.Pad{
  aim_stick: :left | :right | nil,
  axes: %{required({non_neg_integer(), atom()}) => float()},
  bindings: %{required(control()) => [Cauldron2D.Input.action()]},
  buttons: %{required({non_neg_integer(), atom()}) => true},
  deadzone: float(),
  push: push() | nil,
  sticks: %{required({non_neg_integer(), atom()}) => float()}
}

Functions

aim(pad)

@spec aim(t()) :: {float(), float()} | nil

Where the aim stick points: a direction of length one, or nil with no aim stick or inside the deadzone.

aim_stick(pad)

@spec aim_stick(t()) :: :left | :right | nil

The stick bound to :aim, or nil.

axis(pad, axis)

@spec axis(t(), atom()) :: float()

Where axis stands now, -1.0..1.0 (0.0..1.0 for a trigger): the reading furthest from centre over every controller, or 0.0 while none is past the deadzone.

binds_axis?(pad, axis)

@spec binds_axis?(t(), atom()) :: boolean()

Whether the padmap binds either direction of axis to an action.

default_map(actions)

@spec default_map([Cauldron2D.Input.action()]) :: padmap()

The padmap for actions that steers with the d-pad and the left stick.

Of the actions given, :left, :right, :up and :down are bound to the matching d-pad button and direction of the left stick; the rest are left unbound.

handle(pad, arg2)

@spec handle(t(), event()) :: t()

Apply one controller event.

held(pad)

@spec held(t()) :: MapSet.t(Cauldron2D.Input.action())

The actions held by any controller.

new(padmap, opts \\ [])

@spec new(padmap(), keyword()) :: t()

A pad reading padmap.

Options

  • :deadzone — the axis magnitude below which an axis holds nothing. Default 0.3

push(pad)

@spec push(t()) :: push() | nil

What the aim stick pushes when pushed far, or nil.

strength(pad)

@spec strength(t()) :: %{required(Cauldron2D.Input.action()) => float()}

How hard each action held only through an axis is pushed, 0.0..1.0.

An action a button holds is held in full and has no entry.