Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | 44x 44x 44x 44x 44x 44x 44x 44x 44x 44x 44x 44x | /**
* Shared physics constants for Black Trigram combat system.
*
* **Korean**: 물리 상수
*
* This module provides shared constants for physics calculations across
* combat and training systems, ensuring consistency in coordinate transformations
* and unit conversions.
*
* ## Physics-First Architecture
*
* The game uses a physics-first coordinate system where:
* - All internal calculations use meters (m) and meters/second (m/s)
* - Arena sizes are determined by screen resolution (6m, 8m, 10m, 12m, 14m)
* - Pixel conversion happens only at render time
* - The pixels-per-meter ratio varies by device/resolution
*
* @module types/physicsConstants
* @category Constants
* @korean 물리상수
*/
/**
* Base stamina regeneration rate (stamina per second).
*
* **Korean**: 기본 체력 재생 속도
*
* This is the base rate at which stamina regenerates when not affected by
* combat state penalties, breathing disruption, or other modifiers.
*
* - Increased from 3 to 15 stamina/second (5x faster) for fluid combat
* - Allows players to move around and attack frequently without exhaustion
* - Subject to penalties from breathing disruption (25%-75% reduction)
* - Subject to combat state penalties (20%-100% reduction when attacking/stunned)
*
* @example
* ```typescript
* // Calculate stamina regen with breathing disruption
* const baseRegen = regenRate * BASE_STAMINA_REGEN_RATE;
* const modifiedRegen = BreathingDisruptionSystem.calculateStaminaRegen(
* player,
* baseRegen
* );
* ```
*
* @public
* @category Combat Constants
* @korean 기본체력재생속도
*/
export const BASE_STAMINA_REGEN_RATE = 15.0 as const;
/**
* Base movement acceleration rate (m/s²).
*
* **Korean**: 기본 이동 가속도
*
* This is the base rate at which characters accelerate during movement.
* Used by both MovementPhysics and SpeedModifierSystem for consistency.
*
* - Increased from 12.0 to 30.0 m/s² (2.5x faster) for instant-response combat
* - Reaches 6 m/s walking speed in 0.2 seconds
* - Reaches 10 m/s sprint speed in 0.33 seconds
* - Provides arcade-style responsiveness suitable for Korean martial arts combat
* - Subject to combat state penalties (20%-100% reduction when attacking/stunned)
*
* @example
* ```typescript
* // Calculate acceleration with combat state penalty
* const effectiveAcceleration = BASE_MOVEMENT_ACCELERATION * (1 - statePenalty);
* const velocityChange = effectiveAcceleration * deltaTime;
* ```
*
* @public
* @category Physics Constants
* @korean 기본이동가속도
*/
export const BASE_MOVEMENT_ACCELERATION = 30.0 as const;
/**
* Reference pixels-per-meter ratio for scale calculations.
*
* **Korean**: 참조 미터-픽셀 변환
*
* This is the REFERENCE ratio used for calculating scale factors.
* The actual pixels-per-meter varies by device resolution:
* - Calculate actual ratio: `arenaWidthPixels / arenaWidthMeters`
* - Calculate scale: `actualRatio / REFERENCE_PIXELS_PER_METER`
*
* **Do NOT use this for direct coordinate conversion.**
* Use `bounds.width / bounds.worldWidthMeters` instead.
*
* @example
* ```typescript
* // Calculate actual pixels per meter from arena bounds
* const actualPixelsPerMeter = bounds.width / bounds.worldWidthMeters;
*
* // Calculate scale relative to reference
* const scale = actualPixelsPerMeter / REFERENCE_PIXELS_PER_METER;
* ```
*
* @public
* @category Coordinate Constants
* @korean 참조픽셀미터비율
*/
export const REFERENCE_PIXELS_PER_METER = 100 as const;
/**
* @deprecated Use `bounds.width / bounds.worldWidthMeters` for dynamic conversion.
* This constant is kept for backward compatibility only.
*
* Legacy conversion factor from meters to pixels. The actual ratio now varies
* by screen resolution and arena size.
*/
export const METERS_TO_PIXELS_SCALE = 100 as const;
/**
* Conversion factor from meters to training scene units.
*
* **Korean**: 미터-훈련 단위 변환
*
* Training scenes are authored in real-world meters and use a 1:1 conversion
* ratio. This means 1 meter in the game world equals 1 unit in the training
* scene coordinate system.
*
* **IMPORTANT**: This differs from combat AI which uses dynamic pixels-per-meter.
* The 3D world uses 1:1 meter scale for consistent physics.
*
* @example
* ```typescript
* // Convert reach from meters to training units (1:1)
* const reachInUnits = reachInMeters * METERS_TO_TRAINING_UNITS;
* ```
*
* @public
* @category Coordinate Constants
* @korean 미터훈련비율
*/
export const METERS_TO_TRAINING_UNITS = 1.0 as const;
/**
* Default body radius for hit distance calculation (training dummy).
*
* **Korean**: 기본몸체반경 (Default Body Radius)
*
* When calculating hit distance, we measure center-to-center, but attacks
* land on the target's body surface, not their center point. This constant
* represents the default body radius for entities without physical attributes
* (like training dummies).
*
* For player archetypes, use `calculateBodyRadius(physicalAttributes)` from
* `utils/skeletonScaling.ts` which calculates based on shoulder width.
*
* Based on average human proportions:
* - Average shoulder width: ~45cm
* - Body depth ratio: 0.5 × shoulderWidth = 22.5cm
* - Result: ~0.225m (rounded to 0.23m)
*
* @example
* ```typescript
* // For training dummy (no archetype):
* const effectiveDistance = centerToCenter - DEFAULT_BODY_RADIUS_METERS;
*
* // For player (use archetype):
* import { calculateBodyRadius } from '@/utils/skeletonScaling';
* const radius = calculateBodyRadius(physicalAttributes);
* const effectiveDistance = centerToCenter - radius;
* ```
*
* @public
* @category Physics Constants
* @korean 기본몸체반경
*/
export const DEFAULT_BODY_RADIUS_METERS = 0.23 as const;
/**
* @deprecated Use DEFAULT_BODY_RADIUS_METERS or calculateBodyRadius() instead.
* Kept for backward compatibility.
*/
export const BODY_RADIUS_METERS = DEFAULT_BODY_RADIUS_METERS;
/**
* Standard arena sizes in meters (4:3 aspect ratio).
*
* @public
*/
export const ARENA_SIZE_METERS = {
/** Small screens (< 768px): 6m × 4.5m */
SMALL: 6,
/** Medium screens (768-1199px): 8m × 6m */
MEDIUM: 8,
/** Large screens (1200-1919px): 10m × 7.5m */
LARGE: 10,
/** XLarge screens (1920-2559px): 12m × 9m */
XLARGE: 12,
/** Ultra screens (≥ 2560px): 14m × 10.5m */
ULTRA: 14,
} as const;
/**
* Combat ranges in METERS for physics-first system.
*
* **Korean**: 전투범위미터 (Combat Ranges in Meters)
*
* These values define combat distance thresholds for AI decision-making
* and hit detection. Use these instead of pixel-based COMBAT_RANGES.
*
* @public
*/
export const COMBAT_RANGES_METERS = {
/** Melee range: very close, grappling distance (0.5m) */
MELEE: 0.5,
/** Close range: punching/elbow distance (0.8m) */
CLOSE: 0.8,
/** Medium range: kicking distance (1.2m) */
MEDIUM: 1.2,
/** Long range: max attack distance (2.0m) */
LONG: 2.0,
/** Maximum range: engagement distance (3.0m) */
MAX: 3.0,
} as const;
/**
* AI movement constants in METERS for physics-first system.
*
* **Korean**: AI이동상수미터 (AI Movement Constants in Meters)
*
* @public
*/
export const AI_MOVEMENT_METERS = {
/** Step size for AI movement (0.5m per step) */
STEP_SIZE: 0.5,
/** Minimum distance threshold to avoid division by zero */
MIN_DISTANCE_THRESHOLD: 0.05,
/** Horizontal arena margin (based on character width ~0.6m) */
ARENA_MARGIN_X: 0.6,
/** Vertical arena margin (based on character depth ~1.8m for movement) */
ARENA_MARGIN_Y: 1.8,
/** Flanking offset base (0.4m) */
FLANK_OFFSET_BASE: 0.4,
/** Flanking offset random range (0.2m) */
FLANK_OFFSET_RANDOM: 0.2,
} as const;
/**
* Player starting positions as PERCENTAGES of arena dimensions.
*
* **Korean**: 시작위치비율 (Starting Position Ratios)
*
* Use these ratios with arena dimensions to calculate starting positions:
* - playerStartX = arenaX + (arenaWidth * PLAYER_START_POSITIONS.PLAYER1_X)
*
* @public
*/
export const PLAYER_START_POSITIONS = {
/** Player 1 starts at 25% from left edge */
PLAYER1_X: 0.25,
/** Player 2 starts at 75% from left edge */
PLAYER2_X: 0.75,
/** Both players start at 50% depth (center vertically) */
CENTER_Y: 0.5,
} as const;
/**
* AI personality optimal ranges in METERS.
*
* **Korean**: AI성격최적범위미터 (AI Personality Optimal Ranges in Meters)
*
* @public
*/
export const AI_OPTIMAL_RANGE_METERS = {
/** Musa - Traditional warrior: close quarters */
MUSA: 0.5,
/** Amsalja - Shadow assassin: stealth melee */
AMSALJA: 0.4,
/** Hacker - Cyber warrior: mid-range analysis */
HACKER: 1.2,
/** Jeongbo Yowon - Intelligence operative: tactical mid-range */
JEONGBO_YOWON: 0.8,
/** Jojik Pokryeokbae - Organized crime: brutal close combat */
JOJIK: 0.6,
} as const;
|