ヨノアメゲームズ.log

業界歴10年のゲームプログラマーがゲームを作ったり遊んだりします。 目標は1万本ダウンロードされるゲームを作る事!

Unityで画面振動、シェイク

ゆらす

この記事は、以下の「桜井政博のゲーム作るには」の「画面振動 【エフェクト】」の回で、

youtu.be

「画面振動は大きなショックを表現するのにうってつけなので、
 どんどん織り込んでいくべき」

と桜井さんもおっしゃっており、自分のゲームにも早速実装してみたので、
動画では説明されていなかった、具体的な実装方法についてUnityを使って説明をしようと思います。

画面振動の実装を簡単に行うために以下の無料のアセット「DOTween」を導入します。

assetstore.unity.com


細かい使い方についてはここでは解説しません。

コード全体はこのような感じです。

using DG.Tweening;
using UnityEngine;

public class ObjectFollower : MonoBehaviour
{
    [SerializeField] private GameObject followObj = null;
    [SerializeField] private bool isFollowable = true;
    private Tweener tw = null;
    private Vector3 defaultPos = Vector3.zero;

    void Start()
    {
        Follow();
    }

    void LateUpdate()
    {
        Follow();
    }

    private void Follow()
    {
        if (!isFollowable)
        {
            return;
        }
        transform.position = new Vector3(followObj.transform.position.x, followObj.transform.position.y, transform.position.z);
    }

    public void SetFollowable(bool value)
    {
        isFollowable = value;
    }

    public void Shake(float strength, float duration)
    {
        if (tw != null && tw.IsActive() && tw.IsPlaying())
        {
            return;
        }
        isFollowable = false;
        tw = transform.DOShakePosition(duration, strength).OnComplete(() => { isFollowable = true; });
    }

    public void Shake(float x, float y, float duration)
    {
        if (tw != null && tw.IsActive() && tw.IsPlaying())
        {
            return;
        }
        defaultPos = transform.localPosition;
        isFollowable = false;
        tw = transform.DOLocalMove(new Vector3(x, y, transform.localPosition.z), duration).SetEase(Ease.InCubic).OnComplete(() =>
        {
            transform.DOLocalMove(defaultPos, duration).SetEase(Ease.OutCubic).OnComplete(() =>
            {
                isFollowable = true;
            });
        });
    }
}

これはカメラにアタッチして、インスペクター上でfollowObjにプレイヤーのオブジェクトをアタッチする事で、
プレイヤーを追従するクラスです。
コードにコメントを追加して説明します。

    public void Shake(float x, float y, float duration)
    {
        if (tw != null && tw.IsActive() && tw.IsPlaying()) //tweenが存在しているかどうか、アクティブか、再生中かをチェック
        {
            return;
        }
        defaultPos = transform.localPosition; //Tweenした後に元の座標に戻るために自分の座標を保存しておく
        isFollowable = false; //一時的にfalseにすることで、Followメソッドでの追従を止めてます。

        //tweenに、移動先のXY座標と、移動演出の時間を設定、動きの種類をInCubicに変更
        tw = transform.DOLocalMove(new Vector3(x, y, transform.localPosition.z), duration).SetEase(Ease.InCubic).OnComplete(() =>
        {
            //1つ目のDOLocalMoveが終わったら、保存しておいた最初の座標に戻る
            transform.DOLocalMove(defaultPos, duration).SetEase(Ease.OutCubic).OnComplete(() =>
            {
                //一連の処理が終わったのでFollowメソッドで再び追従するように
                isFollowable = true;
            });
        });
    }

上記のような実装で、簡単に画面振動、シェイクを実装する事ができます。
2Dでの使用を想定していますが、応用すれば3Dでも使えるかと思います。

今回ローグライクの移動で壁にぶつかった時に振動するようにしてみました。
まだ移動しかできないゲームとも呼べない状態の代物ですが、
この画面振動を実装した事で、ゲームを遊ぶプレイヤーに対して親切な演出が追加されて、
なんだか少しリッチに感じました。

壁に当たった時だけでなく、自分が攻撃をした時、攻撃を受けた時などにもこの画面演出を使おうと思います。

今後も桜井さんの動画の中で自分が実装できた事があれば、また記事にして共有しようと思います。
あの桜井さんが言ってる事なので、全部実戦できたらきっと素晴らしい神ゲーができるはず!
と思ってるので、引き続き頑張ります。