MonoGame / MonoGame.Samples

A few cross-platform game samples using MonoGame.
www.monogame.net
Other
564 stars 300 forks source link

iOS > accelerometer.cs not implemented; default MG implementation laggy #25

Open gomski opened 10 years ago

gomski commented 10 years ago

The current implementation of the acceleroment.cs is only working on windows phones. I have used the default way of implementing accelerometer but doing it this way the accelero data becomes very laggy after a minute or so. I switched to th Xamarin implementation of the accelerometer and it was working fine on my iPad. Maybe it would be useful to implement the accelero abstraction for iOS in MG according to http://developer.xamarin.com/recipes/ios/input/accelerometer/use_coremotion_with_accelerometer/

gomski commented 10 years ago

region File Description

//----------------------------------------------------------------------------- // Accelerometer.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //-----------------------------------------------------------------------------

endregion

region Using Statements

using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using MonoTouch.CoreMotion; using MonoTouch.Foundation;

endregion

namespace Platformer2D { ///

/// A static encapsulation of accelerometer input to provide games with a polling-based
/// accelerometer system.
/// </summary>

public static class Accelerometer
{

if IPHONE

    private static CMMotionManager accelerometer = new CMMotionManager();

endif

if WINDOWS_PHONE

    // the accelerometer sensor on the device
    private static Microsoft.Devices.Sensors.Accelerometer accelerometer = new Microsoft.Devices.Sensors.Accelerometer();

endif

    // we need an object for locking because the ReadingChanged event is fired
    // on a different thread than our game
    private static object threadLock = new object();
    // we use this to keep the last known value from the accelerometer callback
    private static Vector3 nextValue = new Vector3();

    // we want to prevent the Accelerometer from being initialized twice.
    private static bool isInitialized = false;

    // whether or not the accelerometer is active
    private static bool isActive = false;

    /// <summary>
    /// Initializes the Accelerometer for the current game. This method can only be called once per game.
    /// </summary>
    public static void Initialize()
    {
        // make sure we don't initialize the Accelerometer twice
        if (isInitialized)
        {
            throw new InvalidOperationException("Initialize can only be called once");
        }

if IPHONE

        if (accelerometer.AccelerometerAvailable)
        {
            accelerometer.AccelerometerUpdateInterval = 1f/60;
            accelerometer.StartAccelerometerUpdates(NSOperationQueue.CurrentQueue, (data, error) =>
            {
                nextValue = new Vector3((float)data.Acceleration.X, (float)data.Acceleration.Y, (float)data.Acceleration.Z);
            });
            isActive = accelerometer.AccelerometerActive;
        }

endif

if WINDOWS_PHONE

        // try to start the sensor only on devices, catching the exception if it fails  
        if (Microsoft.Devices.Environment.DeviceType == Microsoft.Devices.DeviceType.Device)  
        {
            try
            {
                accelerometer.ReadingChanged += new EventHandler<Microsoft.Devices.Sensors.AccelerometerReadingEventArgs>(sensor_ReadingChanged);
                accelerometer.Start();
                isActive = true;
            }
            catch (Microsoft.Devices.Sensors.AccelerometerFailedException)
            {
                isActive = false;
            }
        }
        else
        {
            // we always return isActive on emulator because we use the arrow
            // keys for simulation which is always available.
            isActive = true;
        }

endif

        // remember that we are initialized
        isInitialized = true;
    }

if WINDOWS_PHONE

    private static void sensor_ReadingChanged(object sender, Microsoft.Devices.Sensors.AccelerometerReadingEventArgs e)
    {
        // store the accelerometer value in our variable to be used on the next Update
        lock (threadLock)
        {
            nextValue = new Vector3((float)e.X, (float)e.Y, (float)e.Z);
        }
    }

endif

    /// <summary>
    /// Gets the current state of the accelerometer.
    /// </summary>
    /// <returns>A new AccelerometerState with the current state of the accelerometer.</returns>
    public static AccelerometerState GetState()
    {
        // make sure we've initialized the Accelerometer before we try to get the state
        if (!isInitialized)
        {
            throw new InvalidOperationException("You must Initialize before you can call GetState");
        }

        // create a new value for our state
        Vector3 stateValue = new Vector3();

if IPHONE

        stateValue = nextValue;

endif

if WINDOWS_PHONE

        // if the accelerometer is active
        if (isActive)
        {
            if (Microsoft.Devices.Environment.DeviceType == Microsoft.Devices.DeviceType.Device)
            {
                // if we're on device, we'll just grab our latest reading from the accelerometer
                lock (threadLock)
                {
                    stateValue = nextValue;
                }
            }
            else
            {
                // if we're in the emulator, we'll generate a fake acceleration value using the arrow keys
                // press the pause/break key to toggle keyboard input for the emulator
                KeyboardState keyboardState = Keyboard.GetState();
                stateValue.Z = -1;

                if (keyboardState.IsKeyDown(Keys.Left))
                    stateValue.X--;
                if (keyboardState.IsKeyDown(Keys.Right))
                    stateValue.X++;
                if (keyboardState.IsKeyDown(Keys.Up))
                    stateValue.Y++;
                if (keyboardState.IsKeyDown(Keys.Down))
                    stateValue.Y--;

                stateValue.Normalize();
            }
        }

endif

        return new AccelerometerState(stateValue, isActive);
    }
}

/// <summary>
/// An encapsulation of the accelerometer's current state.
/// </summary>
public struct AccelerometerState
{
    /// <summary>
    /// Gets the accelerometer's current value in G-force.
    /// </summary>
    public Vector3 Acceleration { get; private set; }

    /// <summary>
    /// Gets whether or not the accelerometer is active and running.
    /// </summary>
    public bool IsActive { get; private set; }

    /// <summary>
    /// Initializes a new AccelerometerState.
    /// </summary>
    /// <param name="acceleration">The current acceleration (in G-force) of the accelerometer.</param>
    /// <param name="isActive">Whether or not the accelerometer is active.</param>
    public AccelerometerState(Vector3 acceleration, bool isActive)
        : this()
    {
        Acceleration = acceleration;
        IsActive = isActive;
    }

    /// <summary>
    /// Returns a string containing the values of the Acceleration and IsActive properties.
    /// </summary>
    /// <returns>A new string describing the state.</returns>
    public override string ToString()
    {
        return string.Format("Acceleration: {0}, IsActive: {1}", Acceleration, IsActive);
    }
}

}

SimonDarksideJ commented 10 years ago

This issue needs raising against the main MonoGame project, it's not a sample specific issue.

Can you please close this issue and re raise it on the MonoGame project GitHub

SimonDarksideJ commented 9 years ago

Any update @gomski did you create an issue in the main MG repo? if so can we close this issue?