@@ -7,8 +7,18 @@ import "core:fmt"
77MAX_PROJECTILES :: 10000
88
99MAX_SHIP_SPEED :: 1000.0
10- MAX_WARP_MULTIPLIER :: 3.0
11- WARP_SPEED_THRESHOLD :: 997.0
10+ MAX_WARP_MULTIPLIER :: 70.0
11+ WARP_SPEED_THRESHOLD :: 997.45
12+
13+ SHIP_ACCELERATION :: 997.5
14+ SHIP_SCALE :: 30.0
15+ SHIP_FRICTION :: 0.39346
16+ SHIP_SHOOT_INTERVAL :: 0.0125
17+
18+ ROTATION_DEGREES_PER_SECOND :: 360.0
19+
20+ MOVEMENT_INERTIA :: 0.021
21+ WARP_INERTIA :: 0.05
1222
1323Projectile :: struct {
1424 position: rl.Vector2,
@@ -22,40 +32,43 @@ Ship :: struct {
2232 position: rl.Vector2, // Screen/local position (for rendering and collision)
2333 world_position: rl.Vector2, // World position (for exploration and camera)
2434 arena_position: rl.Vector2, // Position within arena bounds (for wrapping mode)
25- velocity: rl.Vector2,
35+ velocity: rl.Vector2, // Current velocity (with inertia)
36+ target_velocity: rl.Vector2, // Target velocity from WASD input
2637 rotation: f32 ,
2738 acceleration: f32 ,
2839 friction: f32 ,
2940 shoot_cooldown: f32 ,
3041 shoot_interval: f32 ,
3142 projectiles: [MAX_PROJECTILES]Projectile,
3243 ship_speed: f32 , // Current speed magnitude
44+ warp_speed_target: f32 , // Target warp speed (1.0 to MAX_WARP_MULTIPLIER)
3345 warp_speed: f32 , // Warp speed multiplier (1.0 to MAX_WARP_MULTIPLIER)
3446 trail: Ship_Trail, // Ship trail system
3547}
3648
3749init_ship :: proc (window_width: f32 , window_height: f32 ) -> Ship {
3850 start_pos := rl.Vector2{window_width / 2 , window_height / 2 }
3951 ship := Ship {
40- scale = 30 ,
52+ scale = SHIP_SCALE ,
4153 position = start_pos,
42- world_position = start_pos, // Start at same position as screen
43- arena_position = start_pos, // Initialize arena position
54+ world_position = start_pos,
55+ arena_position = start_pos,
4456 velocity = rl.Vector2{0.0 , 0.0 },
57+ target_velocity = rl.Vector2{0.0 , 0.0 },
4558 rotation = 0.0 ,
46- acceleration = 500.0 ,
47- friction = 0.39346 ,
59+ acceleration = SHIP_ACCELERATION ,
60+ friction = SHIP_FRICTION ,
4861 shoot_cooldown = 0.0 ,
49- shoot_interval = 0.0125 ,
62+ shoot_interval = SHIP_SHOOT_INTERVAL ,
5063 projectiles = [MAX_PROJECTILES]Projectile{},
5164 ship_speed = 0.0 ,
65+ warp_speed_target = 1.0 ,
5266 warp_speed = 1.0 ,
5367 trail = Ship_Trail{},
5468 }
5569
56- // Initialize the trail system
57- init_ship_trail (&ship.trail, ship.scale * 0.25 ) // Use half the ship scale as radius
58- reset_ship_trail (&ship.trail, ship.world_position, 0.0 ) // Initialize with world position
70+ init_ship_trail (&ship.trail, ship.scale * 0.25 )
71+ reset_ship_trail (&ship.trail, ship.world_position, 0.0 )
5972
6073 return ship
6174}
@@ -86,19 +99,16 @@ shoot_projectile :: proc(ship: ^Ship) {
8699update_projectiles :: proc (ship: ^Ship, delta_time: f32 , window_width: f32 , window_height: f32 ) {
87100 for &projectile in &ship.projectiles {
88101 if projectile.active {
89- // store previous position to calculate distance traveled
90102 prev_position := projectile.position
91103
92104 projectile.position.x += projectile.velocity.x * delta_time
93105 projectile.position.y += projectile.velocity.y * delta_time
94106
95- // calculate distance traveled this frame
96107 dx := projectile.position.x - prev_position.x
97108 dy := projectile.position.y - prev_position.y
98109 distance_this_frame := math.sqrt (dx * dx + dy * dy)
99110 projectile.traveled += distance_this_frame
100111
101- // wrap around screen edges
102112 if projectile.position.x < 0 {
103113 projectile.position.x = window_width
104114 } else if projectile.position.x > window_width {
@@ -111,7 +121,6 @@ update_projectiles :: proc(ship: ^Ship, delta_time: f32, window_width: f32, wind
111121 projectile.position.y = 0
112122 }
113123
114- // deactivate projectiles after they've traveled far enough
115124 if projectile.traveled > 10000.0 {
116125 projectile.active = false
117126 }
@@ -128,46 +137,66 @@ draw_projectiles :: proc(ship: ^Ship) {
128137}
129138
130139update_ship :: proc (ship: ^Ship, camera: ^Camera_State, delta_time: f32 , window_width: f32 , window_height: f32 ) {
131- // ship rotation
132- if rl.IsKeyDown (rl.KeyboardKey.RIGHT) || rl.IsKeyDown (rl.KeyboardKey.D) {
133- ship.rotation += 180.0 * delta_time
134- }
140+ input_direction := rl.Vector2{0 , 0 }
141+
135142 if rl.IsKeyDown (rl.KeyboardKey.LEFT) || rl.IsKeyDown (rl.KeyboardKey.A) {
136- ship.rotation -= 180.0 * delta_time
143+ input_direction.x -= 1.0
144+ }
145+ if rl.IsKeyDown (rl.KeyboardKey.RIGHT) || rl.IsKeyDown (rl.KeyboardKey.D) {
146+ input_direction.x += 1.0
137147 }
138-
139- // ship thrust
140148 if rl.IsKeyDown (rl.KeyboardKey.UP) || rl.IsKeyDown (rl.KeyboardKey.W) {
141- radians := ship.rotation * rl.DEG2RAD
142- ship.velocity.x += math.cos (radians) * ship.acceleration * delta_time
143- ship.velocity.y += math.sin (radians) * ship.acceleration * delta_time
149+ input_direction.y -= 1.0
144150 }
151+ if rl.IsKeyDown (rl.KeyboardKey.DOWN) || rl.IsKeyDown (rl.KeyboardKey.S) {
152+ input_direction.y += 1.0
153+ }
154+
155+ input_direction = rl.Vector2Normalize (input_direction)
156+ ship.target_velocity = input_direction * ship.acceleration
157+ ship.velocity.x += ease (ship.target_velocity.x, ship.velocity.x, MOVEMENT_INERTIA, delta_time, f32 (rl.GetFPS ()))
158+ ship.velocity.y += ease (ship.target_velocity.y, ship.velocity.y, MOVEMENT_INERTIA, delta_time, f32 (rl.GetFPS ()))
159+
160+ if rl.Vector2Length (input_direction) > 0.1 {
161+ target_rotation := math.atan2 (input_direction.y, input_direction.x) * rl.RAD2DEG
162+ rotation_diff := target_rotation - ship.rotation
145163
146- // apply friction (exponential decay - frame rate independent)
147- friction_factor := math.pow (1.0 - ship.friction, delta_time)
148- ship.velocity.x *= friction_factor
149- ship.velocity.y *= friction_factor
164+ // eliminates gimbal lock
165+ if rotation_diff > 180.0 {
166+ rotation_diff -= 360.0
167+ } else if rotation_diff < -180.0 {
168+ rotation_diff += 360.0
169+ }
170+
171+ max_rotation_this_frame := ROTATION_DEGREES_PER_SECOND * delta_time
172+
173+ if math.abs (rotation_diff) < max_rotation_this_frame {
174+ ship.rotation = target_rotation
175+ } else {
176+ if rotation_diff > 0 {
177+ ship.rotation += max_rotation_this_frame
178+ } else {
179+ ship.rotation -= max_rotation_this_frame
180+ }
181+ }
182+ }
150183
151- // calculate ship speed from velocity magnitude
152184 ship.ship_speed = math.sqrt (ship.velocity.x * ship.velocity.x + ship.velocity.y * ship.velocity.y)
153185
154- // calculate warp speed multiplier based on ship speed
155186 if ship.ship_speed >= WARP_SPEED_THRESHOLD && ship.ship_speed <= MAX_SHIP_SPEED {
156- ship.warp_speed = remap (ship.ship_speed, WARP_SPEED_THRESHOLD, MAX_SHIP_SPEED, 1.0 , MAX_WARP_MULTIPLIER)
187+ ship.warp_speed_target = remap (ship.ship_speed, WARP_SPEED_THRESHOLD, MAX_SHIP_SPEED, 1.0 , MAX_WARP_MULTIPLIER)
157188 } else if ship.ship_speed > MAX_SHIP_SPEED {
158- ship.warp_speed = MAX_WARP_MULTIPLIER
189+ ship.warp_speed_target = MAX_WARP_MULTIPLIER
159190 } else {
160- ship.warp_speed = 1.0
191+ ship.warp_speed_target = 1.0
161192 }
162193
163- // ALWAYS update world position accurately - no more freezing!
194+ ship.warp_speed += ease (ship.warp_speed_target, ship.warp_speed, WARP_INERTIA, delta_time, f32 (rl.GetFPS ()))
195+
164196 ship.world_position.x += ship.velocity.x * ship.warp_speed * delta_time
165197 ship.world_position.y += ship.velocity.y * ship.warp_speed * delta_time
166-
167- // Keep arena position synced with world position
168198 ship.arena_position = ship.world_position
169199
170- // update screen/local position based on camera mode
171200 switch camera.mode {
172201 case .FOLLOW_SHIP:
173202 // In exploration mode, ship position relative to camera
@@ -273,24 +302,20 @@ draw_ship_to_texture :: proc(ship: ^Ship) -> rl.Texture2D {
273302 return g_state.ship_render_target.texture
274303}
275304
276- // cleanup ship resources
277- // Hot reload ship system
278305ship_hot_reload :: proc (ship: ^Ship) -> bool {
279306 fmt.printf (" === HOT RELOADING SHIP SYSTEM ===\n " )
280307
281- // Store current state for continuity
282- current_scale := ship.scale
308+ // store current runtime state (preserve continuity)
283309 current_position := ship.position
284310 current_world_position := ship.world_position
285311 current_arena_position := ship.arena_position
286312 current_velocity := ship.velocity
313+ current_target_velocity := ship.target_velocity
287314 current_rotation := ship.rotation
288- current_acceleration := ship.acceleration
289- current_friction := ship.friction
290315 current_shoot_cooldown := ship.shoot_cooldown
291- current_shoot_interval := ship.shoot_interval
292316 current_projectiles := ship.projectiles
293317 current_ship_speed := ship.ship_speed
318+ current_warp_speed_target := ship.warp_speed_target
294319 current_warp_speed := ship.warp_speed
295320
296321 fmt.printf (" Ship state preserved: pos=(%.2f,%.2f), world_pos=(%.2f,%.2f), vel=(%.2f,%.2f), rot=%.2f\n " ,
@@ -299,7 +324,13 @@ ship_hot_reload :: proc(ship: ^Ship) -> bool {
299324 current_velocity.x, current_velocity.y,
300325 current_rotation)
301326
302- // Hot reload the ship trail
327+ // get updated constants directly (pick up code changes on hot reload)
328+ new_scale := f32 (SHIP_SCALE)
329+ new_acceleration := f32 (SHIP_ACCELERATION)
330+ new_friction := f32 (SHIP_FRICTION)
331+ new_shoot_interval := f32 (SHIP_SHOOT_INTERVAL)
332+
333+ // hot reload the ship trail
303334 if ship.trail.initialized {
304335 fmt.printf (" Hot reloading ship trail...\n " )
305336 if !ship_trail_hot_reload (&ship.trail) {
@@ -311,26 +342,33 @@ ship_hot_reload :: proc(ship: ^Ship) -> bool {
311342 fmt.printf (" Ship trail not initialized, skipping trail hot reload\n " )
312343 }
313344
314- // Restore all state
315- ship.scale = current_scale
345+ // restore runtime state (preserve continuity)
316346 ship.position = current_position
317347 ship.world_position = current_world_position
318348 ship.arena_position = current_arena_position
319349 ship.velocity = current_velocity
350+ ship.target_velocity = current_target_velocity
320351 ship.rotation = current_rotation
321- ship.acceleration = current_acceleration
322- ship.friction = current_friction
323352 ship.shoot_cooldown = current_shoot_cooldown
324- ship.shoot_interval = current_shoot_interval
325353 ship.projectiles = current_projectiles
326354 ship.ship_speed = current_ship_speed
355+ ship.warp_speed_target = current_warp_speed_target
327356 ship.warp_speed = current_warp_speed
328357
358+ // apply new config values
359+ ship.scale = new_scale
360+ ship.acceleration = new_acceleration
361+ ship.friction = new_friction
362+ ship.shoot_interval = new_shoot_interval
363+
364+ fmt.printf (" Hot reload: Updated acceleration: %.2f, friction: %.6f, scale: %.2f, shoot_interval: %.4f\n " ,
365+ ship.acceleration, ship.friction, ship.scale, ship.shoot_interval)
366+
329367 fmt.printf (" Ship state restored successfully\n " )
330368 fmt.printf (" === SHIP HOT RELOAD COMPLETE ===\n " )
331369 return true
332370}
333371
334372cleanup_ship :: proc (ship: ^Ship) {
335373 destroy_ship_trail (&ship.trail)
336- }
374+ }
0 commit comments