これちのPost-it

技術ネタをペラペラと

剣を自在に振ってスライムを倒すHoloQuestを作ってみた【HoloLens+ARKit】

今回作ったもの

今回HoloQuestという、HoloLensとiPhoneを使った簡単なアクションゲームを作成しました。
HoloLensを通してiPhoneの位置にARの武器が表示され、その剣を使って敵モンスターを倒すゲームです。
youtu.be

動機

  1. 現実空間でスライムと戦ってみたかった(重要)
  2. HoloLens と ARKit を組み合わせればこんなものが作れるよというのを見せたかった・試したかった

使用した機材

  • HoloLens
    • HoloQuestが動作
      • iPhoneの位置に剣を表示
      • スライムの表示なども行う
  • iPhone6s(iOS11)
    • HoloControllerアプリが動作
      • ARKitを使い自身のpositionとrotationを取得
      • 自身のpositionとrotationをHoloLensに送信
    • コントローラーとして使用

開発環境

  • Unity 2017.1.1f1
    • HoloQuestとHoloClientの実装
  • Visual Studio 2017
    • HoloQuestアプリのビルドに使用

お借りした素材

実装

剣をiPhoneの位置に表示

どうやって剣をiPhoneの位置に追従させて表示させるかのイメージ図がこちら。
f:id:korechi:20171004104458p:plain
それではiPhone側で動作するHoloClientアプリと、HoloLens側で動作するHoloQuestの実装それぞれについて説明します。

HoloClient(iPhone側)の実装

iPhone側で動作するアプリは非常に単純で、必要とした機能は以下の2つです。
1. AR Kitを動作させ常に自身のpositionとrotationを取得
2. 自身のpositionとrotationをHoloLensに毎フレーム送信
この際には凹みさんのuOSCを使用させていただきました。
github.com
3. マーカーを画面に表示
自身の位置をHoloLensに知ってもらうために表示しています。マーカーは何でも良いです。
HoloLens側ではvuforiaというマーカー認識ソフトを使用します。

HoloQuest(HoloLens側)の実装

HoloLensとiPhoneはそれぞれが別のアプリが動作しており、どちらのアプリもアプリが起動した瞬間の自分(カメラ)の位置を(0, 0, 0)としてスタートします。
そのため、HoloLensから見てiPhoneがどこに存在するかの相対位置は分かりません。
そこで2通りの位置合わせ方法を今回使用しました。

①HoloControllerアプリをHoloLensの指定された位置で起動

手順は以下の通りです。
1. HoloQuestが起動した時にHoloLensの前に剣を表示
- 今回は(2,0,2)に表示
2. iPhoneをその剣に重ねた状態でHoloClientアプリを起動
- HoloLensからした(2,0,2)の位置がiPhoneにとっては(0,0,0)だと認識される
3. iPhoneから受信したpositionである(x,y,z)に(2,0,2)を足した場所に剣を表示し続ける
f:id:korechi:20171004113533p:plain

②vuforiaを使い、iPhone上に表示されたマーカーを認識して剣の位置を再調整

しかし、iPhoneを振り続けていると剣とiPhoneの位置がだんだんとずれていってしまいます。(原因はまだわかっていません)
そこでゲームのプレイ中に位置がずれたなーと思った時にiPhoneの位置を再調整するためにvuforiaというマーカー認識ソフトを使いました。
vuforiaの参考記事はこちら
vuforiaではマーカーを認識している間、マーカーのpositionとrotationを取得することができます。
その機能を利用し、剣がずれたなーと思った時にHoloLensの前にiPhoneを持ち上げマーカーを認識させるとiPhoneの位置が再度取得できます。
f:id:korechi:20171004114542p:plain

スライムとの戦闘

これは単純にスライムオブジェクトと剣オブジェクトにcolliderを設定し、OnCollisionEnter()で衝突を検知します。
f:id:korechi:20171004114902p:plain

OnCollisionEnter (Collider collider) {
    if (collider.gameObject.tag == “Army”) {
         this.hitPoint -= 1;
    }
}

気をつけたUI

プレイヤーは敵モンスターをどこから見るか分かりません。
後ろから見た時にモンスターの後ろ姿が見えるのは問題ないのですが、HPは常にプレイヤーの方向を向くように設定しました。

今回やらなかったこと

床・壁・天井に別テクスチャを貼る

床を芝生にしたり天井を空っぽく見せることでゲーム空間っぽい演出をしようかなーと思ったのですが今回はしませんでした。
参考記事
http://www.naturalsoftware.jp/entry/2016/06/14/110111www.naturalsoftware.jp
理由は2つあり、1つは処理が重くなる。もう1つは視野角が狭いため敵モンスターを見ていると周りの風景があまり見えないから。 ここらへんは改善の余地ありかもしれません。

最後に

HoloLens + ARKitでゲームを作ってみましたがとても相性が良かったように思えます。
両者ともセンサーを必要としないため、どんなに歩いても問題ありません。(非常にでかい) しかし、どうしても両者の相対位置はずれてきてしまいます。
実用面で考えるならば、新しいコードレスコントローラが発売されるか、vuforia以外のもっと良い位置合わせ方法が求められると思います。
HoloQuestを実際にリリースすることはありませんが、HoloLens + ARKitは面白い組み合わせですし、可能性があると思うので、みなさまも是非お試し下さい!

Hololensとスマートフォン間で通信を行う方法【uOSC】

はじめに

Hololensとスマートフォン(iPhoneAndroid)間でデータをやりとりする方法をまとめました。
具体的には、凹みさんの記事で紹介されていますUnity向けのOSC実装を使っています。
tips.hecomi.com
これがとても使いやすかったので、自分で使い方を忘れないためにも、記事に使い方をまとめておこうと思います。

前提

UnityでHololensアプリを作成し、Hololens実機でのビルドができること。

必要なもの

実装

今回、Hololensとスマートフォン間で通信を行うために、Hololens側とスマートフォン側の2つアプリを作る必要があります。

Hololens側

  1. 新規プロジェクトを作成しuOSC-v0.0.1.unitypackageHoloToolkit-Unity-v1.2017.1.0.unitypackageをインポート
    f:id:korechi:20170908164637p:plain:h200
  2. HoloToolKitタブにあるConfigureのApply*を全て行う
    f:id:korechi:20170909002517p:plain:h100
  3. uOSC Serverオブジェクトを作成し(名前は何でも良い)、uOscServer.csServerTest.csをuOSC Serverオブジェクトに追加
    場所は以下にあります。
    uOSC/Scripts/uOscServer.cs
    uOSC/Examples/Scripts/ServerTest.cs
    f:id:korechi:20170908165603p:plain
  4. File->BuildSettingでPlatformにてUniversalWindowsPlatformを選択
    今回はSDKを10.0.14393.0を選択します。
    f:id:korechi:20170908170907p:plain:h300
  5. Player Settingsから、Publishing SettingsのCapabilitiesのInternetClientとInternetClientServerにチェック
    環境認識も行いたい場合はSpatial Perceptionにチェックを入れます。忘れがちなので要注意です。
    f:id:korechi:20170908171154p:plain:h300
    また、開発マシンのセキュリティソフトやファイアーウォールを無効化しておかないと、データがHololensに届かない場合があります。
  6. Build
  7. 出力されたソリューションファイルをVisual Studio 2017で開き、Hololensを接続し以下の設定でビルド
    f:id:korechi:20170909000158p:plain
  8. おそらく、初回ビルドは失敗するので、project.lockファイルを開き、UAP,Version=v10.0.***の部分を全てUAP,Version=v10.0に書き換えます
  9. もう1度Visual Studioでビルドするとビルドが通ります
    f:id:korechi:20170909002955p:plain
    ログは右下の出力タブに出力されますので、そこを確認しましょう。

スマートフォン

こちらはずっと簡単です。
1. 新規プロジェクトを立ち上げ、uOSC-v0.0.1.unitypackageをインポート
2. uOSC Clientオブジェクトを作成し(名前は何でも良い)、uOscClient.csClientTest.csをuOSC Clientオブジェクトに追加
f:id:korechi:20170909004015p:plain:h200
場所は以下の場所にあります。
uOSC/Scripts/uOscClient.cs
uOSC/Examples/Scripts/ClientTest.cs
IPAddressや送信する内容は固定となっていますので、そこらへんを変えたい場合は上記2ファイルを修正(主にClientTest.cs)を変更しましょう。
3. AndroidもしくはiOS用にビルド

最後に

Hololensでのアプリ開発はまだ不安定な部分もあり、SDKのバージョンによっては動かなかったりします。そのため、今回ご紹介したバージョンでの開発をおすすめします。

追記

UnityのバージョンをUnity 2017.1.1f1にし、MixedRealityToolkit-Unity for Unity 2017.1.1f1を使用したところ、Hololens側の手順8,9が必要なくなりました。
1度目のビルドで無事Hololens上でアプリが起動したのを確認しました。

ARKit用サンプルアプリを作る2つの方法

はじめに

ARKit用サンプルアプリの作成する以下の2つの手順を紹介します。
1. Xcodeのみを使ってアプリを作成
2. Unityでアプリを作成し、Xcodeを使ってビルド

1はiOSのネイティブコードでARKitを直接利用する方法、2はUnity ARKit Pluginを使用してUnityでアプリを作成し、最後にXcodeを使ってビルドする方法です。
ARKitについては前回の記事で紹介したため、そちらも読んでください。
korechipostit.hatenablog.com
どちらを使うかは作りたいアプリによって使い分けると良いと思います。この記事では両方の方法でサンプルアプリを作る方法を紹介します。

Xcodeのみを使ってアプリを作成

まずはAppleの公式ドキュメントでも紹介されている、Xcodeのみを使ったサンプルアプリの作成方法について説明します。

アプリの実行結果

f:id:korechi:20170817233833g:plain
宙に飛行機オブジェクトが浮かんでいるのが確認できるアプリとなっています。

必要なもの

  • Xcode 9 beta ← ここからDL
  • iOS11がインストールされたデバイス(A9プロセッサ以降のもの)

アプリの作成

  1. Xcode-betaを起動し、Create a new Xcode projectを選択します。
    f:id:korechi:20170817000321p:plain:h300
  2. Augmented Reality Appを選択→Nextをクリック
    f:id:korechi:20170817000851p:plain:h250
  3. アプリの初期設定を行う
    f:id:korechi:20170817001251p:plain:h250
    • 任意の値を入れてください。
    • 「Product Name」と「Organization Identifier」から成る「Bundle Identifier」は、世界中のアプリの中から自身のアプリを識別するIDとなります。主に、ドメインを逆さまから並べたものをOrganization Identifierに設定することが推奨されています。
    • Content Technologyは、「Scene Kit」「Sprite Kit」「Metal」の3つから選べますが、今回はとりあえず「Scene Kit」を選択しました。

アプリのビルド

  1. ビルド対象のデバイスを自身のデバイスに設定
    f:id:korechi:20170817003200p:plain
    ここにある「Generic iOS Device」という箇所をクリックし、自身のデバイスを選択してください。
  2. ビルド

無事、宙に飛行機が浮かぶサンプルアプリがiPhone上で実行されるはずです。 コードの中身が気になる方は各自Xcodeを確認してください。

②Unityでアプリを作成し、Xcodeを使ってビルドする方法

こちらはUnityを使ってARKit用アプリを作成する方法を紹介します。
何となくこっちの方がTangoでの開発に近い気もします。

アプリの実行結果

f:id:korechi:20170817233250g:plain

必要なもの

Unityでの操作

  1. 新規Unityプロジェクトの作成
  2. unity-arkit-plugin.unitypackageをインポート
    f:id:korechi:20170817101140p:plain:h300
    Projectビューは以下のようになっています。
    f:id:korechi:20170817101252p:plain:h200
  3. Build Settings -> PlatformをiOSに切り替える
  4. No iOS module loadedとなっている方は、横にある「open download page」ボタンをクリックしてください(DLが終わるまで1時間弱かかる場合があります)
    f:id:korechi:20170817010324p:plain:h300
  5. Build Settings -> Platform -> iOSを選択し、PlayerSettingsからIdentificationを設定
  6. Camera Usage Descriptionに何らかしらの文字を入れる(これをやらないとアプリがカメラ利用許可を得られず、起動時に落ちるらしい)
    f:id:korechi:20170817101656p:plain:h300
  7. Assetsフォルダ直下にある、UnityARKitScene.unityをダブルクリックしてシーンを開く
    シーンを開くと以下のような画面になります。
    f:id:korechi:20170817102111p:plain:h300
  8. Build Settings -> Add Open Scenes をクリック 注)これをしないと現在のシーンがビルド対象となりませんので注意してください
    f:id:korechi:20170817102346p:plain:h300
  9. UnityParticlePainter.unityのシーンも同様にビルド対象とし、ビルドします
    ただし、Unityのパッチが古いと以下のようなエラーが出ます。
Assets/Plugins/iOS/UnityARKit/UnityARVideo.cs(59,31): error CS0117: `UnityEngine.TextureFormat' does not contain a definition for `R8'
Assets/Plugins/iOS/UnityARKit/UnityARVideo.cs(66,31): error CS0117: `UnityEngine.TextureFormat' does not contain a definition for `RG16'

エラーが出なかった場合は、Xcode向けにビルドされたプロジェクトが生成されます。

Xcodeでの操作

  1. Unityから生成されたXcodeプロジェクトを開きます
    f:id:korechi:20170817104622p:plain:h250
  2. 実機で実行(やり方は①Xcodeのみを使ってアプリを作成、と同じ)
    ただし以下のようなエラーが出てしまいました。
ARKitUnitySample[3217:1623803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ARFrame displayTransformWithViewportSize:orientation:]: unrecognized selector sent to instance 0x1c42eff80'

調べたところこれは、unitypackageが少し古いために発生した問題みたいです。
もしそのようなエラーが出てアプリが強制終了してしまった方は、unitypackageを使わずにUnity-ARKit-pluginをbitbucketからダウンロードして、それをそのままUnityで開いてください
それ以外の手順は大体同じです!

最後に

Xcodeのみを使ってアプリを作成する方法と、Unityを使ってアプリを作成する方法を紹介しました。
どちらを選択するかは皆さんに判断をお任せしますが、やはり3Dオブジェクトをごりごり動かしたい場合はUnityの方が良いのではないかとも思います。
反対に、そうでないものを作るのならばXcodeのみで開発した方が良さそうにも思えます。
自分はもう少し両方のパターンで慣れて見てから判断しようと思います!

AppleのARKitについて調べてみた

はじめに

AppleのARKitに最近興味がわいたので、今回調べてみました。
Appleの公式ドキュメントを読んでまとめつつ、補足をつけたりしています。
アプリの制作方法は次の記事でまとめたいと思います。

ARKit とは

OSデバイスのカメラとモーション機能を統合することで、iアプリやゲーム内で拡張現実体験を提供するフレームワークです。
具体的には、デバイスのモーション機能、カメラによるシーンのキャプチャ、高度なシーン処理、便利さの表示を組み合わせて、AR体験の構築を単純化しています。

ARKitを使ったデモ例

こちらはARKitとUnityを使ってロボットが部屋の中で踊るデモです。
床の上を綺麗に動き回っているのが特徴的です。他にも様々なサンプルアプリが世に出回っているみたいです。

ARKitを利用するには(デバイス側)

A9以降のプロセッサを搭載した、iOS11以降のOSがインストールされたデバイスが必要です。

  • A9: iPhone6s, 6sPlus, SE, iPad(第5世代)
  • A9X: iPad Pro
  • A10: iPhone7, 7Plus

ARKitを利用するためには(アプリ側)

ARKitをサポートしたデバイスのみでアプリを動作させるには、アプリのInfo.plistUIReauiredDeviceCapabilitiesセクションの中でarkitキーを使用してください。
もし、AR機能がアプリにとって二次的な機能ならisSupportedプロパティを使用してください。

ワールドトラッキングの仕組み

現実世界と仮想空間の間の対応関係を構築するために、visual-inertial odometryという技術を使用しています。

visual-inertial odometryとは

iOSバイスのモーションセンサーとカメラから見えた映像の分析結果を結合するプロセス。
ARKitはシーン画像内の特徴点を認識し、その特徴点からのずれを追跡し、モーションセンサーからのデータと比較することで、高い精度でデバイスの位置と動きを得ることができます。

ARKitができること

  • 平面検知
    • ARHitTestResultクラスを使えば、カメラ画像内にある平面(現実世界における)を検知
    • planeDetectionをenableにすることで、ARKitはカメラ内の平面を検知し、その位置とサイズを知らせてくれる
  • それ以外はできないのかな?(まだよく分かっていませんが)
    • Tangoは平面だけでなく壁や特徴点の3次元座標を取得可能だったがARKitは平面検知しか行えないっぽい
    • Tangoは学習した現実空間の座標情報をADFファイルとして保存し、アプリ起動時に読み込むことで以前に学習した空間とのマッチングを行うことができたが、ARKitにその機能はついていないみたいです

ARKitを使用するコツ

  • 明るい環境での使用を促す
    • ワールドトラッキングはカメラ画像をもとに行われるため、暗い場所や細部が見えない環境では精度が落ちてしまいます。
  • ラッキングがうまくいっているかユーザにその都度知らせる
    • ARKitはデバイスが動いているほどシーンを理解できる。しかし、あまりに早く動かしたり、遠くからトラッキングをしてしまうと検知がうまくいかない場合があります。そこで、ARCameraクラスを使うことで、ユーザにトラッキングの情報を教え、トラッキングがうまくできていない時にもどうすれば良いかユーザに伝えるUIを作ることができます。
  • 時間をかけて平面検知を行い、必要とする平面が検知されたらそれ以降は平面検知をしないようにする
    • 平面検知の結果は時間とともに変化する。なぜなら、ARKitはシーン内の情報を常に更新し、その情報をもとに平面の情報を上書きし続けるからです。(これはつまり、一番最初に検知した平面は不正確な場合があるということです)

様々なクラス

ARKitのAR機能を使うためにいくつかのクラスが用意されています。

ARSessionクラス

  • 拡張現実体験に必要なデバイスカメラとモーション処理を管理する共有オブジェクト
  • ARKitが拡張現実感を作成するために実行する主要なプロセスを調整
    • このプロセスにはデバイスのモーションセンシングハードウェアからのデータの読み取り、デバイスの内蔵カメラの制御、キャプチャされたカメライメージのイメージ分析の実行が含まれる
  • AR機能を使うためには、このARSessionオブジェクトが必要
    • ARSCNViewやARSKViewオブジェクトを使用する場合はARSessionオブジェクトが生成されているが、自分でARコンテンツを自作する場合は、ARSessionオブジェクトを生成し、扱う必要がある

ARWorldTrackingConfigurationクラス

  • バイスの動きを6軸自由度(6DOF)を使ってトラッキングする設定
    • 3つの回転軸(roll, pitch, yaw)
    • 3つの平行移動軸(x, y, zの移動)
    • これらの情報とカメラ画像を組み合わせることで、仮想の物体を現実空間に配置することができる f:id:korechi:20170815194141p:plain:h300

AROrientationTrackingConfigurationクラス

  • バイスの向き(3軸)のみを使ってトラッキングする設定
  • ARWorldTrackingConfigurationクラスを使うことが推奨されているっぽい(当然か)

ARConfigurationクラス

  • 抽象クラス
  • 具象クラスとしてARWorldTrackingConfigurationクラスとAROrientationTrackingConfigurationクラスが存在

まとめ

  • ARKitは現実空間にARオブジェクトを配置する技術
  • カメラ画像とモーションセンサーのデータを使ってそれを実現
  • 現在、カメラ画像内の平面検知が行えるため、平面の上に物を置いたりすることができるみたい
  • iPhone6s以降に発売された端末で利用できる

画像の手前にTextMeshを表示していたら見る角度によってTextMeshが消えた

今回見つかった問題

Unityのシーン内でTextMeshを特定の画像の手前に表示しようとした時、特定の角度から眺めるとTextMeshのテキストが消えてしまいました
f:id:korechi:20170810100223g:plain こんな感じに。
(gifの撮影はScreen To Gifというアプリを使いました)
ちゃんとTextMeshは画像より手前にあるはずなのに突然消えてしまう!
一方向からしか見ないなら問題はないんだけど、ARとかVRでオブジェクトを表示するといろんな角度から眺めることもあるので対応する必要があります。
そのため今回、この問題について調査してみました。

発生状況

  • Unity 5.6.2f1
  • OS:Windows10

原因

どうもTextMeshではなく、後ろにある画像オブジェクトのMaterialの設定が良くなかったみたいです。
f:id:korechi:20170810104043p:plain
このように、materialのshaderをUnlit/Transparentにしていました。それを
f:id:korechi:20170810104313p:plain
Unlit/Transparent Cutoutに変えたところTextMeshが消えなくなりました!
f:id:korechi:20170810110411g:plain

おまけ

ビルトインシェーダー

さっきのmaterialのshader、結局どう変わったの?という疑問が自分にあったので、Unityのシェーダー/マテリアルについてちょっと調べました。

ビルトインシェーダー 内容
Standard 石、木、ガラス、プラスチック、金属など「現実世界」のオブジェクトをレンダリングするのに使用され、広範囲のシェーダータイプや組み合わせをサポート
FX ライティングとガラスのエフェクト
GUIとUI UI グラフィック
Mobile モバイル デバイス用に簡素化されたハイパフォーマンス シェーダー
Nature 樹木および地形
Particles パーティクルシステムエフェクト
Skybox すべてのジオメトリの裏側でレンダリングする背景環境
Sprites 2D スプライトシステムとともに使用
Toon カートゥーン(漫画)風のレンダリング
Unlit すべてのライトとシャドウイングを完全にバイパスするレンダリング
Legacy スタンダードシェーダーに取って代わられる古いシェーダーの大きい集合

シェーダー

シェーダーとは、モデル表面のピクセルの見え方を決めるための、数学的な計算とアルゴリズムを格納したスクリプトです。
シェーダーが定義するのは、

  • オブジェクトを描画する方法です。光源の角度や、視野角、そしてその他の関連性のある計算を含む、コードと数学的な計算です。シェーダーでは、エンドユーザーのグラフィックスハードウェアに依存する、さまざまな方法を使う事もできます。
  • テクスチャマップや色、その他数々のマテリアルインスペクターで変更できるパラメータ。

マテリアルが定義するのは、

  • マテリアルをレンダリングするために使用するシェーダー
  • シェーダー パラメーターの特定の値 - テクスチャマップ、色、数的値など
    です。

Unityでアプリを終了させてもデータを残しておく2つの方法

作りたいもの

例えばゲームのMaxスコアを保存したり、フレンドのリストをローカルに保存しておきたい場合があるとします。
それらのデータはアプリを終了して消えてしまったら当然困るので、アプリ終了時にデータをスマートフォン上に保存する必要があります。
その処理を今回紹介したいと思います。

データをローカルに保存する2つの方法

xmlファイルを使う方法

保存したいデータが以下のようなとあるクラスのインスタンス変数の中身だとします。

public class SaveData {
    [XmlElement("text")]
    public string m_text;
    [XmlElement("position")]
    public Vector3 m_pos;
}

これらをxmlファイルに保存する方法は以下のようにします。

// 保存したいデータのインスタンスのリスト
private List<SaveData> m_saveData;

// xmlファイルに入れるためのデータを作成
List<SaveData > xmlDataList = new List<SaveData > ();
foreach (SaveData data in m_saveData) {
    SaveData temp = new SaveData();
    temp.m_text = data.m_text;
    temp.m_pos = data.m_pos;
    xmlDataList.Add (temp);
}
string fileName = "korechi_memo";
string path = Application.persistentDataPath + "/" + fileName + ".xml";
// XmlSerializerのインスタンスを生成
var serializer = new XmlSerializer (typeof(List<SaveData>));
// ファイル生成
using (var stream = new FileStream (path, FileMode.Create)) {
    serializer.Serialize (stream, xmlDataList);
}

そして保存したxmlファイルをロードする方法を以下に示します。

string fileName = "korechi_memo";
string path = Application.persistentDataPath + "/" + fileName + ".xml";

var serializer = new XmlSerializer(typeof(List<PostItData>));
var stream = new FileStream(path, FileMode.Open);

List<SaveData> xmlDataList = serializer.Deserialize(stream) as List<SaveData>;

if (xmlDataList == null)
{
    Debug.Log("xmlDataList is null");
    return;
}

foreach (SaveData data in xmlDataList)
{
    // 取り出した後の処理
}

PlayerPrefsを使う方法

この方法は以前の記事で紹介した korechipostit.hatenablog.com
下の方にかかれています。その時使ったコードを載せておきますのでうまいこと参考にしていただければと思います。

Unityで気象情報をWebから取得し、1日の天気を表示してみる

作りたいもの

Unityを使って気象情報を取得し、1日の天気や取得した瞬間の天気を取得する。
用途としては例えば、ダイアリーアプリを作る時に天気の情報を載せたり、Unityで作ったゲーム内の天気を現実の天気に合わせるのにも使えそう。

今回使用するWebAPI

DarkSky.netという気象情報サービスを使用します。
URLはここ
f:id:korechi:20170801231014p:plain:w600
1日に1000リクエストまで無料でAPIを使用することができます。それ以降は課金が必要となり、適宜請求が来るみたいです。

他の気象情報API

他の気象情報を取得できるサービスとして、例えば
OpenWeatherMap
あたりがあります。
これもフリーで利用できるAPIが提供されており、1日のうち3時間ごとの天気などが取得可能です。
地点はTokyo,jpのように、大まかな範囲で指定できます。
このサービスは完全にフリーでリクエストごとの課金とかがありません。なので使っていて安心なのですが、緯度経度が指定できたり、1時間ごとの天気を取得できるDarkSky.netを今回使用します。

DarkSky.netのAPIの使い方

このサービスを使用するにはまずサインインする必要があるため、上にあるDevelopersをクリックしてサインアップしてください。
f:id:korechi:20170801231100p:plain:w400
そしてシークレットキーを取得してください。
URLリクエストに使うURLは以下のようになります。

https://api.darksky.net/forecast/<Secret Key>/<longitude>,<latitude>

longitudeには、気象情報を取得したい地点の緯度を、latitudeには経度を入れてください。
このURLリクエストを行うと、JSON形式で気象データが受信できます。
f:id:korechi:20170801232450p:plain
ただしこのままだと非常に見づらいので、自分の欲しいデータだけうまいこと取得する必要があります。

Unityで気象情報を取得してみる

UnityからWebAPIを叩く

WWWクラスを使います。

public class ExampleClass : MonoBehaviour {
    // 適切な値を埋め込んでください
    string url = "https://api.darksky.net/forecast/<Secret Key>/<longitude>,<latitude>";

    IEnumerator Start() {
        WWW www = new WWW(url);
        yield return www;
        string jsonString = www.test;
        Debug.Log(jsonString);
    }
}

jsonStringオブジェクトに取得したJSONのテキストが格納されています。

位置情報を取得

これは、こちらのサイトが参考になりました。
[Unity] Unityで位置情報を取得する: ものづくりログ

JSONのパース

UnityにJSONのパーサはあったのですが、リストに対応していなかったりと使い勝手がイマイチっぽかったので、自分でJSONデータをパースしました。
パースとは言うものの、JSONのデータをstring型の変数として格納し、1文字1文字読み進めていき文字列を地道に探すというやり方です(非効率ですみません)。
例えば上のJSONをよーく見ると"summary":"Partly Cloudy"という部分が天気を表しているらしいことが分かります。
そのためsummaryの次の"“で囲まれている部分のstringを取り出せば天気が取得できたことになります。 サンプルコードは下のようになります。

for (;; ) {
  // summaryから始まる部分を探す
  if (jsonString.StartsWith("summary")) {
    // summaryの次のstringを抜き出す処理
    // "summary":" の部分がいらないため11文字Removeする
    jsonString.Remove(0, 11);
    string weather = "";
    int i = 0;
    while (jsonString[i] != "\"") {
      i++;
      weather += jsonString[i];
    }
  } else {
    // 1文字目を削除->jsonStringを先に進めていくイメージ
    jsonString = jsonString.Remove(0, 1);
  }
}

こうしてjsonStringから天気の情報を抜き出すことができます。(正確なコードではないので適宜修正して下さい)
時間については"time":1501596000の部分に記載されているため上と同様にすることで時間も取得できます。
ただしこれはUNIX時間なので日本時間に直す処理は別途必要となります。
あとは取得した情報をUniyで表示してあげれば終了です。

サンプルコード

緯度経度を取得し、気象情報を取得しログに出力するサンプルコードをのせておきます。