using UnityEngine;
namespace BrewMonster
{
///
/// Abstract base class for all projectile movement patterns.
/// Mirrors C++ CGfxMoveBase exactly.
/// 所有弹道移动模式的抽象基类,完全镜像C++ CGfxMoveBase。
///
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相同)
///
/// Normalize vector, return original magnitude. Returns 0 if too small.
/// 归一化向量,返回原始长度。如果太小则返回0。
///
protected static float Normalize(ref Vector3 v)
{
float mag = v.magnitude;
if (mag < 1e-6f) { v = Vector3.zero; return 0f; }
v /= mag;
return mag;
}
///
/// Calculate emission range vectors based on movement direction.
/// 根据移动方向计算发射范围向量。
///
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;
}
///
/// Get random offset based on emission shape.
/// 根据发射形状获取随机偏移。
///
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; }
public void SetRange(Vector3 vSize) { m_vSize = vSize; }
///
/// Virtual — subclasses can override for custom param handling.
/// 虚函数 — 子类可以重写以自定义参数处理。
///
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相同)
///
/// Create movement method by mode. Only Linear and OnTarget implemented for Phase 1.
/// 根据模式创建移动方法。第一阶段仅实现Linear和OnTarget。
///
public static CGfxMoveBase CreateMoveMethod(GfxMoveMode mode)
{
switch (mode)
{
case GfxMoveMode.enumOnTarget: return new CGfxOnTargetMove(mode);
case GfxMoveMode.enumLinearMove: return new CGfxLinearMove(mode);
// TODO Phase 3: Add remaining movement modes
// 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);
}
}
}
}