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

注意


最新のgameCanvasとunityの組み合わせでは、
androidでビルドできない不具合が出ています。
(どうしても試したい、という方はandroidの古いsdkを自前でインストールする必要があるようです)

地図が表示されなくなってしまっています。
課題2(地図の表示)は飛ばしてください。
課題3は、数値を頼りに開始地点の周りを回るアプリになります。

注意


googleApiが有償化された為、クレカの登録などをしないと 地図が表示されなくなってしまっています。
課題2(地図の表示)は飛ばしてください。
課題3は、数値を頼りに開始地点の周りを回るアプリになります。

GameCanvasについて

・GameCanvasの機能:今週使う変数、メソッド

    ・(bool)gc.HasGeolocationPermission
   ・GPSが使えるかどうか
  ・gc.StartGeolocationService();
   ・GPSの緯度経度取得を開始する
  ・gc.StopGeolocationService();
   ・GPSの緯度経度取得を終了する
  ・(bool)gc.HasGeolocationUpdate
   ・GPSの値を取得できたかどうか
  ・(float)gc.GeolocationLastLatitude;
   ・GPSで取得できた緯度
  ・(float)gc.GeolocationLastLongitude;
   ・GPSで取得できた経度

課題

(1)GPSを使って、緯度経度を表示してみましょう。 (2)付近の地図を表示してみましょう。 (3)開始地点の周囲を回るアプリを作ってみましょう。 (4)その他、プログラムを改良したり、学んだ技術を駆使して、何か面白いことをやってみましょう。
作ったC#のプログラムを添付してください。
(プロジェクトを保存したフォルダのasset以下にあると思います。
コメント欄には、どこまでやったかと、(3)のハイスコアを書いてください。


課題の進め方

前回、apkが作れなかった人、xcodeを用いてうまく実機で動かせなかったmax&iOSユーザーは、前回の課題の問題解決から始めましょう。
「課題の進め方」
※今回は第8回なので、フォルダはk08に改名してください。
サンプルの起動を確認し、スクリプトが編集できる状態になったら、
続きを読み進めてください。

課題1をやってみましょう

  1. プログラムを編集

    (クラスに入った直後)に変数の宣言を足す

    
        float lat; 
        float lng; 
        string text; 
        bool isStartGPS = false;
    
    

    (InitGame()の中)に初期化処理を足す

    
            gc.SetResolution(720, 1280);        
            lat = 35.685410f; 
            lng = 139.752842f; 
            text = "取得中"; 
    
    

    (UpdateGame()の中)に下記の行を足す

    
    
            if(!isStartGPS){       
                gc.StartGeolocationService(); 
                isStartGPS = true;
            }
    
            if(!gc.HasGeolocationPermission){ 
                text = "位置情報サービスが無効です"; 
            } 
    
            if(gc.HasGeolocationUpdate){ 
                lat = gc.GeolocationLastLatitude; 
                lng = gc.GeolocationLastLongitude; 
                text = string.Format("緯度: {0}\n経度: {1}", lat, lng); 
            } 
    
    

    DrawGame()の中(ClearScreenの後)に下記の行を記載

    
            gc.ClearScreen(); 
            gc.SetColor(0,0,0);    
            gc.DrawString(text, 0, 0); 
    
    
  2. セーブして実行してみましょう。
  3. PCではGPSを使用できず、無効ですと表示されます。
  4. uapkを作って実機に入れて実行したり、 xcodeでビルドしてiOS端末で動かしたもしてみましょう。
  5. (UniteRemoteではGPSの値は取れません)
  6. lat,lngが表示されれば課題は成功です。

課題2のヒント

※googleApiが有償化された為、クレカの登録などをしないと
地図が表示されなくなってしまっています。
課題2(地図の表示)は飛ばして、課題3に進んでください。
※登録した場合も、送信情報にapikeyの追加が必要です。
また、下記の地図サイトもうまくくみこめば地図情報の表示が可能です。
http://cyberjapandata.gsi.go.jp/xyz/std/1/0/0.png
http://cyberjapandata.gsi.go.jp/xyz/std/1/1/0.png
http://cyberjapandata.gsi.go.jp/xyz/std/1/0/1.png
http://cyberjapandata.gsi.go.jp/xyz/std/1/1/1.png
http://cyberjapandata.gsi.go.jp/xyz/std/17/116299/51744.png
http://cyberjapandata.gsi.go.jp/xyz/std/18/232599/103488.png

gpsでデータを取得できたら地図を表示してみましょう。 下記を追加します。
//変数宣言
         string url; 

//初期化処理
             var w = gc.CanvasWidth / 2; 
             var h = gc.CanvasHeight / 2; 
             url = string.Format("https://maps.googleapis.com/maps/api/staticmap?center={0},{1}&zoom=15&format=png&sensor=false&size={2}x{3}&scale=2&maptype=roadmap&markers={0},{1}", lat, lng, w, h); 

//緯度経度を取得した後
              var w = gc.CanvasWidth / 2; 
              var h = gc.CanvasHeight / 2; 
              url = string.Format("http://maps.googleapis.com/maps/api/staticmap?center={0},{1}&zoom=15&format=png&sensor=false&size={2}x{3}&scale=2&maptype=roadmap&markers={0},{1}", lat, lng, w, h); 

//描画部分
//DrawStringの前に足しましょう
             gc.DrawOnlineImage(url, 0, 0); 

課題3のヒント

下記を適宜配置したりなどしてみましょう。 (座標は640x480用なので必要に応じて変更してください) (oxの上下左右が入れ替わってますので、mapと一致させたい場合は修正しましょう)
//用意する変数
  int gameState = 0;
  float base_lat=0,base_lng=0;
  float player_lat=0,player_lng=0;
  const int CHECK_NUM = 9;
  int [] check_dx = new int[CHECK_NUM] ;
  int [] check_dy = new int[CHECK_NUM] ;
  bool [] isCheck = new bool[CHECK_NUM];
  bool isComplete;
  float calcRate = 0.001f;
  int playcount ;

//初期化用メソッド
//プログラム末尾、クラスが終わる}の前に追加します。
//また、追加したメソッドをInitGame()から呼んであげましょう
void resetValue(){
  for(int i=0;i < CHECK_NUM;i++){
    isCheck[i]= false;
    check_dx[i] = (i%3) -1;
    check_dy[i] = (i/3) -1;
  }
  isComplete = false;
  playcount = 0;
}

//UpdateGame,DrawGameの構成
if(gameState == 0){
  //タイトル画面の処理
}
else if(gameState == 1){
  //ゲーム中の処理
}
else if(gameState == 2){
  //ゲームクリアー時の処理
}


//処理の例(ゲーム前)
if(gc.GetPointerFrameCount(0)==1){
  gameState = 1;
  base_lat = lat;
  base_lng = lng;
  resetValue();
}

//処理の例(ゲーム中)
playcount++;

player_lat = lat - base_lat;
player_lng = lng - base_lng;

//今いる場所をtrueに
for (int i = 0; i < CHECK_NUM; i++) {
		    float check_lat = check_dx[i] * calcRate;
		    float check_lng = check_dy[i] * calcRate;

		    if( 
player_lat - check_lat > -calcRate/2 && 
player_lat - check_lat <  calcRate/2 &&
player_lng - check_lng > -calcRate/2 &&
player_lng - check_lng <  calcRate/2
  ){
   isCheck [i] = true;
  }
}

//全部通ったかの判定
isComplete = true;
for (int i = 0; i < CHECK_NUM; i++) {
  if (!isCheck [i]) {
    isComplete = false;
  }
}
if (isComplete) {
  gameState = 2;
}

//描画の例(ゲーム前)
gc.DrawString("TAP TO START!",320, 60);

//描画の例(ゲーム中)
gc.DrawString("PLAYING",320, 60);
gc.DrawString ("SCORE"+playcount,320, 90);
gc.DrawString ("lat:" + player_lat/calcRate,320, 120);
gc.DrawString ("lng:" + player_lng/calcRate,320, 150);

for( int i = 0;i < CHECK_NUM; i++){
  if(isCheck[i]){
   gc.DrawString("o",400+check_dx[i]*30,250+check_dy[i]*30 );
  }
  else {
   gc.DrawString("x",400+check_dx[i]*30,250+check_dy[i]*30 );
  }
}

//描画の例(ゲーム後)
gc.DrawString("CLEAR!!",320, 60 );
gc.DrawString ("SCORE:"+playcount,320, 90);


課題4のヒント

より良くする案を考えてみましょう。

補足

通信メソッド

 gameCanvasではwebsocketを使用した通信もできるようになっています。
 ネットワークの知識がある方は、こちらも試してみると良いかもしれません。


よくある質問

GPSがうまく動かない

UnityRemoteでより安定して動くよう、課題1のテキストを更新しました。

UnityRemoteでは、iPhoneでもAndroidでも位置情報が取れるようになっているのではないかと思います。

(具体的には、startからではなくcalc内でGPSの初期化命令を呼ぶように変えています。)

なお、iOSのバージョンにもよりますが、iphoneの実機ビルドにて位置情報を取得できない不具合が確認されており、対応策を検討中です。

スクリプトを更新したのに、何も変わらない

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

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

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