Accelerometer controls for mobile game

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
Accelerometer controls for mobile game
Simple
from 1 business day to 3 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1050
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Implementing Accelerometer Controls for Mobile Games

Phone tilt as gamepad — intuitive control for racing games, ball games, arcades. Developers often add it in a day. Then spend a week polishing: smoothing latency, fighting drift, tuning dead zones, calibration. Proper implementation requires understanding sensor fusion and where responsiveness is lost.

Why "Just Take Accelerometer" Doesn't Work

Raw accelerometer contains gravity. On level table: (x: 0, y: 0, z: -9.81) — not motion, it's gravity on Z. If person holds phone at 45° in game, gravity vector spreads across axes. Tilting left-right changes x, but also changes z. This confusion breaks control.

Correct source: Device Motion / Linear Acceleration — data already without gravity. But they have noise and slow gyro drift on long sessions.

Implementation on iOS (Unity + CoreMotion native plugin)

For native UIKit/SwiftUI games (SpriteKit, SceneKit):

let motionManager = CMMotionManager()
motionManager.deviceMotionUpdateInterval = 1.0 / 60.0

motionManager.startDeviceMotionUpdates(
    using: .xArbitraryZVertical, // no magnetometer — lower latency
    to: OperationQueue.main
) { [weak self] motion, _ in
    guard let motion = motion else { return }
    self?.applyTilt(
        pitch: Float(motion.attitude.pitch),
        roll: Float(motion.attitude.roll)
    )
}

xArbitraryZVertical doesn't require magnetometer, reducing latency ~5–10 ms and power consumption. For racing games, north direction irrelevant.

For Unity use Input.gyro + Input.acceleration via UnityEngine.InputSystem:

using UnityEngine.InputSystem;

void Update()
{
    var attitude = AttitudeSensor.current;
    if (attitude == null || !attitude.enabled) return;

    Quaternion deviceOrientation = attitude.attitude.ReadValue();
    // Compensate screen orientation
    Quaternion fixedOrientation = Quaternion.Euler(90, 0, 0) * deviceOrientation;
    float roll = fixedOrientation.eulerAngles.z;
    float pitch = fixedOrientation.eulerAngles.x;

    MovePlayer(roll, pitch);
}

AttitudeSensor — new Input System. Old Input.gyro.attitude works but deprecated.

Implementation on Android

private var baselineAttitude: FloatArray? = null
private val currentRotationMatrix = FloatArray(16)

// In SensorEventListener.onSensorChanged for TYPE_ROTATION_VECTOR:
val rotationMatrix = FloatArray(9)
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values)

val orientationAngles = FloatArray(3)
SensorManager.getOrientation(rotationMatrix, orientationAngles)

val pitch = orientationAngles[1] // forward/back tilt
val roll = orientationAngles[2]  // left/right tilt

// Apply to baseline (calibration)
val calibratedPitch = pitch - (baselineAttitude?.get(0) ?: 0f)
val calibratedRoll = roll - (baselineAttitude?.get(1) ?: 0f)

gameEngine.setTilt(calibratedPitch, calibratedRoll)

Smoothing: Low-Pass Filter

Raw data jitters — hands never perfectly still. Simple exponential filter:

struct LowPassFilter {
    var value: Float = 0
    let alpha: Float // 0.1 = strong smoothing, 0.8 = nearly raw data

    mutating func update(_ newValue: Float) -> Float {
        value = alpha * newValue + (1 - alpha) * value
        return value
    }
}

// alpha = 0.3 for racing game (balance between responsiveness and smoothness)
var rollFilter = LowPassFilter(alpha: 0.3)
let smoothRoll = rollFilter.update(rawRoll)

Tuning alpha — empirically. Rule: smaller alpha = smoother but more latency. For maze ball — 0.2, for racing — 0.3–0.4, for aiming shooter — 0.6–0.7.

Calibrating "Neutral" Position

Users hold phone differently: one at 30°, another at 60°. "Neutral" should be where phone starts, not strictly horizontal.

fun calibrate() {
    baselineAttitude = floatArrayOf(currentPitch, currentRoll)
}

Call on "Calibrate" button press or automatically 2 seconds after game start. Save baseline in SharedPreferences — no recalibration next launch.

Dead Zone and Nonlinear Sensitivity

Central dead zone ±5° — removes unintended movement while holding:

func applyDeadZone(_ value: Float, threshold: Float = 0.087) -> Float { // 5 degrees in radians
    guard abs(value) > threshold else { return 0 }
    let sign: Float = value > 0 ? 1 : -1
    return sign * (abs(value) - threshold)
}

Nonlinear sensitivity (power function): small tilts — slow movement, large — fast. Allows precise control and quick turns:

let normalizedRoll = clamp(calibratedRoll / maxAngle, -1, 1) // normalize to [-1, 1]
let curvedInput = sign(normalizedRoll) * pow(abs(normalizedRoll), 1.5)
playerSpeed = curvedInput * maxSpeed

Combining with Touch

Give users choice: accelerometer or virtual joystick. Part of audience doesn't like tilt — especially in transport. Both modes work without restart, switching via settings.

Timeline

Basic tilt control with calibration and filtering — 3–5 work days. With polishing for specific genre, nonlinear sensitivity, and device pool testing — 1–2 weeks.