diff --git a/README.md b/README.md deleted file mode 100644 index c048214..0000000 --- a/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Space Invaders - -## About -This is a simple clone I wrote in a weekend using `odin-lang` and the available `raylib` bindings. - -# Software used -* `Aseprite` for pixel art -* `neovim` and the `ols` LSP -* `make` - -# Building & running -This should be buildable through the makefile on any platform (Windows, OSX & Linux) as long as you have the Odin compiler on hand. -If the makefile is causing you trouble the project can be directly ran with (which creates a binary file as well): - -```bash -odin run . -``` -or compiled to a binary with a custom output directory & speed optimizations (although they are not needed at all): -```bash -odin build . -out:space_invaders.exe -o:speed -``` - -# Gallery -![Space Invaders Start Game Screen](https://git.stefanstefanov.eu/bersk/odin-space-invaders/raw/commit/fd0cb31206a526aefe8be0cbf391e7f446c86afe/repo/start_game_screenshot.png) - -![In Game Screen](https://git.stefanstefanov.eu/bersk/odin-space-invaders/raw/commit/fd0cb31206a526aefe8be0cbf391e7f446c86afe/repo/in_game_screenshot.png) \ No newline at end of file diff --git a/game.odin b/game.odin index a2b2cef..b3ac427 100644 --- a/game.odin +++ b/game.odin @@ -54,8 +54,8 @@ setup_game :: proc(state: ^GameState) { using state player_pos = glm.vec2 { - f32(screen_width) / 2, - f32(screen_height) - PLAYER_RECT.x, + f32(screen_width) / (2 * camera.zoom), + f32(screen_height) / camera.zoom - PLAYER_RECT.x, } player_score = 0 player_health = 3 @@ -101,8 +101,14 @@ update_game :: proc(state: ^GameState) { // update bullet frame idx if frame_counter % 10 == 0 {BULLET_FRAME_ANIM = (BULLET_FRAME_ANIM + 1) % len(BULLET_TO)} + // Press enter to change to ENDING screen + if (rl.IsKeyPressed(rl.KeyboardKey.ENTER)) { + state.screen = .ENDING + log.info("Updated screen enum", state.screen) + } + // Press space to change to fire - if (rl.IsKeyPressed(rl.KeyboardKey.SPACE) || rl.IsKeyPressed(rl.KeyboardKey.ENTER)) { + if (rl.IsKeyPressed(rl.KeyboardKey.SPACE)) { fire_bullet(&bullets, &bullet_index) } @@ -141,7 +147,6 @@ update_game :: proc(state: ^GameState) { if game_over { screen = .ENDING - log.info("Game over!", game_end) return } } @@ -172,7 +177,7 @@ update_game :: proc(state: ^GameState) { corner_alien_pos := shuffle_dir == .RIGHT ? aliens[ALIENS_PER_ROW - 1].position : aliens[0].position if corner_alien_pos.x <= SPRITE_CELL || - corner_alien_pos.x >= f32(screen_width) - SPRITE_CELL || + corner_alien_pos.x >= f32(screen_width / GLOBAL_SPRITE_SCALE) - SPRITE_CELL || shuffle_dir == .DOWN { switch shuffle_dir { case .RIGHT: @@ -368,7 +373,7 @@ draw_game :: proc(state: ^GameState) { texture_atlas, {HEART_TO.x, HEART_TO.y, SPRITE_CELL, SPRITE_CELL}, { - f32(screen_width) - f32(hi * SPRITE), + f32(screen_width / GLOBAL_SPRITE_SCALE) - f32(hi * SPRITE_CELL * GLOBAL_SPRITE_SCALE), 0, f32(PLAYER_RECT.x), f32(PLAYER_RECT.y), diff --git a/main.odin b/main.odin index 291bab2..6c300cf 100644 --- a/main.odin +++ b/main.odin @@ -6,6 +6,9 @@ import glm "core:math/linalg/glsl" import rl "vendor:raylib" +// orignal resolution of space invaders +// 256 x 224 px + TEXTURE_ATLAS_PATH :: "./assets/texture_atlas.png" DEBUG_MODE :: false @@ -16,35 +19,55 @@ GameEndType :: enum { AliensReachedPlayer, } +GameState :: struct { + // window + target_fps: c.int, + title: cstring, + screen_width: c.int, + screen_height: c.int, + // frame stats + frame_counter: int, + current_frame_time: f64, + last_frame_time: f64, + delta_time: f64, + // game vars + screen: GameScreen, + previous_screen: GameScreen, + last_frame_screen: GameScreen, + game_end: GameEndType, + reset_game: bool, + aliens: #soa[ALIENS]Alien, + bullets: #soa[MAX_BULLETS]Bullet, + bullet_index: int, + player_last_time_fired: f64, + player_pos: glm.vec2, + player_health: c.int, + player_score: c.int, + player_high_score: c.int, + shuffle_dir: ShuffleDirection, + last_shuffle_dir: ShuffleDirection, +} state: GameState -ratio: f32 texture_atlas_image: rl.Image texture_atlas: rl.Texture2D -window_width: i32 -window_height: i32 +camera := rl.Camera2D { + zoom = 2, +} -// orignal resolution of space invaders: 256 x 224 px setup :: proc(state: ^GameState) { using state target_fps = 60 - - // monitor := rl.GetCurrentMonitor() - window_width = rl.GetScreenWidth() - window_height = rl.GetScreenHeight() + screen_width = 800 * 2 + screen_height = 600 * 2 + title = "Space Invaders (raylib+odin-lang edition)" current_frame_time = rl.GetTime() previous_screen = .TITLE screen = .TITLE rl.SetTargetFPS(target_fps) - - if !ODIN_DEBUG { - rl.SetExitKey(nil) - } else { - log.info("Built with Odin compiler version: ", ODIN_VERSION) - } } update :: proc(state: ^GameState) { @@ -59,31 +82,12 @@ update :: proc(state: ^GameState) { update_screen(state) } -target: rl.RenderTexture2D draw :: proc(state: ^GameState) { - rl.BeginTextureMode(target) - { - draw_screen(state) - } - rl.EndTextureMode() - rl.BeginDrawing() - { - rl.ClearBackground(rl.RAYWHITE) - rl.DrawTexturePro( - target.texture, - {0, 0, f32(target.texture.width), f32(-target.texture.height)}, - { - (f32(window_width) - (f32(target.texture.width) * ratio)) / 2, - 0, - f32(target.texture.width) * ratio, - f32(target.texture.height) * ratio, - }, - {0, 0}, - 0, - rl.WHITE, - ) - } + rl.ClearBackground(rl.RAYWHITE) + rl.BeginMode2D(camera) + draw_screen(state) + rl.EndMode2D() rl.EndDrawing() } @@ -92,21 +96,16 @@ main :: proc() { log.info(state.screen) - - rl.InitWindow(1200, 720, "title") - defer rl.CloseWindow() - rl.RestoreWindow() - rl.SetWindowState({.WINDOW_RESIZABLE, .WINDOW_MAXIMIZED}) - setup(&state) - state.screen_width = 720 - state.screen_height = 520 - rl.SetWindowMinSize(state.screen_width, state.screen_height) + rl.InitWindow(state.screen_width, state.screen_height, state.title) + defer rl.CloseWindow() - target = rl.LoadRenderTexture(state.screen_width, state.screen_height) - defer rl.UnloadRenderTexture(target) - ratio = f32(window_height) / f32(target.texture.height) + if !ODIN_DEBUG { + rl.SetExitKey(nil) + } else { + log.info("Built with Odin compiler version: ", ODIN_VERSION) + } texture_atlas_image = rl.LoadImage(TEXTURE_ATLAS_PATH) texture_atlas = rl.LoadTextureFromImage(texture_atlas_image) @@ -114,11 +113,6 @@ main :: proc() { log.info("Loaded images") for !rl.WindowShouldClose() { - if rl.IsWindowResized() { - window_width = rl.GetScreenWidth() - window_height = rl.GetScreenHeight() - ratio = f32(window_height) / f32(target.texture.height) - } update(&state) draw(&state) } diff --git a/repo/in_game_screenshot.png b/repo/in_game_screenshot.png deleted file mode 100644 index 5444f6d..0000000 Binary files a/repo/in_game_screenshot.png and /dev/null differ diff --git a/repo/start_game_screenshot.png b/repo/start_game_screenshot.png deleted file mode 100644 index 9cfa28a..0000000 Binary files a/repo/start_game_screenshot.png and /dev/null differ diff --git a/screens.odin b/screens.odin index 2c5f5ec..f7c9634 100644 --- a/screens.odin +++ b/screens.odin @@ -9,6 +9,7 @@ GameScreen :: enum { ENDING, } + update_screen :: proc(state: ^GameState) { using state @@ -50,22 +51,27 @@ draw_screen :: proc(state: ^GameState) { switch state.screen { case .TITLE: { - rl.DrawRectangle(0, 0, state.screen_width, state.screen_height, rl.BLACK) + rl.DrawRectangle(0, 0, state.screen_width, state.screen_height, rl.WHITE) rl.DrawTexturePro( texture_atlas, {LOGO_TO[0].x, LOGO_TO[0].y, LOGO_TO[1].x, LOGO_TO[1].y}, - {0, 0, LOGO_TO[1].x * 4, LOGO_TO[1].y * 4}, - {f32(-screen_width/4), f32(-screen_height/3)}, + { + f32(screen_width / GLOBAL_SPRITE_SCALE) / 2, + f32(screen_height / GLOBAL_SPRITE_SCALE) / 2, + LOGO_TO[1].x * 4, + LOGO_TO[1].y * 4, + }, + {LOGO_TO[1].x * 2, LOGO_TO[1].y * 2}, 0, rl.GREEN, ) - text: cstring = "PRESS ENTER TO START GAME" - size := rl.MeasureText(text, 20) - rl.DrawText( + text : cstring = "PRESS ENTER TO START GAME" + size := rl.MeasureText(text, 20) + rl.DrawText( text, - (screen_width / 2) - (size / 2), - screen_height - 20, + (screen_width/4) - (size/2), + (screen_height / 2)- 20, 20, rl.DARKGREEN, ) diff --git a/sprites.odin b/sprites.odin index 9c05760..95707f3 100644 --- a/sprites.odin +++ b/sprites.odin @@ -9,23 +9,22 @@ LOGO_TO :: [2]glm.vec2{{0, 0}, {128-(SPRITE_CELL * 2), SPRITE_CELL * 2}} GLOBAL_SPRITE_SCALE :: 2 SPRITE_CELL :: 16 -SPRITE :: SPRITE_CELL * GLOBAL_SPRITE_SCALE ALIEN_ROWS :: 5 ALIENS_PER_ROW :: 11 ALIENS :: ALIEN_ROWS * ALIENS_PER_ROW ALIEN_SIDE_STEP :: 20 * GLOBAL_SPRITE_SCALE -ALIEN_RECT :: glm.vec2{SPRITE, SPRITE} +ALIEN_RECT :: glm.vec2{SPRITE_CELL * GLOBAL_SPRITE_SCALE, SPRITE_CELL * GLOBAL_SPRITE_SCALE} // note: this multiplication by GLOBAL_SPRITE_SCALE is a hack, but it's a weekend project // so i won't bother refactoring it MAX_BULLETS :: 100 BULLET_SPEED :: 240 -BULLET_RECT :: glm.vec2{SPRITE, SPRITE} +BULLET_RECT :: glm.vec2{SPRITE_CELL * GLOBAL_SPRITE_SCALE, SPRITE_CELL * GLOBAL_SPRITE_SCALE} MAX_PLAYER_HEALTH :: 3 PLAYER_SPEED :: 120 -PLAYER_RECT :: glm.vec2{SPRITE, SPRITE} +PLAYER_RECT :: glm.vec2{SPRITE_CELL * GLOBAL_SPRITE_SCALE, SPRITE_CELL * GLOBAL_SPRITE_SCALE} // texture offset for ship SHIP_TO :: glm.vec2{0, 112} diff --git a/state.odin b/state.odin deleted file mode 100644 index 67f1673..0000000 --- a/state.odin +++ /dev/null @@ -1,33 +0,0 @@ -package space_invaders - -import "core:c" -import glm "core:math/linalg/glsl" - -GameState :: struct { - // window - target_fps: c.int, - title: cstring, - screen_width: c.int, - screen_height: c.int, - // frame stats - frame_counter: int, - current_frame_time: f64, - last_frame_time: f64, - delta_time: f64, - // game vars - screen: GameScreen, - previous_screen: GameScreen, - last_frame_screen: GameScreen, - game_end: GameEndType, - reset_game: bool, - aliens: #soa[ALIENS]Alien, - bullets: #soa[MAX_BULLETS]Bullet, - bullet_index: int, - player_last_time_fired: f64, - player_pos: glm.vec2, - player_health: c.int, - player_score: c.int, - player_high_score: c.int, - shuffle_dir: ShuffleDirection, - last_shuffle_dir: ShuffleDirection, -}