Sensors (Accelerometer)

Microsoft::Xna::Framework::Input — Accelerometer, AccelerometerState

Implementation status: The Accelerometer API is Partial — the class is declared and compiles on all platforms. The SDL3 sensor backend is structurally wired for Android. Runtime validation on physical Android hardware is still pending. On desktop platforms (Linux, Windows) and WebAssembly, sensors return a zero-vector.

Android hardware validation needed: The SDL3 sensor path for Android is structurally complete but has not yet been confirmed on real Android hardware. Treat accelerometer readings on Android as unvalidated until this notice is removed. If you test on Android hardware, please report results via the issue tracker.

Overview

XNA 4.0 introduced the Accelerometer class as part of its Windows Phone support, providing a straightforward polling API for tilt and shake detection. CNA maps this API onto the SDL3 sensor subsystem so that the same game code can run on Android without modification.

Like all XNA input classes, Accelerometer follows a polling model: call Accelerometer::GetState() once per frame, store the result in an AccelerometerState snapshot, and read the Acceleration vector from it. No callbacks or event subscriptions are required.

On platforms where the hardware sensor is absent (desktop Linux, desktop Windows), the API is still present and callable — it simply returns a zero-vector so that code that guards on Accelerometer::IsSupported degrades gracefully without needing preprocessor guards.

Accelerometer static class

Accelerometer is a static class with no instances. It exposes two members that cover all common use cases:

Member Type Description
GetState() AccelerometerState Returns a snapshot of the current accelerometer reading. Safe to call every frame.
IsSupported bool (static property) true on Android; false on desktop (Linux/Windows) and WebAssembly.

AccelerometerState members

AccelerometerState is a value type (struct) returned by GetState(). It carries two fields:

Member Type Description
Acceleration Vector3 Current acceleration in G-forces. See axis breakdown below.
IsActive bool true when the sensor is running and returning live data; false on unsupported platforms.

Acceleration axis conventions

The Acceleration vector uses the same coordinate conventions as XNA 4.0 on Windows Phone, measured in G-forces (1 G ≈ 9.81 m/s²):

Component Physical meaning Typical value (device flat)
Acceleration.X Left/right tilt — positive toward the right edge of the device 0.0
Acceleration.Y Forward/back tilt — positive toward the top edge of the device 0.0
Acceleration.Z Up/down (gravity component) — approximately 1.0 when the screen faces up and the device is stationary ~1.0

When the device is held upright (portrait orientation), gravity shifts from Z into the Y axis, so Acceleration.Y approaches −1.0 and Acceleration.Z approaches 0.0. A shake produces transient spikes across all three axes.

Platform support

Platform IsSupported Acceleration result Status
Android true Live sensor data via SDL3 Needs hardware validation
Linux (desktop) false Zero-vector (not applicable) Compiles, returns zero
Windows (desktop) false Zero-vector (not applicable) Compiles, returns zero
WebAssembly (Emscripten) false Zero-vector (browser security policy restricts sensor access) Compiles, returns zero

Code examples

Checking support before use

Always guard sensor use with Accelerometer::IsSupported so that your game degrades gracefully on desktop builds:

// In Game::Initialize() or your platform detection pass
if (Accelerometer::IsSupported) {
    // Sensor is available; enable tilt controls
    tiltControlsEnabled = true;
} else {
    // Fall back to keyboard/gamepad controls
    tiltControlsEnabled = false;
}

Reading the accelerometer each frame (tilt-to-move)

A typical tilt-to-move mechanic reads the state once in Update() and maps the X/Y axes directly to horizontal and vertical forces on a physics body or velocity vector:

// Declared in your Game class
AccelerometerState previousAccel;

// In Update(GameTime gameTime)
AccelerometerState currentAccel = Accelerometer::GetState();

if (currentAccel.IsActive) {
    // Map tilt to movement — dead-zone to filter hand tremor
    const float deadZone = 0.1f;

    float tiltX = currentAccel.Acceleration.X;
    float tiltY = currentAccel.Acceleration.Y;

    if (std::abs(tiltX) < deadZone) tiltX = 0.0f;
    if (std::abs(tiltY) < deadZone) tiltY = 0.0f;

    // Apply as velocity (scale to your game's units per second)
    float speed = 200.0f;
    playerVelocity.X = tiltX * speed;
    playerVelocity.Y = tiltY * speed;  // positive Y = forward on the device
}

previousAccel = currentAccel;

Shake detection

A shake produces a spike in the acceleration magnitude above the normal gravity baseline of ~1 G. Compare the length of the vector against a threshold:

AccelerometerState state = Accelerometer::GetState();

if (state.IsActive) {
    float magnitude = state.Acceleration.Length();
    const float shakeThreshold = 2.5f;  // 2.5 G — adjust per game feel

    if (magnitude > shakeThreshold) {
        // Player shook the device — trigger action
        OnShakeDetected();
    }
}

WebAssembly note

On the Emscripten (WebAssembly) target, browser security policies require an explicit user permission grant before JavaScript can expose DeviceMotionEvent data. CNA's SDL3 WebAssembly backend does not currently request this permission, so Accelerometer::IsSupported returns false and GetState() returns a zero-vector on all browsers. This is consistent with the XNA behaviour on platforms without sensor hardware.

Future sensors

SDL3 exposes additional sensor types beyond the accelerometer. The following sensors are planned for a future CNA release but are not yet wired up:

Sensor SDL3 support CNA status
Gyroscope Yes — SDL_SENSOR_GYRO Not yet wired
Compass Yes — SDL_SENSOR_MAGNETIC Not yet wired

The gyroscope reports angular velocity in radians per second around each axis, which enables more precise orientation tracking and complements the accelerometer for robust tilt controls. The compass provides a magnetic heading. Both will follow the same polling model as Accelerometer once implemented.