最近よくあるホール系ゲームと言うんですかね。床の穴が大きくなって飲み込んでいく系ゲーム。
必要なオブジェクトの準備
GameObjectの名前はGroundに変更
Position(0,0,0)、Rotation(90,0,0)、Scale(10,10,10)
TransformはResetでOK。(Transformコンポーネントを右クリックReset選択)
HoleParentの子供にCylinder:Holeを追加
TransformはReset後にScale(0,0.1,0)
TransformはReset
2Dto3DColliderの子供にGameObject:2DGroundを追加
2DGroundにPolygonCollider2Dを追加
Points>Paths>Element 0を以下の様に設定。
2Dto3DColliderの子供にGameObject:2DHoleを追加
2DHoleにPolygonCollider2Dを追加。こちらは一旦設定しなくてそのままでOK。
ここで、各コライダーの状態が、選択状態でないと見えないのが少し編集しづらいので、プロジェクト設定を変更します。
Edit>Project Settingsからプロジェクト設定を開きます。Physics2DのGizmosを開いてAlways Show Colliders にチェックを入れてください。
すると選択してない状態でも2つのコライダーが表示されるようになります。
穴の位置変化についてくるためのスクリプト
まずは下記スクリプト(HoleColliderBuilder)を作成
using UnityEngine;
public class HoleColliderBuilder : MonoBehaviour
{
[SerializeField] private PolygonCollider2D hole2D;
[SerializeField] private PolygonCollider2D ground2D;
private void FixedUpdate()
{
if (transform.hasChanged)
{
transform.hasChanged = false;
hole2D.transform.position = new Vector2(transform.position.x, transform.position.z);
MakeHole2D();
}
}
private void MakeHole2D()
{
Vector2[] pointPositions = hole2D.GetPath(0);
for (int i = 0; i < pointPositions.Length; i++)
{
pointPositions[i] = hole2D.transform.TransformPoint(pointPositions[i]);
}
ground2D.pathCount = 2;
ground2D.SetPath(1, pointPositions);
}
}
スクリプトを保存したら、HoleParentに貼り付けて、コンポーネントに2DHoleと2DGroundをセットします。セットできたらUnityを再生してHoleParentを水平方向に移動させてみてください。下図の様にPolygonCollider2Dが連動して動いたらここまでの実装は成功です!
2Dのコライダーの表示確認はここまででOKですので、Project Settings>Physics 2D>Gizmos>Always Show Collidersのチェックは外しておきましょう!
穴の空いた床の当たり判定を作る
スクリプトを少し変更します。長いですが全部載せておきます。
using UnityEngine;
public class HoleColliderBuilder : MonoBehaviour
{
[SerializeField] private PolygonCollider2D hole2D;
[SerializeField] private PolygonCollider2D ground2D;
[SerializeField] private MeshCollider generatedMeshCollider;
private Mesh generatedMesh;
private void FixedUpdate()
{
if (transform.hasChanged)
{
transform.hasChanged = false;
hole2D.transform.position = new Vector2(transform.position.x, transform.position.z);
MakeHole2D();
MakeMeshCollider();
}
}
private void MakeHole2D()
{
Vector2[] pointPositions = hole2D.GetPath(0);
for (int i = 0; i < pointPositions.Length; i++)
{
pointPositions[i] = hole2D.transform.TransformPoint(pointPositions[i]);
}
ground2D.pathCount = 2;
ground2D.SetPath(1, pointPositions);
}
private void MakeMeshCollider()
{
if (generatedMesh != null)
{
Destroy(generatedMesh);
}
generatedMesh = ground2D.CreateMesh(true, true);
generatedMeshCollider.sharedMesh = generatedMesh;
}
}
スクリプトを更新したら、Unity側の設定。
2Dto3DColliderの子供に空のGameObject:3DGroundColliderを追加
3DGroundColliderにMeshColliderをAddComponent追加。追加後はHoldeColliderBuilderのGeneratedMeshColliderにセット。
この状態でUnityを再生して、先程同様にHoleParentを水平方向に動かすと、当たり判定が動いているのが確認出来ます。下図はわかりやすくするためにWindow>Analysis>Physics DebuggerをOnにしてシーンビュー右下のCollision GeometryをOnにしています。(見なくても良くなったならPhysics Debuggerウインドを閉じてください)
当たり判定の表示に満足したら、3DGroundCollider>Rotation(90,0,0)に変更。Groundの当たり判定は使わなくなるのでGroundのMeshColliderのチェックを外すか、コンポーネントごと削除しておきましょう。
当たり判定の調整
固定の大きさでしか対応出来ないと、遊びとしては使いづらいので、HoleParentのスケールに影響を受けるように変更します。スクリプトの追加を行いますが、1行のみのため、さすがに変更点のみ表示。
private void FixedUpdate()
{
if (transform.hasChanged)
{
transform.hasChanged = false;
hole2D.transform.position = new Vector2(transform.position.x, transform.position.z);
hole2D.transform.localScale = transform.localScale * 0.5f;
MakeHole2D();
MakeMeshCollider();
}
}
この変更を適応すると、HoleParentのサイズを変更すると、穴の当たり判定も影響を受けます。
実際に穴に落ちてもらう
ここまで来たら、あとはCubeなどを用意して穴に落としてみましょう。下図はCubeのLayerを別のものを用意して、PhysicsDebuggerで表示させないように少しだけ変更を加えています。もし落下しない場合は、Groundの当たり判定が残ったままであったり、CubeにRigidbodyがついていなかったりしないか確認してみてください。
落下はすれど、沼に埋もれていくような表現になっていますね。実際のゲームで穴の空いた床として利用する場合はもう少し表示の工夫が必要ですね。
穴の空いた表現を取り入れたい場合はこちらの記事がおすすめです。
コメント