Implement DDA raycasting, fix bug in path smoothing
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include "../math/vec2i.h"
|
#include "../math/vec2i.h"
|
||||||
|
|
||||||
#include <cute_tiled.h>
|
#include <cute_tiled.h>
|
||||||
|
#include <raymath.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
BzTileMap BZ_TILEMAP_INVALID = {.isValid = false};
|
BzTileMap BZ_TILEMAP_INVALID = {.isValid = false};
|
||||||
@@ -381,6 +382,80 @@ BzTileObjectGroup *bzTileMapGetObjects(BzTileMap *map, i32 slotID) {
|
|||||||
BZ_ASSERT(slotID >= 0 && slotID < map->objectGroupCount);
|
BZ_ASSERT(slotID >= 0 && slotID < map->objectGroupCount);
|
||||||
return &map->objectGroups[slotID];
|
return &map->objectGroups[slotID];
|
||||||
}
|
}
|
||||||
|
static f32 abs(f32 x) {
|
||||||
|
return x > 0 ? x : -x;
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 bzTileMapRayCast(BzTileMap *map, Vector2 from, Vector2 to, f32 maxDst, Vector2 *outIntersection) {
|
||||||
|
// Digital Differential Analyzer (DDA)
|
||||||
|
Vector2 scale = {1.0f / map->tileWidth, 1.0f / map->tileHeight};
|
||||||
|
from = Vector2Multiply(from, scale);
|
||||||
|
to = Vector2Multiply(to, scale);
|
||||||
|
|
||||||
|
Vector2 dir = Vector2Subtract(to, from);
|
||||||
|
dir = Vector2Normalize(dir);
|
||||||
|
|
||||||
|
//Vector2 stepSize = {
|
||||||
|
// sqrtf(1 + (dir.y / dir.x) * (dir.y / dir.x)),
|
||||||
|
// sqrtf(1 + (dir.x / dir.y) * (dir.x / dir.y))
|
||||||
|
//};
|
||||||
|
Vector2 stepSize = {abs(1.0f / dir.x), abs(1.0f / dir.y)};
|
||||||
|
|
||||||
|
i32 cellX = (i32) from.x;
|
||||||
|
i32 cellY = (i32) from.y;
|
||||||
|
if (bzTileMapHasCollision(map, cellX, cellY)) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
Vector2 rayLength = Vector2Zero();
|
||||||
|
i32 stepX, stepY;
|
||||||
|
|
||||||
|
if (dir.x < 0) {
|
||||||
|
stepX = -1;
|
||||||
|
rayLength.x = (from.x - (f32) (cellX)) * stepSize.x;
|
||||||
|
} else {
|
||||||
|
stepX = 1;
|
||||||
|
rayLength.x = ((f32) cellX + 1.0f - from.x) * stepSize.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir.y < 0) {
|
||||||
|
stepY = -1;
|
||||||
|
rayLength.y = (from.y - (f32) cellY) * stepSize.y;
|
||||||
|
} else {
|
||||||
|
stepY = 1;
|
||||||
|
rayLength.y = ((f32) cellY + 1 - from.y) * stepSize.y;
|
||||||
|
}
|
||||||
|
f32 distance = 0.0f;
|
||||||
|
while (distance < maxDst) {
|
||||||
|
if (rayLength.x < rayLength.y) {
|
||||||
|
cellX += stepX;
|
||||||
|
distance = rayLength.x * map->tileWidth;
|
||||||
|
rayLength.x += stepSize.x;
|
||||||
|
} else {
|
||||||
|
cellY += stepY;
|
||||||
|
distance = rayLength.y * map->tileHeight;
|
||||||
|
rayLength.y += stepSize.y;
|
||||||
|
}
|
||||||
|
if (cellX >= 0 && cellX < map->width && cellY >= 0 && cellY < map->height &&
|
||||||
|
map->collisionMap[cellY * map->width + cellX]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outIntersection) {
|
||||||
|
Vector2 intersection = from;
|
||||||
|
intersection = Vector2Add(intersection, Vector2Scale(dir, distance));
|
||||||
|
intersection.x *= map->tileWidth;
|
||||||
|
intersection.y *= map->tileHeight;
|
||||||
|
*outIntersection = intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
bool bzTileMapCanRayCastLine(BzTileMap *map, Vector2 from, Vector2 to) {
|
||||||
|
f32 dst = Vector2Distance(from, to);
|
||||||
|
f32 rayDst = bzTileMapRayCast(map, from, to, dst, NULL);
|
||||||
|
return rayDst >= dst;
|
||||||
|
}
|
||||||
|
|
||||||
void bzTileMapDraw(BzTileMap *map) {
|
void bzTileMapDraw(BzTileMap *map) {
|
||||||
for (i32 i = 0; i < map->layerCount; i++) {
|
for (i32 i = 0; i < map->layerCount; i++) {
|
||||||
|
|||||||
@@ -124,6 +124,9 @@ void bzTileMapOverrideObjectGroup(BzTileMap *map, i32 slotID, BzTileObjectsFunc
|
|||||||
BzTileLayer *bzTileMapGetLayer(BzTileMap *map, i32 slotID);
|
BzTileLayer *bzTileMapGetLayer(BzTileMap *map, i32 slotID);
|
||||||
BzTileObjectGroup *bzTileMapGetObjects(BzTileMap *map, i32 slotID);
|
BzTileObjectGroup *bzTileMapGetObjects(BzTileMap *map, i32 slotID);
|
||||||
|
|
||||||
|
f32 bzTileMapRayCast(BzTileMap *map, Vector2 from, Vector2 to, f32 maxDst, Vector2 *outIntersection);
|
||||||
|
bool bzTileMapCanRayCastLine(BzTileMap *map, Vector2 from, Vector2 to);
|
||||||
|
|
||||||
void bzTileMapDraw(BzTileMap *map);
|
void bzTileMapDraw(BzTileMap *map);
|
||||||
void bzTileMapDrawCollisions(BzTileMap *map);
|
void bzTileMapDrawCollisions(BzTileMap *map);
|
||||||
bool bzTileMapHasCollision(BzTileMap *map, i32 x, i32 y);
|
bool bzTileMapHasCollision(BzTileMap *map, i32 x, i32 y);
|
||||||
|
|||||||
@@ -29,21 +29,6 @@ static PathData *pushPathWaypoint(PathData *pathData, Position waypoint, BzObjec
|
|||||||
return pathData;
|
return pathData;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool canRayCastLine(BzTileMap *map, Position from, Position to) {
|
|
||||||
Vector2 step = Vector2Subtract(to, from);
|
|
||||||
step = Vector2Normalize(step);
|
|
||||||
|
|
||||||
while (Vector2DistanceSqr(from, to) > 1.0f) {
|
|
||||||
from = Vector2Add(from, step);
|
|
||||||
|
|
||||||
BzTile tileX = 0, tileY = 0;
|
|
||||||
bzTileMapPosToTile(map, from, &tileX, &tileY);
|
|
||||||
if (bzTileMapHasCollision(map, tileX, tileY))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reversePath(PathData *pathData) {
|
static void reversePath(PathData *pathData) {
|
||||||
while (pathData) {
|
while (pathData) {
|
||||||
for (i32 i = 0; i < pathData->numWaypoints / 2; i++) {
|
for (i32 i = 0; i < pathData->numWaypoints / 2; i++) {
|
||||||
@@ -61,8 +46,9 @@ static void reversePath(PathData *pathData) {
|
|||||||
static void smoothPath(BzTileMap *map, PathData *pathData, BzObjectPool *pool) {
|
static void smoothPath(BzTileMap *map, PathData *pathData, BzObjectPool *pool) {
|
||||||
// Our smoothed path
|
// Our smoothed path
|
||||||
PathData *outPath = pathData;
|
PathData *outPath = pathData;
|
||||||
size_t outIdx = 1;
|
|
||||||
Position outPos = outPath->waypoints[0];
|
Position outPos = outPath->waypoints[0];
|
||||||
|
size_t outIdx = 1;
|
||||||
|
Position lastPos = outPos;
|
||||||
|
|
||||||
#define NEXT_WAYPOINT(path, idx, len) \
|
#define NEXT_WAYPOINT(path, idx, len) \
|
||||||
do { \
|
do { \
|
||||||
@@ -74,18 +60,20 @@ do { \
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
PathData *currPath = pathData;
|
PathData *currPath = pathData;
|
||||||
size_t currIdx = 0;
|
|
||||||
PathData *nextPath = pathData;
|
PathData *nextPath = pathData;
|
||||||
|
size_t currIdx = 0;
|
||||||
size_t nextIdx = 0;
|
size_t nextIdx = 0;
|
||||||
Position lastPos = outPos;
|
|
||||||
// Needed, because we overwrite numWaypoints
|
// Needed, because we overwrite numWaypoints
|
||||||
size_t currPathLen = currPath->numWaypoints;
|
size_t currPathLen = currPath->numWaypoints;
|
||||||
size_t nextPathLen = nextPath->numWaypoints;
|
size_t nextPathLen = nextPath->numWaypoints;
|
||||||
|
|
||||||
// Second element
|
// Second element
|
||||||
|
currIdx++;
|
||||||
NEXT_WAYPOINT(currPath, currIdx, currPathLen);
|
NEXT_WAYPOINT(currPath, currIdx, currPathLen);
|
||||||
// Third element
|
// Third element
|
||||||
|
nextIdx++;
|
||||||
NEXT_WAYPOINT(nextPath, nextIdx, nextPathLen);
|
NEXT_WAYPOINT(nextPath, nextIdx, nextPathLen);
|
||||||
|
nextIdx++;
|
||||||
NEXT_WAYPOINT(nextPath, nextIdx, nextPathLen);
|
NEXT_WAYPOINT(nextPath, nextIdx, nextPathLen);
|
||||||
|
|
||||||
outPath->numWaypoints = 1;
|
outPath->numWaypoints = 1;
|
||||||
@@ -100,7 +88,7 @@ do { \
|
|||||||
NEXT_WAYPOINT(currPath, currIdx, currPathLen);
|
NEXT_WAYPOINT(currPath, currIdx, currPathLen);
|
||||||
NEXT_WAYPOINT(nextPath, nextIdx, nextPathLen);
|
NEXT_WAYPOINT(nextPath, nextIdx, nextPathLen);
|
||||||
|
|
||||||
if (!canRayCastLine(map, outPos, nextPos)) {
|
if (!bzTileMapCanRayCastLine(map, outPos, nextPos)) {
|
||||||
outPos = currPos;
|
outPos = currPos;
|
||||||
outPath->waypoints[outIdx++] = currPos;
|
outPath->waypoints[outIdx++] = currPos;
|
||||||
outPath->numWaypoints = outIdx;
|
outPath->numWaypoints = outIdx;
|
||||||
@@ -113,7 +101,6 @@ do { \
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#undef NEXT_WAYPOINT
|
#undef NEXT_WAYPOINT
|
||||||
BZ_ASSERT(lastPos.x != INFINITY && lastPos.y != INFINITY);
|
|
||||||
outPath->waypoints[outIdx++] = lastPos;
|
outPath->waypoints[outIdx++] = lastPos;
|
||||||
outPath->numWaypoints = outIdx;
|
outPath->numWaypoints = outIdx;
|
||||||
|
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ void renderDebugPath(ecs_iter_t *it) {
|
|||||||
Path *path = ecs_field(it, Path, 1);
|
Path *path = ecs_field(it, Path, 1);
|
||||||
|
|
||||||
for (i32 i = 0; i < it->count; i++) {
|
for (i32 i = 0; i < it->count; i++) {
|
||||||
PathData *pathData = path->paths;
|
PathData *pathData = path[i].paths;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
while (pathData) {
|
while (pathData) {
|
||||||
for (i32 iPath = 0; iPath < pathData->numWaypoints; iPath++) {
|
for (i32 iPath = 0; iPath < pathData->numWaypoints; iPath++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user