62
60

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Unity]タップして波紋エフェクトを出す手順

Last updated at Posted at 2017-06-10

概要

Unityのシェーダーを使ってタップ(またはクリック)した時に波紋のアニメーションを生成する方法

demo.gif

こんな感じで水面に広がる波紋のようにアニメーションさせるスクリプトを書いてみました。
https://github.com/katsuma99/TapRippleShader

以下にシェーダーのソースを載せていますが、今回は細かい解説はなしに波紋エフェクトが使えるように手順を説明していきます。また、波紋エフェクトはタップした時に発生させることを想定しているため、タップ時の当たり判定についても少し解説します。

Ripple.shader
Shader "Custom/Ripple" {
	Properties
	{
		[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
		[HideInInspector]_StartTime("StartTime", Float) = 0
		_AnimationTime("AnimationTime", Range(0.1, 10.0)) = 1.5
		_Width("Width", Range(0.1, 3.0)) = 0.3
		_StartWidth("StartWidth", Range(0, 1.0)) = 0.3
		[Toggle] _isAlpha("isAlpha",Float) = 1
		[Toggle] _isColorShift("isColorShift",Float) = 1
		[MaterialToggle] PixelSnap("Pixel snap", Float) = 1
	}

	SubShader
	{
		Tags
		{
			"Queue" = "Transparent"
			"IgnoreProjector" = "True"
			"PreviewType" = "Plane"
		}

		Lighting Off
		ZWrite Off
		Fog{ Mode Off }
		Blend SrcAlpha OneMinusSrcAlpha

		Pass
		{
			CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile DUMMY PIXELSNAP_ON
#include "UnityCG.cginc"

			struct v2f
			{
				float4 vertex   : SV_POSITION;
				half2 texcoord  : TEXCOORD0;
			};

			v2f vert(appdata_base IN)
			{
				v2f OUT;
				OUT.vertex = UnityObjectToClipPos(IN.vertex);
				OUT.texcoord = IN.texcoord;
				return OUT;
			}

			fixed3 shift_col(fixed3 RGB, half3 shift)
			{
				fixed3 RESULT = fixed3(RGB);
				float VSU = shift.z*shift.y*cos(shift.x*3.14159265 / 180);
				float VSW = shift.z*shift.y*sin(shift.x*3.14159265 / 180);

				RESULT.x = (.299*shift.z + .701*VSU + .168*VSW)*RGB.x
					+ (.587*shift.z - .587*VSU + .330*VSW)*RGB.y
					+ (.114*shift.z - .114*VSU - .497*VSW)*RGB.z;

				RESULT.y = (.299*shift.z - .299*VSU - .328*VSW)*RGB.x
					+ (.587*shift.z + .413*VSU + .035*VSW)*RGB.y
					+ (.114*shift.z - .114*VSU + .292*VSW)*RGB.z;

				RESULT.z = (.299*shift.z - .3*VSU + 1.25*VSW)*RGB.x
					+ (.587*shift.z - .588*VSU - 1.05*VSW)*RGB.y
					+ (.114*shift.z + .886*VSU - .203*VSW)*RGB.z;

				return RESULT;
			}

			sampler2D _MainTex;
			float _StartTime,_Width,_StartWidth, _AnimationTime, _isAlpha,_isColorShift;
			fixed4 frag(v2f IN) : SV_Target
			{
				fixed4 color = tex2D(_MainTex, IN.texcoord);
				float2 pos = (IN.texcoord - float2(0.5,0.5)) * 2; //-1~1 幅2
				float dis = (_Time.y - _StartTime) / _AnimationTime + _StartWidth - length(pos);

				if (dis < 0 || dis > _Width)
					return fixed4(0,0,0,0);

				float alpha = 1;
				if (_isAlpha == 1)
				{
					alpha = clamp((_Width - dis) * 3, 0.1, 1.5);
				}

				fixed3 shiftColor = color;
				if (_isColorShift == 1)
				{
					half3 shift = half3(_Time.w * 10, 1, 1);
					shiftColor = shift_col(color, shift);
				}

				return fixed4(shiftColor, color.a * alpha);
			}
			ENDCG
		}
	}
	Fallback "Sprites/Default"
}

使用するための手順

 1. マテリアルの作成
 2. ゲームオブジェクトの作成
 3. タッチパネルの作成

Step1.マテリアルの作成

まずは、波紋シェーダーをアタッチするために、ProjectタブでマテリアルTapRippleMatを作成します。

  マテリアルの作成:Project > Create > Material

次に、シェーダーRippleを作成し、冒頭で紹介したコードをそのままコピペして上書きします。

  シェーダーの作成:Project > Create > Shader > ImageEffectShader

最後に、作成したTapRippleMatRippleをアタッチし、InspectorタブのShaderプルダウンでCustom/Rippleを指定します。これで、波紋シェーダーのマテリアルが完成しました。シェーダーのパラメータをいじることで様々な波紋エフェクトを作成できます。(後で説明)

シェーダーinspector.PNG

Step2.ゲームオブジェクトの作成

タップした場所に波紋を生成するゲームオブジェクトTapEffectを作成します。正確には波紋を描画するための平面をアタッチしたゲームオブジェクトを生成するため、Hierarchy上でSpriteを生成します。

  スプライトの作成:Hierarchy > 2DObject > Sprite

次に、以下のテクスチャをProject上にドラック&ドロップでインポートします。そして、TapEffectのSpriteRenderer > Spriteに割り当てます。

TapCircle.png

次に、C#スクリプトTapCircleを作成し、以下のコードをコピペで上書きして、TapEffectにアタッチします。

  C#スクリプトの作成:Project > Create > C#Script

TapCircle
using UnityEngine;

[RequireComponent(typeof(SpriteRenderer))]
[RequireComponent(typeof(Collider2D))]
public class TapCircle : MonoBehaviour
{
    SpriteRenderer mSpriteRenderer;
    Collider2D mCircleCollider;

    void Awake()
    {
        mSpriteRenderer = transform.GetComponent<SpriteRenderer>();
        mCircleCollider = transform.GetComponent<Collider2D>();
    }

    void Start()
    {
        Invoke("unenabledTrigger", 0.05f);

        mSpriteRenderer.material.SetFloat("_StartTime", Time.time);

        float animationTime = mSpriteRenderer.material.GetFloat("_AnimationTime");
        float destroyTime = animationTime;
        destroyTime -= mSpriteRenderer.material.GetFloat("_StartWidth") * animationTime;
        destroyTime += mSpriteRenderer.material.GetFloat("_Width") * animationTime;
        Destroy(transform.gameObject, destroyTime);
    }

    public void unenabledTrigger()
    {
        mCircleCollider.enabled = false;
    }

    public void OnTriggerEnter2D(Collider2D collider)
    {
        //タップしたオブジェクト : collider

        //-----------------処理-----------------//

    }
}

すると自動的にTapEffectにCircleCollider2Dがアタッチされるので、CircleCollider2D > Radiusに0.5を指定してください。

ちなみに、タップの当たり判定についてはTapCircleのOnTriggerEnter2Dの関数内でタップしたオブジェクトcolliderに対して処理を行うことができます。
なお、タップするオブジェクトにはColliderと一緒にRigidbodyもアタッチしておいてください。当たり判定はColliderをアタッチしたどちらかのゲームオブジェクトにRigidbodyがないとできない仕様になっています。

  当たり判定の注意:Colliderの他にRigidbodyが必要

以上で、ゲームオブジェクトの設定ができたので、TapEffectをHierarchyからProjectへ移しておいてください。

inspector.PNG

Step3.タッチパネルの作成

まずは、C#スクリプトPlayTouchPanelを作成し、以下のコードをコピペして上書きしてください。

PlayTouchPanel
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
public class PlayTouchPanel : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
	public GameObject mTapEffect;

    public void OnPointerDown(PointerEventData eventData)
    {
        //マウスクリック時
        NewTapEffect(eventData.position);
    }

    public void OnPointerUp(PointerEventData eventData)
    {
    }

    public void OnDrag(PointerEventData eventData)
    {
    }


    void Update()
    {
        //タップ時
        CheckTap();
    }

    void CheckTap()
    {
        foreach (Touch t in Input.touches)
        {
            if (t.phase == TouchPhase.Began)
            {
                NewTapEffect(t.position);
            }
        }
    }

    //タップエフェクトを出す
    void NewTapEffect(Vector2 pos)
    {
        Vector2 worldPos = Camera.main.ScreenToWorldPoint(pos);
        Object.Instantiate(mTapEffect, worldPos, Quaternion.identity, transform);
    }
}

以上でProjectの編集は完了し、以下のように6ファイルを作成できていると思います。

project.PNG

次に、HierarchyにキャンバスTouchCanvasを作成し、その下に空のゲームオブジェクトTouchPanelを作ります。EventSystemはキャンバスを作成すると自動的に作られるタッチイベントを可能にするゲームオブジェクトです。

  キャンバスの作成:Hierarchy > UI > Canvas
  空のオブジェクトの作成:Hierarchy > CreateEmpty

Hierarchy.PNG

TouchPanelPlayTouchPanelをアタッチし、Scene上でTouchPanelの枠を操作して、RectTransformの領域をカメラ画面に合わせておきます。
またPlayTouchPanelをアタッチすると、自動的にCanvasRendererとImageがアタッチされていることがわかります。この2種類のコンポーネントはタッチイベントを発生させるために必要です。タッチイベントは、キャンバス上のイメージにタッチすることがトリガーとなっていることに注意してください。

  タッチイベントの注意:CanvasRendererとImageが必要

touchPanelInspector.PNG

以上でタッチパネルの作成が完了しました。
アプリを実行して画面にタッチすることで波紋が出ることを確認してい下さい。

パラメーターをいじる

項目 意味
AnimationTime 波紋エフェクトが発生して消えるまでの時間
Width 広がる波紋の幅(全長 : 2)
StartWidth エフェクト発生時の波紋の広がり度合(中心からの距離)
isAlpha   波紋にアルファをかけて柔らかくする
isColorShift 波紋の色を変えてカラフルにする

ripple1.gifripple1.PNG

ripple2.gifripple2.PNG

ripple3.gifripple3.PNG

お気に入りの波紋アニメーションを作成してみよう。

使用例

落ちてくる物をタップして、得点を稼ぐゲームです。
特にタップゲーはタップした時になにか反応がないと、タッチしたかわからず、操作性が微妙ってことになってしまうと思います。
タップした部分に波紋を広げることで、爽快感とタップした触感を視覚的に与えることができるのではないでしょうか。

使用例.gif



と、ただのゲームの宣伝なのですが。。。よければ応援お願いしますm・・m

参考資料

62
60
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
60

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?