個人的なメモ

Tomohiro Suzuki @hiro128_777 のブログです。Microsoft MVP for Developer Technologies 2017- 本ブログと所属組織の公式見解は関係ございません。

Xamarin + Cocos Sharp で iOS, Android 対応のゲームを開発する手順 (8) Android で加速度センサーの値を取得する

今回は Android で加速度センサーの値を取得する方法です。

iOS のときの繰り返しになりますが、
Cocos Sharp でも CCAccelerometer で加速度センサーの値を取得できますが、
この方法だと、センサーの値が遅延して取得されるという不具合があるので、
ネイティブで取得したセンサーの値をグローバルで参照できるクラスに書込み、
その値を Cocos Sharp 側から参照する方法を採用しています。

CocosSharpGameSample.Core 側の準備は iOS 版で整っているので、
ネイティブ部分のみの実装です。

CocosSharpGameSample.Android プロジェクトの MainActivity.cs に、ISensorEventListener の継承を追加します。

f:id:hiro128:20160318153334p:plain

public class MainActivity : AndroidGameActivity, ISensorEventListener

MainActivity.cs のフィールドに、SensorManager を定義します。
また、センサーの値を書き込む際のロックキーを定義します。

// センサーマネージャ
private SensorManager sensorManager;
// ロックキー
private object accelerometerSyncLock = new object();

OnCreate メソッドに、センサーをセットアップする処理を追加します。

protected override void OnCreate(Bundle bundle)
{
	base.OnCreate(bundle);
	// センサーのセットアップ
	this.sensorManager = (SensorManager)GetSystemService(Context.SensorService);
	// ゲームを起動する。
	var application = new CCApplication();
	application.ApplicationDelegate = new SampleGameApplicationDelegate();
	SetContentView(application.AndroidContentView);
	application.StartGame();
}

センサーの精度が変更されたときにコールされる OnAccuracyChanged メソッド、
センサーの値が変更されたときにコールされる OnSensorChanged メソッドを実装し、
OnSensorChanged メソッドで加速度センサーの値を取得します。

// センサーの精度が変更されたときのハンドラ
public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
{
	// 何もしない
}

// センサーの値が変更されたときのハンドラ
public void OnSensorChanged(SensorEvent e)
{
	// 加速度センサーの値を取得
	lock (this.accelerometerSyncLock)
	{
		AccelerometerInfo.Default.AccelerationX = e.Values[0];
		AccelerometerInfo.Default.AccelerationY = e.Values[1];
		AccelerometerInfo.Default.AccelerationZ = e.Values[2];
	}
}

OnResume メソッドで加速度センサーのリスナーを登録し、監視対象にします。
SensorDelay は値取得の頻度です。
ゲームを作成するので SensorDelay.Game にしておきます。

protected override void OnResume()
{
	base.OnResume();
	this.sensorManager.RegisterListener(this, sensorManager.GetDefaultSensor(SensorType.Accelerometer), SensorDelay.Game);
}

protected override void OnPause()
{
	base.OnPause();
	this.sensorManager.UnregisterListener(this);
}

以上をまとめると MainActivity.cs は下記のようになります。

using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Hardware;
using Android.OS;
using CocosSharp;
using CocosSharpGameSample.Core;
using Microsoft.Xna.Framework;

namespace CocosSharpGameSample.Android
{
	[Activity(Label = "CocosSharpGameSample.Android"
		, MainLauncher = true
		, Icon = "@drawable/icon"
		, AlwaysRetainTaskState = true
		, LaunchMode = LaunchMode.SingleInstance
		, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden
	)]
	public class MainActivity : AndroidGameActivity, ISensorEventListener
	{
		// センサーマネージャ
		private SensorManager sensorManager;
		// ロックキー
		private object accelerometerSyncLock = new object();

		protected override void OnCreate(Bundle bundle)
		{
			base.OnCreate(bundle);
			// センサーのセットアップ
			this.sensorManager = (SensorManager)GetSystemService(Context.SensorService);
			// ゲームを起動する。
			var application = new CCApplication();
			application.ApplicationDelegate = new SampleGameApplicationDelegate();
			SetContentView(application.AndroidContentView);
			application.StartGame();
		}

		// 画面の向きを Landscape に固定
		public override ScreenOrientation RequestedOrientation
		{
			get
			{
				return ScreenOrientation.Landscape;
			}
			set
			{
				base.RequestedOrientation = ScreenOrientation.Landscape;
			}
		}

		// センサーの精度が変更されたときのハンドラ
		public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
		{
			// 何もしない
		}

		// センサーの値が変更されたときのハンドラ
		public void OnSensorChanged(SensorEvent e)
		{
			lock (this.accelerometerSyncLock)
			{
				AccelerometerInfo.Default.AccelerationX = e.Values[0];
				AccelerometerInfo.Default.AccelerationY = e.Values[1];
				AccelerometerInfo.Default.AccelerationZ = e.Values[2];
			}
		}

		protected override void OnResume()
		{
			base.OnResume();
			this.sensorManager.RegisterListener(this, sensorManager.GetDefaultSensor(SensorType.Accelerometer), SensorDelay.Game);
		}

		protected override void OnPause()
		{
			base.OnPause();
			this.sensorManager.UnregisterListener(this);
		}

	}
}

これで、ゲーム画面でセンサーの値が更新されるようになりました。

f:id:hiro128:20160318153346p:plain

今回はここまでです。