Реализация управления акселерометром для мобильной игры

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Реализация управления акселерометром для мобильной игры
Простая
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

Реализация управления акселерометром для мобильной игры

Наклон телефона как геймпад — интуитивный способ управления для гоночных игр, игр-шариков, аркад. Разработчики часто добавляют его за день. Потом неделю полируют: сглаживают задержку, борются с дрейфом, настраивают мёртвую зону, делают калибровку. Правильная реализация требует понимания того, как работает sensor fusion и где теряется отзывчивость.

Почему «просто взять акселерометр» не работает

Сырой акселерометр содержит гравитацию. На ровном столе: (x: 0, y: 0, z: -9.81) — это не движение, это гравитация по Z. Если человек держит телефон под углом 45° в игре, вектор гравитации размазывается по осям. При наклоне влево-вправо меняется x, но меняется и z. Это путаница, которая ломает управление.

Правильный источник: Device Motion / Linear Acceleration — данные уже без гравитации. Но они же имеют шум и медленный дрейф гироскопа при длительной сессии.

Реализация на iOS (Unity + CoreMotion native plugin)

Для нативных UIKit/SwiftUI-игр (SpriteKit, SceneKit):

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

motionManager.startDeviceMotionUpdates(
    using: .xArbitraryZVertical, // без магнитометра — меньше задержка
    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 не требует магнитометр, что снижает задержку на ~5–10 мс и потребление. Для гоночных игр направление север неважно.

Для Unity используем Input.gyro + Input.acceleration через UnityEngine.InputSystem:

using UnityEngine.InputSystem;

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

    Quaternion deviceOrientation = attitude.attitude.ReadValue();
    // Компенсируем ориентацию экрана
    Quaternion fixedOrientation = Quaternion.Euler(90, 0, 0) * deviceOrientation;
    float roll = fixedOrientation.eulerAngles.z;
    float pitch = fixedOrientation.eulerAngles.x;

    MovePlayer(roll, pitch);
}

AttitudeSensor — новый Input System. Старый Input.gyro.attitude работает, но deprecated.

Реализация на Android

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

// В SensorEventListener.onSensorChanged для TYPE_ROTATION_VECTOR:
val rotationMatrix = FloatArray(9)
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values)

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

val pitch = orientationAngles[1] // наклон вперёд/назад
val roll = orientationAngles[2]  // наклон влево/вправо

// Применяем к baseline (калибровка)
val calibratedPitch = pitch - (baselineAttitude?.get(0) ?: 0f)
val calibratedRoll = roll - (baselineAttitude?.get(1) ?: 0f)

gameEngine.setTilt(calibratedPitch, calibratedRoll)

Сглаживание: low-pass фильтр

Сырые данные дёргаются — руки не бывают абсолютно неподвижными. Простой экспоненциальный фильтр:

struct LowPassFilter {
    var value: Float = 0
    let alpha: Float // 0.1 = сильное сглаживание, 0.8 = почти сырые данные

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

// alpha = 0.3 для гоночной игры (баланс между отзывчивостью и плавностью)
var rollFilter = LowPassFilter(alpha: 0.3)
let smoothRoll = rollFilter.update(rawRoll)

Подбор alpha — эмпирически. Правило: чем меньше alpha, тем плавнее, но больше задержка. Для шарика-лабиринта — 0.2, для гонки — 0.3–0.4, для шутера с прицеливанием — 0.6–0.7.

Калибровка «нейтральной» позиции

Пользователи держат телефон по-разному: один под 30°, другой под 60°. «Нейтраль» должна быть там, где телефон при старте, а не строго горизонтально.

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

Вызываем при нажатии кнопки «Калибровать» или автоматически через 2 секунды после запуска игры. Сохраняем baseline в SharedPreferences — чтобы при следующем запуске не перекалибровывать.

Мёртвая зона и нелинейная чувствительность

Центральная мёртвая зона ±5° — убирает непреднамеренное движение при удержании:

func applyDeadZone(_ value: Float, threshold: Float = 0.087) -> Float { // 5 градусов в радианах
    guard abs(value) > threshold else { return 0 }
    let sign: Float = value > 0 ? 1 : -1
    return sign * (abs(value) - threshold)
}

Нелинейная чувствительность (степенная функция): малые наклоны — медленное движение, большие — быстрое. Позволяет точно управлять и резко поворачивать:

let normalizedRoll = clamp(calibratedRoll / maxAngle, -1, 1) // нормализуем к [-1, 1]
let curvedInput = sign(normalizedRoll) * pow(abs(normalizedRoll), 1.5)
playerSpeed = curvedInput * maxSpeed

Комбинирование с тачем

Дать пользователю выбор: акселерометр или виртуальный джойстик. Часть аудитории принципиально не любит наклон — особенно в транспорте. Оба режима должны работать без перезапуска, переключение через настройки.

Сроки

Базовое управление наклоном с калибровкой и фильтрацией — 3–5 рабочих дней. С полировкой под конкретный жанр, нелинейной чувствительностью и тестированием на парке устройств — 1–2 недели.