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.
126 lines
3.9 KiB
C#
126 lines
3.9 KiB
C#
2 days ago
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|