- 投稿日:2020-11-25T23:39:14+09:00
リングフィットアドベンチャーのようにJoyConを用いてGoogleStreetViewの世界を歩き回る【Unity+GoogleMapsJavaScriptAPI】
リングコンは使いません(レッグバンドとジョイコンだけ)
経緯
- スタンディングデスク+ステッパーという意識高そうな在宅ワーク環境を手に入れた...のはいいものの、すぐ飽きた。座りたい。
- 運動の動機付けとしてサイクリングマシンでストリートビューを操作するやつ(これとか)をステッパーで作ってみようと思った。
- 運動を検知するためにセンサーが必要。何かしらの動きをマイコンで検知するとして、さらにそれを何かしらの手段でPCに送信して、...結構大変だなあ。お金もかかりそうだ。
- どっかに運動(特に傾き)を検知できて、BluetoothでPCに接続できる機械ないかなあ~~~~~。
- あった~~~~~~!!!!。ジョイコンで傾き検知が可能。ついでにレッグバンド(リングフィットアドベンチャーの付属品)でちょうど足につけられる。(レッグバンドはなくてもどうにでもなります)
というわけでジョイコンを用いてストリートビューの世界を歩き回ろうと思います。
方針
joyコンとの連携のためにライブラリが充実しているUnityを使用することは決定。ただしストリートビューを利用するためにはブラウザからHTMLファイルとして開く必要があるらしい。よって、Unityからブラウザを開く+開いたページをSeleniumで操作するという方針に決定。
以下の二つから構成される。
- 表示するページ(HTML+javascript)
- GoogleMapsJavaScriptAPIを用いてグーグルストリートビューの表示を行う。
- 「ボタンを押すと前進する」という機能だけ持つ。
- Unity側
- selenium+chromeDriverを用いてページを開く。
- ジョイコンの傾きを検知し、歩数をカウントする。歩くたびにwebページのボタンを押す。
表示するページ
参考サイト:
GoogleStreetViewが勝手に動く!?GoogleMapAPIを使った自動再生プログラムを作ってみる。|株式会社アーティス
https://www.asobou.co.jp/blog/web/streetviewまずAPIキーを取得します。このページ等を参考にしてGoogleMapsJavaScriptAPIの有効化とキーの取得を行ってください。googleのAPIには無料枠があり、月額200ドル分まで(およそ14000回ほど)無料で使えるようです。
表示するページは以下のように作成します。これはほとんど参考サイトで書かれたコードのままですが、ボタンを追加してそれを押すたびに(5回に1回)移動する、というように書き換えました。また、この記事を参考に多少座標がずれても修正できるようにしています。
<html> <head> <title>StreetView</title> <meta name="viewport" content="initial-scale=1.0"> <meta charset="utf-8"> <input type="button" onclick="proceed()" id="count" value="0歩"> <style> html, body { height: 100%; margin: 0; padding: 0; } #street-view { height: 100%; } </style> </head> <body> <div id="street-view"></div> <script> const LIMIT = 300; // 移動回数の上限値 const START_LAT_LNG = {lat: 任意の緯度, lng: 任意の経度}; // 開始地点の緯度、経度 //const START_LAT_LNG = {lat: 35.1010033, lng: 139.0779688}; // 例 const START_HEADING = 180; // 開始時の方角 let panorama; isProceed = false; let count = 0; let m = 0; let n = 5; // 何歩ごとに1進むか。Unityでも設定する。少ない方が嬉しいが無料枠に注意 let buttonText = document.getElementById('count'); function initMap() { let Links, count = 0, timer_id; panorama = new google.maps.StreetViewPanorama( document.getElementById('street-view'), { position: START_LAT_LNG, pov: { heading: START_HEADING, pitch: 0 }, zoom: 1 }); // // 座標の微妙なズレに補正を加える svs = new google.maps.StreetViewService(); svs.getPanoramaByLocation(START_LAT_LNG, 50, function(result, status) { if (status == google.maps.StreetViewStatus.OK){ panorama.setPosition(result.location.latLng); } }); Links = panorama.getLinks(); } function proceed() { m++; if(m >= n) { m = 0; if (panorama.getStatus() == "OK") { Links = panorama.getLinks(); if (count > LIMIT) { alert('stop'); return false; } let target = 0; if (Links.length >= 4) { target = Math.floor(Math.random() * Links.length); } else { let val = 360; let currentPov = panorama.getPov(); Links.forEach(function (element, index) { let ans = Math.abs(currentPov.heading - element.heading); if (val > ans) { val = ans; target = index; } }); } panorama.setPov({ heading: Links[target].heading, pitch: 0 }); panorama.setPano(Links[target]['pano']); }; } count++; buttonText.value = String(count) + "歩"; } </script> <script src="https://maps.googleapis.com/maps/api/js?key=取得したキー&callback=initMap" async defer></script> </body> </html>Unity側の設定
ジョイコン検知のための設定
以下のサイトを参考にしました。
【Unity】Nintendo Switch の Joy-Con を使用する方法
【Unity】Nintendo Switch の Joy-Con のジャイロ・加速度・傾きの値を取得したり、振動させたりすることができる「JoyconLib」紹介
上の内容に従いProject Settingsから入力の変更、二つのライブラリの導入を行いました。
selenium+chromedriverの導入
参考サイト: UnityのC#からSelenium経由でChromeをゴニョゴニョする
上の内容に従い、SeleniumとChromeDriverの導入を行いました。ChromeDriverはバージョンに注意してください。
コード
Start()時にChromeDriverを用いてブラウザを起動。歩行を感知するたびにボタンを押す。
歩数の取得をどうやるかは一考の余地がありますが、とりあえず以下のように設定しました。
using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; public class JoyConWalker : MonoBehaviour { private ChromeDriver _driver; private List<Joycon> m_joycons; private Joycon m_joyconL; private Joycon m_joyconR; private Joycon.Button? m_pressedButtonL; private Joycon.Button? m_pressedButtonR; int count = 0; float LlastUpper = 0; float LlastLower = 0; float Llast = 0; bool LisUp = true; float theta = 0.08f; //閾値。設定は微妙なので要調整。 void Start() { var path = Application.streamingAssetsPath; _driver = new ChromeDriver(path); _driver.Navigate().GoToUrl(Application.dataPath + "/StreetView.html"); m_joycons = JoyconManager.Instance.j; if ( m_joycons == null || m_joycons.Count <= 0 ) return; m_joyconL = m_joycons.Find( c => c.isLeft ); m_joyconR = m_joycons.Find( c => !c.isLeft ); } void Update() { var orientationL = m_joyconL.GetVector(); var current = orientationL.z; if(LisUp) { if(current >= Llast) { LlastUpper = current; } else { if(LlastUpper - LlastLower >= theta) { Proceed(); } LisUp = false; LlastLower = current; } } else { if(current <= Llast) { LlastLower = current; } else { if(LlastUpper - LlastLower >= theta) { Proceed(); } LisUp = true; LlastUpper = current; } } Llast = current; } void Proceed() { count++; Debug.Log(count); _driver.FindElement(By.Id("count")).Click(); } void OnDestroy() { _driver.Dispose(); } }Unityで組み立てる
シーンに空のゲームオブジェクトを配置して↑のcsファイルと、JoyConManager.csをつける。htmlファイルをAssets下に配置。
これで完成。起動し、ページが開いたら左のジョイコンをレッグバンドに入れて足踏みをします。
座標は自分の好きな観光地である熱海に設定。歩数表示が左上に出ています。ステッパーで足踏みしてる間、延々と熱海をさまようことができます。
https://github.com/NNNiNiNNN/JoyCon_StreetView
課題
初期座標の決定が難しいこと
現在は完全に固定した座標からスタートして、(アルゴリズム的に)完全に固定されたルートを通るようになっています。座標の決定を完全にランダムにしてから最寄りのデータを持つ座標に補正する、というやり方も試してみましたが、この手段で得られるパノラマ座標は「ストリートビューとして移動できるパノラマ座標」に限らないため、移動先を失うパターンが多くありました。apiも他にどのようなものが使えるのか把握していないため、自分がすぐ直すのは難しそうです。理想を言えば初期地点と目的地点を手動で決定して自動でルート案内するのがいいと思います。実装も多分可能ですが、今回はなしで。
歩行の検知
単純にジョイコンの傾きの差を取ればいいだけ、だとは思うのですがいまいち最適化できていません。そもそもxyzのどれを取ればいいのかもはっきり決め切れていません。現在は動きの閾値を小さめに設定することでだいたいの動きを無理やり取る形にしています。
ジョイコンの接続エラー?
一度接続したジョイコンは、その接続が途切れた後はPCを再起動しないと再接続できなくなることがあります。理由も再現性もよくわかっていません。
あとがき
課題は多くありますが、よく見るフィットネスバイク+ストリートビュー....の亜種を自力で作れたことが嬉しいです。ジョイコンとかgoogleのAPIとか、見渡せば色々便利なものがあるんですねえ。苦戦した部分もありましたが、最終的には簡単な内容で仕上がったのもよかったです。
作ったもので運動するかはわかりません。
参考
GoogleStreetViewが勝手に動く!?GoogleMapAPIを使った自動再生プログラムを作ってみる。|株式会社アーティス
Googleマップストリートビューで目的地に最寄りのストリート位置(座標情報)を取得する方法
【Unity】Nintendo Switch の Joy-Con を使用する方法
【Unity】Nintendo Switch の Joy-Con のジャイロ・加速度・傾きの値を取得したり、振動させたりすることができる「JoyconLib」紹介
- 投稿日:2020-11-25T23:39:14+09:00
リングフィットアドベンチャーの道具でグーグルストリートビューを歩き回る【Unity+GoogleMapsJavaScriptAPI】
リングコンは使いません(レッグバンドとジョイコンだけ)
経緯
- スタンディングデスク+ステッパーという意識高そうな在宅ワーク環境を手に入れた...のはいいものの、すぐ飽きた。座りたい。
- 運動の動機付けとしてサイクリングマシンでストリートビューを操作するやつ(これとか)をステッパーで作ってみようと思った。
- 運動を検知するためにセンサーが必要。何かしらの動きをマイコンで検知するとして、さらにそれを何かしらの手段でPCに送信して、...結構大変だなあ。お金もかかりそうだ。
- どっかに運動(特に傾き)を検知できて、BluetoothでPCに接続できる機械ないかなあ~~~~~。
- あった~~~~~~!!!!。ジョイコンで傾き検知が可能。ついでにレッグバンド(リングフィットアドベンチャーの付属品)でちょうど足につけられる。(レッグバンドはなくてもどうにでもなります)
というわけでジョイコンを用いてストリートビューの世界を歩き回ろうと思います。
方針
joyコンとの連携のためにライブラリが充実しているUnityを使用することは決定。ただしストリートビューを利用するためにはブラウザからHTMLファイルとして開く必要があるらしい。よって、Unityからブラウザを開く+開いたページをSeleniumで操作するという方針に決定。
以下の二つから構成される。
- 表示するページ(HTML+javascript)
- GoogleMapsJavaScriptAPIを用いてグーグルストリートビューの表示を行う。
- 「ボタンを押すと前進する」という機能だけ持つ。
- Unity側
- selenium+chromeDriverを用いてページを開く。
- ジョイコンの傾きを検知し、歩数をカウントする。歩くたびにwebページのボタンを押す。
表示するページ
参考サイト:
GoogleStreetViewが勝手に動く!?GoogleMapAPIを使った自動再生プログラムを作ってみる。|株式会社アーティス
https://www.asobou.co.jp/blog/web/streetviewまずAPIキーを取得します。このページ等を参考にしてGoogleMapsJavaScriptAPIの有効化とキーの取得を行ってください。googleのAPIには無料枠があり、月額200ドル分まで(およそ14000回ほど)無料で使えるようです。
表示するページは以下のように作成します。これはほとんど参考サイトで書かれたコードのままですが、ボタンを追加してそれを押すたびに(5回に1回)移動する、というように書き換えました。また、この記事を参考に多少座標がずれても修正できるようにしています。
<html> <head> <title>StreetView</title> <meta name="viewport" content="initial-scale=1.0"> <meta charset="utf-8"> <input type="button" onclick="proceed()" id="count" value="0歩"> <style> html, body { height: 100%; margin: 0; padding: 0; } #street-view { height: 100%; } </style> </head> <body> <div id="street-view"></div> <script> const LIMIT = 300; // 移動回数の上限値 const START_LAT_LNG = {lat: 任意の緯度, lng: 任意の経度}; // 開始地点の緯度、経度 //const START_LAT_LNG = {lat: 35.1010033, lng: 139.0779688}; // 例 const START_HEADING = 180; // 開始時の方角 let panorama; isProceed = false; let count = 0; let m = 0; let n = 5; // 何歩ごとに1進むか。要検討。少ない方が嬉しいが無料枠に注意 let buttonText = document.getElementById('count'); function initMap() { let Links, count = 0, timer_id; panorama = new google.maps.StreetViewPanorama( document.getElementById('street-view'), { position: START_LAT_LNG, pov: { heading: START_HEADING, pitch: 0 }, zoom: 1 }); // // 座標の微妙なズレに補正を加える svs = new google.maps.StreetViewService(); svs.getPanoramaByLocation(START_LAT_LNG, 50, function(result, status) { if (status == google.maps.StreetViewStatus.OK){ panorama.setPosition(result.location.latLng); } }); Links = panorama.getLinks(); } function proceed() { m++; if(m >= n) { m = 0; if (panorama.getStatus() == "OK") { Links = panorama.getLinks(); if (count > LIMIT) { alert('stop'); return false; } let target = 0; if (Links.length >= 4) { target = Math.floor(Math.random() * Links.length); } else { let val = 360; let currentPov = panorama.getPov(); Links.forEach(function (element, index) { let ans = Math.abs(currentPov.heading - element.heading); if (val > ans) { val = ans; target = index; } }); } panorama.setPov({ heading: Links[target].heading, pitch: 0 }); panorama.setPano(Links[target]['pano']); }; } count++; buttonText.value = String(count) + "歩"; } </script> <script src="https://maps.googleapis.com/maps/api/js?key=取得したキー&callback=initMap" async defer></script> </body> </html>Unity側の設定
ジョイコン検知のための設定
以下のサイトを参考にしました。
【Unity】Nintendo Switch の Joy-Con を使用する方法
【Unity】Nintendo Switch の Joy-Con のジャイロ・加速度・傾きの値を取得したり、振動させたりすることができる「JoyconLib」紹介
上の内容に従いProject Settingsから入力の変更、二つのライブラリの導入を行いました。
selenium+chromedriverの導入
参考サイト: UnityのC#からSelenium経由でChromeをゴニョゴニョする
上の内容に従い、SeleniumとChromeDriverの導入を行いました。ChromeDriverはバージョンに注意してください。
コード
Start()時にChromeDriverを用いてブラウザを起動。歩行を感知するたびにボタンを押す。
歩数の取得をどうやるかは一考の余地がありますが、とりあえず以下のように設定しました。
using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; public class JoyConWalker : MonoBehaviour { private ChromeDriver _driver; private List<Joycon> m_joycons; private Joycon m_joyconL; private Joycon m_joyconR; private Joycon.Button? m_pressedButtonL; private Joycon.Button? m_pressedButtonR; int count = 0; float LlastUpper = 0; float LlastLower = 0; float Llast = 0; bool LisUp = true; float theta = 0.08f; //閾値。設定は微妙なので要調整。 void Start() { var path = Application.streamingAssetsPath; _driver = new ChromeDriver(path); _driver.Navigate().GoToUrl(Application.dataPath + "/StreetView.html"); m_joycons = JoyconManager.Instance.j; if ( m_joycons == null || m_joycons.Count <= 0 ) return; m_joyconL = m_joycons.Find( c => c.isLeft ); m_joyconR = m_joycons.Find( c => !c.isLeft ); } void Update() { var orientationL = m_joyconL.GetVector(); var current = orientationL.z; if(LisUp) { if(current >= Llast) { LlastUpper = current; } else { if(LlastUpper - LlastLower >= theta) { Proceed(); } LisUp = false; LlastLower = current; } } else { if(current <= Llast) { LlastLower = current; } else { if(LlastUpper - LlastLower >= theta) { Proceed(); } LisUp = true; LlastUpper = current; } } Llast = current; } void Proceed() { count++; Debug.Log(count); _driver.FindElement(By.Id("count")).Click(); } void OnDestroy() { _driver.Dispose(); } }Unityで組み立てる
シーンに空のゲームオブジェクトを配置して↑のcsファイルと、JoyConManager.csをつける。htmlファイルをAssets下に配置。
これで完成。起動し、ページが開いたら左のジョイコンをレッグバンドに入れて足踏みをします。
座標は自分の好きな観光地である熱海に設定。歩数表示が左上に出ています。ステッパーで足踏みしてる間、延々と熱海をさまようことができます。
https://github.com/NNNiNiNNN/JoyCon_StreetView
課題
初期座標の決定が難しいこと
現在は完全に固定した座標からスタートして、(アルゴリズム的に)完全に固定されたルートを通るようになっています。座標の決定を完全にランダムにしてから最寄りのデータを持つ座標に補正する、というやり方も試してみましたが、この手段で得られるパノラマ座標は「ストリートビューとして移動できるパノラマ座標」に限らないため、移動先を失うパターンが多くありました。apiも他にどのようなものが使えるのか把握していないため、自分がすぐ直すのは難しそうです。理想を言えば初期地点と目的地点を手動で決定して自動でルート案内するのがいいと思います。実装も多分可能ですが、今回はなしで。
歩行の検知
単純にジョイコンの傾きの差を取ればいいだけ、だとは思うのですがいまいち最適化できていません。そもそもxyzのどれを取ればいいのかもはっきり決め切れていません。現在は動きの閾値を小さめに設定することでだいたいの動きを無理やり取る形にしています。
ジョイコンの接続エラー?
一度接続したジョイコンは、その接続が途切れた後はPCを再起動しないと再接続できなくなることがあります。理由も再現性もよくわかっていません。
あとがき
課題は多くありますが、よく見るフィットネスバイク+ストリートビュー....の亜種を自力で作れたことが嬉しいです。ジョイコンとかgoogleのAPIとか、見渡せば色々便利なものがあるんですねえ。苦戦した部分もありましたが、最終的には簡単な内容で仕上がったのもよかったです。
作ったもので運動するかはわかりません。
参考
GoogleStreetViewが勝手に動く!?GoogleMapAPIを使った自動再生プログラムを作ってみる。|株式会社アーティス
Googleマップストリートビューで目的地に最寄りのストリート位置(座標情報)を取得する方法
【Unity】Nintendo Switch の Joy-Con を使用する方法
【Unity】Nintendo Switch の Joy-Con のジャイロ・加速度・傾きの値を取得したり、振動させたりすることができる「JoyconLib」紹介
- 投稿日:2020-11-25T19:25:46+09:00
【Unity】Transform座標をRectTransform座標に変換する方法
キャラクターの手前にHPゲージを表示したかったのだが、キャラクターがTransform、HPゲージは円ゲージを採用していたのでRectTransform。つまりワールド座標をスクリーン座標に変換してImageを表示する必要があった。
方法
テラシュールブログさんでやりかたが載っていたのでありがたく参考にさせていただいた。
ソールファイルはキャンバスオブジェクトにつける。test.cpp[SerializeField] private Image bossHp = default; // ボスHP画像 [SerializeField] private Vector2 bossHpPos = default; // ボスHP座標調整 private RectTransform bossHpRectTrans; private RectTransform canvasRectTrans; private void Awake() { bossHpRectTrans = bossHp.GetComponent<RectTransform>(); canvasRectTrans = GetComponent<RectTransform>(); } /// <summary> /// ボスのHP座標を設定する /// </summary> /// <param name="target">ボス座標</param> public void SetBossHpPotision(Vector3 target) { var newPos = Vector2.zero; var camera = Camera.main; var screenPos = RectTransformUtility.WorldToScreenPoint(camera, target); RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTrans, screenPos, camera, out newPos); bossHpRectTrans.localPosition = newPos + bossHpPos; }解説としては
1つ目のRectTransformUtility.WorldToScreenPointでTransform(ワールド)座標をスクリーン座標に変換する。
2つ目のRectTransformUtility.ScreenPointToLocalPointInRectangleでスクリーン座標をRectTransform座標に変換する。おそらく2つ目のほうはカメラ、キャンバスが複数あった場合、どのカメラに映っているキャンバス用RectTransformに変換するか?ということだと思う。キャンバスごとにカメラで映る解像度が変更できるし、Overlay設定とかもあるからそれのためなのかな?よくわからん…
今回もそうなんだけどSpineキャラクターは足元とかが中心座標になってたりするのでHP画像を表示する際には位置調整用に変数も追加。実行中に座標調整ができるという点に関してUnityは本当に便利。
まぁ、とりあえずこれでやりたいことはできたので一安心。
ワールド座標とスクリーン座標の違いすらよく分かってなかったし、いつもマウスの座標取得すら手当たり次第に関数ぶつけて確認してるくらいの未熟者だったから今回のはマジでよくわからなかった。調査&実装で3時間。+備忘録作成に1時間もかかってしまった…これがなかなか難しいねんな。
- 投稿日:2020-11-25T19:16:21+09:00
Blenderのマテリアルを削除する方法【Blender2.8x】
- 投稿日:2020-11-25T12:34:52+09:00
UnityでTOMLファイルを扱う
概要
Unityの趣味プロジェクトでTOMLファイルの読み込みをしたくなったので、TOMLファイルを取り扱えるライブラリをインポートしたときの作業ログです。
Unityや.NET周りの開発は完全に素人で、手探りで進めているため、不必要にまわりくどい方法をとっていたりもするかと思います。
そのような点を見つけましたら、指摘して貰えると喜びます。バージョン
- Unity 2019.4.15f1
ログ
ライブラリのインポート
NettというTOMLファイルをパースできるライブラリがあるので、これをUnityから使えるようにしたい。
https://github.com/paiden/Nett
.NETのライブラリなので.NET用のパッケージマネージャであるNuGetでインストールする。
https://www.nuget.org/
NuGetにはUnity用の実装があるのでこれを使う。
https://github.com/GlitchEnzo/NuGetForUnity
README上のリンク
https://github.com/GlitchEnzo/NuGetForUnity/releases
から最新のリリースのunitypackageファイルをダウンロードしてきて、UnityのAssets>Import Package>Custom Package...
からインポートする。
UnityのツールバーにNuGetが追加されるので、NuGet>Manage NuGet Pakages
からNettを探してインストール。Disabling WSA platform on asset settings for ThisProjectPath\Assets\packages.configなるWarningが出たが現状問題ないのでとりあえず無視。
ファイル読み込み
NettのリポジトリのREADMEのDocumentationが工事中で情報がないので、APIの情報を探す。
ここにまとまっていたので、参考にしつつファイルを読み込む。
プロジェクトのルートディレクトリにinput/test_input.toml
を作成。中身は下記test_input.tomltitle = "Input file example"Test.csusing UnityEngine; using System.Collections; using Nett; public class Test : MonoBehaviour { // Start is called before the first frame update void Start() { // read input file string input_file_path = Application.dataPath + "/../input/test_input.toml"; TomlTable root = Toml.ReadFile(input_file_path); string title = root.Get<string>("title"); Debug.Log("The input file title is " + title); } }Unityで実行してコンソールに適切に出力されていることを確認。
The input file title is Input file example UnityEngine.Debug:Log(Object) Test:Start() (at Assets/Test.cs:8)他に参考にした記事