Better steering

- If they're already turning in one direction, they are more likely to steer in that direction for objects
- Bots have to want to turn in 1 direction for a few frames in a row before it'll let them

Prevents twitching & makes them less indecisive in general
This commit is contained in:
Sally Coolatta 2020-05-24 11:12:38 -04:00
parent ca7154f521
commit edfc14c506
6 changed files with 95 additions and 41 deletions

View file

@ -650,7 +650,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->bot_difficulty = players[i].botvars.difficulty;
rsp->bot_itemdelay = players[i].botvars.itemdelay;
rsp->bot_itemconfirm = players[i].botvars.itemconfirm;
rsp->bot_lastturn = players[i].botvars.lastturn;
rsp->bot_turnconfirm = players[i].botvars.turnconfirm;
rsp->hasmo = false;
//Transfer important mo information if the player has a body.
@ -779,7 +779,7 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].botvars.difficulty = rsp->bot_difficulty;
players[i].botvars.itemdelay = rsp->bot_itemdelay;
players[i].botvars.itemconfirm = rsp->bot_itemconfirm;
players[i].botvars.lastturn = rsp->bot_lastturn;
players[i].botvars.turnconfirm = rsp->bot_turnconfirm;
//We get a packet for each player in game.
if (!playeringame[i])

View file

@ -289,7 +289,7 @@ typedef struct
UINT8 bot_difficulty;
tic_t bot_itemdelay;
tic_t bot_itemconfirm;
INT16 bot_lastturn;
SINT8 bot_turnconfirm;
//player->mo stuff
UINT8 hasmo; // Boolean

View file

@ -428,7 +428,7 @@ typedef struct botvars_s
tic_t itemdelay;
tic_t itemconfirm;
INT16 lastturn;
SINT8 turnconfirm;
} botvars_t;
// ========================================================================

View file

@ -410,6 +410,7 @@ fixed_t distancetocheck = 0;
fixed_t closestlinedist = INT32_MAX;
INT16 curturn = 0;
INT16 badsteerglobal = 0;
fixed_t eggboxx, eggboxy;
@ -761,30 +762,60 @@ static void K_SteerFromObject(mobj_t *bot, mobj_t *thing, fixed_t fulldist, fixe
{
angle_t destangle = R_PointToAngle2(bot->x, bot->y, thing->x, thing->y);
angle_t angle;
SINT8 flip = 1;
amount = (amount * FixedDiv(distancetocheck - fulldist, distancetocheck)) / FRACUNIT;
if (amount == 0)
{
// Shouldn't happen
return;
}
if (towards)
{
if (xdist < (bot->radius + thing->radius))
if (xdist < FixedHypot(bot->radius, thing->radius))
{
// Don't need to turn any harder!
if (abs(badsteerglobal) <= amount)
{
badsteerglobal = 0;
}
else
{
if (badsteerglobal > 0)
{
badsteerglobal -= amount;
}
else if (badsteerglobal < 0)
{
badsteerglobal += amount;
}
}
return;
}
amount = -amount;
// Still turning towards it, flip.
flip = -flip;
}
angle = (bot->angle - destangle);
if (angle < ANGLE_180)
{
badsteerglobal -= amount;
flip = -flip;
}
else
// If going in the opposite direction of where you wanted to turn,
// then reduce the amount that you can turn in that direction.
if ((flip == 1 && curturn < 0)
|| (flip == -1 && curturn > 0))
{
badsteerglobal += amount;
amount /= 4;
}
badsteerglobal += amount * flip;
}
static boolean K_BotSteerObjects(mobj_t *thing)
@ -876,7 +907,7 @@ static boolean K_BotSteerObjects(mobj_t *thing)
K_SteerFromObject(botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge));
break;
case MT_RANDOMITEM:
if (anglediff > 90)
if (anglediff >= 60)
{
break;
}
@ -887,7 +918,7 @@ static boolean K_BotSteerObjects(mobj_t *thing)
}
break;
case MT_EGGMANITEM:
if (anglediff > 90)
if (anglediff >= 60)
{
break;
}
@ -908,7 +939,7 @@ static boolean K_BotSteerObjects(mobj_t *thing)
}
break;
case MT_FLOATINGITEM:
if (anglediff > 90)
if (anglediff >= 60)
{
break;
}
@ -920,7 +951,7 @@ static boolean K_BotSteerObjects(mobj_t *thing)
break;
case MT_RING:
case MT_FLINGRING:
if (anglediff > 90)
if (anglediff >= 60)
{
break;
}
@ -932,8 +963,8 @@ static boolean K_BotSteerObjects(mobj_t *thing)
{
K_SteerFromObject(botmo, thing, fulldist, xdist, true,
(RINGTOTAL(botmo->player) < 3
? (2 * (KART_FULLTURN + attack))
: ((KART_FULLTURN + attack) / 2))
? (4 * (KART_FULLTURN + attack))
: (KART_FULLTURN + attack))
);
}
break;
@ -985,7 +1016,7 @@ static boolean K_BotSteerObjects(mobj_t *thing)
fixed_t theirweight = K_GetMobjWeight(thing, botmo);
fixed_t weightdiff = 0;
if (anglediff > 90)
if (anglediff >= 90)
{
weightdiff = theirweight - ourweight;
}
@ -1006,6 +1037,11 @@ static boolean K_BotSteerObjects(mobj_t *thing)
}
break;
case MT_BOTHINT:
if (anglediff >= 60)
{
break;
}
if (thing->extravalue1 == 0)
{
K_SteerFromObject(botmo, thing, fulldist, xdist, false, thing->extravalue2 * (KART_FULLTURN + dodge));
@ -1025,14 +1061,15 @@ static boolean K_BotSteerObjects(mobj_t *thing)
return true;
}
static INT16 K_BotFindObjects(player_t *player)
static INT16 K_BotFindObjects(player_t *player, INT16 turn)
{
INT32 xl, xh, yl, yh, bx, by;
badsteerglobal = 0;
botmo = player->mo;
distancetocheck = (player->mo->radius * 32) + (player->speed * 4);
curturn = turn;
distancetocheck = 2048*mapobjectscale;
xl = (unsigned)(botmo->x - distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(botmo->x + distancetocheck - bmaporgx)>>MAPBLOCKSHIFT;
@ -1409,11 +1446,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
cmd->forwardmove /= 2;
cmd->buttons |= BT_BRAKE;
}
else if (dirdist <= realrad)
{
// Steer towards/away from objects!
turnamt += K_BotFindObjects(player);
}
if (dirdist <= rad)
{
@ -1446,6 +1478,12 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
turnamt /= 4;
}
}
if (anglediff < 60)
{
// Steer towards/away from objects!
turnamt += K_BotFindObjects(player, turnamt);
}
}
}
@ -2169,8 +2207,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
if (turnamt != 0)
{
const INT16 minturn = KART_FULLTURN/2;
if (turnamt > KART_FULLTURN)
{
turnamt = KART_FULLTURN;
@ -2180,26 +2216,39 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
turnamt = -KART_FULLTURN;
}
if ((turnamt > minturn && player->botvars.lastturn >= 0)
|| (turnamt < -minturn && player->botvars.lastturn <= 0))
if (turnamt > 0)
{
if (turnamt > 0)
if (player->botvars.turnconfirm < 0)
{
player->botvars.lastturn = 1;
}
else if (turnamt < 0)
{
player->botvars.lastturn = -1;
// Reset turn confirm
player->botvars.turnconfirm = 0;
}
if (player->botvars.turnconfirm < BOTTURNCONFIRM)
{
player->botvars.turnconfirm++;
}
}
else if (turnamt < 0)
{
if (player->botvars.turnconfirm > 0)
{
// Reset turn confirm
player->botvars.turnconfirm = 0;
}
if (player->botvars.turnconfirm > -BOTTURNCONFIRM)
{
player->botvars.turnconfirm--;
}
}
if (abs(player->botvars.turnconfirm) >= BOTTURNCONFIRM)
{
// You're probably commiting to your turn, here you go.
cmd->driftturn = turnamt;
cmd->angleturn += K_GetKartTurnValue(player, turnamt);
}
else
{
// Can reset turn dir
player->botvars.lastturn = 0;
}
}
if (predict != NULL)

View file

@ -13,8 +13,13 @@
#include "k_waypoint.h"
#include "d_player.h"
// Maximum value of botvars.difficulty
#define MAXBOTDIFFICULTY 9
// How many tics in a row do you need to turn in this direction before we'll let you turn.
// Made it as small as possible without making it look like the bots are twitching constantly.
#define BOTTURNCONFIRM 7
// Path that bot will attempt to take
typedef struct botprediction_s {
fixed_t x, y;

View file

@ -272,7 +272,7 @@ static void P_NetArchivePlayers(void)
WRITEUINT8(save_p, players[i].botvars.difficulty);
WRITEUINT32(save_p, players[i].botvars.itemdelay);
WRITEUINT32(save_p, players[i].botvars.itemconfirm);
WRITEINT16(save_p, players[i].botvars.lastturn);
WRITESINT8(save_p, players[i].botvars.turnconfirm);
}
}
@ -448,7 +448,7 @@ static void P_NetUnArchivePlayers(void)
players[i].botvars.difficulty = READUINT8(save_p);
players[i].botvars.itemdelay = READUINT32(save_p);
players[i].botvars.itemconfirm = READUINT32(save_p);
players[i].botvars.lastturn = READINT16(save_p);
players[i].botvars.turnconfirm = READSINT8(save_p);
}
}