You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HighGroundRoyaleNetcode/Assets/Scripts/Gameplay/MeteorStrikeEffect.cs

126 lines
3.9 KiB
C#

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();
}
}
/// <summary>
/// Public method to kick off the meteor shower at this GameObject's position.
/// </summary>
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<NetworkObject>(out var netObj))
{
netObj.Spawn(true);
}
else
{
// otherwise ensure it falls via physics
var rb = go.GetComponent<Rigidbody>() ?? go.AddComponent<Rigidbody>();
rb.useGravity = true;
}
// attach our collision-forwarder
var mb = go.AddComponent<MeteorBehavior>();
mb.controller = this;
yield return new WaitForSeconds(interval);
}
}
/// <summary>
/// Override this in a subclass or add logic here to handle when a meteor hits something.
/// </summary>
/// <param name="hitObject">The object struck by the meteor.</param>
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);
}
/// <summary>
/// Internal helper attached to each spawned meteor to forward collisions.
/// </summary>
private class MeteorBehavior : MonoBehaviour
{
[HideInInspector] public MeteorStrikeEffect controller;
private void OnCollisionEnter(Collision collision)
{
if (controller != null && controller.IsServer)
{
controller.OnHit(collision.gameObject);
}
Destroy(gameObject);
}
}
}