diff --git a/game.odin b/game.odin index 8d8740e..901cb3e 100644 --- a/game.odin +++ b/game.odin @@ -9,8 +9,11 @@ Rect :: rl.Rectangle SCREEN_WIDTH : i32 = 1000 SCREEN_HEIGHT : i32 = 800 +BW := f32(SCREEN_WIDTH) +BH := f32(SCREEN_HEIGHT) -SCALE: f32 = 0.5 + +SCALE: f32 = 0.37 SHIP_W: f32 = 70 * SCALE SHIP_H: f32 = 100 * SCALE @@ -31,21 +34,42 @@ Asteroid :: struct { rot: f32, } -GameState :: struct { - dt: f32, - ship_pos: Vec2, - ship_angle: f32, - ship_vel: Vec2, - bullets: [dynamic]Bullet, - asteroids: [dynamic]Asteroid, +Player :: struct { + pos: Vec2, + points: [4]Vec2, + angle: f32, + vel: Vec2 } -get_ship_shape :: proc(s : GameState) -> (Vec2, Vec2, Vec2, Vec2) { - v1 := rl.Vector2Rotate({ SHIP_H*0.5, 0}, s.ship_angle) + s.ship_pos - v2 := rl.Vector2Rotate({-SHIP_H*0.5, -SHIP_W*0.5}, s.ship_angle) + s.ship_pos - v3 := rl.Vector2Rotate({-SHIP_H*0.5*0.5, 0}, s.ship_angle) + s.ship_pos - v4 := rl.Vector2Rotate({-SHIP_H*0.5, SHIP_W*0.5}, s.ship_angle) + s.ship_pos - return v1, v2, v3, v4 +PlayerSpinningPart :: struct { + points: [2]Vec2, + rotation_speed: f32, + vel: Vec2, +} + +Death :: struct { + flying_parts: [4]PlayerSpinningPart +} + +PlayerState :: union #no_nil { + Player, + Death, +} + +GameState :: struct { + dt: f32, + player_state: PlayerState, + bullets: [dynamic]Bullet, + asteroids: [dynamic]Asteroid, + bullet_pop_idxs: [dynamic]int, + asteroid_pop_idxs: [dynamic]int, +} + +update_ship_shape :: proc(p : ^Player) { + p.points[0] = rl.Vector2Rotate({ SHIP_H*0.5, 0}, p.angle) + p.pos + p.points[1] = rl.Vector2Rotate({-SHIP_H*0.5, -SHIP_W*0.5}, p.angle) + p.pos + p.points[2] = rl.Vector2Rotate({-SHIP_H*0.5*0.5, 0}, p.angle) + p.pos + p.points[3] = rl.Vector2Rotate({-SHIP_H*0.5, SHIP_W*0.5}, p.angle) + p.pos } swap_n_pop :: proc(bullets: ^[dynamic]$T, idx: int) { @@ -58,25 +82,127 @@ swap_n_pop :: proc(bullets: ^[dynamic]$T, idx: int) { } } +player_input :: proc(s: ^GameState) { + switch &player in s.player_state { + case Player: + if rl.IsKeyDown(.D) { + player.angle += ANGULAR_SPEED * s.dt + } + if rl.IsKeyDown(.A) { + player.angle -= ANGULAR_SPEED * s.dt + } + if rl.IsKeyDown(.W) { + player.vel.x += math.cos(player.angle) * THRUST_SPEED * s.dt + player.vel.y += math.sin(player.angle) * THRUST_SPEED * s.dt + } + if rl.IsKeyPressed(.SPACE) { + b_vel := Vec2{ math.cos(player.angle) , math.sin(player.angle) } * BULLET_SPEED + append(&s.bullets, Bullet{player.points[0], b_vel}) + } + case Death: + if rl.IsKeyDown(.ENTER) { + // restart game + } + } +} + +update :: proc(s: ^GameState) { + switch &player in s.player_state { + case Player: + update_ship_shape(&player) + player.pos += player.vel * (5000 * s.dt) + ship_collision := false + for i := 0; i < len(s.asteroids); i += 1 { + s.asteroids[i].rect.x += s.asteroids[i].vel.x + s.asteroids[i].rect.y += s.asteroids[i].vel.y + for j := 0; j < len(player.points); j += 1 { + if rl.CheckCollisionPointRec(player.points[j], s.asteroids[i].rect) { + ship_collision = true + } + } + } + for i := 0; i < len(s.bullets); i += 1 { + if ( s.bullets[i].pos.x < 0 || s.bullets[i].pos.x > BW + || s.bullets[i].pos.y < 0 || s.bullets[i].pos.y > BH) { + append(&s.bullet_pop_idxs, i) + } + s.bullets[i].pos += s.bullets[i].vel + for j := 0; j < len(s.asteroids); j += 1 { + if rl.CheckCollisionCircleRec(s.bullets[i].pos, BULLET_RADIUS, s.asteroids[j].rect) { + append(&s.bullet_pop_idxs, i) + append(&s.asteroid_pop_idxs, j) + } + } + } + + bpi_len := len(s.bullet_pop_idxs) + for i := 0; i < bpi_len; i += 1 { + swap_n_pop(&s.bullets, s.bullet_pop_idxs[i]) + } + if bpi_len > 0 { + clear(&s.bullet_pop_idxs) + } + api_len := len(s.asteroid_pop_idxs) + for i := 0; i < api_len; i += 1 { + swap_n_pop(&s.asteroids, s.asteroid_pop_idxs[i]) + } + if bpi_len > 0 { + clear(&s.asteroid_pop_idxs) + } + + if ship_collision { + // Randomize everything + s.player_state = Death { + + } + } else { + if player.pos.x + SHIP_W < 0 { player.pos.x = BW + SHIP_W} + if player.pos.x - SHIP_W > BW { player.pos.x = -SHIP_W} + if player.pos.y + SHIP_H < 0 { player.pos.y = BH + SHIP_H} + if player.pos.y - SHIP_H > BH { player.pos.y = -SHIP_H} + } + + case Death: + } +} + +draw2d :: proc(s: ^GameState) { + switch &player in s.player_state { + case Player: + // Draw ship + rl.DrawLineEx(player.points[0], player.points[1], 1, rl.WHITE) + rl.DrawLineEx(player.points[1], player.points[2], 1, rl.WHITE) + rl.DrawLineEx(player.points[2], player.points[3], 1, rl.WHITE) + rl.DrawLineEx(player.points[3], player.points[0], 1, rl.WHITE) + case Death: + } + for i := 0; i < len(s.asteroids); i += 1 { + rl.DrawRectangleLinesEx(s.asteroids[i].rect, 1, rl.WHITE) + } + + for i := 0; i < len(s.bullets); i += 1 { + rl.DrawCircleLinesV(s.bullets[i].pos, BULLET_RADIUS, rl.WHITE) + } +} + main :: proc() { rl.SetTraceLogLevel(.ERROR) rl.InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Asteroids") + start_pos := Vec2{BW / 2 - SHIP_W / 2, BH / 2 - SHIP_H / 2} s := GameState{ rl.GetFrameTime(), - {0,0}, - -math.PI / 2, - {0,0}, + Player { + start_pos, + [4]Vec2{{0,0},{0,0},{0,0},{0,0}}, + -math.PI / 2, + {0,0} + }, make([dynamic]Bullet, 0, 64), make([dynamic]Asteroid, 0, 64), + make([dynamic]int, 0, 64), + make([dynamic]int, 0, 64), } - s.ship_pos = {600, 350} - - bw := f32(SCREEN_WIDTH) - bh := f32(SCREEN_HEIGHT) - - bullet_pop_idxs := make([dynamic]int, 0, 64) - asteroid_pop_idxs := make([dynamic]int, 0, 64) get_rand_angle :: proc(min: i32, max: i32) -> f32 { return f32(rl.GetRandomValue(min, max)) * rl.DEG2RAD @@ -84,7 +210,7 @@ main :: proc() { for i := 0; i < 5; i += 1 { rand_angle := get_rand_angle(-50, 50) - rand_pos := Vec2{ f32(rl.GetRandomValue(0, i32(bw))), -50 } + rand_pos := Vec2{ f32(rl.GetRandomValue(0, i32(BW))), -50 } rand_size := f32(rl.GetRandomValue(25, 60)) rand_vy := f32(rl.GetRandomValue(1, 2)) * 0.5 asteroid := Asteroid { @@ -98,82 +224,14 @@ main :: proc() { for !rl.WindowShouldClose() { s.dt = rl.GetFrameTime() - v1, v2, v3, v4 := get_ship_shape(s) + player_input(&s) - if rl.IsKeyDown(.D) { - s.ship_angle += ANGULAR_SPEED * s.dt - } - if rl.IsKeyDown(.A) { - s.ship_angle -= ANGULAR_SPEED * s.dt - } - if rl.IsKeyDown(.W) { - s.ship_vel.x += math.cos(s.ship_angle) * THRUST_SPEED * s.dt - s.ship_vel.y += math.sin(s.ship_angle) * THRUST_SPEED * s.dt - } - if rl.IsKeyPressed(.SPACE) { - b_vel := Vec2{ math.cos(s.ship_angle) , math.sin(s.ship_angle) } * BULLET_SPEED - append(&s.bullets, Bullet{v1,b_vel}) - } - - s.ship_pos += s.ship_vel * (5000 * s.dt) - - for i := 0; i < len(s.asteroids); i += 1 { - s.asteroids[i].rect.x += s.asteroids[i].vel.x - s.asteroids[i].rect.y += s.asteroids[i].vel.y - } - - for i := 0; i < len(s.bullets); i += 1 { - if ( s.bullets[i].pos.x < 0 || s.bullets[i].pos.x > bw - || s.bullets[i].pos.y < 0 || s.bullets[i].pos.y > bh) { - append(&bullet_pop_idxs, i) - } - s.bullets[i].pos += s.bullets[i].vel - for j := 0; j < len(s.asteroids); j += 1 { - if rl.CheckCollisionCircleRec(s.bullets[i].pos, BULLET_RADIUS, s.asteroids[j].rect) { - fmt.println(s.bullets[i], s.asteroids[j]) - append(&bullet_pop_idxs, i) - append(&asteroid_pop_idxs, j) - } - } - } - - bpi_len := len(bullet_pop_idxs) - for i := 0; i < bpi_len; i += 1 { - swap_n_pop(&s.bullets, bullet_pop_idxs[i]) - } - if bpi_len > 0 { - clear(&bullet_pop_idxs) - } - api_len := len(asteroid_pop_idxs) - for i := 0; i < api_len; i += 1 { - swap_n_pop(&s.asteroids, asteroid_pop_idxs[i]) - } - if bpi_len > 0 { - clear(&asteroid_pop_idxs) - } - - - if s.ship_pos.x + SHIP_W < 0 { s.ship_pos.x = bw + SHIP_W} - if s.ship_pos.x - SHIP_W > bw { s.ship_pos.x = -SHIP_W} - if s.ship_pos.y + SHIP_H < 0 { s.ship_pos.y = bh + SHIP_H} - if s.ship_pos.y - SHIP_H > bh { s.ship_pos.y = -SHIP_H} + update(&s) rl.BeginDrawing() rl.ClearBackground(rl.BLACK) - // Draw ship - rl.DrawLineEx(v1, v2, 1, rl.WHITE) - rl.DrawLineEx(v2, v3, 1, rl.WHITE) - rl.DrawLineEx(v3, v4, 1, rl.WHITE) - rl.DrawLineEx(v4, v1, 1, rl.WHITE) - - for i := 0; i < len(s.asteroids); i += 1 { - rl.DrawRectangleLinesEx(s.asteroids[i].rect, 1, rl.WHITE) - } - - for i := 0; i < len(s.bullets); i += 1 { - rl.DrawCircleLinesV(s.bullets[i].pos, BULLET_RADIUS, rl.WHITE) - } + draw2d(&s) rl.EndDrawing() }