Raspberlyのブログ

Raspberlyのブログ

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

【Unity】DOTweenでUIアニメーションが連続で呼ばれた時に少しずつズレる問題の解決方法【DOTween】

この記事はUnity Advent Calendar 2023 その2 24日目の記事です。

qiita.com

 

実行環境

Unity 2022.3.14f1

DOTween ver1.0.375

 

 

やること

DOTweenを使って連続でUIアニメーションを再生した時に、
少しずつズレる問題の解決方法についてまとめます。

 

 

 

解決方法

忙しい人向けに先に書いておきます。

 

連続でアニメーションを再生する時は、以下の方法でキャンセル処理をかけば解決します

  • .DOComplete()か.DOKill(true)でキャンセル
  • Sequenceを使っている時は.Complete()か.Kill(true)でキャンセル

 

つまり、実行中のアニメーションを最後まで再生しきってから次のアニメーションを実行すればいいわけです。
キャンセルしない、またはキャンセルに引数を渡さない.DOKill()を使うとこの問題がおきます。

 

 

 

 

 

 

 

 

 

 

以下、暇な人向け

少しずつズレる原因

この現象は、以下のアニメーション*1を連続で再生する時、キャンセル処理が正しくないと発生します

  • .SetRelative()をした相対的なアニメーション
  • DOShake系、DOJump系、DOPunch系

キャンセル処理が正しくないとは、
キャンセルに.DOKill()を使っている、またはキャンセルをしていない状態を指します。

 

 

ズレる例

実際にズレる例を出します。
こんな画面があり、InputFieldに文字が入力されていない状態でNextボタンが押されたら、
InputFieldを揺らすアニメーションを再生したい時。

 

揺らすアニメーションはDOTweenで実装。
やり方はいろいろありますが今回はDOPunchを使用します。

    [SerializeField] private RectTransform rectTransform;
    [SerializeField] private float duration;

    public void NegativeAnimation()
    {
        rectTransform.DOKill();
        rectTransform.DOPunchPosition(new Vector3(30, 0, 0), duration);
    }

 

NegativeAnimation()を再生するとこうなります

 

 

しかしキャンセル処理に.DOKill()を使っているので連打すると少しずつズレます



 

解決方法

先に書いた通り、キャンセル処理に.DOComplete()か.DOKill(true)を使用すれば解決します
DOKill()は引数を与えないと、最後までアニメーションを再生しきらずに終了するので注意。

public void NegativeAnimation()
    {
        //または rectTransform.DOComplete();
        rectTransform.DOKill(true);
        rectTransform.DOPunchPosition(new Vector3(30, 0, 0), duration);
    }

 

これで、最後までアニメーションを再生しきってから次のアニメーションを再生するのでズレません

 

Sequenceの場合

Sequenceでのキャンセルは、.Complete()か.Kill(true)です

    private Sequence sequence;
    
    public void NegativeAnimation()
    {
        //または sequence.Complete();
        sequence.Kill(true);
        sequence = DOTween.Sequence()
            .Append(rectTransform.DOLocalMoveX(-40, duration).SetRelative())
            .Append(rectTransform.DOLocalMoveX(40, duration).SetRelative());
    }

 

 

 

まとめ

連続でアニメーションを再生する時は、以下の方法でキャンセル処理をかけば解決

  • .DOComplete()か.DOKill(true)でキャンセル
  • Sequenceを使っている時は.Complete()か.Kill(true)でキャンセル

 

 

以上です。

 

 

 

おまけ CompleteとKillの違い

ここがわかりやすい

www.hanachiru-blog.com

 

 

過去のUnity アドベントカレンダー記事

raspberly.hateblo.jp

raspberly.hateblo.jp

 

過去のDOTween関係の記事

raspberly.hateblo.jp

 

raspberly.hateblo.jp

 

*1:他にもあるかも

【Unity】空のGameObjectを可視化する【Gizmos】

今回はUnityネタをやっていきます。
Gizmosを使って空のGameObjectを可視化する方法についてまとめます。

 

やりたいこと

Prefabを配置する時、位置参照用に空のGameObjectを配置して使うが多いと思います。
しかし空のGameObjectなので選択しない限りはSceneビュー上で見ることができません
そこで、今回はGizmosを使って空のGameObjectを可視化してみます。

 

 

Gizmosの表示

Gizmosの表示はOnDrawGizmos()を使用します。
適当なScript内にOnDrawGizimos()を書いて、それをGameObjectにアタッチします。

using UnityEngine;

public class DrawGizmos : MonoBehaviour
{
    private void OnDrawGizmos()
    {
        // ここに表示したいものを書く
    }
}

 

Gizmosの有効化

Gizmosを表示するためにはGizmosの表示を有効にしておきます。
右上のボタンが押されていることを確認しましょう。

 

 

Objectの表示

最も単純なObjectの表示

SphereやCubeを表示

Gizmos.Draw○○()で表示します。第二引数はScaleの値です。

        private void OnDrawGizmos()
        {
            Gizmos.DrawSphere(transform.position, 0.2f);
        }

Sphereが表示されました。

 

Cubeの場合はGizmos.DrawCube()を使います。

        private void OnDrawGizmos()
        {
            Gizmos.DrawCube(transform.position, new Vector3(0.2f, 0.2f, 0.2f));
        }

 

 

ワイヤーフレームで表示

Gizmos.DrawWire○○()ワイヤーフレームにできます

        private void OnDrawGizmos()
        {
            Gizmos.DrawWireSphere(transform.position, 0.3f);
        }

 

 

色を変える

Gizmos.colorを書き換えると色が変わります

        private void OnDrawGizmos()
        {
            Gizmos.color = Color.green;
            Gizmos.DrawSphere(transform.position, 0.2f);
        }

 

 

 

Textの表示

UnityEditor.Handles.Label()*1*2を使って文字を表示します。

#if UNITY_EDITOR
        private void OnDrawGizmos()
        {
            UnityEditor.Handles.Label(transform.position, "point");
        }
#endif

変数を渡して何かの値を表示するという使い方もできますね。

 

位置の調整

Gizmos.DrawSphere()などと併用するとTextが埋まるので位置を変えるといいです

        private void OnDrawGizmos()
        {
            var position = transform.position;
            Gizmos.color = Color.green;
            Gizmos.DrawSphere(position, 0.2f);
            
            UnityEditor.Handles.Label(position + new Vector3(0, 0.4f, 0), "point");
        }

 

 

スタイルの調整(フォントサイズ、色、整列)

GUIStyleを使ってスタイルを変えることもできます

        private void OnDrawGizmos()
        {
            var position = transform.position;
            Gizmos.color = Color.green;
            Gizmos.DrawSphere(position, 0.2f);
            
            var style = new GUIStyle();
            style.fontSize = 20;
            style.normal.textColor = Color.white;
            style.alignment = TextAnchor.MiddleCenter;
            UnityEditor.Handles.Label(position + new Vector3(0, 0.5f, 0), "point", style);
        }

 

 

 

カメラからの距離によって表示を変える

たくさんGizmoがある状態でカメラを引いた時ごちゃごちゃして見えにくいです。

そのためカメラの距離によって見え方を変えてみます。

 

カメラが近い時だけ表示する

SceneビューのCameraを取得し、距離が離れたら表示しないようにします。

        private void OnDrawGizmos()
        {
            var position = transform.position;
            var sceneCamera = UnityEditor.SceneView.currentDrawingSceneView.camera;
            var cameraDistance = Vector3.Distance( sceneCamera.transform.position , position);
            if(cameraDistance > 50) return;
            
            Gizmos.color = Color.green;
            Gizmos.DrawSphere(position, 0.2f);
            
            var style = new GUIStyle();
            style.fontSize = 20;
            style.normal.textColor = Color.white;
            style.alignment = TextAnchor.MiddleCenter;
            UnityEditor.Handles.Label(position + new Vector3(0, 0.5f, 0), "point", style);
        }

 

 

 

 

まとめ

今回は空のGameObjectを可視化してみました。
Sceneビュー上で確認できるので位置合わせなどでとても便利ですね。

 

他にもLineを引いてつなげたり、任意の画像を表示したりもできます。
公式リファレンスから確認してみましょう。

docs.unity3d.com

 

以上です。

 

 

参考資料

www.urablog.xyz

sleepygamersmemo.blogspot.com

 

game.daraha.me

 

www.urablog.xyz

 

tsubakit1.hateblo.jp

 

nakamura001.hatenablog.com

 

 

youtu.be

 

*1:#if UNITY_EDITORで囲んでおくといいでしょう

*2:UnityEditorはusingしておいてもいいです

【Unity】NavMeshSurfaceでNavMeshを動的にBakeする【NavMesh】

 

内容

NavMeshSurfaceを使い、NavMeshを動的Bakeする方法についてまとめます。

 

開発環境

Unity 2022.3.9f1
AI Navigation ver1.1.4

 

 

パッケージのインストール

Unity Package ManagerからAI Navigationをインストール

 

Unity 2021の場合

Package Managerの左上にある+ボタンから、

「com.unity.ai.navigation」を入力し、Addするとインストールされます。

 

 

SceneにNavMesh Surfaceを作成します。
Sceneビュー右クリックのメニューにAIの項目が増えているのでNavMesh Surfaceを選択

シーン内にNavMeshSurface(がアタッチされたオブジェクト)が作成されました。

 

 

各パラメータを見ていきます
(Unityのバージョンによって微妙に違いがあります)

Agent Type

影響を受けるNavMeshAgentの対象
Humanoidなら、HumanoidのAgentだけがこのエリアを影響を受ける。

Default Type

生成するエリアのタイプ。
歩行可能なエリアだけ作成する、歩行できないエリアだけ作成するといった使い方ができる。

NavMeshLinkの作成の有無。
複数のNavMeshSurfaceを接続する時に使う。

Use Geometry

使用するジオメトリの設定。
Render Meshesなら、レンダリングされるメッシュ(Terrainを含む)に合わせてベイク。
Physics Collidersなら、Collider(IsTriggerでないもの)に合わせてベイク。

Object Collection

ベイク対象のGameObjectを選別する設定

  • All Game Objects:Scene内の全てのオブジェクトが対象
  • Volume:Scene内の指定範囲内のオブジェクトが対象
  • CurrentObjectHierarchy:NavMeshSurfaceの子オブジェクトが対象
  • NavMeshModifierコンポーネントがアタッチされたオブジェクトのみが対象

Include Layers

ベイク対象のレイヤー

 

 

InspectorのBakeボタンを押すとBakeされNavMeshが生成されます。

 

Scriptからは以下のようにBakeできます

using UnityEngine;
using Unity.AI.Navigation;

public class Builder : MonoBehaviour
{
    [SerializeField] private NavMeshSurface surface;
    public void Build()
    {
        surface.BuildNavMesh();
    }
}

 

当然ゲーム実行中にBakeできます。

 

 

まとめ

NavMeshSurfaceを使ってNavMeshを動的にBakeしました。
ランダム生成ダンジョンなど、リアルタイムにNavMeshを更新したい時に役立ちますね。


昔はGitHubからパッケージを落としてこないと使えない機能でしたが、今ならUnityPackageManagerで導入できるので大分使いやすくなりました。

 

以上です。

 

 

おまけ AI Navigation Displayの表示切替

AI NavigationをインストールするとSceneビューにこのようなDisplayが表示されます。

これは右クリックからHideを選ぶと非表示になります。

 

もう一度表示したい時は、Sceneビューの右上端にある3点マークを押してOverlay Menuを選択し、

Overlays Menuが出るので、AI Navigationの目をクリックすると表示されます



 

 

参考資料

 

 

www.matatabi-ux.com

 

 

 

【Unity】 振り子を作る 【HingeJoint + LineRenderer】

今回はUnityネタをやっていきます。
Unityで振り子を作る方法についてまとめておきます

 

直近のUnity 1週間ゲームジャムでリール動画を作成しました。

youtu.be

 

お題が表示されるシーンはUnityで作成していて、その時の実装方法についてまとめておきます。

 

 

開発環境

Unity 2021.3.12f1

 

 

支点と振り子の作成

支点となるオブジェクトと、振り子(揺れる)となるオブジェクトを作成します。

支点の作成

シーン内にCubeを作成、名前を「Pivot」に変更。
Rigidbodyをアタッチし、IsKinematicにチェックを入れます。

 

振り子の作成

シーン内にSphereを作成、名前を「Furiko」に変更。
Rigidbodyをアタッチします。

HingeJointのアタッチ

振り子の揺れる処理はHingeJointコンポーネント*1を使用します。
これは2つのRigidbodyをつなげて動きに制限をつけるコンポーネントです。

docs.unity3d.com

 

 

「Furiko」にHingeJointコンポーネントをアタッチ
ConnectedBodyにPivotを指定、AnchorのYを5、今回は横にだけ揺らしたいのでAxisのZを1AutoConfigureConnectedのチェックを外しておきます。

Anchorは支点との距離です。

 

この状態で、ゲームを起動し「Pivot」を動かすと「Furiko」が振り子のような挙動をするのが確認できます。

 

 

揺れの調整

そのままだとゆったりした揺れになるので調整します。
HingeJointのUseSpringにチェックを入れておきます。

 

Springで揺れる力を調整

Springは振り子が元の位置(この場合支点の真下)に戻る力の強さです。
この値が大きいほど振り子の動きが大きくなります

 

 

Damperで減衰力を調整

Damperは揺れの減衰を表します。
この値が大きいほど揺れが早く収まります

 

上のSpring1000の状態でDamperを100にした場合のGIF。

 

 

 

振り子の糸を作る

支点と振り子を糸でつなぎます。

LineRendererのアタッチ

糸の描画にはLineRendererコンポーネントを使用します。
「Pivot」にLineRendererをアタッチ。

 

そのままだとピンクの太い線になるので、Widthを小さくMaterialsにDefault-Lineを設定します。



LineRendererの制御

LineRendererの制御用Scriptを作成します。
下記のFurikoLine.csを「Pivot」にアタッチ。

using UnityEngine;

public class FurikoLine : MonoBehaviour
{
    [SerializeField] LineRenderer lineRenderer;
    [SerializeField] Transform startPoint;
    [SerializeField] Transform endPoint;

    void Update()
    {
        var positions = new Vector3[] { startPoint.position, endPoint.position, };
        lineRenderer?.SetPositions(positions);
    }
}

 

LineRendererとStartPointには「Pivot」を紐づけ、EndPointには「Furiko」を紐づけます。

これで振り子の糸ができました。

 

 

リール動画でやっていること

糸の色

LineRendererの色を調整し、最初の方を透明にすることでイイカンジの糸に仕上げました。

 

糸の終点

文字を使う関係上LineRendererの終点が真ん中だと困るので、
参照用の空のGameObjectを上側に配置することでイイカンジにしました。

 

インチキ

揺れ方など何度調整しても動画にぴったりな絵がなかなか撮れなかったので、
最終的にTimescaleを変更して良さそうな絵を撮りました。
こういうのもアリ

 

 

 

まとめ

・HingeJointを使って振り子を作成しました。揺れの大きさと減衰力もパラメータで調整できます。
・振り子の糸はLineRendererで作成しました。

 

 

以上です。

 

*1:ヒンジで連結するかのような制約をつけられるのでHingeJointといいます

【アセット紹介】Feel でヒットストップを作る【Unity】

今回はアセット「Feel」を使ってヒットストップを実装する方法についてまとめます。

 

 

どんなアセット?

音やエフェクトなどゲームに様々な演出を簡単に実装するアセットです。
過去に紹介記事を投稿しています。

 

基本的な概要や使い方はこちらの記事をどうぞ

raspberly.hateblo.jp

今回は、発展的な内容として、ヒットストップを実装する手段をまとめます

 

 

開発環境

Unity 2021.3.12f1

Feel ver3.12

 

 

やりたいこと

Feelを使ってヒットストップを実装します。

以下の3種類の方法を用いて解説します。

・Time.timeScaleを0にする

・Animator.speedを0にする

・Animator.speedを遅くする

 

 

下準備

アセットとかの準備

プレイヤーにSD ユニティちゃん、敵にCubeを用意。

 

攻撃モーションとエフェクトも用意します。
モーションとエフェクトは下記のアセットを使用しています。これはなんでもいいです。

 

 

プレイヤーの作成

シーンに空のGameObjectを作成、名前をPlayerにしてユニティちゃんを配置、手のボーンに剣を持たせます。

剣には攻撃判定用のColliderをアタッチしておきます。

 

 

PlayerのAnimator

Animatorを作成。
ステートを2つ作成し、待機モーションと攻撃モーションを持たせます。
bool型パラメータattackを追加し、attackのオンオフでステートが切り替わるようにします。

 

PlayerのScript

以下のFeelPlayer.csを作成し、Playerにアタッチ。
キーボードのスペースキーを押すと、登録したFeedbacksを再生する単純なScriptです。

using UnityEngine;
using UnityEngine.InputSystem;
using MoreMountains.Feedbacks;

public class FeelPlayer : MonoBehaviour
{
    [SerializeField] MMFeedbacks attackFeedbacks;

    void Update()
    {
        if(Keyboard.current.spaceKey.isPressed)
        {
            attackFeedbacks?.PlayFeedbacks();
        }

        // 旧InputManagerでやりたい人用
        //if(Input.GetKeyDown(KeyCode.Space))
        //{
        //    attackFeedbacks?.PlayFeedbacks();
        //}
    }
}

 

攻撃Feedbacksを作成

空のGameObjectを作成、名前をAttackFeedbacksに。

 

MMFeedbacksコンポーネントをアタッチし、各種Feedbackを実装していきます。
攻撃時にAnimatorのパラメーターを書き換えるAnimationと、
攻撃判定用ColliderのActiveを切り替えるSetActiveを追加。

 

Animationの方は、対象のAnimatorとパラメータを設定。

 

Feedbackの紐づけ

PlayerにFeelPlayer.csをアタッチし、AttackFeedbacksを紐づけます。

 

これでゲームを開始しスペースキーを押すと攻撃します。

 

わかりにくいですが、攻撃モーション中ColliderもActiveになっています。

これでPlayerは完成。

 

 

敵の作成

空のGameObjectを作成、名前をEnemyにしてCubeを配置します。

EnemyのScript

以下のFeelEnemy.csを作成。
OnTriggerEnterで登録したFeedbacksを再生する単純なScriptです。

using UnityEngine;
using MoreMountains.Feedbacks;

public class FeelEnemy : MonoBehaviour
{
    [SerializeField] MMFeedbacks hitFeedbacks;

    private void OnTriggerEnter(Collider other)
    {
        hitFeedbacks?.PlayFeedbacks();
    }
}

 

ヒットFeedbacksを作成

攻撃が当たったときにエネミーが呼び出すFeedbacksを作成します。
空のGameObjectを作成、名前をAttackFeedbacksに。

 

MMFeedbacksコンポーネントをアタッチし、各種Feedbackを実装していきます。
Cubeの大きさが変化するScaleと、攻撃時にエフェクトを出すParticlesPlayを追加。

 

ヒットストップとは直接関係ない賑やかしなので、特になくてもいいです。
ここはお好みで。

 

 

 

最後、EnemyにFeelEnemy.csをアタッチ、ColliderとRigidbodyもアタッチします。
HitFeedbacksも紐づけます。



 

これでEnemyの準備を完了。
後はヒットストップを追加していくだけです。

 

 

 

MMTimeManagerを配置

最後に空のGameObjectを作成し、MMTimeManagerをアタッチします。
これはFeelで時間を制御する時に必要なコンポーネントです。シーン内に必ず存在する必要があります。

 

 

これで下準備は終わり。
次からヒットストップを実装していきます。

 

 

ヒットストップを実装

TimeScaleを0にする

一番手早いヒットストップ。Time.timeScaleを0にします。
特徴は時間が止まるため、他のオブジェクトやエフェクトも全て停止するという点です。

HitFeedbacksに、Time/FreezeFrameを追加します。
これは指定の秒数、時間を止めるFeedbackです。

 

今回は0.2秒止めてみます。FreezeFrameDurationに0.2を設定



これで完成、攻撃ヒット時0.2秒間Time.timeScaleが0になります。

 

 

 

プレイヤーのアニメーションを止める

攻撃ヒット時、プレイヤーのアニメーションを一瞬止めます。

HitFeedbacksに、GameObject/AnimatorSpeedを追加します。
これはAnimatorの再生速度を変えるFeedbackです。


今回は0.3秒止めてみます。
Bound AnimatorにユニティちゃんのAnimatorを紐づけ、
ModeをInstant Then Resetに、Durationを0.3にします。



これで完成、攻撃ヒット時0.3秒間アニメーションの再生速度が0になります。

 

 

プレイヤーのアニメーションを遅くする

攻撃ヒット時、プレイヤーのアニメーションを遅くします。
やり方はさっきとほとんど同じです。New Speed Minに0.05を設定します。

 

 

これで完成、攻撃ヒット時0.3秒間アニメーションの再生速度が0.05倍になります。

 

 

 

まとめ

今回はアセット「Feel」を使って、ヒットストップを実装しました。
Time.timeScaleを0にする方法、Animatorの再生速度を0にする方法、
Animatorの再生速度を遅くする方法の3つを紹介しました。

 

 

プレイヤーに爽快感や良い手触りを与える演出ですが、FeelならScriptを編集せずに実装できますね。
参考資料にある動画も、タメになるのでぜひどうぞ。

以上です。

 

 

参考資料

youtu.be

youtu.be

wikiwiki.jp

 

 

 

 

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

raspberly.hateblo.jp

 

 

 

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

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

【Unity】入力がなくなったらカメラが定位置まで戻るカメラワークを作る【Cinemachine + Input System】

今回はUnityネタをやっていきます。
UnityのCinemachineとInputSystemを使って、
プレイヤーの入力がなければカメラが定位置まで戻るカメラワークを作成します。


見下ろし視点のゲームで使うことを想定しています。

 

挙動としてはリメイク前のバイオハザード4とかに近いです。

 

 

 

開発環境

Unity 2021.3.12f1

Cinemachine ver2.8.9

Input System ver1.4.4

 

 

 

パッケージのインストール

Unity Package ManagerからCinemachineとInput Systemをインストールしておきます。

 

ステージの作成

最初に簡単なステージを作ります。
床になるPlaneとキャラクターを配置します。
これはなんでもいいですが、今回はSDユニティちゃんを使用します。

 

 

基本的なカメラの設定

Virtual Cameraの作成

シーン内にVirtual Cameraを作成します。
Create/CInemachine/VirtualCameraで作成。

 

Inspectorから、BodyをFraming Transporserに、AimをPOVに設定。

 

Input Systemの入力を有効にしたいので、Add Input Providerを押します。

すると、Cinemachine Input Providerというコンポーネントがアタッチされます。
Input Actionsはデフォルトのやつをそのまま使います。

 

 

最後に、追従対象のオブジェクトを設定します。
FollowにSDユニティちゃんを設定。

 

 

これで基本的なカメラの挙動ができました。
マウス、およびゲームパッドの右スティックでカメラが回転します。

 

 

 

カメラの調整

ここは好みですが、今回は見下ろし視点のゲームを想定しているので、
カメラの動く範囲を制限していきます。

(必要ないのなら飛ばしていいです)

位置設定

SDユニティちゃんの場合、カメラの中央を頭にしたいのでオフセットのYを1にします。
(これはオフセットの値を変えるよりも、Virtual Cameraが参照する用のGameObjectをキャラクターの子に持たせて調整した方がいいかも)

 

Cameraとの距離も少し短くします。

 

 

角度制限

カメラを回転する角度を制限します。
上下の角度は20~70度まで、左右の角度は-40~40度までとします。

 

 

ここまででゲームを実行するとこんな感じ

 

 

Recenteringの設定

ここがこの記事のキモ
視点操作(入力)がなくなったら、一定の角度にカメラが戻るようにします

 

この機能自体は、Recenteringという名前でCinemachineに用意されています。
InspectorビューのAimから、Vertical RecenteringとHorizontal Recenteringを有効にし、
Wait Timeを0.1Recentering Timeを0.5にします。

 

Wait Timeは入力がなくなってからRecenteringを開始するまでの時間、
Recentering TimeはRecenteringを終了するまでの時間です。

上の例だと、入力がなくなってから0.1秒後に、0.5秒かけて定位置までカメラを戻ります。

 

 

中央角度の設定

一見よさそうに見えますが、Recenteringする角度がよくないです。
具体的には上下方向の中央角度が20度になっています。
これはデフォルトの中央角度が0であり、一番近い20が中央とされてしまうためです。

 

上下の回転角度は20~70度なので、45度を中央角度に調整します。
InspectorのAimから、Recenter TargetをLook At Target Forwardに設定。
これはLookAtに設定したTransformの正面を中心角度にするという設定です。

 

次にLookAtに設定する用の空のGameObjectを作成します。
(ワールド座標が参照されるので、プレイヤーのキャラクターの子にしない方がいい)

角度Xを45に設定。

これを、CinemachineVirtualCameraのLookAtに設定。

 

これで完成です。
入力がなくなったら、カメラが定位置まで戻るようになりました。

 

 

まとめ

CinemachineとInput Systemを使って、プレイヤーの入力がなければカメラが定位置まで戻るカメラワークを作成しました。
Recentering機能を使えば簡単に実装できます。

 

 

こっちはバーチャルパッドで動くようにしたやつ

 

 

 

以上です。

 

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

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

 

 

 

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

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

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

 

 

開発環境

Unity 2021.3.12f1

UnmaskForUGUI ver1.4.1

DOTween ver1.2.705

 

 

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

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を使用