Visualise path from BFS + Improving BFS
Changelog: - Avoid continuous BFS by changing state after BFS completion - Reset to BFS state on tile changescene_man
parent
5b3cbd1bba
commit
a0f6cf3471
|
@ -141,12 +141,19 @@ typedef struct _BFSTileMap {
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
}BFSTileMap_t;
|
}BFSTileMap_t;
|
||||||
|
|
||||||
|
typedef enum _WaterRunnerState
|
||||||
|
{
|
||||||
|
LOWEST_POINT_SEARCH = 0,
|
||||||
|
LOWEST_POINT_MOVEMENT,
|
||||||
|
}WaterRunerState_t;
|
||||||
|
|
||||||
typedef struct _CWaterRunner {
|
typedef struct _CWaterRunner {
|
||||||
|
BFSTileMap_t bfs_tilemap;
|
||||||
int32_t current_tile;
|
int32_t current_tile;
|
||||||
int32_t target_tile;
|
int32_t target_tile;
|
||||||
struct sc_queue_32 bfs_queue;
|
struct sc_queue_32 bfs_queue;
|
||||||
bool* visited;
|
bool* visited;
|
||||||
BFSTileMap_t bfs_tilemap;
|
WaterRunerState_t state;
|
||||||
}CWaterRunner_t;
|
}CWaterRunner_t;
|
||||||
|
|
||||||
// Credits to bedroomcoders.co.uk for this
|
// Credits to bedroomcoders.co.uk for this
|
||||||
|
|
|
@ -50,13 +50,13 @@ void update_water_runner_system(Scene_t* scene)
|
||||||
// - Scanline fill
|
// - Scanline fill
|
||||||
// A runner is given an amount of movement cost
|
// A runner is given an amount of movement cost
|
||||||
// Within the movement cost, do the following logic
|
// Within the movement cost, do the following logic
|
||||||
// Perform a modified DFS to find the lowest point:
|
// Perform a modified BFS to find the lowest point:
|
||||||
// - Solid tiles are not reachable
|
// - Solid tiles are not reachable
|
||||||
// - If bottom tile is non-solid, that is the only reachable tile,
|
// - If bottom tile is non-solid, that is the only reachable tile,
|
||||||
// - If bottom tile is filled with water fully, down+left+right are reachable
|
// - If bottom tile is filled with water fully, down+left+right are reachable
|
||||||
// - If bottom tile is solid, left+right are reachable
|
// - If bottom tile is solid, left+right are reachable
|
||||||
// - If bottom tile is OOB, terminate
|
// - If bottom tile is OOB, terminate
|
||||||
// Use a LIFO to deal with this.
|
// Use a FIFO to deal with this.
|
||||||
// On DFS completion, find the path to the lowest point. Keep track of this
|
// On DFS completion, find the path to the lowest point. Keep track of this
|
||||||
// The DFS should have figured out all reachable tiles, start scanline filling at the lowest point.
|
// The DFS should have figured out all reachable tiles, start scanline filling at the lowest point.
|
||||||
// On completion, move up update tile reachability by DFS on the current level. (repeat first step)
|
// On completion, move up update tile reachability by DFS on the current level. (repeat first step)
|
||||||
|
@ -72,57 +72,95 @@ void update_water_runner_system(Scene_t* scene)
|
||||||
{
|
{
|
||||||
//Entity_t* ent = get_entity(&scene->ent_manager, ent_idx);
|
//Entity_t* ent = get_entity(&scene->ent_manager, ent_idx);
|
||||||
sc_queue_add_last(&p_crunner->bfs_queue, p_crunner->current_tile);
|
sc_queue_add_last(&p_crunner->bfs_queue, p_crunner->current_tile);
|
||||||
memset(p_crunner->visited, 0, p_crunner->bfs_tilemap.len * sizeof(bool));
|
|
||||||
int32_t lowest_tile = p_crunner->current_tile;
|
switch (p_crunner->state)
|
||||||
while (!sc_queue_empty(&p_crunner->bfs_queue))
|
|
||||||
{
|
{
|
||||||
unsigned int curr_idx = sc_queue_peek_first(&p_crunner->bfs_queue);
|
case LOWEST_POINT_SEARCH:
|
||||||
sc_queue_del_first(&p_crunner->bfs_queue);
|
|
||||||
if (p_crunner->visited[curr_idx]) continue;
|
|
||||||
|
|
||||||
unsigned int curr_height = curr_idx / p_crunner->bfs_tilemap.width;
|
|
||||||
unsigned int curr_low = lowest_tile / p_crunner->bfs_tilemap.width;
|
|
||||||
if (curr_height > curr_low)
|
|
||||||
{
|
{
|
||||||
lowest_tile = curr_idx;
|
for (size_t i = 0; i < p_crunner->bfs_tilemap.len; ++i)
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
p_crunner->visited[curr_idx] = true;
|
|
||||||
p_crunner->bfs_tilemap.tilemap[curr_idx].reachable = true;
|
|
||||||
// Possible optimisation to avoid repeated BFS, dunno how possible
|
|
||||||
|
|
||||||
unsigned int next = curr_idx + p_crunner->bfs_tilemap.width;
|
|
||||||
if (next >= p_crunner->bfs_tilemap.len) continue;
|
|
||||||
|
|
||||||
Tile_t* next_tile = tilemap.tiles + next;
|
|
||||||
if (next_tile->solid != SOLID && next_tile->water_level < next_tile->max_water_level)
|
|
||||||
{
|
|
||||||
sc_queue_add_last(&p_crunner->bfs_queue, next);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
next = curr_idx - 1;
|
|
||||||
if (next % p_crunner->bfs_tilemap.width != 0)
|
|
||||||
{
|
{
|
||||||
next_tile = tilemap.tiles + next;
|
p_crunner->bfs_tilemap.tilemap[i].from = -1;
|
||||||
if (next_tile->solid != SOLID && next_tile->water_level < next_tile->max_water_level)
|
}
|
||||||
|
memset(p_crunner->visited, 0, p_crunner->bfs_tilemap.len * sizeof(bool));
|
||||||
|
int32_t lowest_tile = p_crunner->current_tile;
|
||||||
|
while (!sc_queue_empty(&p_crunner->bfs_queue))
|
||||||
|
{
|
||||||
|
unsigned int curr_idx = sc_queue_peek_first(&p_crunner->bfs_queue);
|
||||||
|
sc_queue_del_first(&p_crunner->bfs_queue);
|
||||||
|
|
||||||
|
unsigned int curr_height = curr_idx / p_crunner->bfs_tilemap.width;
|
||||||
|
unsigned int curr_low = lowest_tile / p_crunner->bfs_tilemap.width;
|
||||||
|
if (curr_height > curr_low)
|
||||||
|
{
|
||||||
|
lowest_tile = curr_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_crunner->visited[curr_idx] = true;
|
||||||
|
p_crunner->bfs_tilemap.tilemap[curr_idx].reachable = true;
|
||||||
|
// Possible optimisation to avoid repeated BFS, dunno how possible
|
||||||
|
|
||||||
|
unsigned int next = curr_idx + p_crunner->bfs_tilemap.width;
|
||||||
|
if (next >= p_crunner->bfs_tilemap.len) continue;
|
||||||
|
|
||||||
|
Tile_t* next_tile = tilemap.tiles + next;
|
||||||
|
if (
|
||||||
|
next_tile->solid != SOLID
|
||||||
|
&& next_tile->water_level < next_tile->max_water_level
|
||||||
|
&& !p_crunner->visited[next]
|
||||||
|
)
|
||||||
{
|
{
|
||||||
sc_queue_add_last(&p_crunner->bfs_queue, next);
|
sc_queue_add_last(&p_crunner->bfs_queue, next);
|
||||||
|
p_crunner->bfs_tilemap.tilemap[next].from = curr_idx;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
next = curr_idx + 1;
|
|
||||||
if (next % p_crunner->bfs_tilemap.width != 0)
|
|
||||||
{
|
|
||||||
next_tile = tilemap.tiles + next;
|
|
||||||
if (next_tile->solid != SOLID && next_tile->water_level < next_tile->max_water_level)
|
|
||||||
{
|
{
|
||||||
sc_queue_add_last(&p_crunner->bfs_queue, next);
|
next = curr_idx - 1;
|
||||||
|
if (next % p_crunner->bfs_tilemap.width != 0)
|
||||||
|
{
|
||||||
|
next_tile = tilemap.tiles + next;
|
||||||
|
if (
|
||||||
|
next_tile->solid != SOLID
|
||||||
|
&& next_tile->water_level < next_tile->max_water_level
|
||||||
|
&& !p_crunner->visited[next]
|
||||||
|
)
|
||||||
|
{
|
||||||
|
sc_queue_add_last(&p_crunner->bfs_queue, next);
|
||||||
|
p_crunner->bfs_tilemap.tilemap[next].from = curr_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next = curr_idx + 1;
|
||||||
|
if (next % p_crunner->bfs_tilemap.width != 0)
|
||||||
|
{
|
||||||
|
next_tile = tilemap.tiles + next;
|
||||||
|
if (
|
||||||
|
next_tile->solid != SOLID
|
||||||
|
&& next_tile->water_level < next_tile->max_water_level
|
||||||
|
&& !p_crunner->visited[next]
|
||||||
|
)
|
||||||
|
{
|
||||||
|
sc_queue_add_last(&p_crunner->bfs_queue, next);
|
||||||
|
p_crunner->bfs_tilemap.tilemap[next].from = curr_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
p_crunner->target_tile = lowest_tile;
|
||||||
|
|
||||||
|
// Trace path from lowest_tile
|
||||||
|
unsigned int prev_idx = lowest_tile;
|
||||||
|
unsigned int curr_idx = p_crunner->bfs_tilemap.tilemap[prev_idx].from;
|
||||||
|
while (p_crunner->bfs_tilemap.tilemap[prev_idx].from >= 0)
|
||||||
|
{
|
||||||
|
p_crunner->bfs_tilemap.tilemap[curr_idx].to = prev_idx;
|
||||||
|
prev_idx = curr_idx;
|
||||||
|
curr_idx = p_crunner->bfs_tilemap.tilemap[prev_idx].from;
|
||||||
|
}
|
||||||
|
p_crunner->state = LOWEST_POINT_MOVEMENT;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
p_crunner->target_tile = lowest_tile;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
21
water_test.c
21
water_test.c
|
@ -91,6 +91,22 @@ static void level_scene_render_func(Scene_t* scene)
|
||||||
unsigned int y = ((p_runner->target_tile) / tilemap.width) * tilemap.tile_size;
|
unsigned int y = ((p_runner->target_tile) / tilemap.width) * tilemap.tile_size;
|
||||||
DrawCircle(x+16, y+16, 8, ColorAlpha(BLUE, 0.2));
|
DrawCircle(x+16, y+16, 8, ColorAlpha(BLUE, 0.2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_runner->state != LOWEST_POINT_SEARCH)
|
||||||
|
{
|
||||||
|
unsigned int curr_idx = p_runner->current_tile;
|
||||||
|
unsigned int next_idx = p_runner->bfs_tilemap.tilemap[curr_idx].to;
|
||||||
|
while(curr_idx != p_runner->target_tile)
|
||||||
|
{
|
||||||
|
unsigned int x1 = (curr_idx % tilemap.width) * tilemap.tile_size + tilemap.tile_size / 2;
|
||||||
|
unsigned int y1 = (curr_idx / tilemap.width) * tilemap.tile_size + tilemap.tile_size / 2;
|
||||||
|
unsigned int x2 = (next_idx % tilemap.width) * tilemap.tile_size + tilemap.tile_size / 2;
|
||||||
|
unsigned int y2 = (next_idx / tilemap.width) * tilemap.tile_size + tilemap.tile_size / 2;
|
||||||
|
DrawLine(x1, y1, x2, y2, BLACK);
|
||||||
|
curr_idx = next_idx;
|
||||||
|
next_idx = p_runner->bfs_tilemap.tilemap[curr_idx].to;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[64] = {0};
|
char buffer[64] = {0};
|
||||||
|
@ -195,6 +211,11 @@ static void toggle_block_system(Scene_t* scene)
|
||||||
if (new_type == SOLID_TILE) tilemap.tiles[tile_idx].water_level = 0;
|
if (new_type == SOLID_TILE) tilemap.tiles[tile_idx].water_level = 0;
|
||||||
change_a_tile(&tilemap, tile_idx, new_type);
|
change_a_tile(&tilemap, tile_idx, new_type);
|
||||||
last_tile_idx = tile_idx;
|
last_tile_idx = tile_idx;
|
||||||
|
CWaterRunner_t* p_crunner;
|
||||||
|
sc_map_foreach_value(&scene->ent_manager.component_map[CWATERRUNNER_T], p_crunner)
|
||||||
|
{
|
||||||
|
p_crunner->state = LOWEST_POINT_SEARCH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (IsMouseButtonReleased(MOUSE_RIGHT_BUTTON))
|
else if (IsMouseButtonReleased(MOUSE_RIGHT_BUTTON))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue