All files / utils sharedPhysicsConfig.ts

100% Statements 6/6
100% Branches 2/2
100% Functions 2/2
100% Lines 6/6

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                                                                                                                                                                                                        115x 66x               49x                                                                                                   55x               55x   55x                  
/**
 * Shared physics configuration for Black Trigram screens.
 *
 * **Korean**: 공유 물리 설정
 *
 * This module provides shared physics configuration utilities to ensure
 * consistent physics behavior, coordinate systems, and camera setup across
 * TrainingScreen3D and CombatScreen3D.
 *
 * ## Synchronization Guarantees
 *
 * All screens using these utilities will have:
 * - Identical camera FOV and positioning for same device types
 * - Consistent arena bounds calculations
 * - Same physics constants (acceleration, stamina regen, etc.)
 * - Unified coordinate system (meter-based)
 * - Matching movement speed and range calculations
 *
 * @module utils/sharedPhysicsConfig
 * @category Physics
 * @korean 공유물리설정
 */
 
import {
  BASE_STAMINA_REGEN_RATE,
  BASE_MOVEMENT_ACCELERATION,
  COMBAT_RANGES_METERS,
} from "@/types/physicsConstants";
import {
  calculateArenaConfiguration,
  type ArenaConfiguration,
} from "./arenaWorldDimensions";
 
/**
 * Camera configuration for 3D rendering.
 *
 * **Korean**: 카메라 설정
 *
 * @public
 */
export interface CameraConfiguration {
  /** Field of view in degrees */
  readonly fov: number;
  /** Camera position [x, y, z] in meters */
  readonly position: readonly [number, number, number];
  /** Near clipping plane */
  readonly near: number;
  /** Far clipping plane */
  readonly far: number;
}
 
/**
 * Complete physics configuration for a game screen.
 *
 * **Korean**: 물리 설정
 *
 * Includes all parameters needed to ensure consistent physics
 * behavior across different screens and device types.
 *
 * @public
 */
export interface PhysicsConfiguration {
  /** Arena configuration with pixel and meter dimensions */
  readonly arenaConfig: ArenaConfiguration;
  /** Camera configuration for consistent perspective */
  readonly cameraConfig: CameraConfiguration;
  /** Base stamina regeneration rate (stamina/second) */
  readonly staminaRegenRate: number;
  /** Base movement acceleration (m/s²) */
  readonly movementAcceleration: number;
  /** Combat ranges in meters */
  readonly combatRanges: typeof COMBAT_RANGES_METERS;
  /** Pixels per meter ratio for this configuration */
  readonly pixelsPerMeter: number;
}
 
/**
 * Create camera configuration based on device type.
 *
 * Mobile devices get a tighter FOV and closer camera position
 * for better framing of the smaller arena. Desktop gets a wider
 * FOV and further camera for full arena view.
 *
 * **Korean**: 카메라 설정 생성
 *
 * @param isMobile - Whether the device is mobile
 * @returns Camera configuration for device type
 *
 * @example
 * ```typescript
 * const mobile = createCameraConfig(true);
 * // { fov: 55, position: [0, 6, 10], near: 0.1, far: 1000 }
 *
 * const desktop = createCameraConfig(false);
 * // { fov: 60, position: [0, 8, 12], near: 0.1, far: 1000 }
 * ```
 *
 * @public
 */
export function createCameraConfig(isMobile: boolean): CameraConfiguration {
  if (isMobile) {
    return {
      fov: 55, // Tighter FOV for smaller mobile arena
      position: [0, 6, 10], // Closer camera
      near: 0.1,
      far: 1000,
    };
  }
 
  return {
    fov: 60, // Standard FOV for desktop
    position: [0, 8, 12], // Further back for full view
    near: 0.1,
    far: 1000,
  };
}
 
/**
 * Create complete physics configuration for a screen.
 *
 * This is the primary function for setting up physics in both
 * TrainingScreen3D and CombatScreen3D. It ensures consistent
 * physics behavior by using the same calculations and constants.
 *
 * **Korean**: 물리 설정 생성
 *
 * @param screenWidth - Screen width in pixels
 * @param screenHeight - Screen height in pixels
 * @param topOffset - Pixels reserved at top (HUD, headers)
 * @param bottomOffset - Pixels reserved at bottom (controls, footer)
 * @param isMobile - Whether the device is mobile
 * @returns Complete physics configuration
 *
 * @example
 * ```typescript
 * // Training screen
 * const trainingPhysics = createPhysicsConfig(
 *   1920, 1080, 60, 100, false
 * );
 *
 * // Combat screen
 * const combatPhysics = createPhysicsConfig(
 *   1920, 1080, 60, 100, false
 * );
 *
 * // Both have identical physics configuration
 * trainingPhysics.pixelsPerMeter === combatPhysics.pixelsPerMeter; // true
 * ```
 *
 * @public
 */
export function createPhysicsConfig(
  screenWidth: number,
  screenHeight: number,
  topOffset: number,
  bottomOffset: number,
  isMobile: boolean,
): PhysicsConfiguration {
  // Calculate arena dimensions (same for both screens)
  const arenaConfig = calculateArenaConfiguration(
    screenWidth,
    screenHeight,
    topOffset,
    bottomOffset,
  );
 
  // Create camera config based on device type
  const cameraConfig = createCameraConfig(isMobile);
 
  return {
    arenaConfig,
    cameraConfig,
    staminaRegenRate: BASE_STAMINA_REGEN_RATE,
    movementAcceleration: BASE_MOVEMENT_ACCELERATION,
    combatRanges: COMBAT_RANGES_METERS,
    pixelsPerMeter: arenaConfig.pixelsPerMeter,
  };
}