diff --git a/constants.odin b/constants.odin index 4d2f023..a780aad 100644 --- a/constants.odin +++ b/constants.odin @@ -11,3 +11,5 @@ MAP_HEIGHT :: 60 MAX_ENTITIES :: 256 INVALID_ENTITY :: Entity(0) +MOVE_SPEED :: 4.0 + diff --git a/entity.odin b/entity.odin index 2e6c66c..2f4f741 100644 --- a/entity.odin +++ b/entity.odin @@ -1,15 +1,24 @@ package main +import "core:math" import rl "vendor:raylib" Entity :: distinct u32 Entity_World :: struct { - count: int, - active: [MAX_ENTITIES]bool, - position: [MAX_ENTITIES]Tile_Coord, - color: [MAX_ENTITIES]rl.Color, - is_colonist: [MAX_ENTITIES]bool, + count: int, + active: [MAX_ENTITIES]bool, + position: [MAX_ENTITIES]Tile_Coord, + color: [MAX_ENTITIES]rl.Color, + is_colonist: [MAX_ENTITIES]bool, + move_state: [MAX_ENTITIES]Move_State, + move_target: [MAX_ENTITIES]Tile_Coord, + visual_position: [MAX_ENTITIES]rl.Vector2, +} + +Move_State :: enum { + Idle, + Moving, } entity_world_init :: proc() -> Entity_World { @@ -24,6 +33,8 @@ entity_spawn_colonist :: proc(ew: ^Entity_World, pos: Tile_Coord) -> Entity { ew.color[i] = {80, 140, 220, 225} ew.is_colonist[i] = true ew.count += 1 + ew.visual_position[i] = tile_center_world(pos) + ew.move_state[i] = .Idle return Entity(u32(i + 1)) } } @@ -41,10 +52,8 @@ entity_draw :: proc(ew: ^Entity_World, camera: ^Camera2D) { continue } - pos := ew.position[i] - wx := f32(pos.x * TILE_SIZE) + f32(TILE_SIZE) * 0.5 - wy := f32(pos.y * TILE_SIZE) + f32(TILE_SIZE) * 0.5 - sx, sy := world_to_screen(camera, wx, wy) + vp := ew.visual_position[i] + sx, sy := world_to_screen(camera, vp.x, vp.y) radius := f32(TILE_SIZE) * 0.3 * camera.zoom rl.DrawCircle(i32(sx), i32(sy), radius, ew.color[i]) @@ -52,3 +61,69 @@ entity_draw :: proc(ew: ^Entity_World, camera: ^Camera2D) { } } +tile_center_world :: proc(t: Tile_Coord) -> rl.Vector2 { + return rl.Vector2 { + f32(t.x * TILE_SIZE) + f32(TILE_SIZE) * 0.5, + f32(t.y * TILE_SIZE) + f32(TILE_SIZE) * 0.5, + } +} + +entity_set_move_target :: proc(ew: ^Entity_World, e: Entity, target: Tile_Coord) -> bool { + i := entity_index(e) + if i < 0 || !ew.active[i] {return false} + + if ew.position[i] == target { + ew.move_state[i] = .Idle + return true + } + + ew.move_target[i] = target + ew.move_state[i] = .Moving + return true +} + +entity_update_movement :: proc(ew: ^Entity_World, dt: f32) { + speed := f32(TILE_SIZE) * MOVE_SPEED + + for i in 0 ..< MAX_ENTITIES { + if !ew.active[i] || ew.move_state[i] != .Moving { + continue + } + + pos := ew.position[i] + target := ew.move_target[i] + if pos == target { + ew.move_state[i] = .Idle + continue + } + + next := pos + if pos.x != target.x { + next.x += pos.x < target.x ? 1 : -1 + } else if pos.y != target.y { + next.y += pos.y < target.y ? 1 : -1 + } + + goal := tile_center_world(next) + vp := ew.visual_position[i] + + dx := goal.x - vp.x + dy := goal.y - vp.y + dist := math.sqrt(dx * dx + dy * dy) + + if dist < 1.0 { + ew.position[i] = next + ew.visual_position[i] = goal + } else { + step := speed * dt + if step >= dist { + ew.visual_position[i] = goal + ew.position[i] = next + } else { + ew.visual_position[i].x += dx / dist * step + ew.visual_position[i].y += dy / dist * step + } + } + } +} + diff --git a/game.odin b/game.odin index 529bb8a..be8f502 100644 --- a/game.odin +++ b/game.odin @@ -4,12 +4,13 @@ import "core:math" import rl "vendor:raylib" Game :: struct { - running: bool, - time: f32, // total time elapsed - tilemap: Tilemap, - camera: Camera2D, - selection: Selection, - world: World, + running: bool, + time: f32, // total time elapsed + tilemap: Tilemap, + camera: Camera2D, + selection: Selection, + world: World, + player_colonist: Entity, } Camera2D :: struct { @@ -37,7 +38,7 @@ game_init :: proc() -> Game { g.camera = camera_init() g.world = world_init() center := Tile_Coord{MAP_WIDTH / 2, MAP_HEIGHT / 2} - entity_spawn_colonist(&g.world.entities, center) + g.player_colonist = entity_spawn_colonist(&g.world.entities, center) return g } @@ -102,7 +103,14 @@ game_handle_input :: proc(g: ^Game) { } if rl.IsMouseButtonPressed(.RIGHT) { - g.selection.active = false + mx, my := f32(rl.GetMouseX()), f32(rl.GetMouseY()) + wx, wy := screen_to_world(&g.camera, mx, my) + tx, ty := world_to_tile(wx, wy) + if tile_in_bounds(&g.tilemap, tx, ty) { + entity_set_move_target(&g.world.entities, g.player_colonist, {tx, ty}) + g.selection.active = true + g.selection.tile = {tx, ty} + } } } game_update :: proc(g: ^Game, dt: f32) { @@ -114,6 +122,7 @@ game_update :: proc(g: ^Game, dt: f32) { camera_update(&g.camera, dt) game_handle_input(g) + world_update(&g.world, dt) } game_draw :: proc(g: ^Game) { diff --git a/world.odin b/world.odin index df54cbd..9f41443 100644 --- a/world.odin +++ b/world.odin @@ -14,3 +14,7 @@ world_draw :: proc(w: ^World, camera: ^Camera2D) { entity_draw(&w.entities, camera) } +world_update :: proc(world: ^World, dt: f32) { + entity_update_movement(&world.entities, dt) +} +