Unity uGUI用、分割テレポートシェーダー。画像をスライスして座標移動。
(Slice Teleport Shader for Unity uGUI)
関連ページ
昔のSFCや初期PSの作品では、キャラクターが粒子状になって画面上方に向かいテレポートする演出がよくあった。
ああ言うのが作りたいなと思って、x軸に画像を分割してそれっぽい処理が作れたので共有。ただちょっと使いにくいかも。
このシェーダーを作成後に更に研究を重ねて
粒子テレポートシェーダー
も作れたのでそちらも併せてどうぞ。
似たようなカテゴリーで、
ドラクエのワープ演出っぽいシェーダー
もある。
分割テレポートシェーダー概要
まず実装結果のサンプル動画は次の通り。
今回のシェーダーは事前に対象画像の座標やスケール情報をC#からシェーダーに受け渡す必要がある。
この辺りの処理が複雑で説明するのも少し面倒なので、SliceTeleportControllerというC#の仲介クラスも一緒に作っておいた。
実装に必要なシェーダー、マテリアル、C#スクリプトをまとめてUnityPackage化して、
こちら
にアップロードしてある。
なおSliceTeleportControllerではTweenという機能を使ってアニメーションを実装している。
このため、あらかじめ
DOTween
をアセットストアからインポートしておく必要あり。無料で便利なのでオススメ。
TweenではなくUnity Coroutineで対応したい場合は、SliceTeleportController内のコードを少し書き換える必要がある。
複雑なことはやっていないので、書き換える場合もそんなに難しくないと思う。
後述するがテレポート演出させたい画像に対しては、結構制約がある。
例えばSpriteEditorでスライスしてある画像や、アトラス内にパッケージしてある画像は上手く座標移動ができない。
周囲に透明部分のマージンがない画像は謎の線が走ったりするし、MeshTypeが適切でないと奇妙に画像が途切れる。
分割テレポートシェーダーの実装の仕方
SliceTeleport.UnityPackageをインポートすると、Projectに3つのファイルが追加される。
SliceTeleportControllerはSliceTeleportマテリアルを参照し、SliceTeleportマテリアルはSliceTeleportシェーダーを参照している。
まずはSliceTeleportControllerを、ImageコンポーネントがアタッチされたGameObjectにアタッチする。
するとSliceTeleportController内のReset関数によって、自動でメンバ変数の「Target」と「Canvas」に代入が実行される。
代入が実行されなかった場合(Imageコンポーネントがアタッチされてなかった場合など)はDebug.LogErrorが表示される。
これだけでほぼ前準備は終わりなので、続いてテストに入る。
UnityのPlayボタンを押して実行状態にし、SliceTeleportControllerを右クリック、すると下の方にデバッグコマンドが出てくる。
DebugDoTeleportがテレポートアニメーションの再生、DebugUndoTeleportがテレポートアニメーションの逆再生になる。
下はSliceTeleportController内のC#のコード。
#if UNITY_EDITOR
[ContextMenu("DebugDoTeleport")]
private void DebugDoTeleport()
{
DoTeleport(8, 1.5f);
}
[ContextMenu("DebugUndoTeleport")]
private void DebugUndoTeleport()
{
UndoTeleport(8, 1.5f);
}
#endif
SliceTeleportController内にDoTeleportとUndoTeleportがpublic関数として用意してある。
他のC#スクリプトからこの関数にアクセスし、アニメーションを実行できる。
第1引数の跳躍距離は、ピクセル距離とかではなく自分のImageの高さの何倍かという値になるので注意。
/// <summary>
/// テレポートを実行
/// </summary>
/// <param name="distance">テレポートの跳躍距離</param>
/// <param name="duration">テレポートにかかる時間</param>
public
void
DoTeleport(float
distance,
float
duration)
{
SetBaseMaterialValue();
target.material.SetFloat("_Distance",
distance);
target.material.SetFloat("_TeleportPow",
0);
DOTween.To(()
=>
target.material.GetFloat("_TeleportPow"),
(val)
=>
{
target.material.SetFloat("_TeleportPow",
val);
},
1,
duration).SetEase(Ease.InQuad);
}
/// <summary>
/// テレポートの逆再生
/// </summary>
/// <param name="distance">テレポートの跳躍距離</param>
/// <param name="duration">テレポートにかかる時間</param>
public
void
UndoTeleport(float
distance,
float
duration)
{
SetBaseMaterialValue();
target.material.SetFloat("_Distance",
distance);
target.material.SetFloat("_TeleportPow",
1);
DOTween.To(()
=>
target.material.GetFloat("_TeleportPow"),
(val)
=>
{
target.material.SetFloat("_TeleportPow",
val);
},
0,
duration).SetEase(Ease.OutQuad).OnComplete(()
=>
{
target.material.SetFloat("_Distance",
1);
target.material.SetFloat("_PosY",
0);
});
}
他の機能として、x軸にスライスする回数の変更と、色の変更処理がある。
それぞれ、DoTeleportやUndoTeleportを呼ぶ前に実行する必要がある。
下はスライス回数変更のSliceTeleportController.SetSeliceCount関数。
/// <summary>
/// テレポートする際の画像の分割数を変更する。1~20の指定が可能
/// </summary>
public
void
SetSeliceCount(int
sliceCount)
{
this.sliceCount
=
sliceCount;
}
引数のsliceCountに2を渡すとx軸に3分割、3を渡すと5分割、4を渡すと7分割になる。
つまり1 + (sliceCount - 1) * 2みたいな計算式で我ながら少し分かり辛い。
下はSliceCountを操作した際の見た目の違い。20まで上げると最早ただの矢印になる。
続いて色の変更処理について。このシェーダーは転送が進むにつれて画像が単一色に変化するが、その色を変更できる。
下がその変更処理のSliceTeleportController.SetColor関数。
/// <summary>
/// テレポートする際の単一色の指定
/// </summary>
public
void
SetColor(Color
color)
{
isUseMonoCol
=
true;
monoCol
=
color;
}
下の動画は、色を変更するとどうなるかのサンプル。
また単一色の変化していく効果を切ることもできる。
下はそのSliceTeleportController.UnsetColor関数のコードとサンプル動画。
/// <summary>
/// テレポートする際に単一色に変化させない設定
/// </summary>
public
void
UnsetColor()
{
isUseMonoCol
=
false;
}
実装する際の注意点
テレポートシェーダーを適用させる画像は独立した画像である必要がある。
例えば下のようなキャラチップをまとめた画像があったとする。
SpriteEditorで適切に分割。
分割した一番最初の画像をImageに割り当てたとする。
この状態のImageコンポーネントに対し、テレポートシェーダーを使うと次のようになる。
色々おかしいが、まずもって画像がx軸に分割されていない。
画像全体に対しては分割処理をしているが、対象のキャラチップは画像全体の左端にあり、その狭い範囲では分割されていない。
テレポートする際の画像の座標移動も、キャラチップ単体ではなく、画像全体を基準にして実行している。
似た理屈で、画像をアトラス化してしまうと上手くシェーダーが機能しない。
まだ独立した画像であっても、周囲に透明マージンがないとおかしな事になる。
例えば下のような画像があったとする。見ての通り周囲に全くマージンがない。
これに対しテレポートシェーダーを走らせると次のようになる。
上下に謎の線が走っているのが確認できる。
内部的なことを言うと、このシェーダーはプロパティのDistanceの値の分だけ、頂点シェーダーでy軸に画像を引き伸ばしている。
この引き伸ばし処理の時に、画像端に接してる部分のピクセル色をそのままコピーし続けてしまう。
なので下の画像のように、周囲に透明部分を作って画像端のピクセル色はα=0である必要がある。
画像を用意しただけでは不十分で、インスペクター上で対象画像のMeshTypeをFullRectにする必要がある。
こうしないと親切にもUnity側で勝手にマージン部分を切り詰めてしまう。
ここまで調整すると、まともなテレポート演出が確認できる。
0
0