Triangle physics seemingly done

This commit is contained in:
2025-06-20 11:47:18 -05:00
parent 6af88cc394
commit 47d5291681
5 changed files with 222 additions and 47 deletions

View File

@ -1,8 +1,8 @@
{
"activeFile": "map.tmj",
"activeFile": "overworld.tsx",
"expandedProjectPaths": [
"templates",
"."
".",
"templates"
],
"fileStates": {
":/automap-tiles.tsx": {
@ -13,11 +13,11 @@
"scaleInEditor": 1
},
"map.tmj": {
"scale": 4,
"selectedLayer": 2,
"scale": 3,
"selectedLayer": 0,
"viewCenter": {
"x": 6599.375,
"y": 6795.125
"x": 6520.166666666666,
"y": 6836.833333333333
}
},
"overworld.tsx": {
@ -35,8 +35,8 @@
"project": "map project.tiled-project",
"property.type": "int",
"recentFiles": [
"overworld.tsx",
"map.tmj",
"overworld.tsx",
"entities.tsx"
],
"tileset.lastUsedFilter": "Tiled tileset files (*.tsx *.xml)",

View File

@ -101,9 +101,8 @@ void entityUpdate(entity_t *entity) {
switch(TILE_META_DATA[tile].solidType) {
case TILE_SOLID_FULL:
collision = physicsCheckCircleAABB(
newX, newY, selfCircR,
fx248Mulfx248(x, FIXED248(TILE_WIDTH_HEIGHT, 0)),
fx248Mulfx248(y, FIXED248(TILE_WIDTH_HEIGHT, 0)),
fx248Addfx248(newX, halfTileWH), fx248Addfx248(newY, halfTileWH), selfCircR,
lx, ty,
FIXED248(TILE_WIDTH_HEIGHT, 0),
FIXED248(TILE_WIDTH_HEIGHT, 0)
);
@ -111,44 +110,38 @@ void entityUpdate(entity_t *entity) {
case TILE_SOLID_TRIANGLE_TOP_RIGHT:
collision = physicsCheckCircleTriangle(
newX, newY, selfCircR,
lx, ty,
fx248Addfx248(newX, halfTileWH), fx248Addfx248(newY, halfTileWH), selfCircR,
rx, by,
rx, ty,
rx, by
lx, ty
);
break;
// case TILE_SOLID_TRIANGLE_TOP_LEFT:
// collision = physicsCheckCircleTriangle(
// newX, newY, selfCircR,
// lx, ty,
// rx, ty,
// lx, by
// );
// break;
// case TILE_SOLID_TRIANGLE_BOTTOM_RIGHT:
// collision = physicsCheckCircleTriangle(
// newX, newY, selfCircR,
// fx248Mulfx248(x, FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Addfx248(fx248Mulfx248(y, FIXED248(TILE_WIDTH_HEIGHT, 0)), FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Addfx248(fx248Mulfx248(x, FIXED248(TILE_WIDTH_HEIGHT, 0)), FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Addfx248(fx248Mulfx248(y, FIXED248(TILE_WIDTH_HEIGHT, 0)), FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Mulfx248(x, FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Mulfx248(y, FIXED248(TILE_WIDTH_HEIGHT, 0))
// );
// break;
case TILE_SOLID_TRIANGLE_TOP_LEFT:
collision = physicsCheckCircleTriangle(
fx248Addfx248(newX, halfTileWH), fx248Addfx248(newY, halfTileWH), selfCircR,
lx, by,
lx, ty,
rx, ty
);
break;
// case TILE_SOLID_TRIANGLE_BOTTOM_LEFT:
// collision = physicsCheckCircleTriangle(
// newX, newY, selfCircR,
// fx248Mulfx248(x, FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Addfx248(fx248Mulfx248(y, FIXED248(TILE_WIDTH_HEIGHT, 0)), FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Addfx248(fx248Mulfx248(x, FIXED248(TILE_WIDTH_HEIGHT, 0)), FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Addfx248(fx248Mulfx248(y, FIXED248(TILE_WIDTH_HEIGHT, 0)), FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Addfx248(fx248Mulfx248(x, FIXED248(TILE_WIDTH_HEIGHT, 0)), FIXED248(TILE_WIDTH_HEIGHT, 0)),
// fx248Mulfx248(y, FIXED248(TILE_WIDTH_HEIGHT, 0))
// );
// break;
case TILE_SOLID_TRIANGLE_BOTTOM_RIGHT:
collision = physicsCheckCircleTriangle(
fx248Addfx248(newX, halfTileWH), fx248Addfx248(newY, halfTileWH), selfCircR,
rx, ty,
rx, by,
lx, by
);
break;
case TILE_SOLID_TRIANGLE_BOTTOM_LEFT:
collision = physicsCheckCircleTriangle(
fx248Addfx248(newX, halfTileWH), fx248Addfx248(newY, halfTileWH), selfCircR,
lx, ty,
lx, by,
rx, by
);
break;
default:
continue;

View File

@ -99,13 +99,155 @@ collisionresult_t physicsCheckCircleAABB(
return result;
}
void physicsClosestPointOnSegment(
fixed248_t ax, fixed248_t ay,
fixed248_t bx, fixed248_t by,
fixed248_t px, fixed248_t py,
fixed248_t *outX, fixed248_t *outY
) {
fixed248_t abx = fx248Subfx248(bx, ax);
fixed248_t aby = fx248Subfx248(by, ay);
fixed248_t apx = fx248Subfx248(px, ax);
fixed248_t apy = fx248Subfx248(py, ay);
fixed248_t abLenSq = fx248Addfx248(
fx248Mulfx248(abx, abx),
fx248Mulfx248(aby, aby)
);
if(abLenSq == FIXED248_ZERO) {
*outX = ax;
*outY = ay;
return;
}
fixed248_t t = fx248Divfx248(
fx248Addfx248(fx248Mulfx248(apx, abx), fx248Mulfx248(apy, aby)),
abLenSq
);
if(t < FIXED248_ZERO) t = FIXED248_ZERO;
if(t > FIXED248_ONE) t = FIXED248_ONE;
*outX = fx248Addfx248(ax, fx248Mulfx248(abx, t));
*outY = fx248Addfx248(ay, fx248Mulfx248(aby, t));
}
bool_t physicsIsPointInTriangle(
fixed248_t px, fixed248_t py,
fixed248_t ax, fixed248_t ay,
fixed248_t bx, fixed248_t by,
fixed248_t cx, fixed248_t cy
) {
fixed248_t abx = fx248Subfx248(bx, ax);
fixed248_t aby = fx248Subfx248(by, ay);
fixed248_t bcx = fx248Subfx248(cx, bx);
fixed248_t bcy = fx248Subfx248(cy, by);
fixed248_t cax = fx248Subfx248(ax, cx);
fixed248_t cay = fx248Subfx248(ay, cy);
fixed248_t apx = fx248Subfx248(px, ax);
fixed248_t apy = fx248Subfx248(py, ay);
fixed248_t bpx = fx248Subfx248(px, bx);
fixed248_t bpy = fx248Subfx248(py, by);
fixed248_t cpx = fx248Subfx248(px, cx);
fixed248_t cpy = fx248Subfx248(py, cy);
fixed248_t cross1 = fx248Subfx248(
fx248Mulfx248(abx, apy),
fx248Mulfx248(aby, apx)
);
fixed248_t cross2 = fx248Subfx248(
fx248Mulfx248(bcx, bpy),
fx248Mulfx248(bcy, bpx)
);
fixed248_t cross3 = fx248Subfx248(
fx248Mulfx248(cax, cpy),
fx248Mulfx248(cay, cpx)
);
bool_t hasNeg = (
(cross1 < FIXED248_ZERO) ||
(cross2 < FIXED248_ZERO) ||
(cross3 < FIXED248_ZERO)
);
bool_t hasPos = (
(cross1 > FIXED248_ZERO) ||
(cross2 > FIXED248_ZERO) ||
(cross3 > FIXED248_ZERO)
);
return !(hasNeg && hasPos);
}
collisionresult_t physicsCheckCircleTriangle(
fixed248_t circleX, fixed248_t circleY, fixed248_t circleR,
fixed248_t triX0, fixed248_t triY0,
fixed248_t triX1, fixed248_t triY1,
fixed248_t triX2, fixed248_t triY2
) {
collisionresult_t result;
result.hit = false;
collisionresult_t result = { .hit = false };
fixed248_t vx[3] = { triX0, triX1, triX2 };
fixed248_t vy[3] = { triY0, triY1, triY2 };
fixed248_t closestX = FIXED248_ZERO;
fixed248_t closestY = FIXED248_ZERO;
fixed248_t normalX = FIXED248_ZERO;
fixed248_t normalY = FIXED248_ZERO;
fixed248_t minDistSq = FIXED248_MAX;
for(uint8_t i = 0; i < 3; ++i) {
uint8_t j = (i + 1) % 3;
fixed248_t testX, testY;
physicsClosestPointOnSegment(
vx[i], vy[i], vx[j], vy[j],
circleX, circleY, &testX, &testY
);
fixed248_t dx = fx248Subfx248(circleX, testX);
fixed248_t dy = fx248Subfx248(circleY, testY);
fixed248_t distSq = fx248Addfx248(
fx248Mulfx248(dx, dx),
fx248Mulfx248(dy, dy)
);
if(distSq < minDistSq) {
minDistSq = distSq;
closestX = testX;
closestY = testY;
normalX = dx;
normalY = dy;
}
}
fixed248_t dist = fx248Sqrt(minDistSq);
fixed248_t invDist = (
(dist != FIXED248_ZERO) ?
fx248Divfx248(FIXED248_ONE, dist) :
FIXED248_ONE
);
fixed248_t nx = fx248Mulfx248(-normalX, invDist);
fixed248_t ny = fx248Mulfx248(-normalY, invDist);
if(physicsIsPointInTriangle(
circleX, circleY, vx[0], vy[0], vx[1], vy[1], vx[2], vy[2]
)) {
result.hit = true;
result.depth = fx248Subfx248(circleR, dist);
result.normalX = nx;
result.normalY = ny;
return result;
}
if(dist < circleR) {
result.hit = true;
result.depth = fx248Subfx248(circleR, dist);
result.normalX = nx;
result.normalY = ny;
}
return result;
}

View File

@ -48,6 +48,45 @@ collisionresult_t physicsCheckCircleAABB(
fixed248_t aabbWidth, fixed248_t aabbHeight
);
/**
* Calculate the closest point on a line segment to a point.
*
* @param ax X coordinate of the first endpoint of the segment.
* @param ay Y coordinate of the first endpoint of the segment.
* @param bx X coordinate of the second endpoint of the segment.
* @param by Y coordinate of the second endpoint of the segment.
* @param px X coordinate of the point.
* @param py Y coordinate of the point.
* @param outX Pointer to store the X coordinate of the closest point.
* @param outY Pointer to store the Y coordinate of the closest point.
*/
void physicsClosestPointOnSegment(
fixed248_t ax, fixed248_t ay,
fixed248_t bx, fixed248_t by,
fixed248_t px, fixed248_t py,
fixed248_t *outX, fixed248_t *outY
);
/**
* Check if a point is inside a triangle defined by three vertices.
*
* @param px X coordinate of the point.
* @param py Y coordinate of the point.
* @param x0 X coordinate of the first vertex of the triangle.
* @param y0 Y coordinate of the first vertex of the triangle.
* @param x1 X coordinate of the second vertex of the triangle.
* @param y1 Y coordinate of the second vertex of the triangle.
* @param x2 X coordinate of the third vertex of the triangle.
* @param y2 Y coordinate of the third vertex of the triangle.
* @return true if the point is inside the triangle, false otherwise.
*/
bool_t physicsIsPointInTriangle(
fixed248_t px, fixed248_t py,
fixed248_t x0, fixed248_t y0,
fixed248_t x1, fixed248_t y1,
fixed248_t x2, fixed248_t y2
);
/**
* Check for collision between a circle and a triangle.
*

View File

@ -19,6 +19,7 @@ typedef int32_t fixed248_t;
(((f) * FIXED248_HIGH_MULTIPLIER) / 100) \
))
#define FIXED248_ONE (FIXED248(1, 0))
#define FIXED248_ZERO (FIXED248(0, 0))
/**
* Convert an int32_t value to a fixed248_t value.