Skip to content

Commit 781b1cb

Browse files
updates ship move logic
1 parent 7250740 commit 781b1cb

1 file changed

Lines changed: 91 additions & 53 deletions

File tree

src/gamelogic/ship.odin

Lines changed: 91 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,18 @@ import "core:fmt"
77
MAX_PROJECTILES :: 10000
88

99
MAX_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

1323
Projectile :: 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

3749
init_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) {
8699
update_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

130139
update_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
278305
ship_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

334372
cleanup_ship :: proc(ship: ^Ship) {
335373
destroy_ship_trail(&ship.trail)
336-
}
374+
}

0 commit comments

Comments
 (0)