The Clay GameController plugin provides a unified game input system that supports multiple input sources including keyboard, physical gamepads, and touchscreen controls. It’s designed with simplicity in mind, offering NES-style controller functionality with directional controls and two action buttons.

Getting Started

To use the Clay GameController plugin in your QML files:

import Clayground.GameController

Core Components

  • GameController - Main unified input component with axis and button states
  • GameControllerDV - Debug visualization showing current controller state
  • KeyboardGamepad - Internal keyboard-to-controller mapping
  • TouchscreenGamepad - Virtual on-screen gamepad for touch devices
  • GamepadWrapper - Qt Gamepad API wrapper (currently disabled in Qt6)

Usage Examples

Basic Controller Setup

import QtQuick
import Clayground.GameController

Item {
    GameController {
        id: controller

        // Enable debug visualization
        showDebugOverlay: true

        Component.onCompleted: {
            // Try gamepad first, fallback to keyboard
            if (numConnectedGamepads > 0)
                selectGamepad(0, true)  // Use analog sticks
            else
                selectKeyboard(
                    Qt.Key_W,      // Up
                    Qt.Key_S,      // Down
                    Qt.Key_A,      // Left
                    Qt.Key_D,      // Right
                    Qt.Key_Space,  // Button A
                    Qt.Key_Return  // Button B
                )
        }
    }
}

Player Movement

Rectangle {
    id: player
    width: 50
    height: 50
    color: "blue"

    GameController {
        id: controller
        anchors.fill: parent
    }

    // Move player based on controller input
    x: x + controller.axisX * 5
    y: y - controller.axisY * 5  // Invert Y for screen coordinates

    // Change color when buttons pressed
    color: controller.buttonAPressed ? "red" :
           controller.buttonBPressed ? "green" : "blue"
}

Multi-Controller Support

Row {
    GameController {
        id: player1Controller
        Component.onCompleted: {
            if (numConnectedGamepads > 0)
                selectGamepad(0, false)  // Use D-pad
            else
                selectKeyboard(
                    Qt.Key_Up, Qt.Key_Down,
                    Qt.Key_Left, Qt.Key_Right,
                    Qt.Key_M, Qt.Key_N
                )
        }
    }

    GameController {
        id: player2Controller
        Component.onCompleted: {
            if (numConnectedGamepads > 1)
                selectGamepad(1, false)
            else
                selectTouchscreenGamepad()
        }
    }
}

Touch Controls for Mobile

GameController {
    id: mobileController
    anchors.fill: parent

    Component.onCompleted: {
        // Auto-select input based on platform
        if (Qt.platform.os === "android" || Qt.platform.os === "ios") {
            selectTouchscreenGamepad()
        } else {
            selectKeyboard(
                Qt.Key_Up, Qt.Key_Down,
                Qt.Key_Left, Qt.Key_Right,
                Qt.Key_X, Qt.Key_Z
            )
        }
    }
}

Custom Input Handling

GameController {
    id: controller

    // React to input changes
    onAxisXChanged: {
        if (axisX > 0.5)
            console.log("Moving right")
        else if (axisX < -0.5)
            console.log("Moving left")
    }

    onButtonAPressedChanged: {
        if (buttonAPressed)
            console.log("Jump!")
    }
}

Best Practices

  1. Input Priority: Always check for gamepads first, then fall back to keyboard or touch controls.

  2. Dead Zones: The gamepad implementation includes a 0.2 dead zone for analog sticks to prevent drift.

  3. Platform Detection: Use Qt.platform.os to automatically select appropriate input methods.

  4. Key Forwarding: Use Keys.forwardTo to ensure the controller receives keyboard input.

  5. Debug Mode: Enable showDebugOverlay during development to visualize input states.

Technical Implementation

The GameController plugin implements:

  • Unified API: Single interface for all input types
  • Auto-switching: Seamless switching between input sources
  • Visual Feedback: Built-in debug visualization
  • Touch Adaptation: Virtual joystick with visual feedback for touch screens
  • Simple Design: NES-inspired two-button controller for broad compatibility

Note: Physical gamepad support is currently disabled due to Qt6 compatibility issues but the architecture supports it for future versions.