From e1903a03314c8ac1d7a7c7e7e78a13c5de3b8438 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Wed, 19 Apr 2023 10:23:33 +0200 Subject: [PATCH] Core RTS: Actor movement --- build/rtsgame/array.core | 5 ++ build/rtsgame/main.core | 39 +++++++------ build/rtsgame/map.core | 122 +++++++++++++++++++++++---------------- 3 files changed, 97 insertions(+), 69 deletions(-) diff --git a/build/rtsgame/array.core b/build/rtsgame/array.core index a9768ee..18e0ab8 100644 --- a/build/rtsgame/array.core +++ b/build/rtsgame/array.core @@ -26,6 +26,11 @@ Free :: (a: *Array($T)) Reset :: (a: *Array($T)) a.len = 0 +GetLast :: (a: *Array($T)): *T + Assert(a.len > 0) + result := a.data + a.len-1 + return result + Insert :: (a: *Array($T), item: T, index: int) if index == a.len Add(a, item) diff --git a/build/rtsgame/main.core b/build/rtsgame/main.core index 3b89baf..2d53273 100644 --- a/build/rtsgame/main.core +++ b/build/rtsgame/main.core @@ -101,27 +101,29 @@ main :: (): int InitWindow(WinX, WinY, "Testing") SetTargetFPS(60) - MAP_PathFindStart(MAP_CurrentMap.actors.data) - MAP_PathFindStep() - for !WindowShouldClose() WinX = GetScreenWidth() WinY = GetScreenHeight() MouseX = GetMouseX() MouseY = GetMouseY() MouseP = GetMousePosition() + map := &MAP_CurrentMap + if IsKeyPressed(KEY_F1) ;; Mode = 0 if IsKeyPressed(KEY_F2) ;; Mode = 1 if IsKeyPressed(KEY_F3) - MAP_Reset() + for i := 0, i < map.actors.len, i += 1 + it := map.actors.data + i + MAP_MoveTowardsTarget(it) if IsKeyDown(KEY_SPACE) - MAP_PathFindStep() + for i := 0, i < map.actors.len, i += 1 + it := map.actors.data + i + MAP_PathFindStep(it) BeginDrawing() ClearBackground(RAYWHITE) - map := &MAP_CurrentMap for x := 0, x < map.x, x += 1 for y := 0, y < map.y, y += 1 it := map.data + (x + y*map.x) @@ -141,23 +143,24 @@ main :: (): int DrawRectangleRec(r2, color) for i := 0, i < map.actors.len, i += 1 - it := map.actors.data + i - r := Rectangle{it.p.x->F32 * RectX, it.p.y->F32 * RectY, RectX, RectY} - target_r := Rectangle{it.target_p.x->F32 * RectX, it.target_p.y->F32 * RectY, RectX, RectY} + actor_it := map.actors.data + i + r := Rectangle{actor_it.p.x->F32 * RectX, actor_it.p.y->F32 * RectY, RectX, RectY} + target_r := Rectangle{actor_it.target_p.x->F32 * RectX, actor_it.target_p.y->F32 * RectY, RectX, RectY} DrawRectangleRec(r, YELLOW) DrawRectangleRec(target_r, PURPLE) - for i := 0, i < MAP_OpenPaths.len, i += 1 - it := MAP_OpenPaths.data + i - r := Rectangle{it.p.x->F32 * RectX, it.p.y->F32 * RectY, RectX, RectY} - DrawRectangleRec(r, ORANGE) + for path_i := 0, path_i < actor_it.open_paths.len, path_i += 1 + path_it := actor_it.open_paths.data + path_i + path_r := Rectangle{path_it.p.x->F32 * RectX, path_it.p.y->F32 * RectY, RectX, RectY} + DrawRectangleRec(path_r, ORANGE) + + if actor_it.state == MAP_PATH_REACHED + for path_i := 0, path_i < actor_it.history.len, path_i += 1 + path_it := actor_it.history.data + path_i + path_r := Rectangle{path_it.p.x->F32 * RectX, path_it.p.y->F32 * RectY, RectX, RectY} + DrawRectangleRec(path_r, BLACK) - if MAP_ReachedTarget - for i := 0, i < MAP_History.len, i += 1 - it := MAP_History.data + i - r := Rectangle{it.p.x->F32 * RectX, it.p.y->F32 * RectY, RectX, RectY} - DrawRectangleRec(r, BLACK) if Mode == 0 ;; DrawText("F1", 0, 0, 32, BLACK) if Mode == 1 ;; DrawText("F2", 0, 0, 32, BLACK) diff --git a/build/rtsgame/map.core b/build/rtsgame/map.core index 2a4b8ed..a548675 100644 --- a/build/rtsgame/map.core +++ b/build/rtsgame/map.core @@ -1,10 +1,11 @@ MAP_CurrentMap: MAP_Map -MAP_OpenPaths: Array(MAP_Path) -MAP_ClosePaths: Array(MAP_Path) -MAP_History: Array(MAP_Path) -MAP_TargetP: V2I -MAP_StartP: V2I -MAP_ReachedTarget := false + +MAP_PATH_SEARCHING :: 0 +MAP_PATH_REACHED :: 1 +MAP_PATH_UNREACHABLE :: 2 + +MAP_TILE_BLOCKER :: 1 +MAP_TILE_ACTOR_IS_STANDING :: 2 MAP_Tile :: int MAP_Map :: struct @@ -16,84 +17,103 @@ MAP_Map :: struct MAP_Actor :: struct p: V2I target_p: V2I + map: *MAP_Map + + state: int + open_paths: Array(MAP_Path) + close_paths: Array(MAP_Path) + history: Array(MAP_Path) MAP_Path :: struct value_to_sort_by: int // distance from target p: V2I came_from: V2I -MAP_Reset :: () - bytes := SizeOf(MAP_Tile) * MAP_CurrentMap.x->U64 * MAP_CurrentMap.y->U64 - - Reset(&MAP_CurrentMap.actors) - Reset(&MAP_OpenPaths) - Reset(&MAP_ClosePaths) - Reset(&MAP_History) - MAP_ReachedTarget = false - - memset(MAP_CurrentMap.data, 0, bytes) - Add(&MAP_CurrentMap.actors, {{4, 4}, {8, 8}}) - MAP_PathFindStart(MAP_CurrentMap.actors.data + 0) +MAP_AddActor :: (map: *MAP_Map, p: V2I): *MAP_Actor + Add(&map.actors, {p, p, map}) + Assert(map.data[p.x + p.y * map.x] == 0) + map.data[p.x + p.y * map.x] |= MAP_TILE_ACTOR_IS_STANDING + actor := GetLast(&MAP_CurrentMap.actors) + return actor MAP_Init :: () MAP_CurrentMap.x = 60 MAP_CurrentMap.y = 40 bytes := SizeOf(MAP_Tile) * MAP_CurrentMap.x->U64 * MAP_CurrentMap.y->U64 MAP_CurrentMap.data = malloc(bytes) - MAP_Reset() + memset(MAP_CurrentMap.data, 0, bytes) + actor := MAP_AddActor(&MAP_CurrentMap, {4,4}) + actor.target_p = V2I{8,8} -MAP_InsertOpenPath :: (p: V2I, target_p: V2I, came_from: V2I) - if p.x < 0 || p.x >= MAP_CurrentMap.x ;; return - if p.y < 0 || p.y >= MAP_CurrentMap.y ;; return - if MAP_CurrentMap.data[p.x + p.y * MAP_CurrentMap.x] == 1 ;; return +MAP_InsertOpenPath :: (s: *MAP_Actor, p: V2I, came_from: V2I, ignore_blocks: bool = false) + if p.x < 0 || p.x >= s.map.x ;; return + if p.y < 0 || p.y >= s.map.y ;; return + if ignore_blocks == false && s.map.data[p.x + p.y * s.map.x] != 0 ;; return - for i := 0, i < MAP_ClosePaths.len, i += 1 - it := MAP_ClosePaths.data + i + for i := 0, i < s.close_paths.len, i += 1 + it := s.close_paths.data + i if it.p.x == p.x && it.p.y == p.y ;; return - for i := 0, i < MAP_OpenPaths.len, i += 1 - it := MAP_OpenPaths.data + i + for i := 0, i < s.open_paths.len, i += 1 + it := s.open_paths.data + i if it.p.x == p.x && it.p.y == p.y ;; return - dx := target_p.x - p.x - dy := target_p.y - p.y + dx := s.target_p.x - p.x + dy := s.target_p.y - p.y d := dx*dx + dy*dy - InsertSortedDecreasing(&MAP_OpenPaths, {d, p, came_from}) + InsertSortedDecreasing(&s.open_paths, {d, p, came_from}) -MAP_PathFindStart :: (actor: *MAP_Actor) - Reset(&MAP_OpenPaths) - Reset(&MAP_ClosePaths) - MAP_TargetP = actor.target_p - MAP_StartP = actor.p - MAP_InsertOpenPath(actor.p, actor.target_p, actor.p) - -MAP_GetCloseP :: (p: V2I): *MAP_Path - for i := 0, i < MAP_ClosePaths.len, i += 1 - it := MAP_ClosePaths.data + i +MAP_GetCloseP :: (s: *MAP_Actor, p: V2I): *MAP_Path + for i := 0, i < s.close_paths.len, i += 1 + it := s.close_paths.data + i if it.p.x == p.x && it.p.y == p.y ;; return it Assert(false) return 0 -MAP_PathFindStep :: () - if MAP_ReachedTarget ;; return +MAP_MoveTowardsTarget :: (s: *MAP_Actor) + if s.history.len != 1 + tile := s.map.data + s.p.x + s.p.y * s.map.x + Assert((*tile & MAP_TILE_ACTOR_IS_STANDING) != 0) + Assert((*tile & MAP_TILE_BLOCKER) == 0) + *tile &= ~MAP_TILE_ACTOR_IS_STANDING + Assert((*tile & MAP_TILE_ACTOR_IS_STANDING) == 0) - it := Pop(&MAP_OpenPaths) - Add(&MAP_ClosePaths, it) + step := s.history.data[s.history.len-2] + s.p = step.p - MAP_ReachedTarget = it.p.x == MAP_TargetP.x && it.p.y == MAP_TargetP.y - if MAP_ReachedTarget - Add(&MAP_History, it) - for !(it.p.x == MAP_StartP.x && it.p.y == MAP_StartP.y) - it = *MAP_GetCloseP(it.came_from) - Add(&MAP_History, it) + new_tile := s.map.data + s.p.x + s.p.y * s.map.x + Assert(*new_tile == 0) + *new_tile |= MAP_TILE_ACTOR_IS_STANDING + + s.state = MAP_PATH_SEARCHING + Reset(&s.open_paths) + Reset(&s.close_paths) + Reset(&s.history) + +MAP_PathFindStep :: (s: *MAP_Actor) + if s.state == MAP_PATH_REACHED ;; return + if s.open_paths.len == 0 + MAP_InsertOpenPath(s, s.p, s.target_p, ignore_blocks = true) + + it := Pop(&s.open_paths) + Add(&s.close_paths, it) + + reached_target := it.p.x == s.target_p.x && it.p.y == s.target_p.y + if reached_target + s.state = MAP_PATH_REACHED + Add(&s.history, it) + for !(it.p.x == s.p.x && it.p.y == s.p.y) + it = *MAP_GetCloseP(s, it.came_from) + Add(&s.history, it) return // @language_todo: Add continue keyword // if x == 0 && y == 0 ;; continue + for y := -1, y <= 1, y += 1 for x := -1, x <= 1, x += 1 if (x == 0 && y == 0) == false p := V2I{it.p.x + x, it.p.y + y} - MAP_InsertOpenPath(p, MAP_TargetP, it.p) + MAP_InsertOpenPath(s, p, it.p)