package main import ecs "deps/secs" import rl "vendor:raylib" import "core:fmt" MAX_BUILDINGS :: 100 screenWidth :: 800 screenHeight :: 450 GameStateStartup :: struct {} GameStateStartScreen :: struct {} GameStateLoop :: struct {} GameStateExitRequested :: struct {} GameState :: union { GameStateStartup, GameStateStartScreen, GameStateLoop, GameStateExitRequested, } generate_buildings :: proc( ) -> ( buildings: [MAX_BUILDINGS]rl.Rectangle, buildColors: [MAX_BUILDINGS]rl.Color, ) { spacing: i32 = 0 for i in 0 ..< MAX_BUILDINGS { buildings[i].width = f32(rl.GetRandomValue(50, 200)) buildings[i].height = f32(rl.GetRandomValue(100, 800)) buildings[i].y = screenHeight - 130.0 - buildings[i].height buildings[i].x = f32(-6000.0 + spacing) spacing += i32(buildings[i].width) buildColors[i] = rl.Color( { u8(rl.GetRandomValue(200, 240)), u8(rl.GetRandomValue(200, 240)), u8(rl.GetRandomValue(200, 240)), 255, }, ) } return buildings, buildColors } Drawable :: union { rl.Rectangle, } handle_input :: proc(world: ^ecs.World) { ecs.Work(world, proc(e: ecs.Entity, p: ^Position, d: ^Player) { if rl.IsKeyDown(rl.KeyboardKey.A) do p.x -= 2 if rl.IsKeyDown(rl.KeyboardKey.D) do p.x += 2 if rl.IsKeyDown(rl.KeyboardKey.W) do p.y -= 2 if rl.IsKeyDown(rl.KeyboardKey.S) do p.y += 2 }) } Player :: struct {} Position :: struct { x: f32, y: f32, } CameraTarget :: struct {} camera: rl.Camera2D main :: proc() { rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera") exitWindow := false // Flag to set window to exit world := ecs.NewWorld() e := ecs.CreateEntity(world) ecs.AddComponents( world, e, Player{}, Position{400, 280}, Drawable(rl.Rectangle{0, 0, 40, 40}), CameraTarget{}, ) buildings, buildColors := generate_buildings() game_state: GameState = GameStateStartup{} last_state: GameState = nil camera.offset = rl.Vector2({screenWidth / 2.0, screenHeight / 2.0}) camera.rotation = 0.0 camera.zoom = 1.0 rl.SetTargetFPS(60) for !exitWindow { switch s in game_state { case GameStateStartup: game_state = GameStateStartScreen{} case GameStateStartScreen: game_state = GameStateLoop{} case GameStateLoop: handle_input(world) ecs.Work(world, proc(done: ^bool, e: ecs.Entity, p: ^Position, d: ^CameraTarget) { camera.target = rl.Vector2({p.x + 20, p.y + 20}) done^ = true }) camera.zoom += f32(rl.GetMouseWheelMove() * 0.05) if camera.zoom > 3.0 do camera.zoom = 3.0 else if camera.zoom < 0.1 do camera.zoom = 0.1 if rl.IsKeyPressed(rl.KeyboardKey.R) { camera.zoom = 1.0 camera.rotation = 0.0 } if (rl.WindowShouldClose() || rl.IsKeyPressed(rl.KeyboardKey.ESCAPE)) do game_state = GameStateExitRequested{} case GameStateExitRequested: // A request for close window has been issued, we can save data before closing // or just show a message asking for confirmation if (rl.IsKeyPressed(rl.KeyboardKey.Y) || rl.IsKeyPressed(rl.KeyboardKey.Z)) do exitWindow = true else if (rl.IsKeyPressed(rl.KeyboardKey.N)) do game_state = last_state } rl.BeginDrawing() rl.ClearBackground(rl.RAYWHITE) rl.BeginMode2D(camera) rl.DrawRectangle(-6000, 320, 13000, 8000, rl.DARKGRAY) for i in 0 ..< MAX_BUILDINGS do rl.DrawRectangleRec(buildings[i], buildColors[i]) ecs.Work(world, proc(e: ecs.Entity, p: ^Position, d: ^Drawable) { switch d in d { case rl.Rectangle: rl.DrawRectangleRec(rl.Rectangle{d.x + p.x, d.y + p.y, d.width, d.height}, rl.RED) } }) rl.DrawLine( i32(camera.target.x), -screenHeight * 10, i32(camera.target.x), screenHeight * 10, rl.GREEN, ) rl.DrawLine( -screenWidth * 10, i32(camera.target.y), screenWidth * 10, i32(camera.target.y), rl.GREEN, ) rl.EndMode2D() rl.DrawText("SCREEN AREA", 640, 10, 20, rl.RED) rl.DrawRectangle(0, 0, screenWidth, 5, rl.RED) rl.DrawRectangle(0, 5, 5, screenHeight - 10, rl.RED) rl.DrawRectangle(screenWidth - 5, 5, 5, screenHeight - 10, rl.RED) rl.DrawRectangle(0, screenHeight - 5, screenWidth, 5, rl.RED) rl.DrawRectangle(10, 10, 250, 80, rl.Fade(rl.SKYBLUE, 0.5)) rl.DrawRectangleLines(10, 10, 250, 80, rl.BLUE) rl.DrawText("Free 2d camera controls:", 20, 20, 10, rl.BLACK) rl.DrawText("- WASD to move", 40, 40, 10, rl.DARKGRAY) rl.DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, rl.DARKGRAY) #partial switch _ in game_state { case GameStateExitRequested: rl.DrawRectangle(0, 100, screenWidth, 200, rl.BLACK) rl.DrawText("Are you sure you want to exit program? [Y/N]", 40, 180, 30, rl.WHITE) } rl.EndDrawing() } rl.CloseWindow() }