DiamondGamepad.cs
using System;
using Sandbox;
namespace Diamonds;
/// <summary>
/// Reads both controller sticks as four digital directions. D-pad and face buttons are bound in Input.config;
/// s&box has no gamepad codes for stick directions, so they are thresholded here.
/// </summary>
public static class DiamondGamepad
{
// Hysteresis stops a stick resting near the threshold from chattering between held and released.
const float PressThreshold = 0.5f;
const float ReleaseThreshold = 0.35f;
static bool leftHeld, rightHeld, upHeld, downHeld;
static bool upPressed, downPressed;
public static bool Left => leftHeld;
public static bool Right => rightHeld;
public static bool Up => upHeld;
public static bool Down => downHeld;
/// <summary>A stick was pushed up/down this frame, for stepping menu selections.</summary>
public static bool UpPressed => upPressed;
public static bool DownPressed => downPressed;
/// <summary>Sample the first controller's sticks once per frame.</summary>
public static void Update()
{
float x, y;
// Outside a controller scope, GetAnalog reads zero until a controller button or positive axis marks the controller active.
using ( Input.PlayerScope( Input.PlayerIndex.Controller1 ) )
{
float leftX = Input.GetAnalog( InputAnalog.LeftStickX ), leftY = Input.GetAnalog( InputAnalog.LeftStickY );
float rightX = Input.GetAnalog( InputAnalog.RightStickX ), rightY = Input.GetAnalog( InputAnalog.RightStickY );
// Either stick can drive each direction; take whichever is pushed farther.
x = MathF.Abs( leftX ) >= MathF.Abs( rightX ) ? leftX : rightX;
y = MathF.Abs( leftY ) >= MathF.Abs( rightY ) ? leftY : rightY;
}
leftHeld = Latch( leftHeld, -x );
rightHeld = Latch( rightHeld, x );
// SDL stick Y is positive downward.
bool wasUp = upHeld, wasDown = downHeld;
upHeld = Latch( upHeld, -y );
downHeld = Latch( downHeld, y );
upPressed = upHeld && !wasUp;
downPressed = downHeld && !wasDown;
}
public static void Clear() => leftHeld = rightHeld = upHeld = downHeld = upPressed = downPressed = false;
static bool Latch( bool held, float amount ) => amount >= (held ? ReleaseThreshold : PressThreshold);
}