Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADL: Decouple positioning while walking from game logic #1987

Merged
merged 4 commits into from
May 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Source/cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,12 @@ void CheckCursMove()

// Adjust by player offset and tile grid alignment
CalcTileOffset(&xo, &yo);
sx -= ScrollInfo.offset.x - xo;
sy -= ScrollInfo.offset.y - yo;
PlayerStruct *pPlayer = &plr[myplr];
Point offset = ScrollInfo.offset;
if (pPlayer->IsWalking())
offset = GetOffsetForWalking(pPlayer->AnimInfo, pPlayer->_pdir, true);
sx -= offset.x - xo;
sy -= offset.y - yo;

// Predict the next frame when walking to avoid input jitter
fx = plr[myplr].position.offset2.x / 256;
Expand Down
21 changes: 21 additions & 0 deletions Source/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ struct Point {
return *this;
}

Point &operator*=(const float factor)
{
x *= factor;
y *= factor;
return *this;
}

friend Point operator+(Point a, const Point &b)
{
a += b;
Expand All @@ -103,6 +110,20 @@ struct Point {
return a;
}

friend Point operator-(const Point &a)
{
Point b;
b.x = -a.x;
b.y = -a.y;
return b;
}

friend Point operator*(Point a, const float factor)
{
a *= factor;
return a;
}

/**
* @brief Fast approximate distance between two points, using only integer arithmetic, with less than ~5% error
* @param other Pointer to which we want the distance
Expand Down
17 changes: 17 additions & 0 deletions Source/engine/animationinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ int AnimationInfo::GetFrameToUseForRendering() const
return absoluteAnimationFrame;
}

float AnimationInfo::GetAnimationProgress() const
{
if (RelevantFramesForDistributing <= 0) {
// This logic is used if animation distrubtion is not active (see GetFrameToUseForRendering).
// In this case the variables calculated with animation distribution are not initialized and we have to calculate them on the fly with the given informations.
float ticksPerFrame = (DelayLen + 1);
float totalTicksForCurrentAnimationSequence = gfProgressToNextGameTick + (float)CurrentFrame + (DelayCounter / ticksPerFrame);
float fAnimationFraction = totalTicksForCurrentAnimationSequence / ((float)NumberOfFrames * ticksPerFrame);
return fAnimationFraction;
}

float totalTicksForCurrentAnimationSequence = gfProgressToNextGameTick + (float)TicksSinceSequenceStarted;
float fProgressInAnimationFrames = totalTicksForCurrentAnimationSequence * TickModifier;
float fAnimationFraction = fProgressInAnimationFrames / (float)NumberOfFrames;
return fAnimationFraction;
}

void AnimationInfo::SetNewAnimation(byte *pData, int numberOfFrames, int delayLen, AnimationDistributionFlags flags /*= AnimationDistributionFlags::None*/, int numSkippedFrames /*= 0*/, int distributeFramesBeforeFrame /*= 0*/)
{
if ((flags & AnimationDistributionFlags::RepeatedAction) == AnimationDistributionFlags::RepeatedAction && distributeFramesBeforeFrame != 0 && NumberOfFrames == numberOfFrames && CurrentFrame >= distributeFramesBeforeFrame && CurrentFrame != NumberOfFrames) {
Expand Down
5 changes: 5 additions & 0 deletions Source/engine/animationinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ class AnimationInfo {
*/
int GetFrameToUseForRendering() const;

/**
* @brief Calculates the progress of the current animation as a fraction (0.0f to 1.0f)
*/
float GetAnimationProgress() const;

/**
* @brief Sets the new Animation with all relevant information for rendering
* @param pData Pointer to Animation Data
Expand Down
13 changes: 13 additions & 0 deletions Source/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,19 @@ void PlayerStruct::Stop()
destAction = ACTION_NONE;
}

bool PlayerStruct::IsWalking() const
{
switch (_pmode)
{
case PM_WALK:
case PM_WALK2:
case PM_WALK3:
return true;
default:
return false;
}
}

void SetPlayerGPtrs(byte *pData, byte **pAnim)
{
int i;
Expand Down
5 changes: 5 additions & 0 deletions Source/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,11 @@ struct PlayerStruct {
* opening a chest, picking an item up, etc) this action will also be cancelled.
*/
void Stop();

/**
* @brief Is the player currently walking?
*/
bool IsWalking() const;
};

extern int myplr;
Expand Down
46 changes: 42 additions & 4 deletions Source/scrollrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,36 @@ const char *const szPlrModeAssert[] = {
"quitting"
};

Point GetOffsetForWalking(const AnimationInfo &animationInfo, const direction dir, bool cameraMode /*= false*/)
{
// clang-format off
// DIR_S, DIR_SW, DIR_W, DIR_NW, DIR_N, DIR_NE, DIR_E, DIR_SE,
constexpr Point startOffset[8] = { { 0, -32 }, { 32, -16 }, { 32, -16 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { -32, -16 }, { -32, -16 } };
constexpr Point movingOffset[8] = { { 0, 32 }, { -32, 16 }, { -64, 0 }, { -32, -16 }, { 0, -32 }, { 32, -16 }, { 64, 0 }, { 32, 16 } };
constexpr bool isDiagionalWalk[8] = { false, true, false, true, false, true, false, true };
// clang-format on

float fAnimationProgress = animationInfo.GetAnimationProgress();
Point offset = movingOffset[dir];
offset *= fAnimationProgress;

// In diagonal walks the offset for y is smaller then x.
// This means that sometimes x is updated but y not.
// That result in a small stuttering.
// To fix this we disallow odd x as this is the only case where y is not updated.
if (isDiagionalWalk[dir] && ((offset.x % 2) != 0)) {
offset.x -= offset.x > 0 ? 1 : -1;
}

if (cameraMode) {
offset = -offset;
} else {
offset += startOffset[dir];
}

return offset;
}

/**
* @brief Clear cursor state
*/
Expand Down Expand Up @@ -677,8 +707,12 @@ static void DrawPlayerHelper(const CelOutputBuffer &out, int x, int y, int sx, i
}

PlayerStruct *pPlayer = &plr[p];
int px = sx + pPlayer->position.offset.x - CalculateWidth2(pPlayer->_pAnimWidth);
int py = sy + pPlayer->position.offset.y;
Point offset = ScrollInfo.offset;
if (pPlayer->IsWalking()) {
offset = GetOffsetForWalking(pPlayer->AnimInfo, pPlayer->_pdir);
AJenbo marked this conversation as resolved.
Show resolved Hide resolved
}
int px = sx + offset.x - CalculateWidth2(pPlayer->_pAnimWidth);
int py = sy + offset.y;

DrawPlayer(out, p, x, y, px, py);
}
Expand Down Expand Up @@ -1107,8 +1141,12 @@ static void DrawGame(const CelOutputBuffer &full_out, int x, int y)
: full_out.subregionY(0, (gnViewportHeight + 1) / 2);

// Adjust by player offset and tile grid alignment
sx = ScrollInfo.offset.x + tileOffsetX;
sy = ScrollInfo.offset.y + tileOffsetY;
PlayerStruct *pPlayer = &plr[myplr];
Point offset = ScrollInfo.offset;
if (pPlayer->IsWalking())
offset = GetOffsetForWalking(pPlayer->AnimInfo, pPlayer->_pdir, true);
sx = offset.x + tileOffsetX;
sy = offset.y + tileOffsetY;

columns = tileColums;
rows = tileRows;
Expand Down
9 changes: 9 additions & 0 deletions Source/scrollrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <cstdint>

#include "engine/animationinfo.h"
#include "engine.h"

namespace devilution {
Expand Down Expand Up @@ -35,6 +36,14 @@ extern bool cel_foliage_active;
extern int level_piece_id;
extern bool AutoMapShowItems;

/**
* @brief Returns the offset for the walking animation
* @param animationInfo the current active walking animation
* @param dir walking direction
* @param cameraMode Adjusts the offset relative to the camera
*/
Point GetOffsetForWalking(const AnimationInfo &animationInfo, const direction dir, bool cameraMode = false);

void ClearCursor();
void ShiftGrid(int *x, int *y, int horizontal, int vertical);
int RowsCoveredByPanel();
Expand Down
2 changes: 1 addition & 1 deletion Source/track.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void track_process()
if (cursmx < 0 || cursmx >= MAXDUNX - 1 || cursmy < 0 || cursmy >= MAXDUNY - 1)
return;

if (plr[myplr].AnimInfo.GetFrameToUseForRendering() <= 6 || (plr[myplr]._pmode != PM_WALK && plr[myplr]._pmode != PM_WALK2 && plr[myplr]._pmode != PM_WALK3 && plr[myplr]._pmode != PM_STAND))
if (plr[myplr].AnimInfo.GetFrameToUseForRendering() <= 6 || (!plr[myplr].IsWalking() && plr[myplr]._pmode != PM_STAND))
return;

const Point target = plr[myplr].GetTargetPosition();
Expand Down