1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
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<DamageHost> _scannedHosts = new();
// 速度缩放
private float _speedScale;
// 上一帧的位置
private Vector3 _lastPosition;
private void Start()
{
_collider = GetComponent<BoxCollider>();
}
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<DamageHost>();
if (damageHost != null && _scannedHosts.Add(damageHost))
{
// 碰撞时立刻产生伤害
if (emitOnCollide)
Emit();
}
}
private void OnTriggerExit(Collider other)
{
var damageHost = other.GetComponent<DamageHost>();
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
}
}
|