# Skill GFX System Deep Dive ## Movement System Architecture ### CGfxMoveBase Design **Purpose**: Abstract base for all projectile movement patterns. **Key Responsibilities**: - Calculate position over time - Handle area emission (random offsets) - Support clustering (multiple projectiles) - Provide position/direction queries **Core Methods**: ```csharp public abstract void StartMove(Vector3 vHost, Vector3 vTarget); public abstract bool TickMove(uint dwDeltaTime, Vector3 vHostPos, Vector3 vTargetPos); ``` **Return Value Semantics**: - `StartMove()`: Initialize movement, set initial position/direction - `TickMove()`: - Returns `true` = target reached/hit - Returns `false` = still in flight - Updates `m_vPos` and `m_vMoveDir` ### Movement Mode Details #### CGfxLinearMove - **Pattern**: Straight line from host to target - **Speed**: `_fly_speed = 20.0f / 1000.0f` (units per millisecond) - **Behavior**: - If max fly time allows, uses constant speed - Otherwise, calculates speed to reach target in max time - Updates direction each frame to track moving target #### CGfxOnTargetMove - **Pattern**: Instant hit (no flight) - **Behavior**: - `StartMove()`: Sets position to target immediately - `TickMove()`: Returns `false` (stays at target) - Hit triggered by fly time timeout, NOT by `TickMove()` return - Supports cluster offset (random radius around target) #### CGfxParabolicMove - **Pattern**: Arc trajectory with gravity - **Physics**: - Horizontal velocity constant - Vertical velocity affected by gravity - Calculates initial vertical velocity to reach target #### CGfxMissileMove - **Pattern**: Homing missile - **Behavior**: - Accelerates toward target - Rotates to face target - Constant acceleration until hit #### CGfxMeteoricMove - **Pattern**: Falls from sky - **Behavior**: - Starts above target - Falls straight down - Configurable radius #### CGfxHelixMove - **Pattern**: Spiral path - **Behavior**: - Spiral around center axis - Radius can shrink over time - Configurable radius parameter #### CGfxCurvedMove - **Pattern**: Bezier-like curve - **Behavior**: - Curves from host to target - Can curve left or right - Configurable lateral speed #### CGfxAccMove - **Pattern**: Accelerated flight - **Behavior**: - Constant acceleration - Configurable acceleration value #### CGfxLinkMove - **Pattern**: Lightning chain - **Behavior**: - Links between host and target - Updates GFX parameters dynamically - No movement (stays linked) #### CGfxRandMove - **Pattern**: Random walk - **Behavior**: - Random direction changes - Configurable step size and speed - Uses control points for smoothness ## Area Emission System ### Purpose Emit multiple projectiles in a random area around the start position. ### Configuration - **m_bArea**: Enable area emission - **m_Shape**: Emission shape (Box, Sphere, Cylinder) - **m_vSize**: Size of emission area ### Implementation **CalcRange()**: Calculates X/Y/Z range vectors based on movement direction. ```csharp protected void CalcRange(Vector3 vDir) { m_vYRange = Vector3.up; m_vZRange = new Vector3(vDir.x, 0, vDir.z); // Project to horizontal if (Normalize(ref m_vZRange) < 0.01f) m_vZRange = Vector3.forward; m_vXRange = Vector3.Cross(m_vYRange, m_vZRange); // Perpendicular // Scale by m_vSize } ``` **GetRandOff()**: Generates random offset based on shape. - **Box**: Uniform distribution in box - **Sphere**: Uniform distribution in sphere (rejection sampling) - **Cylinder**: Uniform in horizontal circle, uniform in Y ### Usage ```csharp if (m_bArea) { CalcRange((vTarget - vHost).normalized); m_vPos = vHost + GetRandOff(); } ``` ## Clustering System ### Purpose Emit multiple projectiles with time intervals (e.g., machine gun effect). ### Configuration - **m_bOneOfCluser**: This projectile is part of a cluster - **Cluster params**: Count and interval (handled by manager) ### OnTarget Clustering For `CGfxOnTargetMove`, clustering adds random offset: ```csharp if (m_bOneOfCluser) { float fRandAng = Random.value * 2π; float fRadius = Random.value * m_fRadius; m_vOffset = new Vector3(cos(ang) * radius, 0, sin(ang) * radius); m_vPos += m_vOffset; } ``` ## State Machine Details ### enumWait State - **Entry**: Event created - **Behavior**: - Increment `m_dwCurSpan` - Wait for `m_dwDelayTime` - **Exit**: When `m_dwCurSpan >= m_dwDelayTime` - **Transition**: → `enumFlying` ### enumFlying State - **Entry**: Delay expired - **Behavior**: - Call `m_pMoveMethod.SetMaxFlyTime(m_dwFlyTimeSpan)` - Call `m_pMoveMethod.StartMove(m_vHostPos, m_vTargetPos)` - Each frame: - Update host/target positions if `m_bTraceTarget` - Call `m_pMoveMethod.TickMove(dwDeltaTime, ...)` - Update GFX position - Check timeout: `m_dwCurSpan > m_dwFlyTimeSpan` - **Exit Conditions**: - `TickMove()` returns `true` (target hit) - `m_dwCurSpan > m_dwFlyTimeSpan` (timeout) - **Transition**: → `enumHit` ### enumHit State - **Entry**: Target hit or timeout - **Behavior**: - Release fly GFX (fade out or immediate) - Spawn hit GFX at target position - Update hit GFX position if `m_bTraceTarget` - Check if hit GFX is infinite (`m_bHitGfxInfinite`) - **Exit Conditions**: - Hit GFX completes (not infinite) - Hit GFX timeout (5 seconds for infinite) - Target disappears - **Transition**: → `enumFinished` ### enumFinished State - **Entry**: Hit effect complete - **Behavior**: - Release all GFX - Mark event for cleanup/pooling - **Exit**: Event removed from active list ## Position Tracking ### Host Position - **Source**: Character position from `m_nHostID` - **Update**: Each frame if `m_bHostExist` - **Usage**: - Initial position for `StartMove()` - Dynamic updates for `TickMove()` (if target moves) ### Target Position - **Source**: Character position from `m_nTargetID` - **Update**: Each frame if `m_bTargetExist` and `m_bTraceTarget` - **Usage**: - Target position for `StartMove()` - Dynamic updates for `TickMove()` (tracking) ### GetTargetCenter() - **Abstract method**: Must be implemented by derived class - **Purpose**: Get current target center position - **Implementation**: - `CECSkillGfxEvent`: Gets character position from ID - Can use hooks/bones in future ## GFX Loading & Instantiation ### C++ Pattern ```cpp A3DGFXEx* LoadFlyGfx(A3DDevice* pDev, const char* szPath); void SetFlyGfx(A3DGFXEx* pFlyGfx); ``` ### C# Pattern (Unity) ```csharp // Async loading with Addressables async Task LoadFlyGfxAsync(string path) { var handle = Addressables.LoadAssetAsync(path); await handle.Task; return handle.Result; } // Instantiation GameObject instance = Instantiate(prefab, position, rotation); ``` ### Lifecycle 1. **Load**: Async load prefab (Addressables) 2. **Instantiate**: Create instance at position 3. **Update**: Update position each frame 4. **Release**: Destroy instance, release prefab ## Parameter System ### GFX_SKILL_PARAM Structure ```csharp public struct GFX_SKILL_PARAM { public ValueUnion value; // Union: bVal, nVal, or fVal public bool m_bArea; public EmitShape m_Shape; public A3DVECTOR3 m_vSize; } ``` ### Usage by Movement Mode - **CGfxLinearMove**: Uses `m_bArea`, `m_Shape`, `m_vSize` (default) - **CGfxOnTargetMove**: Also uses `value.fVal` for radius - **CGfxMeteoricMove**: Uses `value.fVal` for fall radius - **CGfxHelixMove**: Uses `value.fVal` for spiral radius - **CGfxCurvedMove**: Uses `value.bVal` for curve direction - **CGfxAccMove**: Uses `value.fVal` for acceleration - **CGfxRandMove**: Uses `value.fVal` for speed ### Setting Parameters ```csharp GFX_SKILL_PARAM param = new GFX_SKILL_PARAM(); param.value.fVal = 5.0f; // Radius for OnTarget param.m_bArea = true; param.m_Shape = EmitShape.enumSphere; param.m_vSize = new A3DVECTOR3(2, 2, 2); m_pMoveMethod.SetParam(param); ``` ## Performance Optimizations ### Object Pooling - **Purpose**: Reuse event instances - **Implementation**: `m_FreeLst` in `CECSkillGfxMan` - **Usage**: - Get from pool when creating event - Return to pool when finished ### GFX Caching - **Purpose**: Avoid reloading same prefabs - **Implementation**: Cache loaded Addressable handles - **Key**: Use path as key ### Batch Updates - **Purpose**: Update all events efficiently - **Implementation**: Single loop through active events - **Optimization**: Early exit for finished events ### LOD System - **Purpose**: Reduce quality for distant effects - **Field**: `m_bGfxUseLod` - **Usage**: Disable expensive effects when far away ## Debugging Tips ### Common Issues 1. **Projectile doesn't move**: Check `StartMove()` called, `m_fSpeed` set 2. **Projectile goes wrong direction**: Check `m_vMoveDir` calculation 3. **Hit doesn't trigger**: Check `TickMove()` return value, timeout 4. **GFX doesn't appear**: Check loading, instantiation, position 5. **Performance issues**: Check pooling, caching, LOD ### Debug Fields - `m_vPos`: Current position - `m_vMoveDir`: Current direction - `m_enumState`: Current state - `m_dwCurSpan`: Current time span - `m_dwFlyTimeSpan`: Max fly time ### Visualization - Draw gizmos for projectile position - Draw line from host to target - Show state in inspector - Log state transitions