172 lines
7.0 KiB
C#
172 lines
7.0 KiB
C#
using UnityEngine;
|
|
|
|
namespace BrewMonster
|
|
{
|
|
/// <summary>
|
|
/// Abstract base class for all projectile movement patterns.
|
|
/// Mirrors C++ CGfxMoveBase exactly.
|
|
/// 所有弹道移动模式的抽象基类,完全镜像C++ CGfxMoveBase。
|
|
/// </summary>
|
|
public abstract class CGfxMoveBase
|
|
{
|
|
protected GfxMoveMode m_Mode;
|
|
protected GfxHitPos m_HitPos = GfxHitPos.enumHitCenter;
|
|
protected Vector3 m_vPos;
|
|
protected Vector3 m_vMoveDir;
|
|
protected bool m_bOneOfCluser; // C++ spelling kept / 保持C++拼写
|
|
protected uint m_dwMaxFlyTime;
|
|
protected bool m_bReverse;
|
|
protected bool m_bArea;
|
|
protected EmitShape m_Shape;
|
|
protected Vector3 m_vSize;
|
|
protected Vector3 m_vXRange;
|
|
protected Vector3 m_vYRange;
|
|
protected Vector3 m_vZRange;
|
|
protected float m_fSquare;
|
|
protected float m_fSquareH;
|
|
|
|
protected CGfxMoveBase(GfxMoveMode mode)
|
|
{
|
|
m_Mode = mode;
|
|
m_HitPos = GfxHitPos.enumHitCenter;
|
|
}
|
|
|
|
// Pure virtual (= 0) → abstract — subclasses MUST override
|
|
// 纯虚函数 → 抽象 — 子类必须重写
|
|
public abstract void StartMove(Vector3 vHost, Vector3 vTarget);
|
|
public abstract bool TickMove(uint dwDeltaTime, Vector3 vHostPos, Vector3 vTargetPos);
|
|
|
|
// ===== Protected helpers (same as C++ CGfxMoveBase) =====
|
|
// 受保护的辅助方法(与C++ CGfxMoveBase相同)
|
|
|
|
/// <summary>
|
|
/// Normalize vector, return original magnitude. Returns 0 if too small.
|
|
/// 归一化向量,返回原始长度。如果太小则返回0。
|
|
/// </summary>
|
|
protected static float Normalize(ref Vector3 v)
|
|
{
|
|
float mag = v.magnitude;
|
|
if (mag < 1e-6f) { v = Vector3.zero; return 0f; }
|
|
v /= mag;
|
|
return mag;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate emission range vectors based on movement direction.
|
|
/// 根据移动方向计算发射范围向量。
|
|
/// </summary>
|
|
protected void CalcRange(Vector3 vDir)
|
|
{
|
|
m_vYRange = Vector3.up;
|
|
m_vZRange = new Vector3(vDir.x, 0, vDir.z);
|
|
if (Normalize(ref m_vZRange) < 0.01f) m_vZRange = Vector3.forward;
|
|
m_vXRange = Vector3.Cross(m_vYRange, m_vZRange);
|
|
m_vXRange *= m_vSize.x;
|
|
m_vYRange *= m_vSize.y;
|
|
m_vZRange *= m_vSize.z;
|
|
m_fSquare = m_vSize.sqrMagnitude;
|
|
m_fSquareH = m_vSize.x * m_vSize.x + m_vSize.z * m_vSize.z;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get random offset based on emission shape.
|
|
/// 根据发射形状获取随机偏移。
|
|
/// </summary>
|
|
protected Vector3 GetRandOff()
|
|
{
|
|
float x, y, z;
|
|
|
|
switch (m_Shape)
|
|
{
|
|
case EmitShape.enumBox:
|
|
x = Random.Range(-1f, 1f);
|
|
y = Random.Range(-1f, 1f);
|
|
z = Random.Range(-1f, 1f);
|
|
break;
|
|
|
|
case EmitShape.enumSphere:
|
|
// Rejection sampling for uniform distribution in sphere
|
|
// 球体内均匀分布的拒绝采样
|
|
do
|
|
{
|
|
x = Random.Range(-1f, 1f);
|
|
y = Random.Range(-1f, 1f);
|
|
z = Random.Range(-1f, 1f);
|
|
}
|
|
while (x * x * m_fSquare / (m_vSize.x * m_vSize.x + 1e-6f)
|
|
+ y * y * m_fSquare / (m_vSize.y * m_vSize.y + 1e-6f)
|
|
+ z * z * m_fSquare / (m_vSize.z * m_vSize.z + 1e-6f) > m_fSquare);
|
|
break;
|
|
|
|
case EmitShape.enumCylinder:
|
|
// Uniform in horizontal circle, uniform in Y
|
|
// 水平圆内均匀分布,Y轴均匀分布
|
|
do
|
|
{
|
|
x = Random.Range(-1f, 1f);
|
|
z = Random.Range(-1f, 1f);
|
|
}
|
|
while (x * x * m_fSquareH / (m_vSize.x * m_vSize.x + 1e-6f)
|
|
+ z * z * m_fSquareH / (m_vSize.z * m_vSize.z + 1e-6f) > m_fSquareH);
|
|
y = Random.Range(-1f, 1f);
|
|
break;
|
|
|
|
default:
|
|
x = y = z = 0;
|
|
break;
|
|
}
|
|
|
|
return m_vXRange * x + m_vYRange * y + m_vZRange * z;
|
|
}
|
|
|
|
// ===== Public accessors (non-virtual, same as C++) =====
|
|
// 公共访问器(非虚函数,与C++相同)
|
|
|
|
public GfxMoveMode GetMode() { return m_Mode; }
|
|
public GfxHitPos GetHitPos() { return m_HitPos; }
|
|
public Vector3 GetPos() { return m_vPos; }
|
|
public Vector3 GetMoveDir() { return m_vMoveDir; }
|
|
public bool IsReverse() { return m_bReverse; }
|
|
public void SetReverse(bool bReverse) { m_bReverse = bReverse; }
|
|
public void SetIsCluster(bool bCluster) { m_bOneOfCluser = bCluster; }
|
|
public void SetMaxFlyTime(uint dwTime) { m_dwMaxFlyTime = dwTime; if (m_dwMaxFlyTime == 0) m_dwMaxFlyTime = 1; }
|
|
public void SetRange(Vector3 vSize) { m_vSize = vSize; }
|
|
|
|
/// <summary>
|
|
/// Virtual — subclasses can override for custom param handling.
|
|
/// 虚函数 — 子类可以重写以自定义参数处理。
|
|
/// </summary>
|
|
public virtual void SetParam(GFX_SKILL_PARAM param)
|
|
{
|
|
m_bArea = param.m_bArea;
|
|
m_Shape = param.m_Shape;
|
|
m_vSize = new Vector3(param.m_vSize.x, param.m_vSize.y, param.m_vSize.z);
|
|
}
|
|
|
|
// ===== Factory method (same as C++ CGfxMoveBase::CreateMoveMethod) =====
|
|
// 工厂方法(与C++ CGfxMoveBase::CreateMoveMethod相同)
|
|
|
|
/// <summary>
|
|
/// Create movement method by mode. All movement modes implemented.
|
|
/// 根据模式创建移动方法。所有移动模式已实现。
|
|
/// </summary>
|
|
public static CGfxMoveBase CreateMoveMethod(GfxMoveMode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case GfxMoveMode.enumOnTarget: return new CGfxOnTargetMove(mode);
|
|
case GfxMoveMode.enumLinearMove: return new CGfxLinearMove(mode);
|
|
case GfxMoveMode.enumParabolicMove: return new CGfxParabolicMove(mode);
|
|
case GfxMoveMode.enumMissileMove: return new CGfxMissileMove(mode);
|
|
case GfxMoveMode.enumMeteoricMove: return new CGfxMeteoricMove(mode);
|
|
case GfxMoveMode.enumHelixMove: return new CGfxHelixMove(mode);
|
|
case GfxMoveMode.enumCurvedMove: return new CGfxCurvedMove(mode);
|
|
case GfxMoveMode.enumAccMove: return new CGfxAccMove(mode);
|
|
case GfxMoveMode.enumLink: return new CGfxLinkMove(mode);
|
|
case GfxMoveMode.enumRandMove: return new CGfxRandMove(mode);
|
|
default: return new CGfxLinearMove(mode);
|
|
}
|
|
}
|
|
}
|
|
}
|