using System.Collections; using Unity.BossRoom.Gameplay.GameplayObjects.Character; using Unity.Netcode; using UnityEngine; [RequireComponent(typeof(NetworkObject))] public class MeteorStrikeEffect : NetworkBehaviour { [Header("Meteor Shower Settings")] [Tooltip("Prefab of a single meteor. Must have Collider + (optionally) Rigidbody + NetworkObject if you want networked meteors.")] public GameObject meteorPrefab; [Tooltip("Number of meteors to spawn over the duration.")] public int meteorCount = 10; [Tooltip("Total time (in seconds) over which meteors will fall.")] public float strikeDuration = 3f; [Tooltip("Horizontal radius (XZ plane) around this object's position where meteors will land.")] public float strikeRadius = 10f; [Tooltip("Vertical offset above this object's position from which meteors spawn.")] public float spawnHeight = 20f; [Tooltip("If checked, the shower will start automatically on network spawn.")] public bool startOnAwake = true; private Coroutine _showerRoutine; public override void OnNetworkSpawn() { // Only run on the server if (!IsServer) return; if (startOnAwake) { StartShower(); } } /// /// Public method to kick off the meteor shower at this GameObject's position. /// public void StartShower() { if (!IsServer) return; if (_showerRoutine != null) StopCoroutine(_showerRoutine); _showerRoutine = StartCoroutine(ShowerCoroutine()); } private IEnumerator ShowerCoroutine() { float interval = strikeDuration / Mathf.Max(1, meteorCount); Vector3 center = transform.position; for (int i = 0; i < meteorCount; i++) { // pick a random landing point in the XZ circle Vector2 offset = Random.insideUnitCircle * strikeRadius; Vector3 spawnPos = new Vector3( center.x + offset.x, center.y + spawnHeight, center.z + offset.y ); // instantiate the meteor var go = Instantiate(meteorPrefab, spawnPos, Quaternion.identity); // if it has a NetworkObject, spawn it on clients if (go.TryGetComponent(out var netObj)) { netObj.Spawn(true); } else { // otherwise ensure it falls via physics var rb = go.GetComponent() ?? go.AddComponent(); rb.useGravity = true; } // attach our collision-forwarder var mb = go.AddComponent(); mb.controller = this; yield return new WaitForSeconds(interval); } } /// /// Override this in a subclass or add logic here to handle when a meteor hits something. /// /// The object struck by the meteor. protected virtual void OnHit(GameObject hitObject) { Debug.Log($"[Server] Meteor hit: {hitObject.name}"); // TODO: your custom hit logic here } private void OnDrawGizmosSelected() { // visualize the landing radius in the editor Gizmos.matrix = transform.localToWorldMatrix; Gizmos.DrawWireSphere(Vector3.zero, strikeRadius); } /// /// Internal helper attached to each spawned meteor to forward collisions. /// private class MeteorBehavior : MonoBehaviour { [HideInInspector] public MeteorStrikeEffect controller; private void OnCollisionEnter(Collision collision) { if (controller != null && controller.IsServer) { controller.OnHit(collision.gameObject); } Destroy(gameObject); } } }