ダメージ時のエフェクトについて

どうも!シューティングゲームとかでダメージを受けたら
一瞬機体が白く光るエフェクトありますよね、あれを実装してみます
イメージ的には以下のようなやつです

今回はクリックしたら一瞬白くなるようにしますが
弾が衝突したら白くするとか応用は効くと思います!
SpriteRendererのColorを白にすればいいだけじゃね?

当初↑のように思っていたのですが実際これでは白くなりません…
例えば以下の画像をUnityに取り込んでみてください

このゲームオブジェクトのSprite Rendererを確認すると既にColorは白色になっているんです…

つまりSprite RendererのColorをSprite上で白色にするということでは
本当の意味で白くすることはできません、なんてこったい!!
じゃぁどうする?

ってことでどうやらUnityの機能でサクッとできる訳じゃないっぽいので
自分でなんとかするしかありません!
どうするといいかなーって考えたのですが、以下のやり方ぐらいしか
思いつきませんでした
とりあえず概要

概要をサクッというとスプライトの下に同じ形の白いスプライトを用意して
ダメージを受けた時に一瞬だけスプライトの表示順序(Orde in Layer)
を変更してあげればできるんじゃね?って思いました
これ、文章だけだと分かりにくいと思いますので
実際に作っていきましょう!
(前提準備)実装しよう!

まず白くしたい元の画像と全く同じ形の白い画像を用意します
今回は以下を用意しました


この画像をUnityに取り込みましょう!

Unityプロジェクト上に画像を取り込めたら
今度はHierarchyウィンドウ上にドラッグ&ドロップして
ゲームオブジェクトとして生成します!

続けて白い丸のスプライトをHierarchyウィンドウ上にある
緑の丸のゲームオブジェクト上にドラッグ&ドロップします!
以下を参考にしてください!

こうすることで白い丸は緑の丸の子オブジェクトとして生成されます
で、最後に緑の丸のOrder in Layerを1に変更してあげましょう

ここまでで前提作業が終了しました
スクリプト上で子オブジェクトのOrder in Layerを変えてあげればいい

ここまで出来たら後はスクリプトでクリックした瞬間に
子オブジェクトである白い丸のOrder in Layer = 2とかにしてあげればいいだけですね
って言葉だけだと簡単なのですがちゃんと実装しようとすると
「クリックしたら」と「一瞬表示順序を変える」っていう大きく二つの
処理を作り込まないとです
なので以下でそれぞれ解説していきます
ゲームオブジェクトをクリックしたら何か処理を行うには?

ボタンの場合はOnClick()でクリックしたら何か処理を行うっていうのは
簡単にできるのですがゲームオブジェクトではそうはいきません。
マウス(スマホの場合はタッチ)の情報、つまり
どこかをクリック(タッチ)したかっていうのを
Unity上で認識できるようにしないとです
そーいうのを管理するのがEvent Systemなんですって!
先に結論からいうと以下が必要です!
・Event System
・Physics 2D Raycaster
・Collider
ってことでEventSystemを生成しよう
Event Systemは最初からあるわけじゃなく
自分で生成しないといけませんので生成しましょう
Hierarchyウィンドウ上で右クリック→UI→Event System
で生成できます

Physics 2D Raycasterをカメラにアタッチする!
実はEvent Systemだけではあんまり意味がありません
Event Systemと何かもう一つでやっと色々できるようになります
なんかそーいう商品(一つだけあってもしょうがない)って世の中に色々ありますよね!
例えばトミカ プラレールなんて正にそうです!
レールだけでも遊べなくはないですけど電車がないと意味がないわけですよ!
よく考えられていますよね!
Event Systemはトミカのレールみたいなもんです、多分。
ということでレールの上を走る電車として今回は
Physics 2D Raycasterをカメラにアタッチしてあげます。
Physics 2D Raycasterとは?

公式のマニュアルによるとPhysics 2D Raycasterとは
シーン内の 2D オブジェクトに対してレイキャストします。
https://docs.unity3d.com/ja/2019.4/Manual/script-Physics2DRaycaster.html
とのことです!おぉ、全然分からない!笑
ここで一番分からないのが「レイキャスト」だと思います
で、レイキャストは簡単に言うと「透明のビームを発射する」ってことらしいです
レイキャストの詳しい説明については以下の参考サイトが分かりやすかったです!
つまりPhysics 2D Raycasterは
シーン内の 2D オブジェクトに対して透明のビームを発射します
ということらしいです
で次に疑問になるのがこのビームを
「いつ」「どこで」発射するのか?ですね
これはマウスクリックや画面タッチによる外部からの入力が行われた瞬間に発射します
ということで以下になります
いつ→マウスクリック or 画面タッチした瞬間
どこで→マウスクリック or 画面タッチした場所
上記が分かるとなぜカメラにアタッチしないといけないか?
も分かってきますね!
ユーザはカメラ上に映っているものしかクリックできないからです
実際にアタッチしてみよう!
アタッチ自体は簡単でカメラのInspectorウィンドウから
Physics 2D Raycasterをアタッチします!

はい、これだけ!
衝突判定させないといけない

ここまでやっておきながら実は
Event System、Physics 2D Raycasterをアタッチするだけでは
あんまり意味がありません
確かにここまですれば透明のビームがどこで発射されたのかを
認識することができるようにはなりました!
なったんですがこのままでは発射されたビームは
どこにも衝突せずに消えてしまいます・・
銃とか弓とかって何かと衝突させるためにあるもので
何もないところで放ってもしょうがないですよね、悲しいかな
ということでビームと衝突させるものを作ってあげます!
前提でゲームオブジェクト自体は作成しましたが
これだけではダメで衝突判定を行うColliderをゲームオブジェクトにアタッチして
あげる必要があったんです!
ってことでアタッチしてあげましょう!
今回はCircle Colliderをアタッチしてあげます!
以下を参考にアタッチしましょう!

最後にスクリプトを作成してデバッグしよう!

これでやっと準備が整いました!
最後にスクリプトを作成してゲームオブジェクトを
クリックした瞬間にコンソールに文字列が
出力されるようにしましょう!
OnPointerDown関数をスクリプトに作成する
ゲームオブジェクトがクリックした時にスクリプトを動作させるには
OnPointerDown関数です!
最低限の実装を以下に示します
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Sample : MonoBehaviour, IPointerDownHandler
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void OnPointerDown(PointerEventData eventData)
{
Debug.Log("CLICK!");
}
}
上記ではEventSystemsをインポートし
IPointerDownHandlerを継承し
OnPointerDown関数を作成しています!
もうこれはこういうもんだと思って実装してみてください!汗
このSampleスクリプトを緑の丸のゲームオブジェクトにアタッチします!

この状態でゲーム開始してみましょう!

クリックした瞬間にコンソールに文字が表示されました!
一瞬だけ表示順序を変えるには?

もうここまで実装できたらあと少しです
白い丸の表示順序を緑の丸より上にしてあげましょう!
緑の丸をクリックした瞬間に白い丸の表示順序を変えて
ちょっとしたらまた白い丸の表示順序を緑の丸の後ろにするんです
これを実現しようとしたらコルーチンの出番ですね!
コルーチン知らないよって方は以下を是非みてくさい!
Sampleスクリプトを以下のように修正してあげましょう!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Sample : MonoBehaviour, IPointerDownHandler
{
[SerializeField]
private GameObject whiteBall;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void OnPointerDown(PointerEventData eventData)
{
// Debug.Log("CLICK!");
StartCoroutine(whiteOut());
}
private IEnumerator whiteOut()
{
whiteBall.GetComponent<SpriteRenderer>().sortingOrder = 2;
yield return new WaitForSeconds(0.1f);
whiteBall.GetComponent<SpriteRenderer>().sortingOrder = 0;
}
}
OnPointerDownでWhiteOut関数を呼び出しています
で、WhiteOut関数ではまず白い丸のsortingOrderを緑の丸より上にしてあげて
0.1秒後にsortingOrderを戻しています!
最後にSampleスクリプトに白い丸を設定してあげれば準備完了です!

これでゲーム開始してみましょう!

クリックすると一瞬白くすることができました!
めでたし、めでたし!
…そういえば、この記事を書いている最中に
アニメーションしているキャラを白くするにはどうするん?
って思ったのですが…それはちょっと難しそうなので
また今度!!汗