Raspberlyのブログ

Raspberlyのブログ

Unityネタをメインとした技術系ブログです。にゃんこ大戦争や日常なども。そろそろブログタイトル決めたい

【Unity】画面遷移時のアイリスイン・アイリスアウトを実装する

今回はUnityネタをやっていきます。
ゲームやアニメでよく見るアイリスイン・アイリスアウトをUnityで実装してみます。

 

 

 

アイリスイン・アイリスアウトとは

ゲームやアニメで画面を切り替えるときに使われる演出の一つです。
画面を少しずつ広げたり絞ったりして暗転させます。(閉じるのがアウト、開くのがイン)

2つ合わせてアイリスショットと言ったりしますね。
今回はこれをUnityで実装してみます。

 

 

 

必要なパッケージとアセットのインストール

UnmaskForUGUIというパッケージを使います。
これを使うと反転したマスクを作成できます。

github.com

 

Unity Package Managerからインストールする場合は、このURLを打ち込めばOK

https://github.com/mob-sakai/UnmaskForUGUI.git

 

 

また、UIアニメーションにDOTweenを使用します。

 

 

 

 

アイリスイン、アイリスアウトを実装する

ここから本題。

Canvasの作成

アイリスイン・アイリスアウトに対応したCanvasを作成するエディター拡張が用意されています。
Hierarchyビューを右クリックして、UI/Unmask/IrisShotを選択。

 

これでシーン内にCanvasが作成されます。
ちなみにCanvasScaleModeConstantPixelSizeなので最初にScaleWithScreenSizeに直しておくといいかも。

 

Canvasの構成

Hierarchyビューはこんな感じ。
Unmaskはアイリスイン・アイリスアウト用の反転したマスク
Screenは画面を覆うパネルです。

 

Screenはデフォルトで半透明になっています、画面遷移に使いたいので単色塗りつぶし状態にしておきます。

 

Unmaskを移動させたり、Scaleを変えるとすでにそれらしい動きが実現できます。

ちなみにデフォルトのSpriteはサイズが小さく、
拡大するとかなりガビガビなので大きいSpriteを用意して差し替えた方がいいです

私はUI Builderというアセットにある円のSpriteを使用します。
これはまあ、サイズの大きいSpriteがあればなんでもいいです

 

 

TweenScript

最後にScriptでアイリスイン・アイリスアウトの動きをつけます。
前述した通り、DOTweenを使用しています。
以下のIrisShot.csを作成。IRIS_IN_SCALEはUnmaskが画面から見えなくなる大きさに調整します

using UnityEngine;
using DG.Tweening;

public class IrisShot : MonoBehaviour
{
    [SerializeField] RectTransform unmask;
    readonly Vector2 IRIS_IN_SCALE = new Vector2(30, 30);
    readonly float SCALE_DURATION = 1;

    public void IrisIn()
    {
        unmask.DOScale(IRIS_IN_SCALE, SCALE_DURATION).SetEase(Ease.InCubic);
    }

    public void IrisOut()
    {
        unmask.DOScale(new Vector3(0, 0, 0), SCALE_DURATION).SetEase(Ease.OutCubic);
    }
}

 

これを適当なオブジェクトにアタッチし、Unmaskを紐づけます。


これで準備完了。
IrisIn()、IrisOut()を呼び出すとこんな感じ。

画面遷移にぴったりなアイリスイン・アイリスアウトが実装できました。

 

 

TweenScript(応用)

今度はちょっと応用。
Unmaskにキャラクターの画像*1を設定し、シルエットを出すようにします。


Scriptにも手を入れ、跳ねるようなアニメーションを作ります。

using UnityEngine;
using DG.Tweening;

public class IrisShot2 : MonoBehaviour
{
    [SerializeField] RectTransform unmask;

    readonly Vector2 IRIS_IN_SCALE = new Vector2(15, 15);
    readonly Vector2 IRIS_MID_SCALE1 = new Vector2(0.8f, 0.8f);
    readonly Vector2 IRIS_MID_SCALE2 = new Vector2(1.2f, 1.2f);

    public void IrisIn()
    {
        unmask.DOScale(IRIS_MID_SCALE2, 0.4f).SetEase(Ease.InCubic); ;
        unmask.DOScale(IRIS_MID_SCALE1, 0.2f).SetDelay(0.4f).SetEase(Ease.OutCubic);
        unmask.DOScale(IRIS_IN_SCALE, 0.2f).SetDelay(0.6f).SetEase(Ease.InCubic);
    }

    public void IrisOut()
    {
        unmask.DOScale(IRIS_MID_SCALE1, 0.2f).SetEase(Ease.InCubic);
        unmask.DOScale(IRIS_MID_SCALE2, 0.2f).SetDelay(0.2f).SetEase(Ease.OutCubic);
        unmask.DOScale(new Vector2(0, 0), 0.4f).SetDelay(0.4f).SetEase(Ease.InCubic);
    }
}

 

これで準備完了。
IrisIn()、IrisOut()を呼び出すとこんな感じ。

かわいいゲームにぴったりなアイリスイン・アイリスアウトが実装できました。

 

背景の変更

Unmaskだけでなく、ScreenにもSprite*2を設定できます

 

変えてみるとこんな感じ。

 

 

 

まとめ

UnmaskForUGUIを使ってアイリスイン・アイリスアウトを実装しました。
今回は使用しませんでしたが、Sprite以外にもTextを反転したマスクとして使うこともできます。
画面遷移の演出にぜひ活用してみてください。

 

 

以上です。

 

© Unity Technologies Japan/UCL

*1:ユニティちゃんHD画像パック Vol.1を使用

*2:UniteJapan2014 Wallpaperを使用

Unity Package ManagerのGit URLからパッケージをインストールしようとしたら出るエラーの解決方法

個人的な忘備録。
Unity Package Manager(UPM)のGit URLからパッケージをインストールしようとしたらエラーが出て困ったときの解決方法

 

Unityのバージョンは2021.3.12f1(多分関係ないはず)
OSはWindows10です。

 

 

解決方法

先に解決方法から載せると、
システムの環境変数にGitのパスを設定すれば解決しました

 

 

 

状況とエラー内容

Unity Package ManagerでUniTaskをインストールしようとしたらエラーがエラーが出てインストールできない。

 

エラー内容は以下の通り

[Package Manager Window] Cannot perform upm operation: Unable to add package https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask:
  No 'git' executable was found. Please install Git on your system then restart Unity and Unity Hub [NotFound].
UnityEditor.EditorApplication:Internal_CallUpdateFunctions ()

 

[Package Manager Window] Error adding package: https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask.
UnityEditor.EditorApplication:Internal_CallUpdateFunctions ()

 

「Gitの実行ファイルが見つからないから、GitをインストールしてUnityとUnity Hubを再起動してね」
と言われています。Gitはインストール済なのに。

 

 

 

 

解決方法

Unity Forumとこちらの動画の方法で解決

forum.unity.com

youtu.be

 

この動画の通りに進めてみます。

 

git.exeがあるフォルダのパスを確認

git.exeが置いてあるフォルダを調べ、そのパスを控えておきます。


git.exeは複数ありますがcmdフォルダ*1にあるものを使います。
私の場合は「C:\Program Files\Git\cmd」でした。このパスをコピーしておきます。

 

 

環境変数に設定

Windowsの検索窓にPathを入力。
検索結果に「システム環境変数の編集」が出てくるので開きます。

 

システムのプロパティというウインドウが開かれるので、環境変数を押します。

 

するとこんな画面が出ると思います。表示されている内容は人によって異なりますが。

 

ここでシステム環境変数からPathを選択し、編集ボタンを押します。

 

環境変数名の編集画面が開きます。

 

右上の新規ボタンを押します。

 

新しい環境編のパスを入力する欄ができるので、そこに先ほどのgit.exeのあるcmdフォルダのパスを入力

最後にOKを押します。

 

 

これで完了です。
UnityとUnity Hubを全て開きなおすとUPMからパッケージをインストールできました。

 

 

 

 

参考になりそうな記事

www.hanachiru-blog.com

 

baba-s.hatenablog.com

 

 

*1:binフォルダでもよさそう

【イベントレポ】: ゲームメーカーズ スクランブル

イベントのレポート(メモ)です。
参加したのは「ゲームメーカーズ スクランブル」
会場は大崎ブライトコアホールです。

connpass.com

ハッシュタグ : #ゲームメーカーズスクランブル

 



 

ゲームメーカーズ スクランブルとは

「ゲームメーカーズ スクランブル」は、ゲームづくりに関わる方同士で盛り上がるための完全無料のリアルイベントです。

ゲームづくりに関する全10講演のセミナーイベントや、Unreal Engine 5Blenderを使ったゲーム開発初心者向けのハンズオン、プロに聞けるなんでも相談所、講演者とも交流可能な懇親会など、さまざまなイベントを用意して皆さまをお待ちしています!

gamemakers.jp

 

ホールが2つに分かれていて、それぞれで講演が行われます。(公式サイトから引用)

 

 

以下講演の感想。
後々、ゲームメーカーズで資料は公開され、講演内容はログミーでまとめられるようです。

1.『作り方』から考えるゲームデザイン

2つあるゲームデザイン講演の内の1つ。こっちは企画寄り
講演者の代表作、それらのこだわりポイントについての内容でした。

 

質疑応答の内容は公開しないでとのことなので詳しくは書けませんが、
会社の文化は会社ごとに違う」という所で多くの人がめっちゃうんうん頷いてたの面白かった。

 

 

 

2. すぐに役立つ!ゲームデザイン

2つあるゲームデザイン講演の内の1つ。こっちは現場での開発寄り
ゲームデザインという言葉の定義と、プレイヤーの介入要素を3つに分けて活かす方法についての内容。

 

 

実際にゲームを例にしてゲームデザインを行う解説がとてもわかりやすかったです

  • 雑魚敵が無造作に出てくるボス戦がある
  • 雑魚敵の存在が不評(邪魔でいらないという声)、だが雑魚敵が沸かないようにしたらボス戦のコンセプトが崩れる
  • 不評の理由を分析すると、「雑魚敵が無造作に沸くためプレイヤーが予測できず、事前に戦術を立てられない」ためストレスを感じるということがわかった
  • 雑魚敵の挙動をプレイヤーが予測しやすいように変える
  • ボス戦前に、その雑魚敵単体と戦える場を用意して、プレイヤーが学べるようにする

→ これで雑魚敵を残したまま問題を解決できる

 

プレイヤーが「ゲームに介入(操作を入力)する前に何を考えているか」、「介入した後はどういう評価をするか」を分析する方法は結構使えそう。

 

 

質疑応答であった、死にゲーでリスポーン地点とボス部屋をあえて遠くする時の意図というのもおもしろかった。
(近いとリトライが早い分適当にプレイしだす。リトライに時間がかかるというリスクを与えると緊張感をもってプレイヤーが遊んでくれる~みたいな話だったと思う)
こういう分析ができるのすごい。

 

 

 

3. ゲームのUIってどうやって作るの? ~チラ見せ!プロの開発テクニック~

ゲームのUIを作るワークフローについての内容。
仕様の作成(UIの目的、UIの機能、UIの画面要素)、配置、色の配分などなど。
操作できる部分をわかりやすくする、表示する情報と見せ方(情報を多くしすぎない)を工夫するというのはとても大事ですね。

 

UIの勉強方法も紹介されていて、たくさんゲームを遊んで、気に入ったUIを作ってみるのがいいとのこと。

この本もすごく勉強になるらしい!!!!!

www.shoeisha.co.jp

 

 

 

4. ゲームエンジンからステップアップ!”オブジェクト指向”早わかりガイド

オブジェクト指向に関する講演。
公演内でも言われていましたが、初歩的な内容なのでこれを元にステップアップをするのがよさそう。

 

講演内容はこちらの書籍を参考にしているみたい

bookplus.nikkei.com

講演者の方は業界2年目のことですが、私だったら固まってしまいそうな質問にもスラスラ答えててすごいと思った。
講演のテーマ的にマサカリありそうとは思ってた

 

 

 

5. ゲーム業界のワークフローに学ぶ、ゲームを作り始める前に知っておくべきこと

エターナらない(ゲームが完成しない状態にしない)ために、どうやってゲーム開発を進めるかという内容。

  • 最初は豆腐(仮素材の白いCube)でゲーム開発を進める、素材を作りこむのは後
  • ゲームは骨子から作る、作りたいものから作り始めるとエターナる
  • 骨子があれば、それは最低限のゲームになる
  • ゲームに完成はない、いくらでも機能を追加できる。締め切りが来た時それが完成。
  • 締め切りがきてもいいように骨子から作る

 

 

バーティカルスライスという単語も初めて知りました。

zenn.dev

 

 

豆腐で思い出しましたが、バイオハザード2で豆腐の隠しキャラクターがいるのも当たり判定に豆腐のような白いモデルを使っていてそれを流用したからという理由があったりします。

私も仕事・個人開発問わずプロトタイプを作る時は白いCubeを使うことが多いですね。
(キャラクターにそのままCubeやCapsuleを使うと、どっちを向いているかわからないので、正面方向にもう一つちっちゃいCubeやSphereをくっつけるという工夫をよくします)

 

 

 

懇親会

終わった後は懇親会、食べ物がオシャレ!

イベントの仕組み上全部の講演は見られないので、違う講演を見た人相手に面白かった講演をプレゼンし合ったりしました。

 

 

 

感想

どの講演もすごいおもしろかったです。
個人的に「すぐに役立つ!ゲームデザイン」が一番良かった。
ゲームデザインの問題点を分析して解決する手法はかなり使えそう。


全体的に質疑応答の時間が長めに取られていて、それらの回答もおもしろかった。
(講演の補足になるものからxxxなものまで)
講演者の方どんな質問もスラスラ答えてるの凄すぎる。

 

講演以外では、書籍の販売・ゲーム開発現場で読まれている書籍の展示ブースもありました。
重いしかさばるから講演が全部終わった後に買おうとしたらその時には撤収中だった( ˘ω˘ )

 

 

好きなゲームを自由に貼れるボードがあるのも特徴
OMORIをすこれ

 

 

おわり

最初に書きましたが、このイベントはゲームメーカーズが開催するイベントです。
いろんな記事があるのでみんな見てね!

 

イベントカレンダーもすっごい有用、Unity1週間ゲームジャムも載ってる!

gamemakers.jp

 

 

 

以上です。

【アセット紹介】Play Mode Saver でPlay Mode中に変更したパラメータを保持する【Unity】

今回はアセットの紹介をしていきます。
紹介するのはPlay Mode Saver
Play Mode中に変更したパラメータを終了後も保持するアセットです。

screenshot

どんなアセット?

Play Mode中に変更したパラメータ(Transformの値など)を、Play Modeが終了した後も保持するアセットです。

 

通常、Play Mode中に変更したパラメータはPlay Modeを終了すると元通りになります。
どうしても保存したい場合、InspectorビューでCopy ComponentしてPlay Modeが終わった後Pasteするというやり方がよく使われます。
このアセットを使えば、それらの保存を簡単に行えます。

 

※レビューによると、Unity 2022.2ベータ版以降では動作しない可能性があります
1年以上更新されていないのでそこは注意

 

 

実行環境

Unity 2021.3.12f1

Play Mode Saver ver1.3.5

 

 

インポートの確認

アセットインポート完了時はこんな感じ。

初期設定とかは必要なし。すぐに実行できます。

 

 

実際に試してみる

基本的な使い方

Unity Editorのメニューから、Window/Play Mode Saverを押して、Play Mode Saverウィンドウを開きます。

 

このウインドウはPlay Mode中にのみ機能します。

 

Play Mode中にScene内のGameObjectをドラッグ&ドロップすると、保持対象として登録され、
Play Modeが終了した時、その瞬間のパラメータが全て保持されます
保存するタイミングは後述のSave Modeにより異なります。

 

ちなみにInspectorビューからドラッグ&ドロップして、特定のコンポーネントだけ対象にすることもできます。
GameObjectを丸ごと登録すると影響範囲が大きいため基本はコンポーネント単位でやったほうがいいかも。

 

ちなみにドラッグ&ドロップ以外にも、GameObjectやコンポーネントを右クリックして登録することもできます。
ドラッグ&ドロップと違い、後述するSave Modeを直接指定できます

この時、ウインドウが開いていない場合は自動的に開かれます。

 

 

Save Mode(保存形式)の違い

Save Mode(保存する形式)は2種類あります。
Save Modeの違いにより保存されるタイミングが違います。

Save on Exit

Play Modeが終了した時のパラメータを保持するモード。

所感ですが、終了時にパラメータがどういう風になるか予想できない場合は使わない方がいいです。

 

Snapshot

Save Snapshotが押されたタイミングのパラメータを保持するモード。

Save on Exitよりは安全。
Play Mode中に一時停止して、きちんと想定した値になっているかを確認してから保存した方がよい
Save Snapshotした後に変更したパラメータは再度Save Snapshotしない限り無視されます。

 

Save Modeの切り替え

モードの切り替えは、同じくPlay Mode Saverウインドウ上でできます。
Save Mode部分のボタンを押すだけ。

ドラッグ&ドロップで登録した場合は、デフォルトでSave on Exitになります。

 

登録の解除方法

Play Mode Saverウインドウから、右側にある×ボタンを押すと解除されます

Unity Personalだとほとんど見えない!

 

 

あるいは、登録したGameObjectかコンポーネントを右クリックして、Forget Play Mode Changesを選択しても解除できます。

 

 

変更したパラメータを元に戻す

Play Mode Saverで変更した値は、Ctrl + Zで元に戻せます
また、Ctrl + Yで元に戻した変更を再適用できます

 

 

 

注意点

親を保持対象にすると子も保持される

親子関係にあるGameObjectで、親を保持対象とした場合、子の変更も保持されます
子オブジェクトが増えたり減ったりした場合も全て保存されます。
複雑な親子関係になっているGameObjectを扱う場合は注意しましょう

 

※子だけ保持対象にすることもでき、その場合親の変更は無視されます。

※登録したGameObjectやそれにアタッチされているコンポーネントをが削除された場合、自動的に登録も解除されます。

 

動的生成されたGameObjectを対象にした場合はそのままSceneに残る

Play Mode後、何らかの方法でSceneに動的生成されたGameObjectを保持対象に登録した場合、
そのGameObjectはPlay Mode終了後もSceneに残り続けます
コンポーネントだけ選んでもGameObjectごと残ります。

Prefabを保持対象とした場合、元のPrefab側は変化しないのでそこは安心。

 

 

 

まとめ

Play Mode Saverを使うと、Play Mode中に変更したGameObjectのパラメータが終了後も保持される
・モードは2つあり、Play Mode終了時のパラメータを保持するモードと、任意のタイミングでパラメータを保持するモードがある
・保持したパラメータを元に戻せるし、再適用も簡単にできる

 

Play Modeを終了し忘れた時だけでなく、プレイヤーの移動速度など実際にゲームを動かしながらパラメータの調整をしたい時にも便利なアセットですね。

 

 

以上です。

 

 

 

他のアセットの紹介記事はこちら↓

raspberly.hateblo.jp

 

 

 

※本記事にはAssetStoreアフィリエイトリンクが含まれています。

他、間違っている箇所、わかりにくい所がありましたらコメントにお願いします。

【エディター拡張】Projectビューの指定のフォルダにあるPrefabをListに格納する【Unity】

今回はUnityのエディター拡張をしていきます。
最近エディター拡張を書くことが多いので、自分用の忘備録です。

 

やること

Projectビューの指定のフォルダにあるPrefabを検索し、それをScriptのListに格納する

 

 

開発環境

Unity 2021.3.12f1

 

 

事前準備

先に格納したいPrefabを作成します。
Assets/Prefabsフォルダを作成し、適当にGameObjectをPrefab化しておきます。

 

 

 

Scriptの作成

以下のScriptを作成します。

ObjectList.cs

GameObject型のListがあるScript。
Listを設定する関数と空にする関数を持つ。

using System.Collections.Generic;
using UnityEngine;

public class ObjectList : MonoBehaviour
{
    [SerializeField] List<GameObject> m_List = new List<GameObject>();

    /// <summary>
    /// GameObjectのListを受け取りm_Listに格納する
    /// </summary>
    /// <param name="objects"></param>
    public void SetObjects(List<GameObject> objects)
    {
        m_List = objects;
    }

    /// <summary>
    /// m_Listを空にする
    /// </summary>
    public void Clear()
    {
        m_List.Clear();
    }
}

 

 

ObjectListEditor.cs

ObjectList.csのエディター拡張Script
プレハブをロードしてListに格納するボタンと、Listを空にするボタンを表示する。

using System.Linq;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(ObjectList))]
public class ObjectListEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        var objectList = target as ObjectList;

        if(GUILayout.Button("プレハブロード"))
        {
            LoadPrefabs(objectList);
            EditorUtility.SetDirty(objectList);
        }

        if(GUILayout.Button("クリア"))
        {
            objectList.Clear();
            EditorUtility.SetDirty(objectList);
        }
    }


    /// <summary>
    /// プレハブのロード
    /// </summary>
    static public void LoadPrefabs(ObjectList objectList)
    {
        // ロード先のディレクトリパス
        var path = "Assets/Prefabs";

        var guids = AssetDatabase.FindAssets("t:GameObject", new string[] { path });
        var paths = guids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).ToArray();
        var list = paths.Select(_ => AssetDatabase.LoadAssetAtPath<GameObject>(_)).ToList();

        if(list.Count == 0)
        {
            Debug.LogWarning("プレハブがない\n" + "検索パス[" + path + "]");
            return;
        }

        Debug.Log("プレハブを検索:" + list.Count + "つ格納\n" + "検索パス[" + path + "]");
        objectList.SetObjects(list);
    }

}

これで完成

 

実行

空のGameObjectを作成し、ObjectListをアタッチするとボタンが表示されます。
ロードボタンを押すと、指定のフォルダにあるPrefabをListに格納します



 

 

調整

以下細かい調整

読み込むフォルダの変更

ObjectListEditor.csのLoadPrefabsにある

var path = "Assets/Prefabs";

ディレクトリパスを指定しているのでここを書き換えればよし。
ここも指定できるようにしていいかも。

 

 

特定のコンポーネントがアタッチされているPrefabのみ格納する

Prefabを検索する時、特定コンポーネントがあるかWhere句を挟むとよい。
例えば、RigidbodyがアタッチされているPrefabだけ格納したいならこうする。

        // 特定のコンポーネントがあるものだけ格納
        var list = paths.Select(_ => AssetDatabase.LoadAssetAtPath<GameObject>(_))
            .Where(_ => _.TryGetComponent(out Rigidbody rigidbody))
            .ToList();

 

    /// <summary>
    /// プレハブのロード
    /// </summary>
    static public void LoadPrefabs(ObjectList objectList)
    {
        // ロード先のディレクトリパス
        var path = "Assets/Prefabs";

        var guids = AssetDatabase.FindAssets("t:GameObject", new string[] { path });
        var paths = guids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).ToArray();

        // 特定のコンポーネントがあるものだけ格納
        var list = paths.Select(_ => AssetDatabase.LoadAssetAtPath<GameObject>(_))
            .Where(_ => _.TryGetComponent(out Rigidbody rigidbody))
            .ToList();

        if(list.Count == 0)
        {
            Debug.LogWarning("プレハブがない\n" + "検索パス[" + path + "]");
            return;
        }

        Debug.Log("プレハブを検索:" + list.Count + "つ格納\n" + "検索パス[" + path + "]");
        objectList.SetObjects(list);
    }

 

AssetDatabase.FindAssets()のフィルタを使えばもっと簡単にできそうだけど、
なぜかうまくいかないのでLINQで対応しています。

 

 

 

まとめ

指定のフォルダにあるPrefabを検索し、ScriptのListに格納するエディター拡張を作りました。
Inspectorを拡張し、格納するボタンを配置しています。
Scriptを編集することで、対象のフォルダや格納するPrefabの条件を設定できます。

 

以上です。

 

 

参考資料

www.urablog.xyz

 

www.hanachiru-blog.com

 

 

 

【アセット紹介】SensorToolkit 2 でオブジェクトを検知する【Unity】

今回はアセットの紹介をしていきます。
紹介するのはSensorToolkit 2
オブジェクトを検知するセンサー機能を提供するアセットです。

 

 

セール情報

現在アセットストアではメガバンドルセールを開催中!

assetstore.unity.com

超お得に多くのアセットを入手できるチャンス!
今回紹介する「SensorToolkit 2」も含まれています。

 

どんなアセット?

オブジェクトの検知に特化したアセットです。

SensorToolkit は、Raycasts、Overlaps、Trigger Colliders などのビルトイン Unity 関数を強力に抽象化したものです。スタンドアロンのセンサー コンポーネントをゲーム オブジェクトに追加し、必要に応じて構成できます。センサーにクエリを実行して、検出対象を特定し、ターゲットの可視性や形状などの追加情報を提供できます。

皆さんがステルスゲームなどで、敵がプレイヤーを検知する仕組みを作りたい場合どうしますか?
二点間のTransformを計算したりColliderを使って近くにPlayerがいるか確認し、その後にRayを飛ばして間に障害物がなければPlayerを発見するといった処理を書いたりするのではないでしょうか。
SensorToolkit 2を使えばそれらの処理を簡単に実装できます

 

 

旧バージョン

過去に前バージョンの紹介記事を投稿しています。
メジャーアップデートにより古いバージョンは使用できなくなったのでご注意ください

raspberly.hateblo.jp

 

拡張性の高い設計への変更といくつかの新機能が追加されています。
ドキュメントはこちら

micosmo.com

 

 

 

開発環境

Unity2021.3.12f1

SensorToolkit 2 ver2.4.1

 

 

 

デモシーンの確認

アセットインポート完了時はこんな感じ。

 

サンプルシーンがいくつか用意されています。


Fundamentalsシーンではアセットにある全てのセンサーが紹介されているので、
インポート後最初に見ることをオススメします。

 

 

センサーとコンポーネントの紹介

Fundamentalsシーンを元に各センサーを簡単に紹介します。
ドキュメントからも詳細が確認できます。

 

Ray Sensor

Rayを飛ばして衝突したオブジェクトを検出するセンサーです。UnityのRayに近い。
レイを完全に遮るレイヤーを設定したり、遮断される斜面の角度を指定できます。

形状をRayから変更するとボリュームのある衝突判定を行うことができます。

最も良い使い方は、Obstructed By Layersに衝突させたいオブジェクトのレイヤーを指定することです。

 

Arc Sensor

Ray Sensorの曲線バージョンです。曲線であること以外はほとんど同じ。

セグメントに対して複数のRay Sensorを呼び出すということをしているので、セグメントをなるべく少なくするのがポイント。
使いどころが難しいですが、公式ドキュメントではキャラクターがジャンプできるかどうかの判定で使用していました。

 

 

Range Sensor

範囲内のオブジェクトを検出するセンサー。

形状はSphere、Box、Capsuleが用意されています。

 

 

Trigger Sensor

OnTriggerEnterOnTriggerExitでオブジェクトを検出するセンサー
センサーがアタッチされたオブジェクトにはColliderと、IsKinematicが有効になったRigidbodyが必要です。
センサーの範囲などはColliderの大きさで調整します。

Range Sensorと似たような役割を持ちますが、こちらの方が多機能で少し複雑です。
UnityのTriggerとColliderによる衝突判定に少し慣れていないと難しいかも。

 

Range Sensorは使える形状が3種類と制限がありましたが、
OnTriggerEnterOnTriggerExitが呼ばれるColliderであればどんなものでも機能します
SensorToolkit 2には円錐状のFOV Colliderが含まれているため、視界内にいるかどうかの判定にぴったりです。

 

 

慣れている方なら推察できる通り、OnTriggerEnterOnTriggerExitを使って検出していることから、検出中のオブジェクトが非アクティブになると判定が取れなくなります。


SensorToolkit 2では、この問題の対処方*1としてSafeModeが用意されています。
このSafeModeが有効だとOnTriggerStayも併用して判定します。

 

SafeModeを使いたくない場合は、非アクティブ前にオブジェクトを遠くまで移動(OnTriggerExitを呼ばせるため)させるというひと手間を加える必要があります。

 

 

Signal Proxy

オブジェクトがセンサーに検出された時、別のオブジェクトを検出対象としてSensorに指示するコンポーネント
センサーではなく、検出される側のオブジェクトにアタッチして使用する。
これは複数のColliderを持つオブジェクトに対して使う。

 

例えば、手足のColliderがSensorに検出された時、手足ではなくルートオブジェクトをSensorに伝えたりなど。

 

 

LOS Sensor(Line of Sight Sensor)

オブジェクトを視認できるを判定し検出するセンサーです。
オブジェクトに複数のRayを飛ばし、それがどれくらい遮られているかを計算して、視認の有無を決定します。
これは他のSensorを併用して判定します。併用しているSensorに検出されたオブジェクトにのみRayを飛ばして視認性を計算します。

 

UserSignalsを使って、Sensorを使わず特定のオブジェクトだけ最初から紐づけて視認性をチェックしたり。

 

最大距離と視野角に制約をつけ、視野角ギリギリや遠くのオブジェクトの視認性にマイナス補正をかけたりできる。

 

 

Boolean Sensor

複数のセンサーをマージするセンサー
複数のセンサーを取得し、OR判定、AND判定でオブジェクトを検出したりできます。

 

 

他にSteering SensorとNavMesh Sensorもある

 

実際に試してみる (NPCの視界を作る)

実際にSensorToolkit 2 を使って、「Playerを視認したら追跡するNPC」を作ってみます。

 

ステージの作成

Navigationで移動させるので、NavMeshをBakeしておきます。
視認の有無がわかりやすいよう、Cubeを変形させて壁として配置しています。

 

 

プレイヤーの作成

適当なプレイヤーを作成します。今回はユニティちゃん(URP)を使用します。

raspberly.hateblo.jp

プレイヤーオブジェクトのレイヤーはPlayerにしておきます。

 

 

エネミーの作成

プレイヤーを追跡するエネミーを作成します。


Enemyオブジェクトを作成し、その子にLOS SensorRangeSensorCapsuleを作成します。

 

RangeSensorにはRangeSensorコンポーネントをアタッチ。
DetectsOnLayersをPlayerにします。


LOS SensorにはLOSSensorコンポーネントをアタッチ。
InputSensorに先ほど作ったRangeSensorを紐づけます。

 

 

Enemyには下記のEnemyAIコンポーネントNavMeshAgentをアタッチします。
EnemyAIのSightにはLOS Sensorを紐づけます。


EnemyAIはこちら
プレイヤーを視認したら追跡し、見失ったら即座に停止します。

using UnityEngine;
using UnityEngine.AI;
// SensorToolkitを使う場合はこれが必要
using Micosmo.SensorToolkit;

public class EnemyAI : MonoBehaviour
{
    [SerializeField] Sensor sight;
    NavMeshAgent agent;
    GameObject target;

    void Start ()
    {
        agent = GetComponent<NavMeshAgent>();
        sight.OnDetected.AddListener(OnDetect);
        sight.OnLostDetection.AddListener(OnLost);
    }

    /// <summary>
    /// 見つけたときに呼ばれる関数
    /// </summary>
    public void OnDetect(GameObject detection, Sensor sensor)
    {
        var detectObjs = sensor.GetDetections();
        // 見つけたら追跡開始
        // 今の所Playerは1体だけなのでこれでやる
        target = detectObjs[0];
        agent.isStopped = false;
    }

    /// <summary>
    /// 見失ったときに呼ばれる関数
    /// </summary>
    public void OnLost(GameObject detection, Sensor sensor)
    {
        target = null;
        agent.isStopped = true;
    }

    void Update ()
    {
        if(target)
        {
            agent.SetDestination(target.transform.position);
        }
    }

}

LOS Sensorにイベントを紐づけて追跡状態を切り替えます。
AddListenerせず、var detectObjs = sight.GetDetections(); で Sensorで検出しているオブジェクトを取得しいろいろやってもいいですね。(最初はそうやってた)

 

 

これで完成、視界が黄色いギズモで表示されていますね。

 

動かしてみると、視界に入っている時だけプレイヤーを追跡しているのがよくわかりますね。

見失ったら即座に停止しているので、数秒は追いかけるという風に書き換えてもいいかも。

 

 

CapsuleをSDユニティちゃんに置き換えたバージョン

 

 

まとめ

SensorToolkit 2はオブジェクトを検出するセンサー機能を提供するアセットです。
各センサーの概要、実際にオブジェクトを検出する方法を紹介しました。
NPCの視界を実装するのに便利!

 

 

 

他のアセットの紹介記事はこちら↓

raspberly.hateblo.jp

 

 

 

※本記事にはAssetStoreアフィリエイトリンクが含まれています。

他、間違っている箇所、わかりにくい所がありましたらコメントにお願いします。

*1:正しい解決方法はあるが複雑なので妥協案としてセーフモードが用意されている

【勉強会レポ】: 📣 unity1week online共有会 #10

勉強会のレポート(メモ)です。
参加したのはこちら「📣 unity1week online共有会 #10」

meetup.unity3d.jp

ハッシュタグ : #u1w共有会

 

 

アーカイブはこちら

youtu.be

unity1week共有会って何?

unity1weekでいろんなゲームを遊んでいると
「どういう実装をしているんだろう」「どんな人が作っているのか」など気になることがいっぱい!

それら気になることを直接聞けばいいじゃん!というのがunity1week共有会の始まりで、
みんなで学んで成長することが趣旨です。

unity1weekについてはこちら

Unity 1週間ゲームジャム | フリーゲーム投稿サイト unityroom

今回は10人の発表者にトークしていただきます。

 

 

※視聴出遅れちゃったのでサクサクいくよ

 

 

LT 1: Resolutionをマネジメントする

画面解像度で変化するゲームシステムと、一般的な画面解像度の取り扱いについて。

 

アキオさんの作られた、Neon Blocks with RESIZING Displayはフルスクリーン環境でのみプレイでき、ディスプレイの解像度によって内容が変化するゲームです。

このゲームの解像度は560x440(14:11)になっていて、この比率は市販のディスプレイには存在しないため、
Screeh.widthとScreen.heightの比率が14:11になっているかどうかでフルスクリーンを判定できるようになっています。
後はフルスクリーン状態のScreeh.widthとScreen.heightを参照してゲーム内容を変化させるとのこと。
発想がすごい。

 

他に画面解像度の取り扱いとしてレイアウト崩れの解決案などを紹介されていました。

 

サンプルはこちら

github.com

解像度サンプル | フリーゲーム投稿サイト unityroom

 

 

 

LT 2: 2Dプラットフォーマーに挑戦

2Dプラットフォームゲームにおけるキャラクターの動きに関するお話でした。
プレイヤーが受ける印象を変えるため、移動やジャンプの動きに少し変化を加えるなど、
細かい部分まで解析されててすごい。

 

移動・ジャンプ以外に、足場にギリギリ届かなそうな場面でも登れる「エッジランディング」、
滞空して着地位置「ホバリング」の2つをオリジナルの機能として紹介されました。

 

 

LT 3: ツールを駆使してボイス付きRTAゲームを作ろう!

RTAゆっくり実況動画をコンセプトに作られたRTA ステータスをあげて物理で殴るゲームと、LTのスライドの作り方についてのお話です。

RTAしながらコメントで実況してる...

 

ボイスはVOICEPEAKを使って作られています。
キャラクターは当初スカーレットちゃんを使用する予定だったが解釈違いのため、AIイラストでジェネリックスカーレットちゃんが作ったとのこと。

 

ちなみにスカーレットちゃんは、ロボットガール・ミーツ・ヒューマン!の主人公です。
遊んでね。

 

 

 

LT 4: u1wから学んだ俺式ゲームづくりのレシピ

過去の参加から得たゲーム開発のコツに関するお話です。

やりたいことをゲームにする

「プレイヤーがやりたいことができるゲーム」が楽しんでもらえる。
第一欲求を満たせる内容と、物語に意味(コンテクスト的なもの)とやりがいを与えることが大事

失敗した時に面白いか

ゲームでミスをする行為はストレスが溜まる。
「失敗が面白い」ありきでゲームを考え、失敗しても見せ場があるようにする

一番面白い所で終わりにする

最後が面白くなかったらダメ。
一番面白いところを最後にもってきて、最後まで遊んでもらえる事が大事

番外編

酒を飲むな、いいアイデアがたくさん出てる気がしてもその品質は判断できていない
遅刻してもいいから良いものを作った方がいい

 

 

 

LT 5: 大切な自作ライブラリ~コスパ追求のすゝめ~

自作ライブラリに関するお話。その手法とか。

 

u1wでゲームを作るたび毎回書いているコードはライブラリ化すること。
そして、毎回する作業はエディター拡張を用いて効率よく開発しようという内容でした。
まっともぉんさんもMornLibで効率的にゲーム開発しているとか。

github.com

 

ライブラリ化がわからない、書き方がわからない方はコードレビュー配信へどうぞ!
忌憚なきインプレッションの時間だ:hugging_face:

matsufriends.notion.site

 

 

 

LT 6: サウンドに全振りしたゲームで気を付けたこと

サウンドに力を入れたときのお話。

一番意識したこと

100人が触ったら100人が「気づく」サウンド仕様にする
作ったときに工夫したポイントが面白い・面白くない以前に気づいてもらうことが大事

今回は音を鳴る・鳴らないの振り切ったものにした

細かな工夫

サウンドとリンクさせることを意識する。
最初は画面を暗く、音が出ると光明るくなるようにし、サウンド演出をグラフィックを補完する。
サウンドとグラフィックの合わせ技が大事

 

 

 

LT 7: Package Manager活用術

ライブラリをPackage Managerで管理するお話。
ライブラリをパッケージ化する具体的な方法を解説しています。

オススメのOSSも紹介していました。

light11.hatenadiary.com

github.com

github.com

github.com

github.com

 

 

 

LT 8: トリックアート

ゲームで絵作りをする時、処理負荷や工数を削減するためにうまく誤魔化して実装するというお話。
プレイヤーを動かすのではなく背景を動かしたり、手を抜ける部分では手を抜き重要な部分にリソースを割くという内容で、具体的なゲーム例を交えて解説されました。

 

 

 

LT 9: パズルゲームの面白さ

パズルゲームを面白くする要素についてのお話でした。

パズルの本質的な面白さ

「ルールは簡単なのにクリアできない」、ルールを理解した上でクリアできずに悩んでいることがパズルの本質的な面白さ
プレイヤーが長く悩むようなパズルはワーキングメモリに負荷をかければ達成できる

ワーキングメモリに負荷をかける

負荷をかける方法は大きく分けて3つ

・覚える要素を増やす
・覚えにくい要素にする(複数種類の要素、意味不明な要素)
・ワーキングメモリ自体に制限をかける(制限時間、アドリブ性の高い要素)

これらはQuad Puzzleにも活かされている

 

 

 

LT 10: サウンドのハナシ

taroさんがゲームを作る時に使っているテクニックに関するお話。

 

めっちゃ面白いからぜひ動画を見てほしい。
スライドの構成とかすごい

youtu.be

最後のオハナシもよい

 

 

 

感想

みんなおもしろかった~
今回はサウンド関係とライブラリ関係のLTが盛り上がってましたね。
サウンドカテゴリー上位3人がいるとかヤバすぎでは。

 

個人的に一番良かったのは、5番目まっともぉんさんのライブラリに関するお話です。
書いたコードを次の開発につなげ、より効率よくゲーム開発するというのはとても大事。
というかパリキン3日で作ったとかマジ?もっとボス増やせ!

 

 

1番目アキオさんのフルスクリーンの仕組みもすごい!
フルスクリーン表示ボタンがゲームスタートボタンになってるとかオシャレですし、
ゲーム画面外にあるボタンをUIとして利用する発想がすごすぎる。

 

トリックアートの話もおもしろい。
私も水面反射がいい感じにでない時、水の中に同じオブジェクトを回転させて配置し擬似的に再現するとかやったことがあります。
unity1weekは時間が限られており、良いやり方が思いつかなかったり、ちゃんとした方法でやろうとすると時間がかかることもあるので、こういう工夫で柔軟に対応するのも大事ですね。

 

 

以上です。
LT登壇者のみなさま本当にありがとうございました。

 

 

 

今回も休憩時間にunity1weekのリール動画を流していただきました。
とと様ありがとうございます。

youtu.be