加速度センサーとは?
加速度センサーは「スマホが机に置かれているか」「手で持っているか」などの状態を検知するのに使われています。
他にもシェイク機能や歩数計、画面の向き(縦向き・横向き)に合わせた回転などでも使われるようです。
加速度センサーではXYZの「軸」の動きを取得できます。
ジャイロセンサー(角速度)とは別物です。
加速度センサーでボールを動かす
今回はシンプルに、加速度センサーを使ってボールを移動させてみます。
Unityのプロジェクトテンプレートには「3D Mobile」を選択し、動作確認はAndroidスマホを使用しています。
スマホの傾きに合わせてボールを移動させる
加速度センサーを使うには「Input.acceleration」を使用します。
動作確認のため、まずはUnityのマニュアルから持ってきたコードをそのまま試してみます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AccelerometerTest : MonoBehaviour
{
float speed = 10.0f;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = -Input.acceleration.y;
dir.z = Input.acceleration.x;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
transform.Translate(dir * speed);
}
}
ヒエラルキービューで「3D Object > Sphere」を追加し、スクリプトをアタッチします。
球が回転しているかどうか分かりやすくするためにボーダー柄のマテリアルをつけてみました。
ビルドして動かしてみると、動きはしましたが傾けた方向とボールの移動する方向が合っていませんでした。
【Unity】加速度センサーを使ってボール動かすテスト1 pic.twitter.com/2mZQAalYBK
— ばにら (@vaniiiirava) June 12, 2023
現状、縦持ち横持ちに関係なく以下のように動いています。
スマホを傾ける方向 | ボールの移動する方向 |
---|---|
右 | 奥 |
左 | 手前 |
手前 | 右 |
奥 | 左 |
このままだと操作しづらいので、スクリプトの以下の部分を修正します。
//dir.x = -Input.acceleration.y;
//dir.z = Input.acceleration.x;
dir.x = Input.acceleration.x;
dir.z = Input.acceleration.y;
Input.accelerationの値はスマホが水平な場所に置かれている状態を基準に、手前に傾けると(0,-1,0)、奥に傾けると(0,1,0)となるため、dir.zの値にInput.acceleration.yを使用するようにします。
また、右に傾けると(1,0,0)、左に傾けると(-1,0,0)だったので、dir.xはInput.acceleration.xを代入しています。
これでスマホの傾きとボールの移動方向が一致するようになりました。
壁と床を追加する
PlaneとCubeのオブジェクトを追加し、壁と床を配置します。
ボールには「Rigidbody」アタッチします。
ゲーム画面も横向きにして、カメラはステージを上から見下ろすような位置に変えました。
ビルドして動かすと、壁にぶつかってからの挙動がおかしくなってしまいました。
【Unity】加速度センサーを使ってボール動かすテスト2 pic.twitter.com/bgm3nkmYbV
— ばにら (@vaniiiirava) June 12, 2023
これではまともに遊べなくなってしまうので、スクリプトを修正します。
//transform.Translate(dir * speed);
transform.Translate(dir * speed, Space.World);
transform.Translateの引数を省略すると「Space.Self」が適用されます。
Selfの場合ローカルの軸が基準となるため、ボールの向きが変わると移動方向も変わり、挙動がおかしくなっていました。
「Space.World」を指定してワールド座標系を基準にすることで、壁にぶつかってボールの向きが変わっても移動方向はそのままになります。
ボールを回転させる
今のままでは壁に当たるまでボールは全く回転していない状態です。
せっかくなので、移動に合わせてボールが回転するようにしてみます。
Updateに以下の記述を追加します。
transform.Rotate(new Vector3(dir.z, 0, -dir.x) * angularSpeed, Space.World);
移動で使っているdirをそのまま使うと回転方向が合わなかったので場所を変更・反転しています。
最終的なスクリプト
完成したスクリプトがこちら。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AccelerometerTest : MonoBehaviour
{
float speed = 10.0f;
float angularSpeed = 360.0f;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = Input.acceleration.x;
dir.z = Input.acceleration.y;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
transform.Translate(dir * speed, Space.World);
transform.Rotate(new Vector3(dir.z, 0, -dir.x) * angularSpeed, Space.World);
}
}
動かしてみると、壁に当たってもどこかに飛んで行ったりせず、思った通りの動きをしてくれるようになりました。
【Unity】加速度センサーを使ってボール動かすテスト3 pic.twitter.com/eyjKc5AwpI
— ばにら (@vaniiiirava) June 12, 2023
さいごに
スコアアイテムや障害物などを追加していけば玉転がしゲームが作れます。
ジャイロセンサーでの実装についても紹介したかったのですが、使っているAndroidがまさかのジャイロ非搭載機種でした。
試していないので何とも言えませんが、公式ドキュメントを見た感じだとジャイロセンサーを使う方が加速度センサーよりも圧倒的に楽に実装できそうな気がします。
Macを買ってiOSのビルドが出来るようになるか、ジャイロ搭載のAndroidが手に入ったら、ジャイロセンサーでの実装も試してみたいです。
加速度センサーについては後述の参考サイトの解説が分かりやすいと思ったので、気になる方は読んでみてください。
コメント