feat: Implement DownDash ability and related systems
- Added DownDash ability with cooldown and speed configuration. - Introduced DownDashState to handle down dashing mechanics, including gravity manipulation and animation playback. - Updated PlayerMovement to support DownDash functionality. - Enhanced PlayerStats to manage spring charge consumption and healing. - Modified PlayerCombat and WeaponHitBoxInstance to support new hit confirmation events. - Updated AbilityType to include new form types for character abilities. - Improved Gizmos for better visualization of enemy detection and attack ranges. - Added feedback systems for form switching in PlayerFeedback and IFeedbackPlayer. - Refactored combat and movement states to accommodate new abilities and ensure smooth transitions.
This commit is contained in:
@@ -61,6 +61,7 @@ namespace BaseGames.Combat
|
||||
_currentSource = source ?? _defaultSource;
|
||||
_attackerTransform = attacker ?? transform;
|
||||
_isActive = true;
|
||||
_collider.enabled = true;
|
||||
// 缓存宿主 Rigidbody2D(沿父层级向上查找)
|
||||
_ownerRigidbody = _attackerTransform.GetComponentInParent<Rigidbody2D>();
|
||||
// 每次激活清空当前激活期已命中目标集合(防止连击连段导致同一阶段多次命中目标)
|
||||
@@ -70,7 +71,8 @@ namespace BaseGames.Combat
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
_isActive = false;
|
||||
_isActive = false;
|
||||
_collider.enabled = false;
|
||||
_hitThisActivation.Clear();
|
||||
_hitCooldownTimers.Clear();
|
||||
}
|
||||
@@ -87,6 +89,8 @@ namespace BaseGames.Combat
|
||||
_collider = GetComponent<Collider2D>();
|
||||
if (!_collider.isTrigger)
|
||||
Debug.LogWarning($"[HitBox] {name}: Collider2D.isTrigger 应为 true。", this);
|
||||
// 初始状态关闭碰撞体,防止未激活时产生物理检测
|
||||
_collider.enabled = false;
|
||||
// 缓存 IClashService:OnTriggerEnter2D 为物理热路径,避免每次调用 Dictionary 查找
|
||||
_clashService = ServiceLocator.GetOrDefault<IClashService>();
|
||||
// 缓存宿主投射物(仅 Projectile GameObject 上挂载的 HitBox 非 null)
|
||||
@@ -96,6 +100,7 @@ namespace BaseGames.Combat
|
||||
private void OnDisable()
|
||||
{
|
||||
_isActive = false;
|
||||
if (_collider != null) _collider.enabled = false;
|
||||
_hitThisActivation.Clear();
|
||||
_hitCooldownTimers.Clear();
|
||||
}
|
||||
@@ -180,116 +185,122 @@ namespace BaseGames.Combat
|
||||
{
|
||||
var col = GetComponent<Collider2D>();
|
||||
if (col == null) return;
|
||||
// HitBox:激活 = 鲜红,非激活 = 极淡红轮廓
|
||||
Gizmos.color = _isActive
|
||||
? new Color(1f, 0.15f, 0.15f, 1f)
|
||||
: new Color(1f, 0.15f, 0.15f, 0.2f);
|
||||
DrawCollider2DWire(col);
|
||||
Color fill = _isActive ? new Color(1f, 0.15f, 0.15f, 0.25f) : new Color(1f, 0.15f, 0.15f, 0.05f);
|
||||
Color outline = _isActive ? new Color(1f, 0.15f, 0.15f, 0.90f) : new Color(1f, 0.15f, 0.15f, 0.25f);
|
||||
DrawCollider2DFilled(col, fill, outline);
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────
|
||||
// Gizmo 辅助(内联,不依赖外部工具类)
|
||||
// ────────────────────────────────────────────────────
|
||||
/// <summary>
|
||||
/// 根据 Collider2D 类型绘制正确的 wire 轮廓。
|
||||
/// 使用 <see cref="Gizmos.matrix"/> 统一应用 Transform 的移动/旋转/缩放。
|
||||
/// </summary>
|
||||
public static void DrawCollider2DWire(Collider2D col)
|
||||
// ── Gizmo 辅助(填充 + 轮廓,不依赖外部工具类)──────────────────────────
|
||||
|
||||
/// <summary>根据 Collider2D 类型绘制带填充色和轮廓的 2D Gizmo(供 HurtBox 等复用)。</summary>
|
||||
public static void DrawCollider2DFilled(Collider2D col, Color fill, Color outline)
|
||||
{
|
||||
var prev = Gizmos.matrix;
|
||||
Gizmos.matrix = col.transform.localToWorldMatrix;
|
||||
var prevMatrix = UnityEditor.Handles.matrix;
|
||||
UnityEditor.Handles.matrix = col.transform.localToWorldMatrix;
|
||||
|
||||
switch (col)
|
||||
{
|
||||
case BoxCollider2D box:
|
||||
DrawWireRect2D(box.offset, box.size);
|
||||
DrawFilledRect2D(box.offset, box.size, fill, outline);
|
||||
break;
|
||||
|
||||
case CircleCollider2D circle:
|
||||
DrawFilledCircle2D(circle.offset, circle.radius, fill, outline);
|
||||
break;
|
||||
|
||||
case CapsuleCollider2D caps:
|
||||
DrawWireCapsule2D(caps.offset, caps.size, caps.direction);
|
||||
DrawFilledCapsule2D(caps.offset, caps.size, caps.direction, fill, outline);
|
||||
break;
|
||||
|
||||
case PolygonCollider2D poly:
|
||||
for (int p = 0; p < poly.pathCount; p++)
|
||||
{
|
||||
var pts = poly.GetPath(p);
|
||||
for (int i = 0; i < pts.Length; i++)
|
||||
Gizmos.DrawLine(pts[i], pts[(i + 1) % pts.Length]);
|
||||
}
|
||||
break;
|
||||
|
||||
case CircleCollider2D circle:
|
||||
DrawWireCircle2D(circle.offset, circle.radius);
|
||||
DrawFilledPolygonPath2D(poly.GetPath(p), fill, outline);
|
||||
break;
|
||||
|
||||
default:
|
||||
// 其他类型回退到 bounds 近似(恢复矩阵后在世界空间绘制)
|
||||
Gizmos.matrix = prev;
|
||||
DrawWireRect2D(col.bounds.center, col.bounds.size);
|
||||
return;
|
||||
UnityEditor.Handles.matrix = Matrix4x4.identity;
|
||||
DrawFilledRect2D(col.bounds.center, col.bounds.size, fill, outline);
|
||||
break;
|
||||
}
|
||||
|
||||
Gizmos.matrix = prev;
|
||||
UnityEditor.Handles.matrix = prevMatrix;
|
||||
}
|
||||
|
||||
/// <summary>在当前 Gizmos 坐标系中绘制轴对齐矩形(2D 线框,兼容透视相机)。</summary>
|
||||
public static void DrawWireRect2D(Vector2 center, Vector2 size)
|
||||
/// <summary>向后兼容的线框接口(内部改调 DrawCollider2DFilled)。</summary>
|
||||
public static void DrawCollider2DWire(Collider2D col)
|
||||
=> DrawCollider2DFilled(col, new Color(1f, 1f, 1f, 0.05f), new Color(1f, 1f, 1f, 0.8f));
|
||||
|
||||
private static void DrawFilledRect2D(Vector2 center, Vector2 size, Color fill, Color outline)
|
||||
{
|
||||
float hx = size.x * 0.5f, hy = size.y * 0.5f;
|
||||
Vector3 tl = new Vector3(center.x - hx, center.y + hy, 0f);
|
||||
Vector3 tr = new Vector3(center.x + hx, center.y + hy, 0f);
|
||||
Vector3 br = new Vector3(center.x + hx, center.y - hy, 0f);
|
||||
Vector3 bl = new Vector3(center.x - hx, center.y - hy, 0f);
|
||||
Gizmos.DrawLine(tl, tr);
|
||||
Gizmos.DrawLine(tr, br);
|
||||
Gizmos.DrawLine(br, bl);
|
||||
Gizmos.DrawLine(bl, tl);
|
||||
}
|
||||
|
||||
/// <summary>用线段近似绘制 2D 圆周(不使用 DrawWireSphere,兼容透视相机)。</summary>
|
||||
public static void DrawWireCircle2D(Vector3 center, float radius, int segs = 32)
|
||||
{
|
||||
float step = 360f / segs;
|
||||
Vector3 prevPt = center + new Vector3(radius, 0f, 0f);
|
||||
for (int i = 1; i <= segs; i++)
|
||||
var verts = new Vector3[]
|
||||
{
|
||||
float a = i * step * Mathf.Deg2Rad;
|
||||
Vector3 nextPt = center + new Vector3(Mathf.Cos(a) * radius, Mathf.Sin(a) * radius, 0f);
|
||||
Gizmos.DrawLine(prevPt, nextPt);
|
||||
prevPt = nextPt;
|
||||
}
|
||||
new Vector3(center.x - hx, center.y + hy, 0f),
|
||||
new Vector3(center.x + hx, center.y + hy, 0f),
|
||||
new Vector3(center.x + hx, center.y - hy, 0f),
|
||||
new Vector3(center.x - hx, center.y - hy, 0f),
|
||||
};
|
||||
UnityEditor.Handles.DrawSolidRectangleWithOutline(verts, fill, outline);
|
||||
}
|
||||
|
||||
/// <summary>绘制 2D 胶囊轮廓(在 col.transform 局部坐标系中)。</summary>
|
||||
private static void DrawWireCapsule2D(Vector2 offset, Vector2 size, CapsuleDirection2D dir)
|
||||
private static void DrawFilledCircle2D(Vector2 center, float radius, Color fill, Color outline)
|
||||
{
|
||||
bool vert = dir == CapsuleDirection2D.Vertical;
|
||||
float radius = vert ? size.x * 0.5f : size.y * 0.5f;
|
||||
float half = Mathf.Max(0f, (vert ? size.y : size.x) * 0.5f - radius);
|
||||
Vector2 axis = vert ? Vector2.up : Vector2.right;
|
||||
Vector2 perp = vert ? Vector2.right : Vector2.up;
|
||||
Vector2 capA = offset + axis * half;
|
||||
Vector2 capB = offset - axis * half;
|
||||
|
||||
Gizmos.DrawLine(capA + perp * radius, capB + perp * radius);
|
||||
Gizmos.DrawLine(capA - perp * radius, capB - perp * radius);
|
||||
DrawArc2D(capA, radius, vert ? 0f : -90f, 180f);
|
||||
DrawArc2D(capB, radius, vert ? 180f : 90f, 180f);
|
||||
Vector3 c = new Vector3(center.x, center.y, 0f);
|
||||
UnityEditor.Handles.color = fill;
|
||||
UnityEditor.Handles.DrawSolidDisc(c, Vector3.back, radius);
|
||||
UnityEditor.Handles.color = outline;
|
||||
UnityEditor.Handles.DrawWireDisc(c, Vector3.back, radius);
|
||||
}
|
||||
|
||||
/// <summary>用多段直线近似绘制 2D 圆弧。</summary>
|
||||
private static void DrawArc2D(Vector2 c, float r, float startDeg, float spanDeg, int segs = 20)
|
||||
private static readonly System.Collections.Generic.List<Vector3> _capsuleVertsBuf
|
||||
= new System.Collections.Generic.List<Vector3>(64);
|
||||
|
||||
private static void DrawFilledCapsule2D(Vector2 offset, Vector2 size,
|
||||
CapsuleDirection2D dir, Color fill, Color outline)
|
||||
{
|
||||
float step = spanDeg / segs;
|
||||
var prev = c + new Vector2(Mathf.Cos(startDeg * Mathf.Deg2Rad) * r,
|
||||
Mathf.Sin(startDeg * Mathf.Deg2Rad) * r);
|
||||
for (int i = 1; i <= segs; i++)
|
||||
bool vert = dir == CapsuleDirection2D.Vertical;
|
||||
float radius = vert ? size.x * 0.5f : size.y * 0.5f;
|
||||
float half = Mathf.Max(0f, (vert ? size.y : size.x) * 0.5f - radius);
|
||||
Vector2 axis = vert ? Vector2.up : Vector2.right;
|
||||
Vector2 capA = offset + axis * half; // 顶部(竖向)或右端(横向)圆心
|
||||
Vector2 capB = offset - axis * half; // 底部(竖向)或左端(横向)圆心
|
||||
|
||||
const int segs = 12;
|
||||
_capsuleVertsBuf.Clear();
|
||||
|
||||
float baseA = vert ? 0f : -Mathf.PI * 0.5f;
|
||||
for (int i = 0; i <= segs; i++)
|
||||
{
|
||||
float a = (startDeg + step * i) * Mathf.Deg2Rad;
|
||||
var next = c + new Vector2(Mathf.Cos(a) * r, Mathf.Sin(a) * r);
|
||||
Gizmos.DrawLine(prev, next);
|
||||
prev = next;
|
||||
float a = baseA + (float)i / segs * Mathf.PI;
|
||||
_capsuleVertsBuf.Add(new Vector3(capA.x + Mathf.Cos(a) * radius,
|
||||
capA.y + Mathf.Sin(a) * radius, 0f));
|
||||
}
|
||||
|
||||
float baseB = vert ? Mathf.PI : Mathf.PI * 0.5f;
|
||||
for (int i = 0; i <= segs; i++)
|
||||
{
|
||||
float a = baseB + (float)i / segs * Mathf.PI;
|
||||
_capsuleVertsBuf.Add(new Vector3(capB.x + Mathf.Cos(a) * radius,
|
||||
capB.y + Mathf.Sin(a) * radius, 0f));
|
||||
}
|
||||
|
||||
var arr = _capsuleVertsBuf.ToArray();
|
||||
UnityEditor.Handles.color = fill;
|
||||
UnityEditor.Handles.DrawAAConvexPolygon(arr);
|
||||
UnityEditor.Handles.color = outline;
|
||||
for (int i = 0; i < arr.Length; i++)
|
||||
UnityEditor.Handles.DrawLine(arr[i], arr[(i + 1) % arr.Length]);
|
||||
}
|
||||
|
||||
private static void DrawFilledPolygonPath2D(Vector2[] path, Color fill, Color outline)
|
||||
{
|
||||
if (path == null || path.Length < 3) return;
|
||||
var verts = System.Array.ConvertAll(path, p => new Vector3(p.x, p.y, 0f));
|
||||
UnityEditor.Handles.color = fill;
|
||||
UnityEditor.Handles.DrawAAConvexPolygon(verts); // 凹多边形仅轮廓准确,填充近似
|
||||
UnityEditor.Handles.color = outline;
|
||||
for (int i = 0; i < verts.Length; i++)
|
||||
UnityEditor.Handles.DrawLine(verts[i], verts[(i + 1) % verts.Length]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user