419 lines
8.6 KiB
Markdown
419 lines
8.6 KiB
Markdown
# 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
|