Android中如何知道手机是向上还是向下倾斜?

问题描述 投票:0回答:2

我正在制作一款游戏,我需要知道手机在横向时是向上倾斜(朝向天空)还是向下倾斜(朝向地面)。

我使用这个答案答案链接作为我的起点。但是当应用程序处于横向时,垂直于地面的手机给出值 0,向上或向下倾斜给出值 90。因此,我无法确定用户是否向上或向下倾斜手机。

如果有人想知道我是如何实现我的传感器的,那么他可以询问,但我认为这么多的背景足以理解这个问题。

android kotlin accelerometer android-sensors gyroscope
2个回答
0
投票

这就是我找到正确解决方案的方法。首先,我创建了一个与多个传感器一起使用的抽象类(从 Phillip Lanckner Youtube 学习)

 abstract class MeasurableSensor(protected  val sensorType : Int) {
        
            protected var onSensorValuesChanged : ((List<Float>) -> Unit)? = null
        
            abstract val doesSensorExist : Boolean
        
            abstract fun startListening()
            abstract fun stopListening()
        
            fun setOnSensorValuesChangedListener(listener : ((List<Float>) -> Unit)){
                onSensorValuesChanged = listener
            }
        }
  

  abstract class AndroidSensor(
        private val context : Context,
        private val sensorFeature : String,
        sensorType : Int
    ) : MeasurableSensor(sensorType) , SensorEventListener{
    
        override val doesSensorExist: Boolean
            get() = context.packageManager.hasSystemFeature(sensorFeature)
    
        private lateinit var sensorManager: SensorManager
        private var sensor : Sensor? = null
    
        override fun startListening() {
            if(!doesSensorExist) return
    
            if(!::sensorManager.isInitialized && sensor == null){
                sensorManager = context.getSystemService(SensorManager :: class.java) as SensorManager
                sensor = sensorManager.getDefaultSensor(sensorType)
            }
    
            sensor?.let {
                sensorManager.registerListener(this , it , SensorManager.SENSOR_DELAY_NORMAL)
            }
        }
    
        override fun stopListening() {
            if(!doesSensorExist || !::sensorManager.isInitialized) return
            sensorManager.unregisterListener(this)
        }
    
    
        override fun onSensorChanged(event: SensorEvent?) {
            if(!doesSensorExist) return
    
            if (event?.sensor?.type == sensorType){
                onSensorValuesChanged?.invoke(event.values.toList())
            }
        }
    
        override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) = Unit
    }
    

这些是在 3D 平面中获得手机精确方向所需的两个传感器。

 class AccelerometerSensor(
        context: Context
    ) : AndroidSensor(
        context,
        PackageManager.FEATURE_SENSOR_ACCELEROMETER,
        Sensor.TYPE_ACCELEROMETER
    )
    class MagnetometerSensor(
        context: Context
    ) : AndroidSensor(
        context,
        PackageManager.FEATURE_SENSOR_ACCELEROMETER,
        Sensor.TYPE_MAGNETIC_FIELD
    )

在viewModel中实现

@HiltViewModel
class ViewModel @Inject constructor(
    private val accelerometerSensor : MeasurableSensor,
    private val magnetometerSensor : MagnetometerSensor,
) : ViewModel() {

  private val _orientation = MutableStateFlow(OrientationState.PERPENDICULAR)
    val orientation : StateFlow<OrientationState> get() = _orientation


    private val accelerometerReading = FloatArray(3)
    private val magnetometerReading = FloatArray(3)

    private val rotationMatrix = FloatArray(9)
    private val orientationAngles = FloatArray(3)

    fun startSensors(){
        accelerometerSensor.startListening()
        magnetometerSensor.startListening()
        initListeners()
    }

    fun stopSensors(){
        accelerometerSensor.stopListening()
        magnetometerSensor.stopListening()
    }

    private fun initListeners() {
        accelerometerSensor.setOnSensorValuesChangedListener { accelerometerReading ->
            this.accelerometerReading[0] = accelerometerReading[0]
            this.accelerometerReading[1] = accelerometerReading[1]
            this.accelerometerReading[2] = accelerometerReading[2]
            computeOrientation()
        }
        magnetometerSensor.setOnSensorValuesChangedListener { magnetometerReading ->
            this.magnetometerReading[0] = magnetometerReading[0]
            this.magnetometerReading[1] = magnetometerReading[1]
            this.magnetometerReading[2] = magnetometerReading[2]
        }
    }

    private fun computeOrientation() {
        SensorManager.getRotationMatrix(
            rotationMatrix,
            null,
            accelerometerReading,
            magnetometerReading
        )

        // "rotationMatrix" now has up-to-date information.

         SensorManager.getOrientation(rotationMatrix, orientationAngles)

        // "orientationAngles" now has up-to-date information.

        val (_ , _ , y) = orientationAngles

 // Values used here , are the ones needed by me , you may or may not need the same values 
        val orientationState = when (y.radToDegrees()) {
                in 226..314 -> OrientationState.PERPENDICULAR
                in 315..359, in 0..44 -> OrientationState.UPWARDS
                in 136..225 -> OrientationState.DOWNWARDS
                else -> OrientationState.PERPENDICULAR
        }

        viewModelScope.launch {
            _orientation.emit(orientationState)
        }
    }

将 rad 转换为度数的扩展函数

fun Float.radToDegrees() : Int {
        return (Math.toDegrees(this.toDouble()).toInt() + 360) % 360
    }

Phillip Lackner 视频可用于详细学习传感器管理,计算设备方向可在 android 文档

中进一步了解

-1
投票

更新:

一个简单的解决方案是使用加速度计来获取当前z轴的重力。

override fun onSensorChanged(event: SensorEvent) {
    if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
        // Check the orientation based on accelerometer data
        val x = event.values[0]
        val y = event.values[1]
        val z = event.values[2]

        // Assuming the device is facing up if the Z-axis is close to 9.81 (gravity)
        val isFacingUp = z > 9.0

        // Assuming the device is facing down if the Z-axis is close to -9.81 (gravity)
        val isFacingDown = z < -9.0

        if (isFacingUp) {
            println("I'm facing up!")
        } else if (isFacingDown) {
            println("I'm facing down!")
        } else {
            println("I'm facing another direction!")
        }
    }
}

旧答案:

如果您遵循 https://developer.android.com/guide/topics/sensors/sensors_position#sensors-pos-orient 中的 Google 示例,您应该获得足够的信息来获取设备的准确方向。

相关数据可以在rotationMatrix(或orientationAngles中的角度)变量中找到。

如果将手中的设备面朝下绕 y 轴旋转,则 x 和 z 轴矢量指向相反的方向。

显示朝上(四舍五入值)

rotationMatrix: [0, 1, 0, -1, 0, 0, 0, 0, 1]

显示朝下(四舍五入值)

rotationMatrix: [0, -1, 0, -1, 0, 0, 0, 0, -1]

这是一个很好的可视化方向的工具: https://ninja-calc.mbedded.ninja/calculators/mathematics/geometry/3d-rotations

© www.soinside.com 2019 - 2024. All rights reserved.