【趣味】【ゲーム開発】2Dクオータービューに3Dスポットライトを適応する応用
目次
この記事の目的
今回の記事では、このクオータービューのマス目管理された
2次元の世界に、3次元のスポットライトを用いて、
懐中電灯で照らしているような表現の実装方法を紹介します。
◎クオータービューとは
2Dゲームのビジュアルにクオータービューというものがあります。
RPGツクールなどでよく見かけるような、
正方形のマス目を並べた世界ではなく、
ひし形のマス目を並べた世界です。
その特徴は、2Dの世界がより立体的に見えるということです。
Unityの機能を利用してクオータービューのマス目管理を行う場合、
“IsometricGrid”というシステムがあります。
これを利用せずとも、スプライトで自前実装することも可能です。
◎クオータービューの基本概念
まず基本的な概念として、クオータービューでは
「奥にあるオブジェクトから順に描画する」ということが必要です。
ここでいう「奥」とは、2次元世界なので “Y軸” です。
“Y軸”の値が大きいものから順に描画します。
しかし、様々な問題で描画関係が前後してしまう不具合があります。
それを解決する方法はこちらの記事をどうぞ。
ここで解説されている方法は、いわゆる2次元世界に “Z軸” の概念を追加し、
通常の “Y軸” に+α “Z軸” の値の大きなものから順に描画する、応用的な対処です。
なので、2次元世界ですがZ軸の概念を付与することになります。
※ここ重要です。
◎基本的なクオータービューにスポットライトを適応
先ほど、クオータービューは2次元世界だといいました。
なので、3次元世界にあるスポットライトで照らしてしまうと、
本来、建物の陰に隠れてほしいスポットライトの光が、
表側で照らされてしまうこともあります。
その対処方法の一つとして、
クオータービューにZ座標の概念を加える方法があります。
その対処は単純です。
ライトで照らしたいオブジェクトをライトよりもZ軸で奥に。
ライトで照らしたくないオブジェクトをライトよりもZ軸で手前に
置いていけばいいのです。
◎競合したZ軸の扱いの棲み分け
…?
ここでまずいなと思った方は勘がいいです。
クオータービューの不具合対応で追加したZ軸の概念と
スポットライトで照らす場合と照らさない場合を
判断するためのZ軸の概念が競合しています。
棲み分けのためのフォーマットを考えてみましょう。
この棲み分けをすれば、競合の問題は無くなりそうですね。
ライトの位置により建物の描画順を変える(本題)
さて、大体の問題は片付きましたが、まだ問題はあります。
クオータービューの建物は、
建物よりも手前にライトがある場合は照らしたいけれど、
建物よりも奥にライトがある場合は照らしたくないです。
この切り替えが必要です。
◎スクリプト
はい。
その切り替えのためのスクリプトがこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
using UnityEngine; public class ZPositionToggler : MonoBehaviour { [Header("境界線")] [SerializeField, Tooltip("境界線設定用の親Transform")] Transform borderParent = default; [SerializeField, Tooltip("Y軸の境界線")] float yBorder = 0.0f; [SerializeField, Tooltip("X軸境界線(Y軸境界線より左側の時)")] float leftXBorder = 0.0f; [SerializeField, Tooltip("X軸境界線(Y軸境界線より右側の時)")] float rightXBorder = 0.0f; [Header("対象のZ座標設定")] [SerializeField, Tooltip("対象のTransform(スポットライトの原点など)")] Transform targetTransform = default; [SerializeField, Tooltip("Z座標設定(X軸境界線よりも上に対象がある時)")] float zPosWhenOverXBorder = 0.1f; [SerializeField, Tooltip("Z座標設定(X軸境界線よりも下に対象がある時)")] float zPosWhenUnderXBorder = -0.1f; [Header("デバッグ表示用")] [SerializeField, Tooltip("X軸境界線の長さ")] float xLineLength = 32.0f; [SerializeField, Tooltip("Y軸境界線の長さ")] float yLineLength = 32.0f; /// <summary> /// ターゲットY座標と比較して比較X軸境界線を取得する /// </summary> float GetXBorderPos(Vector3 targetPos) { float yBorderPos = borderParent.position.x + yBorder; return borderParent.position.y + ((targetPos.x > yBorderPos) ? rightXBorder : leftXBorder); } /// <summary> /// ターゲット座標と比較してZ座標を取得する /// </summary> float GetZPos(Vector3 targetPos) { return ((targetPos.y > GetXBorderPos(targetPos)) ? zPosWhenOverXBorder : zPosWhenUnderXBorder); } /// <summary> /// Unity更新時処理 /// </summary> void FixedUpdate() { // 対象のTransformが未設定のため、早期リターン if (targetTransform == null) { Debug.LogError("対象のTransformが未設定です"); return; } // 境界線の親Transformが未設定のため、早期リターン if (borderParent == null) { Debug.LogError("境界線の親Transformが未設定です"); return; } // Z座標更新 Vector3 temp = transform.position; temp.z = GetZPos(targetTransform.position); transform.position = temp; } /// <summary> /// ギズモ(デバッグ用の線)を描画する /// </summary> void OnDrawGizmosSelected() { // Unityエディタ起動時のみ表示する #if UNITY_EDITOR // 境界線の親Transformが設定されていないなら、 // ギズモ描画不可能なので早期リターン if (borderParent == null) { Debug.LogError("境界線の親Transformが未設定です"); return; } // 計算用変数 Vector3 tempFrom; Vector3 tempTo; // Y軸境界線描画 Vector3 yBorderPos = borderParent.position; yBorderPos.x += yBorder; Gizmos.color = Color.green; tempFrom = yBorderPos; tempFrom.y += yLineLength * 0.5f; tempTo = yBorderPos; tempTo.y -= yLineLength * 0.5f; Gizmos.DrawLine(tempFrom, tempTo); // X軸境界線(左)描画 Gizmos.color = Color.red; tempFrom = yBorderPos; tempFrom.y += leftXBorder; tempTo = tempFrom; tempTo.x -= xLineLength; Gizmos.DrawLine(tempFrom, tempTo); // X軸境界線(右)描画 tempFrom = yBorderPos; tempFrom.y += rightXBorder; tempTo = tempFrom; tempTo.x += xLineLength; Gizmos.DrawLine(tempFrom, tempTo); #endif } } |
◎このスクリプトの使い方
①このスクリプトを建物のオブジェクトに付けます。
建物ごとに分けてそれぞれ付けます
②Inspectorで画像のようにTransformを設定します。
※BorderParentは全ての境界線の位置をまとめて動かすための空のTransformです。
※TargetTransformはここではスポットライトのTransformを設定して下さい。
③”境界線”の設定をします。
Sceneウィンドウでプレビューできます。
この画像のような見た目になるように設定してください。
④”対象のZ座標設定”を設定します。
・Z Pos When Over X Border
X軸境界線を越えている(プレビューの赤い線よりも上にTargetTransformがある)ときのZ座標
・Z Pos When Under Y Border
X軸境界線を越えていない(プレビューの赤い線よりも下にTargetTransformがある)ときのZ座標
◎実行結果イメージ
このような結果になれば、スクリプトの導入は成功です。
終わりに
以上です。
まずは一度挙動を試してみてください。
わからないことや不具合があればご連絡ください。