【Unity】【OculusQuest】急にUnityがOculusを認識しなくなった

f:id:s44511173:20191002172455p:plain

いつも通りにUnityでBuild and Runを実行したら、こんな画面が出てきた。。
なんで?どうして?
Oculus QuestはPCに接続されているのに・・・。

現象

Unityでapkをビルドする際、毎回上図のようなエラーが出るようになってしまいました。昨日までは、問題なくビルドできていたにも関わらず、です。

PCのエクスプローラからは、Oculusが見えていました。
ですが、OculusをPCとつなぎ直すたびに、Oculus側で「このデバイスとの接続を許可しますか?」のメッセージが出るようになってしまいました。

原因

なぜだか、OculusQuestの開発者モードが、勝手にOFFになっていたことが原因でした。チョ、マテヨ。なに勝手にオフってくれてんだよ!!

 

f:id:s44511173:20191002173121j:plain


開発者モード設定は、モバイルにインストールしているOculusソフトの
設定>Oculus>その他の設定>開発者モード
から確認できます。

結論

  1. 急にUnityがOculusを認識しなくなったら、Oculus側の開発者モードを疑おう
  2. 勝手に開発者モードがオフられた原因は不明。(わかり次第、更新します)

 

 

↑↑↑ ぜひ遊んでみてください!↑↑↑

【Unity】【OculusQuest】VRイライラ棒作ってみた

 f:id:s44511173:20191001175736g:plain

 

f:id:s44511173:20191001175741g:plain
OculusQuest、めちゃめちゃ楽しいです。
けど、結構しんどいです。あちこちでドハマリします。
今回はポートフォリオ用に、VRイライラ棒を作ってみました。
なんとなくBEAT SABER的な雰囲気で。え、似てない?光ってるだけやん?
いいんだよ、雰囲気だから。

ということで、イライラ棒が出来上がるまでにドハマリした部分を
(というかほぼ全部)
ご紹介してきたいと思います。詳しいことは、次回から。

ざっと、記事にする内容をラインナップしてみます。

  • イライラ棒をコントローラ表示代わりとする
  • 立ってプレイする
  • Bloomさせる
  • 視点に合わせてテキストを表示する
  • カウントダウン表示する
  • 紙吹雪を散らす
  • 壁を天井側から倒す

他にも思いついたら、書いていきます!

 

 

 

↑↑↑ ぜひ遊んでみてください!↑↑↑

【Unity】子オブジェクトの衝突を親オブジェクトで検知する

Oculus QuestでのVRアプリ制作にハマッています。いろんな意味で。
本日は衝突判定について、新たに知ることができたネタをご紹介します。
基本中の基本かも知れないけど。Oculus関係ないけど。

Oculus IntegrationのOVRGrabber

Oculus Integrationでは、手のアバターで物体をつかめるようにする機能が用意されています。それが掲題のOVRGrabberです。
これを手のオブジェクトにアタッチするわけなのですが、詳細な使い方はまた今度ご紹介するとして。

f:id:s44511173:20190912125900p:plain

このスクリプトをアタッチしたオブジェクトには、ご覧の通りColliderはアタッチされていません。Rigidbodyはありますけど。
では、コードを見てみましょう。

コード内では、OnTriggerEnterとOnTriggerExitが実装されています。
あれれ、Colliderを持っていないのにどうしてコールされるんだ??

親オブジェクトがRigidbodyを持つ場合、子オブジェクトの衝突も検知できる

ということらしい。
ためしにColliderなしのCubeを2個配置します。
それぞれに子オブジェクトを作成し、そちらにBoxColliderをアタッチして実験してみました。

f:id:s44511173:20190912131840g:plain

親にRigidbodyなし版。衝突してない感じ。

f:id:s44511173:20190912131835g:plain

親にRigidbodyあり版。衝突しています!!

結論

  1. 親オブジェクトにRigidbodyを付けることで、子オブジェクトの衝突を検知できる
  2. Oculusハマる。いろんな意味で。

 

 

 

↑↑↑ ぜひ遊んでみてください!↑↑↑

 

【Unity】【Oculus】HMDを外したらポーズ状態にする

Oqulus Questでビートセイバーやっていたら、腕が筋肉痛になりました。
できれば上腕二頭筋ではなく、上腕三頭筋に効いてほしい。

開発環境

  • Unity 2019.1.2f1
  • Oculus Integration 1.39
  • Oculus Quest

HMDを外すとポーズになるゲームがある

ビートセイバー等のゲームは、HMDを外すとポーズ状態になりますよね。
その後15秒ほどすると、Oculus本体がスリープになります。
スリープはOculus自体の設定ですが、ゲームのポーズはゲーム側で設定するようです。

HMDの装着状態を取得する

Oculus IntegrationにはOVRManagerというクラスが用意されています。
こちらのisUserPresentというプロパティから、HMDの装着状態を取得することができます。

developer.oculus.com

↑相変わらず素っ気ない埋め込みリンクですがw
OVRManagerのリファレンスです。英語です。しんどいです。

 

private bool isPose = true; // ポーズ状態
void Update()
{
    if (!OVRManager.instance.isUserPresent) {
        if (!isPose) {
            // ポーズ処理を実装
            isPose = true;
        }
    } else {
        if (isPose) {
            // ポーズ解除処理を実装
            isPose = false;
        }
    }
}

こんな感じのコードを書いてやればOKです。

結論

  1. HMDを外した時にゲームをポーズ状態にするのは、スクリプトで実装する必要がある
  2. OVRManagerには、HMDの装着状態を取得できるプロパティが用意されている

なお、現在のOculus Integrationの最新Verは1.40の模様です。
アップデートしたいけど、なんか動かなくなりそうで怖くてできない(><)

 

 

 

↑↑↑ ぜひ遊んでみてください!↑↑↑

【Unity】Mesh ColliderのConvexオプションについて

fbxをインポートすると、メッシュ情報からMesh Colliderが作られますよね。
そのMesh Collider同士の衝突判定について、めっちゃハマったお話です。

メッシュ同士の衝突について

Unityマニュアルに、以下のように記載されています。

docs.unity3d.com

上の記事には、Convex がオンとなっているメッシュコライダーは、他のメッシュコライダーと衝突することができます。と書かれてあります。
さっそく、試してみることにしました。

衝突したい両方のConvexをオンにしてみた

これが、思った通りに衝突判定してくれない。
正確に言えば、衝突していないのに起動時に衝突検知し、そのあとは衝突させても検知してくれない。
これで、かなり悩みました。

Convexをオンにすると、メッシュ通りのコライダにならない

ということが判明!!!
下のキャプチャを見てみてください。
VRイライラ棒を作っていますw

f:id:s44511173:20190904162547p:plain

こちらがConvexオフ。

f:id:s44511173:20190904162552p:plain

こちらがConvexオン。緑のラインがコライダの形を表しています。
なんと、メッシュの外枠を囲った形になっているではありませんか!!

これのせいで、突き刺さっている棒のコライダが起動時に衝突検知してしまい、そのあとは衝突中判定になっていたのですね。ナンテコッタイ。
コライダの形を簡易化しているってことなのかな。

コライダの形を変えたくない場合はConvexをオフにする

ではどうすれば良いかというと、コライダの形をメッシュ通りにしたいオブジェクトについては、Convexをオフすれば良いようです。
今回は衝突したときに、イライラ棒に電流を流したい(バイブレーションさせる)ので、イライラ棒だけConvexをONにしました。
コライダの形も、まあなんとか。

f:id:s44511173:20190904163334p:plain

前後の四角いコライダは、イライラ棒すっぽ抜け検知用です。

コライダの形を変えたくないけどMesh Collider同士を衝突させたい

そんな無茶な要望に応えてくれるアセットもあるようです。しかも無料!!

kan-kikuchi.hatenablog.com

こちらのサイト様で紹介されていました。
もっと早く気づけばよかった・・・!!
Mesh Colliderを作るのではなく、他のColliderを組み合わせてメッシュと同じ形状を再現してくれるそうです。スバラシイ!!

結論

  1. メッシュに合わせてコライダを作ってくれる。それがMesh Collider。
  2. Mesh Collider同士の衝突判定では、Convexをオンにしよう。
  3. Convexをオンにすると、メッシュ通りのコライダにならないので注意。
  4. アセットもあるよ!

 

 

↑↑↑ ぜひ遊んでみてください!↑↑↑

 

【VR】【Unity】Oculus Questで手が動かせない【2019/11/18更新】

【2019/11/18更新】

せっかくOculus Quest用アプリがビルドできるようになったのに
手のアバターが、なぜだか動いてくれないの。。。

Oculus Integrationのバージョン

2019/08/27現在で最新の1.39を使用しています。
いろんなサイト様で、何もせずとも手のアバターが動作していることから
古いバージョンだと問題ないのかもしれません。

対応方法

qiita.com

こちらのサイト様を参考にさせていただきました。
公式にも手順が書かれております。
Oculusの公式ページを埋め込みリンクにすると、めっちゃ素っ気ないw

developer.oculus.com

  1. まず最初に、シーンに配置したOVR CameraRigのインスペクタで、OVR Manager>Target DevicesのElementをQuestにします。
  2. 次に、Oculusメニュー>Tools>Remove AndroidManifest.xmlを選択します。
  3. さらに、Oculusメニュー>Tools>Create store-compatible AndroidManifest.xmlを選択します。順番は守ってね!
  4. すると、 Assets/Plugins/Androidフォルダの下に、AndroidManifest.xmlが生成されています。これには、以下が記述されているはずです。
    <uses-feature android:name="android.hardware.vr.headtracking" android:version="1" android:required="true" />
  5. AndroidManifest.xmlの<intent-filter>タグ内に、以下を追加します。
    <category android:name="android.intent.category.LAUNCHER"/>

これで、ようやっと手が表示されるようになりました!
長かったよぉぉ。

■2019/11/18更新■

Oculus Integration 1.42を使用した場合、上記手順を踏まなくても手のアバターが動作しました!!
いつの間にアップデートされたのでしょうか。
動かなくなるのが怖くて、ずっと古いバージョンを使っていました・・・反省!!

結論

  1. Oculus Integrationがバージョンアップしたら、動きが(結構)変わる(かも知れない)ことを覚悟しておこう。
  2. 探せば、先駆者様が絶対にいる!めげずにググろう!(今回、かなり泣きそうになったw)
  3. Oculus Integration 1.42を使えば、本記事の手順を踏まなくとも手のアバターが動作します!!

 

 

↑↑↑ ぜひ遊んでみてください!↑↑↑

【VR】【Unity】Oculus Questアプリをビルドする

つつつ、ついに買っちゃいました!
Oculus Quest!!!
PSVRを持っているので、Oculusを買うことは無いかなと思っていたのですが
開発に使うってことで(言い訳?)。

ということで今回は、UnityでOculus Quest用にビルドする方法を備忘録として載せておきます。

Unityのバージョンを確認する

これ、めっちゃ大事。
ぶっちゃけ自分、これのせいで半日無駄にしました(涙)

developer.oculus.com

上記ページに書かれているのですが、推奨されているUnityのバージョンは以下となっております。

  • 2017.4 LTS
  • 2018.4 LTS
  • 2019.1.2f1

そう、私はちょうどこの時、Unityのバージョンをアップグレードしたばかりだったのです!!(2019.2.0f1)
これのせいで、ビルドが失敗していたものと思われます。
なお、2019.1.2でビルドしたら成功するようになりました。

Oculus Integrationをインポートする

assetstore.unity.com

お次に、任意のUnityプロジェクト を作成して、Oculus Integrationをインポートします。そうすると、諸々必要なコンポーネントと共に、たくさんのサンプルシーンもインポートされます。今回はその中から、Assets>Oculus>AampleFramework>Usage>DistanceGrabを開きます。

Unityプロジェクトの設定を変更する

あとはおなじみ、Android向けの設定をプロジェクトに施します。

  1. Build Settings>platformでAndroidを選択し、Switch Platformボタンを押す
  2. Player Settings>Company NameとProduct Nameを任意のものに変更します。
  3. Player Settings>XR SettingsのVirtual Reality Supportedにチェックを入れ、Virtual Reality SDKsの+ボタンからOculusを選択します。
  4. Player Settings>Other Settings>Identification>Minimum API Levelを19~にする。
  5. ヒエラルキビュー上のOVRPlayerController>OVR CameraRigのインスペクタで、OVR Manager>Target DevicesのElement 0をQuestに変更する。
  6. Player Settings>Other Settings>Identification>Package Nameを設定する。
  7. Player Settings>Other Settings>Rendering>Graphics APIsからVulkanを削除する。これを削除しないと、ビルド時にエラーとなります。

Oculus Questを開発者モードに変更する

Oculus Questを接続したOculusアプリの設定からその他の設定>開発者モードを開き、開発者モードをONにします。その際、団体登録を促されますので、登録しましょう。

次に、Oculus QuestをPC(Windows10)に接続します。Oculus側に接続受け入れ許可を聞くダイアログが表示されますので、許可します。

うまく進まないな?と思ったら、Oculus Questを再起動してみます。私もどこかのタイミングで再起動しました(詳細失念・・・)。

ビルドしてOculus Questにapkをインストールする

Build And Runでも、ビルド後にadb installコマンドでもOKです。前者の場合、自動的に実行されています。後者の場合、Oculusのライブラリ>提供者不明のアプリ内から起動します。

結論

  1. Windows10!Unityは2017.4/2018.4/2019.1.2!これ大事!!(実はWindowsでもハマっていたのは内緒だ)
  2. Oculusの提供しているアセットがあるので、それを使う
  3. Oculus Questを開発者モードにする
  4. HMDをかぶる時は、机の上を片付けよう。特に飲み物類!

 

 

↑↑↑ ぜひ遊んでみてください!↑↑↑

【C#】NULL条件演算子について

し、し、知らなかった。

C#6.0以降、null条件演算子なるものがあったってことを・・・。

事の発端

github内のソースを見ていて、ふと目にとまったコードがありました。

  var str = val?.ToString();

こんな風に書かれている箇所がありまして。
これ、なんぞや?と思ってググってみたのです。

まぁ見た感じ、nullチェックなんじゃなかろーかと思って「C# nullチェック」と
検索窓に入れてみたのですよ。
そしたら、

f:id:s44511173:20190809151749p:plain

こーんなステキな検索候補が出てくるじゃありませんか!

NULL条件演算子

さっそく「C# nullチェック 演算子」でググッた結果の一番上の記事(安直w)をオープン!そこは私のバイブル「@IT」の記事でした。

www.atmarkit.co.jp

よーするに、オブジェクトのメソッドやフィールドにアクセスする際のnullチェックを、「オブジェクト名+?」で簡略化できるよってことらしいです。

今までの書き方@自分

自分、不器用なんで。
今まで、こんな風に書いてました。

  var str = val != null ? val.ToString() : null;

これでも間違いではないのです、古い書き方だけど。(三項演算子というらしい)
若かりしころ、こんなコードを書いちゃう自分カッコ良くね?
なんてコッパズカシイことを思っていたものです。
ほんとに若かりしころの話ね。ほんとにほんとね。

ところが@IT様の記事によると、これはスレッドセーフではないと。
val!=nullでnullチェックをした時にはOKだったかもしれないが、ToString()する時点でnullになっているかも知れないと。
そりゃそうだ。むしろとっとと気づけ自分。

それと比較して、null条件演算子はスレッドセーフであるため安全ですし、コードがかなり簡略化できるので非常に使い勝手が良いです。

結論

  • C#6.0以降、null条件演算子なるものが使えるようになった
  • null条件演算子はスレッドセーフ
  • 三項演算子はスレッドセーフではない
  • 常にスレッドセーフを考慮してコーディングしましょう@自分

 

 

↑↑↑ ぜひ遊んでみてください!↑↑↑

【Unity】複数の警告を無視する

インスペクタからオブジェクト等をセットする際、public変数にする方法と、privateで[SerializeField]属性をつける方法があります。
私は後者をよく使うのですが(ボッチ開発だけどpublicは使わないw)、スクリプト内で初期値を設定していないとwarningが出るんですよね。
これを踏まえて、警告を制御する方法をご紹介します。

  • Unityバージョン:2019.3.0a8
  • ランタイム:.NET4.x

[SerializeField]privateするとどうなるか

f:id:s44511173:20190724123036p:plain

上図のような警告がコンソールに表示されます。
出ている警告は、CS0649ですね。これは「値が割り当てられていない、初期化されていないプライベート フィールドまたは内部フィールドの宣言が検出されました。」という警告です。

docs.microsoft.com

スクリプト内で警告を制御する(C#

 これを消す手段の一つとして、スクリプト内で警告を制御する方法があります。
警告が出ているスクリプトファイル内で、次を宣言します。

#pragma warning disable 649

ただし、警告が出ているすべてのスクリプトファイル内で宣言する必要があるため、ちょっとめんどくさいですよね。

csc.rspファイルを作る

便利な方法として、Assets/csc.rspファイルを作成し、以下を記述します。

-nowarn:0649

csc.rspとは、defineをグローバルに定義できるファイルのようです。
つまりここに警告無視を宣言しておけば、すべてのスクリプトで参照されるということになります(多分・・・)。
なお、.NET3.5以下を使用している場合はcsc.rspではなく、msc.rspファイルになるようです。

docs.unity3d.com

 

結論

  • privateな[SerializeField]は、警告が出る
  • 警告を消す方法は、該当ファイルに「pragma・・・」を定義する方法と、Assets/csc.rspに「-nowarn・・・」を定義する方法とがある
  • .NET3.5以下の場合、msc.rspを使用する

 

atelier-hinata.hatenablog.com

【Unity】ゴールしたアイテムの色を変える

f:id:s44511173:20190719114403g:plain

床に転がっている時、Cubeは緑色をしています。
ゴールした時、赤に変わっていますね。
今回は、この手法についてご紹介します。

マテリアルを作成する

オブジェクトの色は、マテリアルで設定します。
※Physic Materialではありません。ただのMaterialです。
Projectメニュー>Materialを選択し、マテリアルを新規作成します。

f:id:s44511173:20190719160748p:plain

色々設定項目がありますが、今回はそのまま!
色だけを設定します。
Albedo項目をクリックするとカラーピッカーが表示されるので、色を指定します。
さらにゴール用にマテリアルをもう一つ作成し、色を赤にします。

スクリプトからマテリアルを変更する

アイテムがゴールしたら、スクリプトからマテリアルを変更します。
アイテムにアタッチされているスクリプトに、以下を追加しましょう。
※新しくスクリプトを作成してアイテムにアタッチしてもOK

/// <summary>
/// インスペクタからゴールマテリアルをセット
/// </summary>
[SerializeField]
private Material goalMat; 

/// <summary>
/// 衝突した際にコールされる
/// </summary>
/// <param name="collision">衝突した相手のコライダ</param>
private void OnCollisionEnter(Collision collision) {
    if(collision.gameObject.tag == Defines.GoalTag) {
        GetComponent<MeshRenderer>().material = this.goalMat;
    }
}

実行する前に、上記のスクリプトのインスペクタでゴールマテリアルをセットするのをお忘れなく!
私はよく忘れてUnity様に怒られます・・・。

これで、ゴールしたアイテムの色が変わるようになりました!

結論

  • オブジェクトの色は、マテリアルで設定する
  • マテリアルはスクリプトから変更できる
  • スクリプトのインスペクタで、オブジェクトをセットするのをよく忘れるw

 

 

 

【Unity】カメラに映るオブジェクトを制限する

f:id:s44511173:20190719151226g:plain 

machokoさんゲームで集めるアイテムを、ゲーム画面の左上に表示(案内アイテム:動画内の赤丸部分)しています。
カメラがmachokoさんに合わせて移動しているにも関わらず、案内アイテムはまるでUIのように、同じ位置に同じ大きさで描画され続けています。
今回はこの手法について、ご紹介します。

案内アイテム用のカメラを作成する

案内アイテムは、あたかもUIのように同じ場所に留まって描画したい。
そんな気持ちにこたえるために、案内アイテム専用のカメラを作っちゃいます。
カメラ作成は、ヒエラルキウィンドウ>メニュー>Cameraで作成できます。

f:id:s44511173:20190719140843p:plain

案内アイテム用のカメラは、machokoさんに追随する必要はありませんので、SmoothFollowはアタッチしません(メインカメラにはアタッチしている)。

また、カメラを新規作成すると、Audio Listenerがくっついてくるんですね。
これはサウンドを出力するいわばラジカセ(古い・・)みたいなもので。
メインカメラにすでについている場合は、削除しちゃいます。
※複数あると、実行時にコンソールにメッセージが出まくってウザいです。

 

レイヤを作成する

さて、カメラが複数できたところで、全てのアイテムを全てのカメラで写す必要はないですよね。
そこで活躍するのが、レイヤの概念です。
レイヤとは「階層」の意味を表しています。Photoshopとかにもありますよね。
Unityのレイヤは、カメラのレンダリング対象選別だけでなく、衝突対象の制限などにも使うことができちゃう、優れものです。

 

f:id:s44511173:20190719135449p:plain

案内アイテムのインスペクタの右上に、Layerのドロップダウンがあります。
この最下段の「Add Layer...」を選択すると、Tags & Layers画面が表示されますので、「UI 3D Layer」を追加します。

f:id:s44511173:20190719135703p:plain

これでレイヤ作成は完了です。

 

レイヤを設定する

f:id:s44511173:20190719135403p:plain

案内アイテムのインスペクタに戻り、Layerドロップダウンから「UI 3D Layer」を選択します。
これで、案内アイテムのレイヤが設定できました。

 

メインカメラのレンダリング対象を設定する

f:id:s44511173:20190719153804p:plain

メインカメラのインスペクタで、Culling Mask項目を開きます。
これはカメラのレンダリング対象のレイヤを設定できる設定項目です。
ここで、先ほどのUI 3D Layerをレンダリング対象外とします。
※上図では、UIレイヤも対象外としています。

案内アイテム用カメラのレンダリング対象を設定する

f:id:s44511173:20190719153935p:plain

案内アイテム用のカメラも同様に、Culling Maskの設定を行います。
レンダリング対象をUI 3D Layerのみとします。
※上図ではUIレイヤも対象としています。 

これらの設定で、同一個所に同一サイズで描画される案内アイテムが実現できました!

 

結論

  • シーン内にカメラを複数設置するこができる
  • カメラのレンダリング対象は、レイヤで選別できる
  • カメラを複数設置することで、いろんな描画ができそう!

【Unity】ゴール判定する

f:id:s44511173:20190719114403g:plain

machokoさんが運んだアイテムは、ゴール内の床に接地することでカウントされます。今回はこれについて、ご紹介します。

ゴール床にコライダを追加する

f:id:s44511173:20190719122028p:plain

今回はゴール床はPlaneオブジェクトを使っているので、あらかじめコライダがついています。もしついていないオブジェクトを使っている場合のみ、追加してください。

アイテムにコライダを追加する

f:id:s44511173:20190719122040p:plain

Cube、Sphere、Cylinder、Coneオブジェクトにもあらかじめコライダがついています。こちらもゴール床と同様、コライダがない場合のみ追加してください。なお、ConeはProBuilderで作成しました。

スクリプトで衝突判定を検知する

コライダで衝突を検知すると、衝突イベントが発生します。イベントを受け取るには、以下のメソッドを必要に応じてオーバーライドします。

  • OnCollisionEnter・・・衝突したときに呼ばれる
  • OnCollisionExit・・・衝突が終了したときに呼ばれる

なお、コライダのIsTriggerをtrueにしている場合は、OnTriggerEnter/OnTriggerExitを使用します。IsTriggerは衝突を検知するのみで、衝突した結果の物理動作を行わない場合にtrueにします(ぶつかっても跳ね返らないようにしたい場合など)。

 

衝突した相手の情報を取得し、ゴール床であればゴール判定とするスクリプトをアイテムにアタッチします。

/// <summary>
/// 衝突した際にコールされる
/// </summary>
/// <param name="collision">衝突した相手のコライダ</param>
private void OnCollisionEnter(Collision collision) {
    // 衝突した相手のタグを確認する
    if(collision.gameObject.tag == Defines.GoalTag) {
        // ゴール処理
        GoalEvent.Invoke();
    }
}

 

 結論

  • ゴール判定は衝突判定を使う
  • 衝突判定には、コライダを使用する
  • ConeオブジェクトはProBuilderで作成できる
  • コライダのIsTriggerは、衝突した結果の物理動作を行いたくない場合にtrueにする

【Unity】GameObjectをバウンドさせる

f:id:s44511173:20190718125404g:plain

ステージ開始直後、machokoさんが集めるアイテムが空から降ってきます。降ってきたアイテムは、床に落ちるとバウンドしていますね。

今回は、このバウンドについてご紹介します。

Physic Materialを利用する

Physic Materialとは、物理特性マテリアルのことを指しています。これをコライダにアタッチすることで、バウンド等の物理特性を追加することができます。

物理特性マテリアルは、メニューバーから Assets > Create > Physic Material を選択して作成します。

どうでもいいけど、Physicってスペルがなかなか覚えられない。あと、Quaternionも覚えられない。VS使っていれば入力候補が出てくるから問題ないけど、ブログ等で自力でスペルを書かなければいけないときは、調べないと書けないw

あーそうか、入力候補が出てきちゃうから覚えられないのか・・・。

パラメータを調整する

Physic Materialのパラメータには、以下があります。

  • Dynamic Friction・・・移動に対する摩擦の大きさ(0~1)
  • Static Friction・・・停止に対する摩擦の大きさ(0~1)
  • Bounciness・・・バウンドの大きさ(0~1)
  • Friction Combine・・・摩擦の計算方法
  • Bounce Combine・・・バウンドの計算方法

数値だけで動きを想定するのは難しいので、実際に動かしてみて、いろいろ調整してみるのが良さそうです。今回は、次のように設定しました。

 f:id:s44511173:20190718131439p:plain

 初期値から、Bouncinessしか変えていませんwそれでもなんとなく、うま~い具合に動いてくれちゃうのがUnityのすごいところ!

 f:id:s44511173:20190718131640p:plain

作成したコイツを、バウンドさせたいアイテムのコライダのMaterialにD&Dすれば完了です!なんてすばらしいw

 

結論

  • 物体をバウンドさせたい時は、Physic Materialを使用する
  • Physic Materialのパラメータは、実際に動かしながら調整するのが良い
  • VSの入力候補は、人間をダメにする(そんなことはない)

【Unity】シーンをまたいでBGMを鳴らし続ける

f:id:s44511173:20190718113740g:plain

machokoさんゲームは、タイトルからエンディングまで、一貫して同じBGMが流れ続けています。

ゲームシーンは①タイトル②チュートリアル③ゲーム④エンディングの4つありますが、同じBGMを途切れさせずに流し続ける方法をご紹介します。

DontDestroyOnLoad指定する

BGMを途絶えさせたくない場合、BGMのAudioSourceを持つGameObjectをシーン切り替え時に削除しなければ良いわけです。

GameObjectを削除しないようにするには、DontDestroyOnLoadメソッドを使用します。

private void Awake() {
    DontDestroyOnLoad(this.gameObject);
}

こんな感じに実装してやります。

ところが、これだけだとGameObjectが削除されないために、同じシーンを再度ロードした際にGameObjectがもう1個生成されてしまいます。

static変数を活用する

この現象を避けるために、static変数を利用します。

static変数とは、プログラム内で唯一の実態を持つ変数です。たとえば、staticなフィールドを持つクラスを複数作成したとします。クラスが複数できてもstaticなフィールド自体は実態が1つしか存在しないため、 クラス全員で同じ唯一の値を参照できることになります。

 static変数を使って、GameObjectがすでに生成されていた場合に自らを破棄するプログラムを書いてみます。

private static bool isLoad = false;// 自身がすでにロードされているかを判定するフラグ
private void Awake() {
    if (this.isLoad ) { // すでにロードされていたら
        Destroy(this.gameObject); // 自分自身を破棄して終了
            return;
        }
    this.isLoad = true; // ロードされていなかったら、フラグをロード済みに設定する
    DontDestroyOnLoad(this.gameObject); 
}

 

こうすることで、シーンをまたいでBGMを鳴らし続けることができます。

これはAudioSourceに限らず、シーンをまたいでGameObjectを使用したい場合に有効な手段となります。

 

結論

  • 新しいシーンのロード時にGameObjectを破棄したくない場合、DontDestroyOnLoadを使う
  • DontDestroyOnLoadを使う際は、シーン再ロードでGameObjectが増殖しないようにする必要がある
  • static変数は、プログラム内で唯一の実態を持つ変数

【Unity】カメラをキャラクターに合わせて動かす

f:id:s44511173:20190717170712g:plain

 

machokoさんの動きに合わせて、カメラが移動しています。これは、StandardAssetsのSmoothFollowスクリプトをカメラにアタッチして実装しています。

SmoothFollowをインポートする

f:id:s44511173:20190717172812p:plain

 StandartAssetsをダウンロードし、インポートします。全部インポートしても良いのですが、今回はピンポイントでSmoothFollowスクリプトのみとしました。SmoothFollow.csは、Standard Assets->Utility下にあります。

ちなみに一部だけインポートすると、インポートしたアイテムが他のアイテムを参照している場合に参照エラーが起きてしまうので、注意が必要です。

 メインカメラにアタッチする

f:id:s44511173:20190717174734p:plain

 先ほどのSmoothFollow.csをメインカメラにアタッチします。インスペクタのAddComponentボタンでも良いし、ヒエラルキーウィンドウにD&DでもOKです。ちなみに私は後者派です。

パラメータを調整する

メインカメラのインスペクタから、 SmoothFollowのパラメータを調整します。

  • Target・・・カメラが追随するターゲットを設定します。
  • Distance・・・カメラとTargetとの距離を設定します。
  • Height・・・Targetからの高さを設定します。
  • Rotation Damping・・・回転速度
  • Height Damping・・・上下移動速度

カスタマイズする

machokoさんがゴール中に入ると、カメラが手前に来すぎてしまい、ステージが見切れてしまう現象が起きました。

 

f:id:s44511173:20190717181013p:plain

これを防ぐために、SmoothFollow.csを少しだけカスタマイズ。

SmoothFollow.csでは、LateUpdateメソッド内でカメラ位置を調整しています。これを、以下のように修正しました。

[SerializeField]
private float zLimit; // Z位置をインスペクタから設定
void LateUpdate()
{
   // ~略~
   // transform.position = new Vector3(transform.position.x ,currentHeight , transform.position.z);
 transform.position = new Vector3(transform.position.x ,currentHeight , Mathf.Max(transform.position.z, zLimit));
}

f:id:s44511173:20190717181023p:plain

 

 結論

  • カメラでターゲットを追随するには、StandardAssetsのSmoothFollowを使うと便利
  • インポートしたスクリプトは、自分好みにカスタマイズしよう
  • アセットは、使うもののみインポートすることができるが、参照エラーが出る場合があるので要注意