スマートデバイスプログラミング 第8回
gps機能を使ってみよう

k08snd.zip(効果音データ)

課題

(1)通信により、位置情報を取得して表示してみましょう。 (2)周辺のマップを表示してみましょう。 (3)gps以外のセンサーを使ってみましょう。 (4)音を鳴らしてみましょう。 (4)その他、プログラムを改良したり、学んだ技術を駆使して、何か面白いことをやってみましょう。
作ったC#のプログラムを添付してください。
(プロジェクトを保存したフォルダのasset以下にあると思います。
コメント欄には、どこまでやったかを書いてください。

  1. 新規プロジェクトを作る(「2D」プロジェクトを選びましょう)
  2. スクリプトを貼りつける、空のゲームオブジェクトを作りましょう(GameObject→Create Empty)
  3. 通信結果表示用のイメージを作りましょう(GameObject→UI→Text)
  4. 座標はx0,y0,サイズはw300,h300にしましょう
  5. 新規スクリプトを作成しましょう。名前はGameManagerで。
  6. スクリプトを編集しましょう。
    
    //3行目に追加
    using UnityEngine.UI;
    
    //class名が違っていたら上書き
    public class GameManager : MonoBehaviour {
    
    //クラス入ってすぐのところに
    public Text txtGps;
    
    //Start内を下記に
    void Start () {
      if (Input.location.isEnabledByUser){
        Input.location.Start();
      }
      else {
        txtGps.text = "No GPS";
      }
    }
    
    //Update内を下記に
    void Update () {
      if (Input.location.isEnabledByUser) {
        switch (Input.location.status) {
          case LocationServiceStatus.Failed: txtGps.text = "GPS Failed"; break;
          case LocationServiceStatus.Initializing: txtGps.text = "GPS Init"; break;
          case LocationServiceStatus.Running: txtGps.text = string.Format("lat: {0:f1}, lng: {1:f1}", Input.location.lastData.latitude, Input.location.lastData.longitude); break;
        }
      }
    }
    
  7. GameObjectにスクリプトをaddComponentして、変数txtGpsの欄には作ったTextをドラッグ&ドロップしましょう。
  8. 実行してみましょう。"No GPS"と表示されます。
  9. UnityRemoteでも結果は同様です。
  10. Android端末ではapkファイルを作るってインストール→実行すると、位置情報の取得が確認できます。
  1. 次に、前回の「通信結果を画像に入れる」プログラムを組み合わせて、googleMapの apiにアクセスして周辺の地図を表示してみましょう。
  2. まずは表示用のRaw Imageを作成しましょう。(GameObject→UI→Raw Image)
  3. 座標はx0,y20,サイズはw400,h300にしましょう
  4. テキストの場所を画像と被らないよう変更しましょう
  5. 座標はx0,y-160,サイズはw300,h60にしましょう
  6. スクリプトGameManagerを再度編集しましょう。変数名など変わるので、追加した部分は一旦消して書き直します。
    
    //3行目に追加
    using UnityEngine.UI;
    
    //class名が違っていたら上書き
    public class GameManager : MonoBehaviour {
    
    //クラス入ってすぐのところに
    public Text label;
    public RawImage img;
    
    private LocationService GPS;
    private float lat, lng;
    private WWW dlImage;
    
    //Start内を下記に
    void Start () {
      GPS = Input.location;
    
      if (GPS.isEnabledByUser)
      {
        // GPSの測位を開始する
        GPS.Start();
    
        // 5秒おきにGPS情報を取得する
        InvokeRepeating("GetLocation", 0, 5);
      }
      else
      {
        // GPSにアクセスできない
        label.text = "GPS不許可";
      }
    	
      // まずはダミー位置情報で読み込む
      lat = 35.686275f;
      lng = 139.752835f;
      StartCoroutine(GetMapImage());
    }
    
    //Update内は空にする
    void Update () {
    }
    
    //メソッド3個追加
    
    //アプリ終了時に呼ばれるメソッド
    void onDisable()
    {
      // アプリ終了時にGPSを停止する(電池節約)
      GPS.Stop();
    }
    
    //位置情報更新用のメソッド
    void GetLocation()
    {
      switch (GPS.status)
      {
        case LocationServiceStatus.Failed:
        // GPS取得失敗
        label.text = "取得失敗";
        CancelInvoke("GetLocation");
        break;
    
        case LocationServiceStatus.Initializing:
        // まだ準備中
        label.text = "取得中…";
        break;
    
        case LocationServiceStatus.Running:
        // GPS利用可能
        var data = GPS.lastData;
        if (lat != data.latitude || lng != data.longitude)
        {
          // 前回と位置が違うなら地図更新
          lat = data.latitude;
          lng = data.longitude;
          StartCoroutine(GetMapImage());
        }
        break;
      }
    }
    	
    //地図を取得するメソッド
    IEnumerator GetMapImage()
    {
      label.text = string.Format("緯度:{0:f6}\n経度:{1:f6}", lat, lng);
    
      // URLを生成
      var url = "http://maps.googleapis.com/maps/api/staticmap";
      url += string.Format("?center={0},{1}", lat, lng);
      url += "&zoom=14&size=400x300&scale=2&maptype=roadmap&sensor=true";
      url += string.Format("&markers={0},{1}", lat, lng);
      Debug.Log(url);
    
      // ダウンロード
      dlImage = new WWW(url);
      yield return dlImage;
    
      // 画像として読み込む
      img.texture = dlImage.texture;
    
      // 注意事項:Google Maps Static APIの頻度制限
      // 同一IPアドレスで、1分間に50回 or 1時間に1000回まで
    }
    
  7. 保存してUnityの画面に戻ります。
  8. 変数labelとimgを、TextとRawImageをドラッグ&ドロップしましょう。
  9. 実行すると、自分の周囲のMapが表示されます。
  10. iOS端末の人は、引き続きgps情報が得られないので、lat,lngを変えて色々試してみると良いでしょう。(初期値は皇居になっています)
  11. googleのapiにはアクセス制限があるので注意してください。
  1. その他のセンサー
  2. ジャイロセンサー、コンパスの情報取得を試してみます。
  3. UnityRemoteでは扱えませんので、飛ばしても構いません。
  4. テキストを2種類設定して、スクリプトを編集しましょう。
  5. (gpsのものに追加しても構いませんが、作り直した方が見やすいかも)
  6. 
    //3行目に追加
    using UnityEngine.UI;
    
    //class名が違っていたら上書き
    public class GameManager : MonoBehaviour {
    
    //クラス入ってすぐのところに
    public Text txtCompass;
    public Text txtGyro;
    
    //Start内を下記に
    void Start () {
      Input.compass.enabled = true;
      Input.gyro.enabled = true;
    
      if (!Input.compass.enabled)
        txtCompass.text = "No Compass";
      if (!SystemInfo.supportsGyroscope)
        txtGyro.text = "No Gyro";
    }
    
    //Update内を下記に
    void Update () {
      // 方位センサー
      if (Input.compass.enabled) {
        txtCompass.text = string.Format("{0:f2}deg", Input.compass.magneticHeading);
      }
    
      // ジャイロセンサー
      if (SystemInfo.supportsGyroscope && Input.gyro.enabled)
      {
        Vector3 gyro = Input.gyro.rotationRate;
        txtGyro.text = string.Format("X: {0:f1}, Y: {1:f1}, Z:{2:f1}", gyro.x, gyro.y, gyro.z);
      }
    }
    
  7. Textを2個作成して、表示が被らない用に座標をずらして、変数うtxtGyroとtxtCompass|にドラッグ&ドロップしてあげましょう。
  8. apkを作って実機にて起動すると、コンパスとジャイロセンサーの値が取れます。
  9. (センサーを積んでいない端末もありますし、アプリによるセンサーの使用が許可されていない場合もあります)
  1. サウンド
  2. k08snd.zipを解凍すると、snd0.wavとsnd1.wavが出てきます。
  3. 画像と同様にAsset以下にresフォルダを作ってドラッグ&ドロップしてみましょう。
  4. snd0,snd1がres上に生成されます。
  5. snd0をGameObjectにドラッグ&ドロップしてみましょう。AddComponentされます。
  6. GameObjectを選択してInspector窓をみると、AudioSourceが追加され、AudioSource内のAudioCilpの欄にsnd0が入っていることがわかります。
  7. 実行ボタンを押してみましょう。コツっと音が鳴ります。
  8. AudioSource内のLoopにチェックを入れて実行ボタンを押してみましょう。コツコツコツと音がループ再生されます。一度確認したらチェックは元に戻しましょう。
  9. AudioSource内のPlay On Awakeのチェックを外すと、実行時に音が鳴らなくなります。チェックを外しておきましょう。
  10. プログラムから鳴らしてみましょう。
  11. 
      //変数宣言のところに追加
      AudioSource audioSource
    
      //Start内に追加
      audioSource = gameObject.GetComponent<AudioSource>();
    
      //Update内に追加
      if (Input.GetMouseButtonDown (0)) {
        audioSource.Play();
      }
    
    
  12. 実行してみましょう。画面をクリックすると音が鳴るようになります。
  13. snd1を鳴らしたい場合は(音の切り替え)
  14. 
      //変数宣言のところに1行追加
      public AudioClip audioClip;
    
      //Update内にif文を追加
      if (Input.GetKeyDown(KeyCode.A)) {
        audioSource.clip = audioClip;
      } 
      if (Input.GetKeyDown(KeyCode.S)){
        audioSource.PlayOneShot( audioClip );
      }
      if(Input.GetKeyDown(KeyCode.D)){
        audioSource.Stop( );
      }
      if(Input.GetKeyDown(KeyCode.F)){
        audioSource.Pause( );
      }
      if(Input.GetKeyDown(KeyCode.G)){
        audioSource.UnPause( );
      }
    
  15. 保存するとGameObjcetのスクリプトのinspector窓に変数audioCilpが追加されますので、snd1をドラッグ&ドロップで入れてあげます。
  16. Aを押すと、次からsnd1が再生されるようになります。
  17. audioSource.PlayOneShot( audioClip );を呼ぶことで、clipを差し換えずに指定した音を1回だけ鳴らすこともできます。(Sを押した場合)
  18. 次にBGMを鳴らしてみましょう。マシン内でmp3ファイルを探すか、フリーのmp3ファイルをDLしてきましょう。
  19. 名前をbgm0.mp3に改名して、UnityのProject窓のres以下にドラッグ&ドロップします。
  20. wavファイルと同様、unity上で使えるようになります。
  21. BGMを鳴らすのに使う場合はloopをオンにしておくと良いでしょう。
  22. audioSource.Play();で再生、audioSource.Stop();で停止、audioSource.Pause();でポーズ、audioSource.UnPause();で途中から再生します。(左クリック、D,F,Gでそれぞれの命令を呼んでいます)

よくある質問

スクリプトを更新したのに、InspectorViewの変数が増えない

プログラムが間違っていてビルドエラーが出ている可能性が高いです。

エディタ上でbuildしてみましょう。

{}の対応が間違っていないか、全角スペースが入っているかなど、確認してみましょう

ビルドエラーが出ていないのに、スクリプトをobjectに追加できない

classの大文字と小文字が違っている可能性があります。

エディタのbuildエラーが出ませんが、Unityでは読み込めない、という状況が確認されています。

保存して再度開いたらブロックやボールが消えた

unityの仕様(不具合)かなと思います。

BG(背景画像)の描画優先度を下げることで解決します。

BGのInspectorViewでOrder in Layerを-1にしてください

(テキストの手順にも追記しておきました)