Reading Raw Input

The most direct way to know what the player is doing is to ask the hardware every frame: is W held right now? did they just click? how far is the stick pushed? This is polling, and it lives in the CometEngine::Input namespace. It's perfect for prototypes, game jams, fixed control schemes and touch handling.

[!TIP] When you're ready for rebindable controls and first-class gamepad support, graduate to the Input Actions system — the same input, but bound to named actions you configure in the editor. This tutorial is the raw layer underneath it.

The three verbs: Down, Pressed, Up

For every button — keyboard, mouse or controller — there are three queries, and choosing the right one is most of the battle:

Query True when... Use it for
GetKeyDown(key) the first frame of the press (an edge) one-shot actions: jump, shoot, confirm, toggle
GetKeyPressed(key) every frame the key is held (a level) continuous actions: walking, charging, aiming
GetKeyUp(key) the frame it is released (an edge) release actions: release a charged shot
using namespace CometEngine;
using namespace CometEngine::Input;

class Player : CometBehaviour
{
    float speed = 5.0F;

    void Update()
    {
        // Continuous movement from held keys (level).
        Vector2 move(0, 0);
        if (Input::GetKeyPressed(KeyCode::W)) move.y += 1.0F;
        if (Input::GetKeyPressed(KeyCode::S)) move.y -= 1.0F;
        if (Input::GetKeyPressed(KeyCode::A)) move.x -= 1.0F;
        if (Input::GetKeyPressed(KeyCode::D)) move.x += 1.0F;

        // Fire once per press (edge).
        if (Input::GetKeyDown(KeyCode::SPACE))
        {
            Fire();
        }

        transform.Translate(move * speed * Time::GetDeltaTime(), Space::World);
    }

    void Fire() { }
}

KeyCode covers the whole keyboard: letters (AZ), digits, SPACE, RETURN, ESCAPE, the arrows (UP/DOWN/LEFT/RIGHT), function keys (F1F12) and modifiers (SHIFT_LEFT, CONTROL_LEFT, ...).

Mouse

using namespace CometEngine;
using namespace CometEngine::Input;

Vector2 mousePos = Input::GetMousePosition();     // screen space, (0,0) top-left
Vector2 delta = Input::GetMouseMotion();          // movement since last frame
float wheel = Input::GetMouseScrollMotion();      // scroll delta

if (Input::GetMouseButtonDown(MouseCode::LEFT))   { /* click */ }
if (Input::GetMouseButtonPressed(MouseCode::RIGHT)) { /* hold to aim */ }

MouseCode is LEFT, MIDDLE, RIGHT, BUTTON_4, BUTTON_5. Mouse position is in screen space — to convert it to world space, go through your camera.

Controllers

Comet supports up to eight controllers. Pass a ControllerNumber to target a specific one, or CONTROLLER_ANY for the first connected:

using namespace CometEngine;
using namespace CometEngine::Input;

// Analog stick — a Vector2 in the range -1..+1 on each axis.
Vector2 leftStick = Input::GetControllerAxisValue(ControllerAxis::LEFT, ControllerNumber::CONTROLLER_1);
float rightTrigger = Input::GetControllerTriggerValue(ControllerTrigger::RIGHT, ControllerNumber::CONTROLLER_1);

// Buttons — same Down / Pressed / Up trio as the keyboard.
if (Input::GetControllerButtonDown(ControllerCode::A, ControllerNumber::CONTROLLER_1))
{
    Jump();
    Input::MakeControllerRumble(0.6F, 0.2F);   // strength 0..1, duration in seconds
}

// Discover what's plugged in at runtime.
array<ControllerNumber> pads = Input::GetControllersConnected();

ControllerCode names the face buttons (A/B/X/Y), the D-pad (DPAD_UP...), shoulders, stick clicks and analog-stick directions as virtual buttons (LEFT_AXIS_UP...). MakeControllerRumble and PlayHapticPreset drive vibration. GetActiveInputDevice() tells you whether the player is currently on keyboard-and-mouse or a gamepad, so you can swap on-screen button prompts to match.

Touch

Touch is multi-touch aware: each finger is a Touch with a stable id you can follow across frames, plus position, motion and a state (STARTED / MOVED / ENDED):

using namespace CometEngine;
using namespace CometEngine::Input;

uint64 touchCount = Input::GetTouchCount();
for (uint64 i = 0; i < touchCount; i++)
{
    Touch touch = Input::GetTouchByIndex(i);
    if (touch.state == TouchState::ENDED) continue;

    // touch.id follows this finger; touch.position is screen space.
    Debug::Log("finger " + touch.id + " at " + touch.position.ToString());
}

This is how the sample project's mobile controller builds a virtual joystick — it claims the first finger that lands on the left half of the screen (tracking it by id) and reads its offset from the touch-down point each frame. Input::IsPinching() and Input::GetPinchZoom() give you two-finger pinch for zoom.

Reading a whole character controller

Putting the verbs together — keyboard and gamepad, movement and a one-shot fire, exactly as the sample project's Player script does it:

using namespace CometEngine;
using namespace CometEngine::Input;

class Player : CometBehaviour
{
    float speed = 6.0F;

    void Update()
    {
        // Movement: keyboard OR left stick, whichever the player uses.
        Vector2 velocity = Input::GetControllerAxisValue(ControllerAxis::LEFT, ControllerNumber::CONTROLLER_1);
        if (Input::GetKeyPressed(KeyCode::W)) velocity.y += 1.0F;
        if (Input::GetKeyPressed(KeyCode::S)) velocity.y -= 1.0F;
        if (Input::GetKeyPressed(KeyCode::A)) velocity.x -= 1.0F;
        if (Input::GetKeyPressed(KeyCode::D)) velocity.x += 1.0F;

        // Fire: space OR the A button, once per press.
        if (Input::GetKeyDown(KeyCode::SPACE) ||
            Input::GetControllerButtonDown(ControllerCode::A, ControllerNumber::CONTROLLER_1))
        {
            Fire();
        }

        transform.Translate(velocity * speed * Time::GetDeltaTime(), Space::World);
    }

    void Fire() { }
}

[!WARNING] Notice this reads two hard-coded keys for every action, and there's no way for the player to rebind them or for a designer to tune deadzones. That's fine for a jam — but the moment you want remappable controls, "hold to charge", or clean multi-device support, it's time for Input Actions.

Where to go next

Turn these reads into movement with Physics, or step up to rebindable, designer-friendly controls with Input Actions.