using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; namespace DamageVolumeSystem { [Icon("Assets/Scripts/DamageVolumeSystem/Icon/DamageGenerator.png")] [RequireComponent(typeof(BoxCollider))] [ExecuteAlways] public class DamageGenerator : MonoBehaviour { [HideInInspector] public DamageHost binding; // 伤害 public int damage = 2500; // 衰减曲线 public AnimationCurve falloffCurveByDistance = AnimationCurve.Linear(0, 1, 1, 0); public AnimationCurve falloffCurveBySpeed = AnimationCurve.Linear(0, 1, 1, 0); // 碰撞体 private BoxCollider _collider; // 碰撞时发生伤害 public bool emitOnCollide = true; // 扫描到的碰撞体 private readonly HashSet _scannedHosts = new(); // 速度缩放 private float _speedScale; // 上一帧的位置 private Vector3 _lastPosition; private void Start() { _collider = GetComponent(); } private void FixedUpdate() { var p = transform.position; var distanceToLast = Vector3.Distance(p, _lastPosition); var next = falloffCurveBySpeed.Evaluate(1 - Mathf.Clamp01(distanceToLast / 1.5f)); _speedScale = 0.5f + next * 2; _lastPosition = p; } public void Update() { #if UNITY_EDITOR _collider.isTrigger = true; _collider.center = Vector3.zero; _collider.size = transform.lossyScale; #endif } private void OnTriggerEnter(Collider other) { var damageHost = other.GetComponent(); if (damageHost != null && _scannedHosts.Add(damageHost)) { // 碰撞时立刻产生伤害 if (emitOnCollide) Emit(); } } private void OnTriggerExit(Collider other) { var damageHost = other.GetComponent(); if (damageHost != null && _scannedHosts.Contains(damageHost)) { _scannedHosts.Remove(damageHost); } } public void Emit() { var pos = transform.position; foreach (var scannedHost in _scannedHosts) { var selfGroup = binding?.group ?? 12; if (selfGroup == scannedHost.group) continue; var posTarget = scannedHost.transform.position; var distance = Vector3.Distance(pos, posTarget); var percent = Mathf.Clamp01(distance / 2); var direction = (posTarget - pos).normalized; // 用衰减曲线重新映射百分比 var rePercent = falloffCurveByDistance.Evaluate(1 - percent); var calcDamage = Mathf.RoundToInt(rePercent * damage * _speedScale); Debug.Log($"[伤害生成器: {gameObject.name}] 对 {scannedHost.name} 造成 {calcDamage} 点伤害 (距离衰减 {percent} -> {rePercent}, 速度增益 {_speedScale})"); scannedHost.onDamageReceived.Invoke(new Damage { Group = binding?.group ?? 12, Force = calcDamage, Direction = direction, }); } } # region Display private void OnDrawGizmos() { var t = transform; Gizmos.color = GetColorByGroupId(binding?.group?? 12); // 画指向线 foreach (var scannedHost in _scannedHosts) { Gizmos.DrawLine(scannedHost.transform.position, t.position); } // 画生成框 Gizmos.matrix = t.localToWorldMatrix; DrawSpecialCube(Vector3.zero, t.lossyScale); } private void DrawSpecialCube(Vector3 center, Vector3 size) { var color = Gizmos.color; Gizmos.DrawWireCube(center, size); Gizmos.color = new Color(color.r, color.g, color.b, 0.5f); Gizmos.DrawCube(center, size); } private Color GetColorByGroupId(int group) { switch (group) { case 0: return Color.red; case 1: return Color.blue; case 2: return Color.green; case 3: return Color.yellow; case 4: return Color.magenta; case 5: return Color.cyan; case 6: return new Color(1f, 0.5f, 0f); case 7: return new Color(0.4f, 0.01f, 0.5f); case 8: return new Color(0.63f, 0.87f, 0f); case 9: return new Color(0.98f, 0.67f, 0.91f); case 10: return new Color(0.49f, 0.93f, 0.67f); case 11: return new Color(0.11f, 0.55f, 0.8f); default: return Color.white; } } #endregion } }