MAP_CurrentMap: MAP_Map 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 data: *MAP_Tile x: int y: int actors: Array(MAP_Actor) 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_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) memset(MAP_CurrentMap.data, 0, bytes) actor := MAP_AddActor(&MAP_CurrentMap, {4,4}) actor.target_p = V2I{8,8} 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 < 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 < 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 := s.target_p.x - p.x dy := s.target_p.y - p.y d := dx*dx + dy*dy InsertSortedDecreasing(&s.open_paths, {d, p, came_from}) 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_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) step := s.history.data[s.history.len-2] s.p = step.p 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(s, p, it.p)