VeloShipper - Module
Specifications & Algorithms
Document Information
1. Core Systems
1.1 Kinematic Character Controller
(KCC)
Module Overview
Custom character controller using kinematic physics for precise, frame-perfect
movement control essential for parkour gameplay.
Key Components
public class KinematicCharacterController : MonoBehaviour
{
[Header("Movement Settings")]
public float walkSpeed = 5f;
public float runSpeed = 10f;
public float sprintSpeed = 15f;
public float acceleration = 50f;
public float deceleration = 30f;
[Header("Physics Settings")]
public float gravity = -25f;
public float groundCheckDistance = 0.1f;
public LayerMask groundMask;
// Core state
private Vector3 velocity;
private bool isGrounded;
private CharacterController controller;
}
Algorithm: Movement Calculation
public void Move(Vector3 inputDirection, float deltaTime)
{
// 1. Calculate target velocity based on input and current state
float targetSpeed = GetTargetSpeed();
Vector3 targetVelocity = inputDirection * targetSpeed;
// 2. Apply acceleration/deceleration
if ([Link] > 0.1f)
{
// Accelerating
velocity.x = [Link](velocity.x, targetVelocity.x,
acceleration * deltaTime);
velocity.z = [Link](velocity.z, targetVelocity.z,
acceleration * deltaTime);
}
else
{
// Decelerating
velocity.x = [Link](velocity.x, 0, deceleration *
deltaTime);
velocity.z = [Link](velocity.z, 0, deceleration *
deltaTime);
}
// 3. Apply gravity
if (isGrounded && velocity.y < 0)
{
velocity.y = -0.5f; // Small downward force to keep grounded
}
else
{
velocity.y += gravity * deltaTime;
}
// 4. Ground check and slope handling
HandleGroundAndSlope();
// 5. Apply movement
[Link](velocity * deltaTime);
}
Algorithm: Ground Detection
private void HandleGroundAndSlope()
{
// Sphere cast for more reliable ground detection
isGrounded = [Link](
[Link] + [Link] * 0.1f,
[Link] * 0.9f,
[Link],
out RaycastHit hit,
groundCheckDistance + 0.1f,
groundMask
);
if (isGrounded)
{
// Project velocity onto slope plane
Vector3 slopeNormal = [Link];
float slopeAngle = [Link](slopeNormal, [Link]);
if (slopeAngle > [Link])
{
// Too steep - slide down
Vector3 slideDirection =
[Link]([Link], slopeNormal).normalized;
velocity += slideDirection * (slopeAngle -
[Link]) * 0.5f;
}
else
{
// Adjust velocity to follow slope
velocity = [Link](velocity,
slopeNormal);
}
}
}
1.2 Parkour Detection System
Module Overview
Raycast-based environment scanning to detect vaultable, climbable, and wall-
runnable surfaces.
Key Components
public class ParkourDetector : MonoBehaviour
{
[Header("Detection Settings")]
public float detectionRadius = 2.5f;
public float vaultHeightMin = 0.5f;
public float vaultHeightMax = 1.5f;
public float climbHeightMax = 2.5f;
public float wallRunAngle = 85f;
[Header("Raycast Origins")]
public Transform eyeLevel;
public Transform waistLevel;
public Transform groundLevel;
private ParkourTarget currentTarget;
}
public struct ParkourTarget
{
public ParkourType type;
public Vector3 targetPosition;
public Vector3 surfaceNormal;
public float height;
public bool isValid;
}
public enum ParkourType
{
None,
Vault,
Climb,
WallRun,
LedgeGrab
}
Algorithm: Multi-Raycast Detection
public ParkourTarget ScanForObstacles(Vector3 moveDirection)
{
ParkourTarget target = new ParkourTarget { isValid = false };
// 1. Forward raycast to detect obstacles
if ([Link]([Link], moveDirection, out
RaycastHit hit, detectionRadius))
{
float obstacleHeight = [Link].y - [Link].y;
float angle = [Link]([Link], [Link]);
// 2. Classify obstacle type
if (angle > 80f && angle < 100f)
{
// Vertical wall - check for wall run
target = DetectWallRun(hit, moveDirection);
}
else if (obstacleHeight >= vaultHeightMin && obstacleHeight
<= vaultHeightMax)
{
// Vaultable obstacle
target = DetectVault(hit, obstacleHeight);
}
else if (obstacleHeight > vaultHeightMax && obstacleHeight
<= climbHeightMax)
{
// Climbable obstacle
target = DetectClimb(hit, obstacleHeight);
}
}
// 3. Check for ledge grabs (when falling)
if (![Link] && velocity.y < 0)
{
target = DetectLedgeGrab();
}
return target;
}
Algorithm: Vault Detection
private ParkourTarget DetectVault(RaycastHit hit, float height)
{
ParkourTarget target = new ParkourTarget
{
type = [Link],
height = height,
surfaceNormal = [Link]
};
// 1. Check clearance on top
Vector3 topPosition = [Link] + [Link] * 0.1f;
if ()
{
// 2. Check landing space on other side
Vector3 vaultDirection = -[Link];
Vector3 landingPosition = [Link] + vaultDirection * 1.5f
+ [Link] * 0.1f;
if ([Link](landingPosition, [Link], out
RaycastHit groundHit, 2f))
{
[Link] = [Link];
[Link] = true;
}
}
return target;
}
Algorithm: Wall Run Detection
private ParkourTarget DetectWallRun(RaycastHit hit, Vector3
moveDirection)
{
ParkourTarget target = new ParkourTarget
{
type = [Link],
surfaceNormal = [Link]
};
// 1. Check if moving somewhat parallel to wall (not directly
into it)
float approachAngle = [Link](moveDirection, -[Link]);
if (approachAngle < 30f || approachAngle > 150f)
return target; // Too direct or moving away
// 2. Check wall height (must be tall enough)
if ()
return target; // Wall too short
// 3. Check for continuous wall surface
Vector3 wallDirection = [Link]([Link],
[Link]).normalized;
bool leftClear = ;
bool rightClear = ;
if (leftClear || rightClear)
{
[Link] = [Link];
[Link] = true;
}
return target;
}
1.3 Momentum System
Module Overview
Core gameplay mechanic tracking and rewarding continuous high-speed movement.
Key Components
public class MomentumSystem : MonoBehaviour
{
[Header("Momentum Settings")]
public float maxMomentum = 100f;
public float decayRate = 5f;
public float gainMultiplier = 10f;
public float flowThreshold = 60f;
public float stallThreshold = 5f;
public float stallTime = 2f;
[Header("Bonuses")]
public float flowSpeedBonus = 1.2f;
public float flowFOVBonus = 20f;
private float currentMomentum;
private float stallTimer;
private bool isInFlowState;
public event Action OnFlowStateEnter;
public event Action OnFlowStateExit;
public event Action OnStall;
}
Algorithm: Momentum Update
public void UpdateMomentum(float currentSpeed, float deltaTime)
{
float previousMomentum = currentMomentum;
// 1. Calculate momentum gain based on speed
float speedRatio = currentSpeed / sprintSpeed;
float gain = speedRatio * gainMultiplier * deltaTime;
// 2. Apply gain
currentMomentum = [Link](currentMomentum + gain, 0,
maxMomentum);
// 3. Apply decay
currentMomentum = [Link](0, currentMomentum - decayRate *
deltaTime);
// 4. Check stall condition
if (currentSpeed < stallThreshold)
{
stallTimer += deltaTime;
if (stallTimer >= stallTime)
{
TriggerStall();
}
}
else
{
stallTimer = 0;
}
// 5. Check flow state transitions
if (!isInFlowState && currentMomentum >= flowThreshold)
{
EnterFlowState();
}
else if (isInFlowState && currentMomentum < flowThreshold)
{
ExitFlowState();
}
}
Algorithm: Flow State Management
private void EnterFlowState()
{
isInFlowState = true;
// Apply bonuses
OnFlowStateEnter?.Invoke();
// Visual feedback
[Link](true);
[Link](true);
// Apply speed multiplier
[Link](flowSpeedBonus);
}
private void ExitFlowState()
{
isInFlowState = false;
OnFlowStateExit?.Invoke();
// Remove bonuses
[Link](false);
[Link](false);
[Link]();
}
private void TriggerStall()
{
currentMomentum = 0;
isInFlowState = false;
OnStall?.Invoke();
// Penalty feedback
[Link]();
[Link]();
}
1.4 Vehicle Mounting System
Module Overview
Handles the 200ms window mounting mechanic for seamless parkour-to-vehicle
transitions.
Key Components
public class VehicleMountSystem : MonoBehaviour
{
[Header("Mount Settings")]
public float mountWindowDuration = 0.2f; // 200ms
public float mountDetectionRadius = 3f;
public float mountAngleThreshold = 45f;
private bool mountWindowActive;
private float mountWindowTimer;
private Vehicle nearbyVehicle;
public event Action<Vehicle> OnMountSuccess;
public event Action OnMountWindowExpired;
}
Algorithm: Mount Window Management
public void UpdateMountWindow(Vector3 position, Vector3 velocity)
{
// 1. Check for nearby vehicles
Vehicle closestVehicle = FindClosestVehicle(position);
if (closestVehicle != null && IsValidMountAngle(velocity,
closestVehicle))
{
if (!mountWindowActive)
{
// Open mount window
mountWindowActive = true;
mountWindowTimer = mountWindowDuration;
nearbyVehicle = closestVehicle;
// Show UI prompt
[Link](true);
}
}
else
{
if (mountWindowActive)
{
// Close mount window
CloseMountWindow();
}
}
// 2. Update window timer
if (mountWindowActive)
{
mountWindowTimer -= [Link];
// Update UI with remaining time
[Link](mountWindowTimer /
mountWindowDuration);
if (mountWindowTimer <= 0)
{
CloseMountWindow();
OnMountWindowExpired?.Invoke();
}
}
}
Algorithm: Seamless Mount
public bool AttemptMount()
{
if (!mountWindowActive || nearbyVehicle == null)
return false;
// Calculate mount trajectory
Vector3 targetPosition = [Link]();
Vector3 currentPosition = [Link];
// Preserve momentum direction but adjust for vehicle entry
Vector3 preservedVelocity = [Link](velocity,
[Link]);
preservedVelocity = [Link](preservedVelocity,
[Link]);
// Trigger mount animation
[Link]("SeamlessMount");
// Attach to vehicle
[Link](this, preservedVelocity);
// Transition state
[Link](new MountedState(nearbyVehicle));
OnMountSuccess?.Invoke(nearbyVehicle);
// Close window
CloseMountWindow();
return true;
}
private void CloseMountWindow()
{
mountWindowActive = false;
mountWindowTimer = 0;
nearbyVehicle = null;
[Link](false);
}
2. World Generation
2.1 Wang Tile Chunk Generator
Module Overview
Procedural generation using Wang Tiles for seamless, varied urban environments.
Key Components
public class WangTileGenerator : MonoBehaviour
{
[Header("Generation Settings")]
public int chunkSize = 50;
public int viewDistance = 2; // Chunks in each direction
public List<WangTile> tilePrefabs;
private Dictionary<Vector2Int, Chunk> activeChunks;
private Queue<WangTile> tilePool;
// Wang tile edge types
public enum EdgeType { Road, Alley, Market, Canal, Wall }
}
public class WangTile
{
public GameObject prefab;
public EdgeType northEdge;
public EdgeType eastEdge;
public EdgeType southEdge;
public EdgeType westEdge;
public float weight = 1f;
}
Algorithm: Wang Tile Selection
public WangTile SelectCompatibleTile(Vector2Int position, EdgeType
requiredNorth,
EdgeType requiredEast, EdgeType requiredSouth, EdgeType
requiredWest)
{
// 1. Filter tiles by compatibility
List<WangTile> compatibleTiles = new List<WangTile>();
foreach (var tile in tilePrefabs)
{
bool compatible = true;
if (requiredNorth != [Link] && [Link] !=
requiredNorth)
compatible = false;
if (requiredEast != [Link] && [Link] !=
requiredEast)
compatible = false;
if (requiredSouth != [Link] && [Link] !=
requiredSouth)
compatible = false;
if (requiredWest != [Link] && [Link] !=
requiredWest)
compatible = false;
if (compatible)
[Link](tile);
}
// 2. Weighted random selection
if ([Link] == 0)
{
[Link]($"No compatible tile found for position
{position}");
return GetDefaultTile();
}
float totalWeight = [Link](t => [Link]);
float randomValue = [Link](0, totalWeight);
float currentWeight = 0;
foreach (var tile in compatibleTiles)
{
currentWeight += [Link];
if (randomValue <= currentWeight)
return tile;
}
return compatibleTiles[[Link] - 1];
}
Algorithm: Chunk Generation
public void GenerateChunk(Vector2Int chunkCoord)
{
// 1. Determine required edges from neighbors
EdgeType requiredNorth = GetEdgeFromNeighbor(chunkCoord,
[Link]);
EdgeType requiredEast = GetEdgeFromNeighbor(chunkCoord,
[Link]);
EdgeType requiredSouth = GetEdgeFromNeighbor(chunkCoord,
[Link]);
EdgeType requiredWest = GetEdgeFromNeighbor(chunkCoord,
[Link]);
// 2. Select compatible tile
WangTile selectedTile = SelectCompatibleTile(chunkCoord,
requiredNorth, requiredEast, requiredSouth, requiredWest);
// 3. Instantiate chunk
Vector3 worldPosition = new Vector3(chunkCoord.x * chunkSize, 0,
chunkCoord.y * chunkSize);
GameObject chunkObj = Instantiate([Link],
worldPosition, [Link]);
Chunk chunk = [Link]<Chunk>();
[Link](chunkCoord, selectedTile);
// 4. Generate traffic
[Link](chunk,
GetTrafficDensity());
// 5. Place diegetic markers
PlaceNavigationMarkers(chunk);
// 6. Register chunk
activeChunks[chunkCoord] = chunk;
}
private EdgeType GetEdgeFromNeighbor(Vector2Int chunkCoord,
Vector2Int direction)
{
Vector2Int neighborCoord = chunkCoord + direction;
if ([Link](neighborCoord, out Chunk neighbor))
{
// Return opposite edge of neighbor
if (direction == [Link]) return [Link];
if (direction == [Link]) return [Link];
if (direction == [Link]) return [Link];
if (direction == [Link]) return [Link];
}
return [Link]; // No constraint
}
2.2 Traffic System
Module Overview
Dynamic NPC traffic with “school of fish” behavior patterns.
Key Components
public class TrafficManager : MonoBehaviour
{
[Header("Traffic Settings")]
public int maxNPCs = 50;
public float baseDensity = 0.3f;
public float spawnRadius = 100f;
public float despawnRadius = 120f;
private List<NPCVehicle> activeVehicles;
private Queue<NPCVehicle> vehiclePool;
[Header("Behavior Settings")]
public float flowStateDistance = 10f;
public float reactionTime = 0.5f;
}
Algorithm: Traffic Spawning
public void SpawnTraffic(Chunk chunk, float density)
{
int targetNPCs = [Link](maxNPCs * density);
int currentNPCs = CountNPCsInChunk(chunk);
int toSpawn = targetNPCs - currentNPCs;
for (int i = 0; i < toSpawn; i++)
{
// Find valid spawn position on road
Vector3 spawnPos = FindValidSpawnPosition(chunk);
if (spawnPos == [Link]) continue;
// Get from pool or create new
NPCVehicle vehicle = GetVehicleFromPool();
[Link] = spawnPos;
[Link](GetRandomBehaviorType());
[Link](vehicle);
}
}
private Vector3 FindValidSpawnPosition(Chunk chunk)
{
// Raycast down from random position in chunk
Vector2 randomOffset = [Link] * chunkSize *
0.4f;
Vector3 checkPos = [Link] + new Vector3(randomOffset.x,
50f, randomOffset.y);
if ([Link](checkPos, [Link], out RaycastHit hit,
100f, roadMask))
{
// Check if position is clear
if ()
{
return [Link];
}
}
return [Link];
}
Algorithm: School of Fish Behavior
public class NPCVehicle : MonoBehaviour
{
public void UpdateBehavior()
{
// 1. Detect nearby vehicles and player
Collider[] nearby =
[Link]([Link], detectionRadius);
Vector3 avoidance = [Link];
Vector3 alignment = [Link];
Vector3 cohesion = [Link];
int neighborCount = 0;
foreach (var col in nearby)
{
if ([Link] == gameObject) continue;
Vector3 toNeighbor = [Link] -
[Link];
float distance = [Link];
// Avoidance - steer away from close vehicles
if (distance < avoidanceRadius)
{
avoidance -= [Link] / distance;
}
// Alignment - match direction of neighbors
if ([Link]<NPCVehicle>(out var neighbor))
{
alignment += [Link];
cohesion += [Link];
neighborCount++;
}
}
// 2. Player interaction (Flow State)
if (PlayerInFlowState && distanceToPlayer <
flowStateDistance)
{
// Open gap for player
Vector3 toPlayer = [Link] - [Link];
Vector3 playerDirection = [Link];
// Shift laterally to create gap
Vector3 lateralShift = [Link](toPlayer,
[Link]).normalized;
if ([Link](lateralShift, playerDirection) > 0)
avoidance += lateralShift * 2f;
else
avoidance -= lateralShift * 2f;
}
// 3. Apply behaviors
if (neighborCount > 0)
{
alignment /= neighborCount;
cohesion = (cohesion / neighborCount) -
[Link];
}
Vector3 steering = avoidance * avoidanceWeight
+ alignment * alignmentWeight
+ cohesion * cohesionWeight;
// 4. Apply steering
velocity += steering * [Link];
velocity = [Link](velocity, maxSpeed);
// 5. Move
[Link] += velocity * [Link];
[Link] = [Link](velocity);
}
}
3. Gameplay Systems
3.1 Cargo Integrity System
Module Overview
Physics-based cargo tracking with damage modeling from collisions.
Key Components
public class CargoContainer : MonoBehaviour
{
[Header("Cargo Settings")]
public float spillThreshold = 50f;
public float dropThreshold = 100f;
public int maxItems = 5;
private List<CargoItem> items;
private float currentIntegrity;
public event Action<float> OnIntegrityChanged;
public event Action OnCargoSpilled;
public event Action OnCargoDropped;
}
public class CargoItem
{
public string name;
public float fragility; // 0-1, lower = more fragile
public float weight;
public bool spilled;
public Rigidbody physicsBody;
}
Algorithm: Force Application
public void ApplyForce(Vector3 force, Vector3 impactPoint)
{
float forceMagnitude = [Link];
// 1. Check thresholds
if (forceMagnitude > dropThreshold)
{
TriggerCargoDrop();
return;
}
if (forceMagnitude > spillThreshold)
{
// 2. Calculate spill probability based on fragility
foreach (var item in items)
{
if ([Link]) continue;
float spillChance = (forceMagnitude - spillThreshold) /
(dropThreshold - spillThreshold);
spillChance *= (1f - [Link]); // More fragile =
higher chance
if ([Link] < spillChance)
{
SpillItem(item);
}
}
if ([Link](i => [Link]))
{
OnCargoSpilled?.Invoke();
}
}
// 3. Update integrity
float damage = forceMagnitude / dropThreshold;
currentIntegrity = [Link](0, currentIntegrity - damage);
OnIntegrityChanged?.Invoke(currentIntegrity);
}
private void SpillItem(CargoItem item)
{
[Link] = true;
// Enable physics for spilled item
if ([Link] != null)
{
[Link] = false;
[Link]([Link] * 2f,
[Link]);
}
// Visual feedback
[Link]([Link]);
}
private void TriggerCargoDrop()
{
// All items drop
foreach (var item in items)
{
SpillItem(item);
}
OnCargoDropped?.Invoke();
[Link]("Cargo Destroyed");
}
3.2 Replay System
Module Overview
Deterministic input recording and playback for ghost racing.
Key Components
public class ReplaySystem : MonoBehaviour
{
[Header("Replay Settings")]
public int maxFrames = 18000; // 5 minutes at 60fps
public float compressionThreshold = 0.01f;
private List<InputFrame> recordedFrames;
private bool isRecording;
private bool isPlaying;
private int currentFrame;
public event Action OnRecordingStarted;
public event Action OnRecordingStopped;
}
public struct InputFrame
{
public int frameNumber;
public float timestamp;
public Vector2 moveInput;
public bool jump;
public bool slide;
public bool mount;
public Vector3 position;
public Quaternion rotation;
public Vector3 velocity;
public string stateName;
}
Algorithm: Frame Recording
public void RecordFrame()
{
if (!isRecording) return;
if ([Link] >= maxFrames) return;
InputFrame frame = new InputFrame
{
frameNumber = [Link],
timestamp = [Link],
moveInput = [Link](),
jump = [Link](),
slide = [Link](),
mount = [Link](),
position = [Link],
rotation = [Link],
velocity = [Link],
stateName = [Link]
};
// Compress: Only record if input changed significantly
if (ShouldRecordFrame(frame))
{
[Link](frame);
}
}
private bool ShouldRecordFrame(InputFrame newFrame)
{
if ([Link] == 0) return true;
InputFrame lastFrame = recordedFrames[[Link] - 1];
// Check if inputs changed
if ([Link] != [Link]) return true;
if ([Link] != [Link]) return true;
if ([Link] != [Link]) return true;
if ([Link]([Link], [Link]) >
compressionThreshold) return true;
if ([Link]([Link], [Link]) >
0.1f) return true;
if ([Link] != [Link]) return true;
return false;
}
Algorithm: Playback
public void StartPlayback(List<InputFrame> frames)
{
recordedFrames = frames;
isPlaying = true;
currentFrame = 0;
// Spawn ghost avatar
GhostAvatar ghost = Instantiate(ghostPrefab);
[Link](frames);
}
public void UpdatePlayback()
{
if (!isPlaying) return;
// Find frame closest to current time
float currentTime = [Link];
while (currentFrame < [Link] - 1 &&
recordedFrames[currentFrame + 1].timestamp <=
currentTime)
{
currentFrame++;
}
// Interpolate between frames
if (currentFrame < [Link] - 1)
{
InputFrame current = recordedFrames[currentFrame];
InputFrame next = recordedFrames[currentFrame + 1];
float t = (currentTime - [Link]) /
([Link] - [Link]);
Vector3 interpolatedPos = [Link]([Link],
[Link], t);
Quaternion interpolatedRot =
[Link]([Link], [Link], t);
[Link](interpolatedPos,
interpolatedRot);
}
}
4. Scoring System
4.1 Score Calculation Algorithm
public class ScoringSystem : MonoBehaviour
{
public float CalculateFinalScore(MissionResult result)
{
float score = 0;
// 1. Time Bonus (exponential decay)
float timeRatio = [Link] / [Link];
float timeBonus = timeRatio * timeRatio *
timeBonusMultiplier;
score += timeBonus;
// 2. Cargo Integrity Bonus
float integrityBonus = [Link] *
integrityBonusMultiplier;
score += integrityBonus;
// 3. Style Points
float styleBonus = [Link] *
stylePointMultiplier;
score += styleBonus;
// 4. Flow State Bonus
float flowRatio = [Link] /
[Link];
float flowBonus = flowRatio * flowBonusMultiplier;
score += flowBonus;
// 5. Multipliers
if ([Link]) score *= 1.5f;
if ([Link]) score *= 1.25f;
if ([Link]) score *= 0.5f;
return [Link](score);
}
}
5. Audio System
5.1 Dynamic Music System
public class DynamicMusicSystem : MonoBehaviour
{
[Header("Music Layers")]
public AudioClip idleLayer;
public AudioClip flowLayer;
public AudioClip intenseLayer;
private float currentIntensity;
private float targetIntensity;
public void UpdateMusic(float playerSpeed, bool inFlowState)
{
// Calculate target intensity based on gameplay
targetIntensity = playerSpeed / sprintSpeed;
if (inFlowState) targetIntensity = 1f;
// Smooth transition
currentIntensity = [Link](currentIntensity,
targetIntensity, 0.1f);
// Adjust layer volumes
[Link] = 1f - currentIntensity;
[Link] = currentIntensity;
[Link] = [Link](0, currentIntensity - 0.7f)
* 3.33f;
// Adjust tempo
float tempoMultiplier = 0.8f + (currentIntensity * 0.4f);
[Link](tempoMultiplier);
}
}
6. Performance Optimizations
6.1 Object Pooling
public class ObjectPool<T> where T : MonoBehaviour
{
private Queue<T> pool;
private T prefab;
private int initialSize;
public T Get()
{
if ([Link] > 0)
{
T obj = [Link]();
[Link](true);
return obj;
}
return [Link](prefab);
}
public void Return(T obj)
{
[Link](false);
[Link](obj);
}
}
6.2 LOD System
public class LODManager : MonoBehaviour
{
public void UpdateLOD(Vector3 playerPosition)
{
float distance = [Link]([Link],
playerPosition);
if (distance < lodDistances[0])
{
SetLOD(0); // Full detail
}
else if (distance < lodDistances[1])
{
SetLOD(1); // Medium detail
}
else if (distance < lodDistances[2])
{
SetLOD(2); // Low detail
}
else
{
[Link](false); // Culled
}
}
}
7. Module Interaction
Summary
InputHandler
│
├──► PlayerController
│ │
│ ├──► KinematicCharacterController ──► Physics
│ │
│ ├──► ParkourDetector ──► Animation
│ │
│ ├──► MomentumSystem ──► AudioManager
│ │ │
│ │ └──► CameraEffects
│ │
│ ├──► VehicleMountSystem
│ │ │
│ │ └──► Vehicle
│ │
│ └──► CargoContainer ──► MissionManager
│ │
│ └──► ScoringSystem
│
└──► ReplaySystem ──► GhostAvatar
WorldGenerator
│
├──► WangTileGenerator
│ │
│ └──► Chunk
│
└──► TrafficManager
│
└──► NPCVehicle
UIManager
│
├──► All Systems (Event-driven updates)
│
└──► DiegeticMarker
SaveManager
│
├──► PlayerData
├──► MissionProgress
└──► ReplayData
8. Implementation Priority
Priority Module Rationale
P0 KinematicCharacterController Core movement
P0 InputHandler All player interaction
P0 PlayerController Central player management
P1 ParkourDetector Key differentiator
P1 MomentumSystem Core gameplay loop
P1 WangTileGenerator World content
P2 VehicleMountSystem Hybrid traversal
P2 CargoContainer Mission objectives
P2 TrafficManager World life
P3 ReplaySystem Speedrun feature
P3 ScoringSystem Progression
P4 AudioManager Polish
P4 UIManager Presentation