mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Improve general bot handling
- Their waypoint radius gets thinner quicker - Waypoint distance is scaled with each ones' floor slope, instead of done once at the end of the prediction. - Prediction is pulled back further when it goes through a wall - Prediction starts earlier and goes less far - Bots will brake at shallower angles (allows them to brake-turn more often) - K_AddDodgeObject and K_AddAttackObject now adjust based on the radius of the object - Fixed K_AddDodgeObject adding to the goto objects instead of avoid objects - Optimized blockmap search size for K_FindObjectsForNudging - Current waypoint is no longer cleared each frame
This commit is contained in:
parent
7d4720b1a6
commit
a8af5b7616
3 changed files with 129 additions and 72 deletions
117
src/k_bot.c
117
src/k_bot.c
|
|
@ -639,7 +639,7 @@ fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t
|
|||
static fixed_t K_GetBotWaypointRadius(waypoint_t *const waypoint)
|
||||
{
|
||||
static const fixed_t maxReduce = FRACUNIT/32;
|
||||
static const angle_t maxDelta = ANGLE_45;
|
||||
static const angle_t maxDelta = ANGLE_22h;
|
||||
|
||||
fixed_t radius = waypoint->mobj->radius;
|
||||
fixed_t reduce = FRACUNIT;
|
||||
|
|
@ -678,6 +678,35 @@ static fixed_t K_GetBotWaypointRadius(waypoint_t *const waypoint)
|
|||
return FixedMul(radius, reduce);
|
||||
}
|
||||
|
||||
static fixed_t K_ScaleWPDistWithSlope(fixed_t disttonext, angle_t angletonext, const pslope_t *slope, SINT8 flip)
|
||||
{
|
||||
if (slope == NULL)
|
||||
{
|
||||
return disttonext;
|
||||
}
|
||||
|
||||
if ((slope->flags & SL_NOPHYSICS) == 0 && abs(slope->zdelta) >= FRACUNIT/21)
|
||||
{
|
||||
// Displace the prediction to go with the slope physics.
|
||||
fixed_t slopeMul = FRACUNIT;
|
||||
angle_t angle = angletonext - slope->xydirection;
|
||||
|
||||
if (flip * slope->zdelta < 0)
|
||||
{
|
||||
angle ^= ANGLE_180;
|
||||
}
|
||||
|
||||
// Going uphill: 0
|
||||
// Going downhill: FRACUNIT*2
|
||||
slopeMul = FRACUNIT + FINECOSINE(angle >> ANGLETOFINESHIFT);
|
||||
|
||||
// Range: 0.25 to 1.75
|
||||
return FixedMul(disttonext, (FRACUNIT >> 2) + ((slopeMul * 3) >> 2));
|
||||
}
|
||||
|
||||
return disttonext;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static botprediction_t *K_CreateBotPrediction(player_t *player)
|
||||
|
||||
|
|
@ -701,8 +730,8 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
const tic_t futuresight = (TICRATE * KART_FULLTURN) / max(1, handling); // How far ahead into the future to try and predict
|
||||
const fixed_t speed = K_BotSpeedScaled(player, P_AproxDistance(player->mo->momx, player->mo->momy));
|
||||
|
||||
const INT32 startDist = (DEFAULT_WAYPOINT_RADIUS * 2 * mapobjectscale) / FRACUNIT;
|
||||
const INT32 maxDist = startDist * 4; // This function gets very laggy when it goes far distances, and going too far isn't very helpful anyway.
|
||||
const INT32 startDist = 0; //(DEFAULT_WAYPOINT_RADIUS * mapobjectscale) / FRACUNIT;
|
||||
const INT32 maxDist = (DEFAULT_WAYPOINT_RADIUS * 3 * mapobjectscale) / FRACUNIT; // This function gets very laggy when it goes far distances, and going too far isn't very helpful anyway.
|
||||
const INT32 distance = min(((speed / FRACUNIT) * (INT32)futuresight) + startDist, maxDist);
|
||||
|
||||
// Halves radius when encountering a wall on your way to your destination.
|
||||
|
|
@ -712,6 +741,8 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
fixed_t smallestradius = INT32_MAX;
|
||||
angle_t angletonext = ANGLE_MAX;
|
||||
INT32 disttonext = INT32_MAX;
|
||||
INT32 distscaled = INT32_MAX;
|
||||
pslope_t *nextslope = player->mo->standingslope;
|
||||
|
||||
waypoint_t *wp = player->nextwaypoint;
|
||||
mobj_t *prevwpmobj = player->mo;
|
||||
|
|
@ -721,15 +752,25 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
boolean pathfindsuccess = false;
|
||||
path_t pathtofinish = {0};
|
||||
|
||||
botprediction_t *predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
|
||||
botprediction_t *predict = NULL;
|
||||
size_t i;
|
||||
|
||||
if (wp == NULL || P_MobjWasRemoved(wp->mobj) == true)
|
||||
{
|
||||
// Can't do any of this if we don't have a waypoint.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
predict = Z_Calloc(sizeof(botprediction_t), PU_STATIC, NULL);
|
||||
|
||||
// Init defaults in case of pathfind failure
|
||||
angletonext = R_PointToAngle2(prevwpmobj->x, prevwpmobj->y, wp->mobj->x, wp->mobj->y);
|
||||
disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y) / FRACUNIT;
|
||||
disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y);
|
||||
nextslope = wp->mobj->standingslope;
|
||||
distscaled = K_ScaleWPDistWithSlope(disttonext, angletonext, nextslope, P_MobjFlip(wp->mobj)) / FRACUNIT;
|
||||
|
||||
pathfindsuccess = K_PathfindThruCircuit(
|
||||
player->nextwaypoint, (unsigned)distanceleft,
|
||||
wp, (unsigned)distanceleft,
|
||||
&pathtofinish,
|
||||
useshortcuts, huntbackwards
|
||||
);
|
||||
|
|
@ -753,12 +794,14 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
}
|
||||
|
||||
angletonext = R_PointToAngle2(prevwpmobj->x, prevwpmobj->y, wp->mobj->x, wp->mobj->y);
|
||||
disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y) / FRACUNIT;
|
||||
disttonext = P_AproxDistance(prevwpmobj->x - wp->mobj->x, prevwpmobj->y - wp->mobj->y);
|
||||
nextslope = wp->mobj->standingslope;
|
||||
distscaled = K_ScaleWPDistWithSlope(disttonext, angletonext, nextslope, P_MobjFlip(wp->mobj)) / FRACUNIT;
|
||||
|
||||
if (P_TraceBotTraversal(player->mo, wp->mobj) == false)
|
||||
{
|
||||
// If we can't get a direct path to this waypoint, predict less.
|
||||
distanceleft /= 2;
|
||||
// If we can't get a direct path to this waypoint, reduce our prediction drastically.
|
||||
distscaled *= 4;
|
||||
radreduce = FRACUNIT >> 1;
|
||||
}
|
||||
|
||||
|
|
@ -768,7 +811,7 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
smallestradius = radius;
|
||||
}
|
||||
|
||||
distanceleft -= disttonext;
|
||||
distanceleft -= distscaled;
|
||||
|
||||
if (distanceleft <= 0)
|
||||
{
|
||||
|
|
@ -794,25 +837,6 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
|
|||
predict->y += P_ReturnThrustY(NULL, angletonext, min(disttonext, distanceleft) * FRACUNIT);
|
||||
}
|
||||
|
||||
if (player->mo->standingslope != NULL)
|
||||
{
|
||||
const pslope_t *slope = player->mo->standingslope;
|
||||
|
||||
if (!(slope->flags & SL_NOPHYSICS) && abs(slope->zdelta) >= FRACUNIT/21)
|
||||
{
|
||||
// Displace the prediction to go against the slope physics.
|
||||
angle_t angle = slope->xydirection;
|
||||
|
||||
if (P_MobjFlip(player->mo) * slope->zdelta < 0)
|
||||
{
|
||||
angle ^= ANGLE_180;
|
||||
}
|
||||
|
||||
predict->x -= P_ReturnThrustX(NULL, angle, startDist * abs(slope->zdelta));
|
||||
predict->y -= P_ReturnThrustY(NULL, angle, startDist * abs(slope->zdelta));
|
||||
}
|
||||
}
|
||||
|
||||
ps_bots[player - players].prediction += I_GetPreciseTime() - time;
|
||||
return predict;
|
||||
}
|
||||
|
|
@ -1109,7 +1133,7 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t *
|
|||
anglediff = abs(anglediff);
|
||||
turnamt = KART_FULLTURN * turnsign;
|
||||
|
||||
if (anglediff > ANGLE_90)
|
||||
if (anglediff > ANGLE_67h)
|
||||
{
|
||||
// Wrong way!
|
||||
cmd->forwardmove = -MAXPLMOVE;
|
||||
|
|
@ -1502,18 +1526,13 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
if (predict == NULL)
|
||||
{
|
||||
// Create a prediction.
|
||||
if (player->nextwaypoint != NULL
|
||||
&& player->nextwaypoint->mobj != NULL
|
||||
&& !P_MobjWasRemoved(player->nextwaypoint->mobj))
|
||||
{
|
||||
predict = K_CreateBotPrediction(player);
|
||||
K_NudgePredictionTowardsObjects(predict, player);
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
}
|
||||
predict = K_CreateBotPrediction(player);
|
||||
}
|
||||
|
||||
if (predict != NULL)
|
||||
{
|
||||
K_NudgePredictionTowardsObjects(predict, player);
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
turnamt = K_HandleBotTrack(player, cmd, predict, destangle);
|
||||
}
|
||||
cmd->buttons &= ~(BT_ACCELERATE|BT_BRAKE);
|
||||
|
|
@ -1539,18 +1558,13 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
if (predict == NULL)
|
||||
{
|
||||
// Create a prediction.
|
||||
if (player->nextwaypoint != NULL
|
||||
&& player->nextwaypoint->mobj != NULL
|
||||
&& !P_MobjWasRemoved(player->nextwaypoint->mobj))
|
||||
{
|
||||
predict = K_CreateBotPrediction(player);
|
||||
K_NudgePredictionTowardsObjects(predict, player);
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
}
|
||||
predict = K_CreateBotPrediction(player);
|
||||
}
|
||||
|
||||
if (predict != NULL)
|
||||
{
|
||||
K_NudgePredictionTowardsObjects(predict, player);
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
turnamt = K_HandleBotTrack(player, cmd, predict, destangle);
|
||||
}
|
||||
}
|
||||
|
|
@ -1561,18 +1575,13 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
if (predict == NULL)
|
||||
{
|
||||
// Create a prediction.
|
||||
if (player->nextwaypoint != NULL
|
||||
&& player->nextwaypoint->mobj != NULL
|
||||
&& !P_MobjWasRemoved(player->nextwaypoint->mobj))
|
||||
{
|
||||
predict = K_CreateBotPrediction(player);
|
||||
K_NudgePredictionTowardsObjects(predict, player);
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
}
|
||||
predict = K_CreateBotPrediction(player);
|
||||
}
|
||||
|
||||
if (predict != NULL)
|
||||
{
|
||||
K_NudgePredictionTowardsObjects(predict, player);
|
||||
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
turnamt = K_HandleBotTrack(player, cmd, predict, destangle);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,6 +271,8 @@ boolean K_BotHatesThisSector(player_t *player, sector_t *sec, fixed_t x, fixed_t
|
|||
--------------------------------------------------*/
|
||||
static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
|
||||
{
|
||||
fixed_t x, y;
|
||||
angle_t a, dir;
|
||||
UINT8 i;
|
||||
|
||||
I_Assert(side <= 1);
|
||||
|
|
@ -280,10 +282,21 @@ static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
|
|||
return;
|
||||
}
|
||||
|
||||
x = thing->x;
|
||||
y = thing->y;
|
||||
a = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, x, y);
|
||||
|
||||
dir = a + (side ? -ANGLE_90 : ANGLE_90);
|
||||
x += FixedMul(thing->radius, FINECOSINE(dir >> ANGLETOFINESHIFT));
|
||||
y += FixedMul(thing->radius, FINESINE(dir >> ANGLETOFINESHIFT));
|
||||
|
||||
x /= mapobjectscale;
|
||||
y /= mapobjectscale;
|
||||
|
||||
for (i = 0; i < weight; i++)
|
||||
{
|
||||
globalsmuggle.gotoAvgX[side] += thing->x / mapobjectscale;
|
||||
globalsmuggle.gotoAvgY[side] += thing->y / mapobjectscale;
|
||||
globalsmuggle.gotoAvgX[side] += x;
|
||||
globalsmuggle.gotoAvgY[side] += y;
|
||||
globalsmuggle.gotoObjs[side]++;
|
||||
}
|
||||
}
|
||||
|
|
@ -303,6 +316,8 @@ static void K_AddAttackObject(mobj_t *thing, UINT8 side, UINT8 weight)
|
|||
--------------------------------------------------*/
|
||||
static void K_AddDodgeObject(mobj_t *thing, UINT8 side, UINT8 weight)
|
||||
{
|
||||
fixed_t x, y;
|
||||
angle_t a, dir;
|
||||
UINT8 i;
|
||||
|
||||
I_Assert(side <= 1);
|
||||
|
|
@ -312,11 +327,22 @@ static void K_AddDodgeObject(mobj_t *thing, UINT8 side, UINT8 weight)
|
|||
return;
|
||||
}
|
||||
|
||||
x = thing->x;
|
||||
y = thing->y;
|
||||
a = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, x, y);
|
||||
|
||||
dir = a + (side ? -ANGLE_90 : ANGLE_90);
|
||||
x += FixedMul(thing->radius, FINECOSINE(dir >> ANGLETOFINESHIFT));
|
||||
y += FixedMul(thing->radius, FINESINE(dir >> ANGLETOFINESHIFT));
|
||||
|
||||
x /= mapobjectscale;
|
||||
y /= mapobjectscale;
|
||||
|
||||
for (i = 0; i < weight; i++)
|
||||
{
|
||||
globalsmuggle.gotoAvgX[side] += thing->x / mapobjectscale;
|
||||
globalsmuggle.gotoAvgY[side] += thing->y / mapobjectscale;
|
||||
globalsmuggle.gotoObjs[side]++;
|
||||
globalsmuggle.avoidAvgX[side] += x;
|
||||
globalsmuggle.avoidAvgY[side] += y;
|
||||
globalsmuggle.avoidObjs[side]++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -366,7 +392,7 @@ static boolean K_PlayerAttackSteer(mobj_t *thing, UINT8 side, UINT8 weight, bool
|
|||
--------------------------------------------------*/
|
||||
static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
|
||||
{
|
||||
INT16 anglediff;
|
||||
INT16 angledelta, anglediff;
|
||||
fixed_t fulldist;
|
||||
angle_t destangle, angle, predictangle;
|
||||
UINT8 side = 0;
|
||||
|
|
@ -404,15 +430,15 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
|
|||
|
||||
if (angle < ANGLE_180)
|
||||
{
|
||||
anglediff = AngleFixed(angle)>>FRACBITS;
|
||||
angledelta = AngleFixed(angle)>>FRACBITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
anglediff = 360-(AngleFixed(angle)>>FRACBITS);
|
||||
angledelta = 360-(AngleFixed(angle)>>FRACBITS);
|
||||
side = 1;
|
||||
}
|
||||
|
||||
anglediff = abs(anglediff);
|
||||
anglediff = abs(angledelta);
|
||||
|
||||
switch (thing->type)
|
||||
{
|
||||
|
|
@ -638,23 +664,40 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
|
|||
|
||||
INT32 xl, xh, yl, yh, bx, by;
|
||||
|
||||
fixed_t distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
fixed_t distToPredict = 0;
|
||||
angle_t angleToPredict = 0;
|
||||
|
||||
fixed_t avgX = 0, avgY = 0;
|
||||
fixed_t avgDist = 0;
|
||||
|
||||
const fixed_t baseNudge = predict->radius;
|
||||
fixed_t maxNudge = distToPredict;
|
||||
fixed_t baseNudge = 0;
|
||||
fixed_t maxNudge = 0;
|
||||
fixed_t nudgeDist = 0;
|
||||
angle_t nudgeDir = 0;
|
||||
|
||||
SINT8 gotoSide = -1;
|
||||
UINT8 i;
|
||||
|
||||
if (predict == NULL)
|
||||
{
|
||||
ps_bots[player - players].nudge += I_GetPreciseTime() - time;
|
||||
return;
|
||||
}
|
||||
|
||||
distToPredict = R_PointToDist2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
angleToPredict = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
|
||||
|
||||
globalsmuggle.distancetocheck = distToPredict >> 1;
|
||||
|
||||
baseNudge = predict->radius * 2;
|
||||
maxNudge = distToPredict;
|
||||
|
||||
globalsmuggle.botmo = player->mo;
|
||||
globalsmuggle.predict = predict;
|
||||
|
||||
globalsmuggle.distancetocheck = distToPredict;
|
||||
// silly variable reuse
|
||||
avgX = globalsmuggle.botmo->x + FixedMul(globalsmuggle.distancetocheck, FINECOSINE(angleToPredict >> ANGLETOFINESHIFT));
|
||||
avgY = globalsmuggle.botmo->y + FixedMul(globalsmuggle.distancetocheck, FINESINE(angleToPredict >> ANGLETOFINESHIFT));
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
|
|
@ -665,10 +708,10 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player)
|
|||
globalsmuggle.avoidObjs[i] = 0;
|
||||
}
|
||||
|
||||
xl = (unsigned)(globalsmuggle.botmo->x - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
xh = (unsigned)(globalsmuggle.botmo->x + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
yl = (unsigned)(globalsmuggle.botmo->y - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
yh = (unsigned)(globalsmuggle.botmo->y + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
xl = (unsigned)(avgX - (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
xh = (unsigned)(avgX + (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
yl = (unsigned)(avgY - (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
yh = (unsigned)(avgY + (globalsmuggle.distancetocheck + MAXRADIUS) - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
|
||||
BMBOUNDFIX(xl, xh, yl, yh);
|
||||
|
||||
|
|
|
|||
|
|
@ -8352,7 +8352,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
|
|||
boolean updaterespawn = false;
|
||||
|
||||
// Our current waypoint.
|
||||
player->currentwaypoint = bestwaypoint = waypoint;
|
||||
bestwaypoint = waypoint;
|
||||
|
||||
if (bestwaypoint != NULL)
|
||||
{
|
||||
player->currentwaypoint = bestwaypoint;
|
||||
}
|
||||
|
||||
// check the waypoint's location in relation to the player
|
||||
// If it's generally in front, it's fine, otherwise, use the best next/previous waypoint.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue