initial upload
This commit is contained in:
92
MMI2-project/Assets/Scripts/RingCheckpoint.cs
Normal file
92
MMI2-project/Assets/Scripts/RingCheckpoint.cs
Normal file
@ -0,0 +1,92 @@
|
||||
using UnityEngine;
|
||||
using HeneGames.Airplane;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
[DefaultExecutionOrder(-100)]
|
||||
public class RingCheckpoint : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private RingCourseTracker tracker;
|
||||
[SerializeField] private int orderIndex;
|
||||
|
||||
private bool passed;
|
||||
|
||||
public int OrderIndex => orderIndex;
|
||||
public bool Passed => passed;
|
||||
|
||||
public void Configure(RingCourseTracker courseTracker, int index)
|
||||
{
|
||||
tracker = courseTracker;
|
||||
orderIndex = index;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
EnsureTriggerCollider();
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
EnsureTriggerCollider();
|
||||
}
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (passed || tracker == null)
|
||||
return;
|
||||
|
||||
if (!IsAirplaneCollider(other))
|
||||
return;
|
||||
|
||||
tracker.RegisterRingPass(this);
|
||||
}
|
||||
|
||||
private static bool IsAirplaneCollider(Collider other)
|
||||
{
|
||||
if (other.TryGetComponent<SimpleAirPlaneCollider>(out _))
|
||||
return true;
|
||||
|
||||
return other.GetComponentInParent<SimpleAirPlaneController>() != null;
|
||||
}
|
||||
|
||||
private void EnsureTriggerCollider()
|
||||
{
|
||||
foreach (var meshCollider in GetComponents<MeshCollider>())
|
||||
meshCollider.enabled = false;
|
||||
|
||||
if (!TryGetComponent<BoxCollider>(out var box))
|
||||
box = gameObject.AddComponent<BoxCollider>();
|
||||
|
||||
box.isTrigger = true;
|
||||
|
||||
if (TryGetComponent<Renderer>(out var renderer))
|
||||
{
|
||||
Bounds bounds = renderer.bounds;
|
||||
box.center = transform.InverseTransformPoint(bounds.center);
|
||||
Vector3 scale = transform.lossyScale;
|
||||
box.size = new Vector3(
|
||||
bounds.size.x / Mathf.Max(Mathf.Abs(scale.x), 0.001f),
|
||||
bounds.size.y / Mathf.Max(Mathf.Abs(scale.y), 0.001f),
|
||||
bounds.size.z / Mathf.Max(Mathf.Abs(scale.z), 0.001f));
|
||||
}
|
||||
else
|
||||
{
|
||||
box.center = Vector3.zero;
|
||||
box.size = Vector3.one * 12f;
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkPassed()
|
||||
{
|
||||
passed = true;
|
||||
|
||||
if (TryGetComponent<Collider>(out var collider))
|
||||
collider.enabled = false;
|
||||
}
|
||||
|
||||
public void ResetCheckpoint()
|
||||
{
|
||||
passed = false;
|
||||
EnsureTriggerCollider();
|
||||
}
|
||||
}
|
||||
11
MMI2-project/Assets/Scripts/RingCheckpoint.cs.meta
Normal file
11
MMI2-project/Assets/Scripts/RingCheckpoint.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c4e9a2b1d8f4e6a9b0c3d5e7f1a2b4c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
111
MMI2-project/Assets/Scripts/RingCourseTracker.cs
Normal file
111
MMI2-project/Assets/Scripts/RingCourseTracker.cs
Normal file
@ -0,0 +1,111 @@
|
||||
using UnityEngine;
|
||||
|
||||
[DefaultExecutionOrder(-50)]
|
||||
public class RingCourseTracker : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Drag each Ring object here in the order they must be flown through.")]
|
||||
[SerializeField] private Transform[] ringsInOrder;
|
||||
|
||||
[SerializeField] private string landInstructionMessage =
|
||||
"All rings complete! Land the plane at the runway.";
|
||||
|
||||
private RingCheckpoint[] checkpoints;
|
||||
private int nextRingIndex;
|
||||
private int ringsPassed;
|
||||
private bool courseComplete;
|
||||
|
||||
public int RingsPassed => ringsPassed;
|
||||
public int TotalRings => checkpoints != null ? checkpoints.Length : 0;
|
||||
public bool CourseComplete => courseComplete;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
BindRings();
|
||||
}
|
||||
|
||||
private void BindRings()
|
||||
{
|
||||
if (ringsInOrder == null || ringsInOrder.Length == 0)
|
||||
{
|
||||
Debug.LogWarning($"[RingCourse] No rings assigned on {name}.", this);
|
||||
checkpoints = System.Array.Empty<RingCheckpoint>();
|
||||
return;
|
||||
}
|
||||
|
||||
checkpoints = new RingCheckpoint[ringsInOrder.Length];
|
||||
|
||||
for (int i = 0; i < ringsInOrder.Length; i++)
|
||||
{
|
||||
Transform ringTransform = ringsInOrder[i];
|
||||
if (ringTransform == null)
|
||||
{
|
||||
Debug.LogWarning($"[RingCourse] Ring slot {i + 1} is empty on {name}.", this);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ringTransform.TryGetComponent(out RingCheckpoint checkpoint))
|
||||
checkpoint = ringTransform.gameObject.AddComponent<RingCheckpoint>();
|
||||
|
||||
checkpoint.Configure(this, i);
|
||||
checkpoint.ResetCheckpoint();
|
||||
checkpoints[i] = checkpoint;
|
||||
}
|
||||
|
||||
nextRingIndex = 0;
|
||||
ringsPassed = 0;
|
||||
courseComplete = false;
|
||||
|
||||
if (TotalRings > 0 && checkpoints[0] != null)
|
||||
Debug.Log($"[RingCourse] Course started. Fly through ring 1: {checkpoints[0].name}");
|
||||
}
|
||||
|
||||
public void RegisterRingPass(RingCheckpoint ring)
|
||||
{
|
||||
if (courseComplete || ring == null || checkpoints == null)
|
||||
return;
|
||||
|
||||
int ringIndex = System.Array.IndexOf(checkpoints, ring);
|
||||
if (ringIndex < 0)
|
||||
return;
|
||||
|
||||
if (ring.Passed)
|
||||
return;
|
||||
|
||||
if (ringIndex != nextRingIndex)
|
||||
{
|
||||
RingCheckpoint expected = checkpoints[nextRingIndex];
|
||||
string expectedName = expected != null ? expected.name : $"ring {nextRingIndex + 1}";
|
||||
Debug.LogWarning(
|
||||
$"[RingCourse] Wrong order. Pass {expectedName} next ({nextRingIndex + 1}/{TotalRings}).");
|
||||
return;
|
||||
}
|
||||
|
||||
ring.MarkPassed();
|
||||
ringsPassed++;
|
||||
nextRingIndex++;
|
||||
|
||||
Debug.Log($"[RingCourse] Ring {ringsPassed}/{TotalRings} passed: {ring.name}");
|
||||
|
||||
if (ringsPassed >= TotalRings)
|
||||
{
|
||||
courseComplete = true;
|
||||
Debug.Log($"[RingCourse] {landInstructionMessage}");
|
||||
return;
|
||||
}
|
||||
|
||||
RingCheckpoint nextRing = checkpoints[nextRingIndex];
|
||||
if (nextRing != null)
|
||||
Debug.Log($"[RingCourse] Next ring ({nextRingIndex + 1}/{TotalRings}): {nextRing.name}");
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[ContextMenu("Fill Rings From Children (scene order)")]
|
||||
private void FillRingsFromChildren()
|
||||
{
|
||||
ringsInOrder = new Transform[transform.childCount];
|
||||
for (int i = 0; i < transform.childCount; i++)
|
||||
ringsInOrder[i] = transform.GetChild(i);
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
11
MMI2-project/Assets/Scripts/RingCourseTracker.cs.meta
Normal file
11
MMI2-project/Assets/Scripts/RingCourseTracker.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d5f0b3c2e9a4f7b8c1d4e6a0b2c3d5e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user