# Code Patterns - C++ to C# Conversions ## Abstract Base Classes ### C++ Pattern ```cpp class CGfxMoveBase { protected: CGfxMoveBase(GfxMoveMode mode) : m_Mode(mode) {} public: virtual ~CGfxMoveBase() {} virtual void StartMove(const A3DVECTOR3& vHost, const A3DVECTOR3& vTarget) = 0; virtual bool TickMove(DWORD dwDeltaTime, ...) = 0; virtual void SetParam(const GFX_SKILL_PARAM* param) { /* default impl */ } static CGfxMoveBase* CreateMoveMethod(GfxMoveMode mode); }; ``` ### C# Pattern ```csharp public abstract class CGfxMoveBase { protected CGfxMoveBase(GfxMoveMode mode) { m_Mode = mode; } // Pure virtual (= 0) → abstract public abstract void StartMove(Vector3 vHost, Vector3 vTarget); public abstract bool TickMove(uint dwDeltaTime, ...); // Virtual with default → virtual public virtual void SetParam(GFX_SKILL_PARAM param) { // default implementation } // Static factory method public static CGfxMoveBase CreateMoveMethod(GfxMoveMode mode) { switch (mode) { case GfxMoveMode.enumLinearMove: return new CGfxLinearMove(mode); default: return new CGfxLinearMove(mode); } } } ``` ## Inheritance Patterns ### C++ Pattern ```cpp class CGfxLinearMove : public CGfxMoveBase { protected: float m_fSpeed; public: CGfxLinearMove(GfxMoveMode mode) : CGfxMoveBase(mode) {} virtual void StartMove(const A3DVECTOR3& vHost, const A3DVECTOR3& vTarget); virtual bool TickMove(DWORD dwDeltaTime, ...); }; ``` ### C# Pattern ```csharp public class CGfxLinearMove : CGfxMoveBase { protected float m_fSpeed; public CGfxLinearMove(GfxMoveMode mode) : base(mode) { } public override void StartMove(Vector3 vHost, Vector3 vTarget) { // implementation } public override bool TickMove(uint dwDeltaTime, ...) { // implementation } } ``` ## Static Factory Methods ### C++ Pattern ```cpp inline CGfxMoveBase* CGfxMoveBase::CreateMoveMethod(GfxMoveMode mode) { switch(mode) { case enumLinearMove: return new CGfxLinearMove(mode); case enumOnTarget: return new CGfxOnTargetMove(mode); default: assert(false); return NULL; } } ``` ### C# Pattern ```csharp public static CGfxMoveBase CreateMoveMethod(GfxMoveMode mode) { switch (mode) { case GfxMoveMode.enumLinearMove: return new CGfxLinearMove(mode); case GfxMoveMode.enumOnTarget: return new CGfxOnTargetMove(mode); default: return new CGfxLinearMove(mode); // fallback } } ``` ## Vector Operations ### Normalize Pattern **C++:** ```cpp A3DVECTOR3 vDir = vTarget - m_vPos; float fDist = vDir.Normalize(); // In-place normalize, returns magnitude if (fDist < 1e-4f) return true; ``` **C#:** ```csharp Vector3 vDir = vTarget - m_vPos; float fDist = Normalize(ref vDir); // Helper method if (fDist < 1e-4f) return true; // Helper implementation: protected static float Normalize(ref Vector3 v) { float mag = v.magnitude; if (mag < 1e-6f) { v = Vector3.zero; return 0f; } v /= mag; return mag; } ``` ### Vector Math **C++:** ```cpp m_vPos += vFlyDir * fFlyDist; m_vMoveDir = vFlyDir; ``` **C#:** ```csharp m_vPos += vFlyDir * fFlyDist; m_vMoveDir = vFlyDir; ``` ## Protected Helper Methods ### C++ Pattern ```cpp protected: void CalcRange(const A3DVECTOR3& vDir) { m_vYRange = _unit_y; m_vZRange.Set(vDir.x, 0, vDir.z); if (m_vZRange.Normalize() < .01f) m_vZRange = _unit_z; m_vXRange = CrossProduct(m_vYRange, m_vZRange); // ... } A3DVECTOR3 GetRandOff() const { if (m_Shape == enumBox) { // ... } // ... } ``` ### C# Pattern ```csharp 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); // ... } protected Vector3 GetRandOff() { if (m_Shape == EmitShape.enumBox) { // ... } // ... } ``` ## State Machine Pattern ### C++ Pattern ```cpp enum { enumWait, enumFlying, enumHit, enumFinished } m_enumState; void Tick(DWORD dwDeltaTime) { if (m_enumState == enumFinished) return; else if (m_enumState == enumHit) { // handle hit state } else if (m_enumState == enumWait) { if (m_dwCurSpan < m_dwDelayTime) return; m_enumState = enumFlying; } else // enumFlying { if (m_pMoveMethod.TickMove(dwDeltaTime, ...)) HitTarget(GetTargetCenter()); } } ``` ### C# Pattern ```csharp protected GfxSkillEventState m_enumState; public virtual void Tick(uint dwDeltaTime) { if (m_enumState == GfxSkillEventState.enumFinished) return; else if (m_enumState == GfxSkillEventState.enumHit) { // handle hit state } else if (m_enumState == GfxSkillEventState.enumWait) { if (m_dwCurSpan < m_dwDelayTime) return; m_enumState = GfxSkillEventState.enumFlying; } else // enumFlying { if (m_pMoveMethod.TickMove(dwDeltaTime, ...)) HitTarget(GetTargetCenter()); } } ``` ## Const Correctness → Readonly ### C++ Pattern ```cpp const A3DVECTOR3& GetPos() const { return m_vPos; } GfxMoveMode GetMode() const { return m_Mode; } ``` ### C# Pattern ```csharp public Vector3 GetPos() { return m_vPos; } // No const needed public GfxMoveMode GetMode() { return m_Mode; } // No const needed ``` ## Delegate Pattern (Virtual Methods) ### C++ Pattern ```cpp class A3DSkillGfxEvent { CGfxMoveBase* m_pMoveMethod; public: GfxMoveMode GetMode() const { return m_pMoveMethod->GetMode(); } void SetReverse(bool bReverse) const { m_pMoveMethod->SetReverse(bReverse); } void SetParam(const GFX_SKILL_PARAM* param) { m_pMoveMethod->SetParam(param); } }; ``` ### C# Pattern ```csharp public class A3DSkillGfxEvent { protected CGfxMoveBase m_pMoveMethod; public GfxMoveMode GetMode() { return m_pMoveMethod.GetMode(); } public void SetReverse(bool bReverse) { m_pMoveMethod.SetReverse(bReverse); } public void SetParam(GFX_SKILL_PARAM param) { m_pMoveMethod.SetParam(param); } } ``` ## Random Number Generation ### C++ Pattern ```cpp float _SymmetricRandom() { return (rand() / (float)RAND_MAX) * 2.0f - 1.0f; } float _UnitRandom() { return rand() / (float)RAND_MAX; } A3DVECTOR3 GetRandOff() const { if (m_Shape == enumBox) { A3DVECTOR3 xOff, yOff, zOff; xOff = _SymmetricRandom() * m_vXRange; yOff = _SymmetricRandom() * m_vYRange; zOff = _SymmetricRandom() * m_vZRange; return xOff + yOff + zOff; } } ``` ### C# Pattern ```csharp private static float SymRandom() { return UnityEngine.Random.value * 2f - 1f; } private static float UnitRandom() { return UnityEngine.Random.value; } protected Vector3 GetRandOff() { if (m_Shape == EmitShape.enumBox) { Vector3 xOff = SymRandom() * m_vXRange; Vector3 yOff = SymRandom() * m_vYRange; Vector3 zOff = SymRandom() * m_vZRange; return xOff + yOff + zOff; } } ``` ## Conditional Compilation → #if UNITY_EDITOR ### C++ Pattern ```cpp #ifdef _DEBUG assert(false); #endif ``` ### C# Pattern ```csharp #if UNITY_EDITOR UnityEngine.Debug.Assert(false); #endif ``` ## Memory Management Patterns ### C++ Pattern ```cpp void ReleaseFlyGfx() { if (m_pFlyGfx) { if (m_bFadeOut) AfxGetGFXExMan()->QueueFadeOutGfx(m_pFlyGfx, 1000); else { m_pFlyGfx->Release(); delete m_pFlyGfx; } m_pFlyGfx = NULL; } } ``` ### C# Pattern ```csharp protected void ReleaseFlyGfx() { if (m_pFlyGfx != null) { if (m_bFadeOut) AfxGetGFXExMan().QueueFadeOutGfx(m_pFlyGfx, 1000); else { m_pFlyGfx.Release(); // C#: Automatic garbage collection, no delete needed } m_pFlyGfx = null; } } ``` ## Common Conversion Checklist When converting a class: - [ ] Abstract base → `abstract class` - [ ] Pure virtual methods → `abstract` methods - [ ] Virtual with default → `virtual` methods - [ ] Non-virtual → regular methods - [ ] Static factory → `static` method - [ ] Const methods → regular methods (no const) - [ ] Pointers → references (remove `*`) - [ ] References → value types or `ref`/`out` - [ ] `DWORD` → `uint` - [ ] `A3DVECTOR3` → `Vector3` - [ ] Union access → `param.value.fVal` - [ ] Hungarian notation → preserved