From 2ddc442e48e4bb1c9e4e46d8fe924a7ebd333a5a Mon Sep 17 00:00:00 2001 From: Mitchell Richters Date: Sat, 4 Apr 2020 15:31:27 +1100 Subject: [PATCH] Exhumed: Improve player input. - Input velocity now consistent irrespective of frame rate. - Angle and horizon calculated at frame rate. - Replace usage of F16() macro with fix16_from_int() in GetInterruptKeys(). Note: Known issues with look up/down keys that is to be repaired. --- source/exhumed/src/exhumed.cpp | 56 ++++--- source/exhumed/src/player.cpp | 260 ++++++++++++++++----------------- source/exhumed/src/ps_input.h | 1 + source/exhumed/src/view.cpp | 9 +- 4 files changed, 158 insertions(+), 168 deletions(-) diff --git a/source/exhumed/src/exhumed.cpp b/source/exhumed/src/exhumed.cpp index 668e0bd20..5ce21f91b 100644 --- a/source/exhumed/src/exhumed.cpp +++ b/source/exhumed/src/exhumed.cpp @@ -480,6 +480,7 @@ enum gametokens }; int exhumed_globalflags; +PlayerInput localInput; static int parsedefinitions_game(scriptfile *, int); @@ -794,18 +795,6 @@ void I_Error(const char *fmt, ...) throw std::runtime_error(buf); } -void faketimerhandler() -{ - if ((totalclock < ototalclock + 1) || bInMove) - return; - ototalclock = ototalclock + 1; - - if (!((int)ototalclock&3) && moveframes < 4) - moveframes++; - - PlayerInterruptKeys(); -} - void timerhandler() { UpdateSounds(); @@ -1549,7 +1538,6 @@ static void GameDisplay(void) // End Section B SetView1(); - faketimerhandler(); if (levelnum == kMap20) { @@ -2309,18 +2297,31 @@ GAMELOOP: } else { - static bool frameJustDrawn; bInMove = kTrue; - if (!bPause && totalclock >= tclocks + 4 && !GUICapture) - { - do - { - if (!frameJustDrawn) - break; - frameJustDrawn = false; + if (GUICapture || bPause) + { + totalclock = tclocks + 4; + } + else + { + while ((totalclock - ototalclock) >= 1 || !bInMove) + { + ototalclock = ototalclock + 1; + + if (!((int)ototalclock&3) && moveframes < 4) + moveframes++; GetLocalInput(); + PlayerInterruptKeys(); + + nPlayerDAng = fix16_sadd(nPlayerDAng, localInput.nAngle); + inita &= kAngleMask; + + lPlayerXVel += localInput.yVel * Cos(inita) + localInput.xVel * Sin(inita); + lPlayerYVel += localInput.yVel * Sin(inita) - localInput.xVel * Cos(inita); + lPlayerXVel -= (lPlayerXVel >> 5) + (lPlayerXVel >> 6); + lPlayerYVel -= (lPlayerYVel >> 5) + (lPlayerYVel >> 6); sPlayerInput[nLocalPlayer].xVel = lPlayerXVel; sPlayerInput[nLocalPlayer].yVel = lPlayerYVel; @@ -2335,27 +2336,22 @@ GAMELOOP: sPlayerInput[nLocalPlayer].horizon = nVertPan[nLocalPlayer]; - do + while (levelnew < 0 && totalclock >= tclocks + 4) { // timerUpdate(); tclocks += 4; GameMove(); // timerUpdate(); - } while (levelnew < 0 && totalclock >= tclocks + 4); - } while (0); - } - else if (GUICapture || bPause) - { - totalclock = tclocks + 4; + } + } } bInMove = kFalse; - faketimerhandler(); + PlayerInterruptKeys(); if (G_FPSLimit()) { GameDisplay(); - frameJustDrawn = true; } } if (!bInDemo) diff --git a/source/exhumed/src/player.cpp b/source/exhumed/src/player.cpp index 872781e0f..f4b2d6ede 100644 --- a/source/exhumed/src/player.cpp +++ b/source/exhumed/src/player.cpp @@ -161,6 +161,9 @@ void PlayerInterruptKeys() CONTROL_GetInput(&info); D_ProcessEvents(); + localInput = {}; + PlayerInput input {}; + if (PlayerList[nLocalPlayer].nHealth == 0) { lPlayerYVel = 0; @@ -175,44 +178,50 @@ void PlayerInterruptKeys() int const keyMove = playerRunning ? 12 : 6; constexpr int const analogTurnAmount = 12; constexpr int const analogExtent = 32767; // KEEPINSYNC sdlayer.cpp - int fvel = 0, svel = 0; - fix16_t q16avel = 0, q16horz = 0; if (buttonMap.ButtonDown(gamefunc_Strafe)) { static int strafeyaw; - svel = -(info.mousex + strafeyaw) >> 6; + input.xVel = -(info.mousex + strafeyaw) >> 6; strafeyaw = (info.mousex + strafeyaw) % 64; - svel -= info.dyaw * keyMove / analogExtent; + input.xVel -= info.dyaw * keyMove / analogExtent; } else { - q16avel = fix16_div(fix16_from_int(info.mousex), F16(32)); - q16avel += fix16_from_int(info.dyaw) / analogExtent * (analogTurnAmount << 1); + input.nAngle = fix16_sadd(input.nAngle, fix16_sdiv(fix16_from_int(info.mousex), fix16_from_int(32))); + input.nAngle = fix16_sadd(input.nAngle, fix16_from_int(info.dyaw / analogExtent * (analogTurnAmount << 1))); } g_MyAimMode = in_mousemode || buttonMap.ButtonDown(gamefunc_Mouse_Aiming); if (g_MyAimMode) - q16horz = fix16_div(fix16_from_int(info.mousey), F16(64)); + input.horizon = fix16_sadd(input.horizon, fix16_sdiv(fix16_from_int(info.mousey), fix16_from_int(64))); else - fvel = -(info.mousey >> 6); + input.yVel = -(info.mousey >> 6); - if (!in_mouseflip) q16horz = -q16horz; + if (!in_mouseflip) input.horizon = -input.horizon; - q16horz -= fix16_from_int(info.dpitch) / analogExtent * analogTurnAmount; - svel -= info.dx * keyMove / analogExtent; - fvel -= info.dz * keyMove / analogExtent; + input.horizon = fix16_ssub(input.horizon, fix16_from_int(info.dpitch * analogTurnAmount / analogExtent)); + input.xVel -= info.dx * keyMove / analogExtent; + input.yVel -= info.dz * keyMove / analogExtent; + + static double lastInputTicks; + auto const currentHiTicks = timerGetHiTicks(); + double const elapsedInputTicks = currentHiTicks - lastInputTicks; + + lastInputTicks = currentHiTicks; + + auto scaleAdjustmentToInterval = [=](double x) { return x * 120 / (1000.0 / elapsedInputTicks); }; if (buttonMap.ButtonDown(gamefunc_Strafe)) { if (buttonMap.ButtonDown(gamefunc_Turn_Left)) - svel -= -keyMove; + input.xVel -= -keyMove; if (buttonMap.ButtonDown(gamefunc_Turn_Right)) - svel -= keyMove; + input.xVel -= keyMove; } else { @@ -249,42 +258,130 @@ void PlayerInterruptKeys() } //if ((counter++) % 4 == 0) // what was this for??? - q16avel += fix16_from_int(turn*2); + input.nAngle = fix16_sadd(input.nAngle, fix16_from_float(scaleAdjustmentToInterval(turn * 2))); } if (buttonMap.ButtonDown(gamefunc_Strafe_Left)) - svel += keyMove; + input.xVel += keyMove; if (buttonMap.ButtonDown(gamefunc_Strafe_Right)) - svel += -keyMove; + input.xVel += -keyMove; if (buttonMap.ButtonDown(gamefunc_Move_Forward)) - fvel += keyMove; + input.yVel += keyMove; if (buttonMap.ButtonDown(gamefunc_Move_Backward)) - fvel += -keyMove; + input.yVel += -keyMove; - fvel = clamp(fvel, -12, 12); - svel = clamp(svel, -12, 12); + localInput.yVel = clamp(localInput.yVel + input.yVel, -12, 12); + localInput.xVel = clamp(localInput.xVel + input.xVel, -12, 12); + localInput.nAngle = fix16_sadd(localInput.nAngle, input.nAngle); - nPlayerDAng += q16avel; - - inita &= kAngleMask; - - lPlayerXVel += fvel * Cos(inita) + svel * Sin(inita); - lPlayerYVel += fvel * Sin(inita) - svel * Cos(inita); - - lPlayerXVel -= (lPlayerXVel >> 5) + (lPlayerXVel >> 6); - lPlayerYVel -= (lPlayerYVel >> 5) + (lPlayerYVel >> 6); + PlayerList[nLocalPlayer].q16angle = fix16_sadd(PlayerList[nLocalPlayer].q16angle, input.nAngle) & 0x7FFFFFF; + PlayerList[nLocalPlayer].q16horiz = fix16_clamp(fix16_sadd(PlayerList[nLocalPlayer].q16horiz, input.horizon), fix16_from_int(0), fix16_from_int(184)); // A horiz diff of 128 equal 45 degrees, // so we convert horiz to 1024 angle units - float horizAngle = atan2f(nVertPan[nLocalPlayer] - F16(92), F16(128)) * (512.f / fPI) + fix16_to_float(q16horz); + float horizAngle = atan2f(nVertPan[nLocalPlayer] - fix16_from_int(92), fix16_from_int(128)) * (512.f / fPI) + scaleAdjustmentToInterval(fix16_to_float(input.horizon)); horizAngle = clamp(horizAngle, -255.f, 255.f); - nVertPan[nLocalPlayer] = fix16_clamp(F16(92) + Blrintf(F16(128) * tanf(horizAngle * (fPI / 512.f))), F16(0), F16(184)); + nVertPan[nLocalPlayer] = fix16_clamp(fix16_from_int(92) + Blrintf(fix16_from_int(128) * tanf(horizAngle * (fPI / 512.f))), fix16_from_int(0), fix16_from_int(184)); + // TODO - tidy / consolidate repeating blocks of code here? + if (buttonMap.ButtonDown(gamefunc_Look_Up)) + { + bLockPan = kFalse; + if (nVertPan[nLocalPlayer] < fix16_from_int(180)) { + nVertPan[nLocalPlayer] = fix16_sadd(nVertPan[nLocalPlayer], fix16_from_float(scaleAdjustmentToInterval(4))); + } + + bPlayerPan = kTrue; + nDestVertPan[nLocalPlayer] = nVertPan[nLocalPlayer]; + } + else if (buttonMap.ButtonDown(gamefunc_Look_Down)) + { + bLockPan = kFalse; + if (nVertPan[nLocalPlayer] > fix16_from_int(4)) { + nVertPan[nLocalPlayer] = fix16_ssub(nVertPan[nLocalPlayer], fix16_from_float(scaleAdjustmentToInterval(4))); + } + + bPlayerPan = kTrue; + nDestVertPan[nLocalPlayer] = nVertPan[nLocalPlayer]; + } + else if (buttonMap.ButtonDown(gamefunc_Look_Straight)) + { + bLockPan = kFalse; + bPlayerPan = kFalse; + nVertPan[nLocalPlayer] = fix16_from_int(92); + nDestVertPan[nLocalPlayer] = fix16_from_int(92); + } + else if (buttonMap.ButtonDown(gamefunc_Aim_Up)) + { + bLockPan = kTrue; + if (nVertPan[nLocalPlayer] < fix16_from_int(180)) { + nVertPan[nLocalPlayer] = fix16_sadd(nVertPan[nLocalPlayer], fix16_from_float(scaleAdjustmentToInterval(4))); + } + + bPlayerPan = kTrue; + nDestVertPan[nLocalPlayer] = nVertPan[nLocalPlayer]; + } + else if (buttonMap.ButtonDown(gamefunc_Aim_Down)) + { + bLockPan = kTrue; + if (nVertPan[nLocalPlayer] > fix16_from_int(4)) { + nVertPan[nLocalPlayer] = fix16_ssub(nVertPan[nLocalPlayer], fix16_from_float(scaleAdjustmentToInterval(4))); + } + + bPlayerPan = kTrue; + nDestVertPan[nLocalPlayer] = nVertPan[nLocalPlayer]; + } + + // loc_1C048: + if (totalvel[nLocalPlayer] > 20) { + bPlayerPan = kFalse; + } + + if (g_MyAimMode) + bLockPan = kTrue; + + // loc_1C05E + fix16_t ecx = fix16_ssub(nDestVertPan[nLocalPlayer], PlayerList[nLocalPlayer].q16horiz); + + if (g_MyAimMode) + { + ecx = 0; + } + + if (ecx) + { + if (ecx / 4 == 0) + { + if (ecx >= 0) { + ecx = 1; + } + else + { + ecx = -1; + } + } + else + { + ecx /= 4; + + if (ecx > fix16_from_int(4)) + { + ecx = fix16_from_int(4); + } + else if (ecx < -fix16_from_int(4)) + { + ecx = -fix16_from_int(4); + } + } + + nVertPan[nLocalPlayer] = fix16_sadd(nVertPan[nLocalPlayer], ecx); + PlayerList[nLocalPlayer].q16horiz = fix16_clamp(nVertPan[nLocalPlayer], fix16_from_int(0), fix16_from_int(184)); + } } void RestoreSavePoint(int nPlayer, int *x, int *y, int *z, short *nSector, short *nAngle) @@ -1080,8 +1177,6 @@ void FuncPlayer(int a, int nDamage, int nRun) } // loc_1A494: - PlayerList[nPlayer].q16angle = (PlayerList[nPlayer].q16angle + sPlayerInput[nPlayer].nAngle) & 0x7FFFFFF; - PlayerList[nPlayer].q16horiz = sPlayerInput[nPlayer].horizon; sprite[nPlayerSprite].ang = fix16_to_int(PlayerList[nPlayer].q16angle); // sprite[nPlayerSprite].zvel is modified within Gravity() @@ -2845,103 +2940,6 @@ loc_1BD2E: PlayerList[nPlayer].nAction = nActionB; PlayerList[nPlayer].field_2 = 0; } - - if (nPlayer == nLocalPlayer) - { - // TODO - tidy / consolidate repeating blocks of code here? - if (buttonMap.ButtonDown(gamefunc_Look_Up)) - { - bLockPan = kFalse; - if (nVertPan[nPlayer] < F16(180)) { - nVertPan[nPlayer] += F16(4); - } - - bPlayerPan = kTrue; - nDestVertPan[nPlayer] = nVertPan[nPlayer]; - } - else if (buttonMap.ButtonDown(gamefunc_Look_Down)) - { - bLockPan = kFalse; - if (nVertPan[nPlayer] > F16(4)) { - nVertPan[nPlayer] -= F16(4); - } - - bPlayerPan = kTrue; - nDestVertPan[nPlayer] = nVertPan[nPlayer]; - } - else if (buttonMap.ButtonDown(gamefunc_Look_Straight)) - { - bLockPan = kFalse; - bPlayerPan = kFalse; - nVertPan[nPlayer] = F16(92); - nDestVertPan[nPlayer] = F16(92); - } - else if (buttonMap.ButtonDown(gamefunc_Aim_Up)) - { - bLockPan = kTrue; - if (nVertPan[nPlayer] < F16(180)) { - nVertPan[nPlayer] += F16(4); - } - - bPlayerPan = kTrue; - nDestVertPan[nPlayer] = nVertPan[nPlayer]; - } - else if (buttonMap.ButtonDown(gamefunc_Aim_Down)) - { - bLockPan = kTrue; - if (nVertPan[nPlayer] > F16(4)) { - nVertPan[nPlayer] -= F16(4); - } - - bPlayerPan = kTrue; - nDestVertPan[nPlayer] = nVertPan[nPlayer]; - } - - // loc_1C048: - if (totalvel[nPlayer] > 20) { - bPlayerPan = kFalse; - } - - if (g_MyAimMode) - bLockPan = kTrue; - - // loc_1C05E - fix16_t ecx = nDestVertPan[nPlayer] - nVertPan[nPlayer]; - - if (g_MyAimMode) - { - ecx = 0; - } - - if (ecx) - { - if (ecx / 4 == 0) - { - if (ecx >= 0) { - ecx = 1; - } - else - { - ecx = -1; - } - } - else - { - ecx /= 4; - - if (ecx > F16(4)) - { - ecx = F16(4); - } - else if (ecx < -F16(4)) - { - ecx = -F16(4); - } - } - - nVertPan[nPlayer] += ecx; - } - } } else // else, player's health is less than 0 { diff --git a/source/exhumed/src/ps_input.h b/source/exhumed/src/ps_input.h index d83b9c266..0cd009631 100644 --- a/source/exhumed/src/ps_input.h +++ b/source/exhumed/src/ps_input.h @@ -62,6 +62,7 @@ void ClearSpaceBar(short nPlayer); void GetLocalInput(); extern PlayerInput sPlayerInput[]; +extern PlayerInput localInput; extern int nNetMoves; END_PS_NS diff --git a/source/exhumed/src/view.cpp b/source/exhumed/src/view.cpp index 30cc6c0cc..c9663f077 100644 --- a/source/exhumed/src/view.cpp +++ b/source/exhumed/src/view.cpp @@ -334,11 +334,6 @@ static inline int interpolate16(int a, int b, int smooth) return a + mulscale16(b - a, smooth); } -static inline fix16_t q16angle_interpolate16(fix16_t a, fix16_t b, int smooth) -{ - return a + mulscale16(((b+F16(1024)-a)&0x7FFFFFF)-F16(1024), smooth); -} - void DrawView(int smoothRatio, bool sceneonly) { int playerX; @@ -396,7 +391,7 @@ void DrawView(int smoothRatio, bool sceneonly) playerZ = interpolate16(PlayerList[nLocalPlayer].opos.z, sprite[nPlayerSprite].z, smoothRatio) + interpolate16(oeyelevel[nLocalPlayer], eyelevel[nLocalPlayer], smoothRatio); nSector = nPlayerViewSect[nLocalPlayer]; - nAngle = q16angle_interpolate16(PlayerList[nLocalPlayer].q16oangle, PlayerList[nLocalPlayer].q16angle, smoothRatio); + nAngle = PlayerList[nLocalPlayer].q16angle; if (!bCamera) { @@ -420,7 +415,7 @@ void DrawView(int smoothRatio, bool sceneonly) int floorZ = sector[sprite[nPlayerSprite].sectnum].floorz; // pan = nVertPan[nLocalPlayer]; - pan = interpolate16(PlayerList[nLocalPlayer].q16ohoriz, PlayerList[nLocalPlayer].q16horiz, smoothRatio); + pan = PlayerList[nLocalPlayer].q16horiz; if (viewz > floorZ) viewz = floorZ;