From 90cca442acb2f3edcfddf7837ca11a384e2adca6 Mon Sep 17 00:00:00 2001 From: codegirl-007 Date: Wed, 1 Jul 2026 21:01:52 -0700 Subject: [PATCH] create a 2d camera + fix small bug --- constants.odin | 4 ++-- game.odin | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- main.odin | 2 +- tilemap.odin | 21 ++++++++++++-------- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/constants.odin b/constants.odin index 4647413..c9f73ed 100644 --- a/constants.odin +++ b/constants.odin @@ -5,6 +5,6 @@ WINDOW_HEIGHT :: 720 WINDOW_TITLE :: "Game 1" TILE_SIZE :: 32 -MAP_WIDTH :: 40 -MAP_HEIGHT :: 25 +MAP_WIDTH :: 80 +MAP_HEIGHT :: 60 diff --git a/game.odin b/game.odin index f50914b..4e0dd18 100644 --- a/game.odin +++ b/game.odin @@ -1,35 +1,87 @@ package main +import "core:math" import rl "vendor:raylib" Game :: struct { running: bool, time: f32, // total time elapsed tilemap: Tilemap, + camera: Camera2D, } +Camera2D :: struct { + offset: rl.Vector2, + zoom: f32, +} + +CAMERA_PAN_SPEED :: 400 + game_init :: proc() -> Game { g := Game { running = true, time = 0, } g.tilemap = tilemap_init() + g.camera = camera_init() return g } +camera_init :: proc() -> Camera2D { + camera_x := f32(MAP_WIDTH * TILE_SIZE) * 0.5 + camera_y := f32(MAP_HEIGHT * TILE_SIZE) * 0.5 + return Camera2D{offset = {camera_x, camera_y}, zoom = 1.0} +} + +camera_update :: proc(camera: ^Camera2D, dt: f32) { + pan := rl.Vector2{0, 0} + if rl.IsKeyDown(.W) || rl.IsKeyDown(.UP) {pan.y -= 1} + if rl.IsKeyDown(.S) || rl.IsKeyDown(.DOWN) {pan.y += 1} + if rl.IsKeyDown(.A) || rl.IsKeyDown(.LEFT) {pan.x -= 1} + if rl.IsKeyDown(.D) || rl.IsKeyDown(.RIGHT) {pan.x += 1} + + if pan.x != 0 || pan.y != 0 { + len := math.sqrt(pan.x * pan.x + pan.y * pan.y) + pan.x /= len + pan.y /= len + camera.offset.x += pan.x * CAMERA_PAN_SPEED * dt / camera.zoom + camera.offset.y += pan.y * CAMERA_PAN_SPEED * dt / camera.zoom + } + + wheel := rl.GetMouseWheelMove() + if wheel != 0 { + camera.zoom = math.clamp(camera.zoom + wheel * 0.15, 0.35, 3.0) + } +} + +world_to_screen :: proc(camera: ^Camera2D, wx, wy: f32) -> (f32, f32) { + screen_x := (wx - camera.offset.x) * camera.zoom + f32(WINDOW_WIDTH) * 0.5 + screen_y := (wy - camera.offset.y) * camera.zoom + f32(WINDOW_HEIGHT) * 0.5 + return screen_x, screen_y +} + +screen_to_world :: proc(camera: ^Camera2D, sx, sy: f32) -> (f32, f32) { + world_x := (sx - f32(WINDOW_WIDTH) * 0.5) / camera.zoom + camera.offset.x + world_y := (sy - f32(WINDOW_HEIGHT) * 0.5) / camera.zoom + camera.offset.y + return world_x, world_y +} + game_update :: proc(g: ^Game, dt: f32) { g.time += dt if rl.IsKeyPressed(.ESCAPE) { g.running = false } + + camera_update(&g.camera, dt) } game_draw :: proc(g: ^Game) { - tilemap_draw(&g.tilemap) + tilemap_draw(&g.tilemap, &g.camera) fps := rl.GetFPS() rl.DrawText(rl.TextFormat("FPS: %i", fps), 10, 36, 20, rl.GREEN) rl.DrawText(rl.TextFormat("Time: %.1fs", g.time), 10, 62, 20, rl.GRAY) + rl.DrawText(rl.TextFormat("Zoom: %2f", g.camera.zoom), 10, 88, 20, rl.GRAY) } game_shutdown :: proc(g: ^Game) { diff --git a/main.odin b/main.odin index 2844992..7464192 100644 --- a/main.odin +++ b/main.odin @@ -11,7 +11,7 @@ main :: proc() { game := game_init() defer game_shutdown(&game) - for !rl.WindowShouldClose() { + for game.running && !rl.WindowShouldClose() { rl.BeginDrawing() defer rl.EndDrawing() diff --git a/tilemap.odin b/tilemap.odin index f50da49..6698e77 100644 --- a/tilemap.odin +++ b/tilemap.odin @@ -39,18 +39,23 @@ tile_color :: proc(type_id: u8) -> rl.Color { } } -tilemap_draw :: proc(tilemap: ^Tilemap) { +tilemap_draw :: proc(tilemap: ^Tilemap, camera: ^Camera2D) { + tile_px := f32(TILE_SIZE) * camera.zoom + for y in 0 ..< tilemap.height { for x in 0 ..< tilemap.width { + wx := f32(x * TILE_SIZE) + wy := f32(y * TILE_SIZE) + sx, sy := world_to_screen(camera, wx, wy) + + if sx + tile_px < 0 || sy + tile_px < 0 {continue} + if sx > f32(WINDOW_WIDTH) || sy > f32(WINDOW_HEIGHT) {continue} + index := tile_index(tilemap, x, y) - type_id := tilemap.tiles[index] - color := tile_color(type_id) + color := tile_color(tilemap.tiles[index]) - px := i32(x * TILE_SIZE) - py := i32(y * TILE_SIZE) - - rl.DrawRectangle(px, py, TILE_SIZE, TILE_SIZE, color) - rl.DrawRectangleLines(px, py, TILE_SIZE, TILE_SIZE, {40, 50, 38, 255}) + rl.DrawRectangle(i32(sx), i32(sy), i32(tile_px), i32(tile_px), color) + rl.DrawRectangleLines(i32(sx), i32(sy), i32(tile_px), i32(tile_px), {40, 50, 38, 255}) } } }