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; if (m_dwMaxFlyTime == 0) m_dwMaxFlyTime = 1; } 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. All movement modes implemented. /// 根据模式创建移动方法。所有移动模式已实现。 /// 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); } } } }