otclient
otclient copied to clipboard
[10.98] Creatures on screen appears to be dashing/teleporting to next tile when walking
Videos
- Super slow motion troll going from up to down and comparing with real gif and sprites: https://streamable.com/2xek1
- Super slow motion troll going from right to left:
https://streamable.com/wmv6e - Gif and sprites of troll going from up to down:
https://ezgif.com/split/ezgif-1-1c80fb2cf982.gif
Description There are 3 big issues on moving animations on client:
- local player walking and idle animations
- creatures being pushed diagonally
- creatures on screen appears to be dashing/teleporting to next tile when walking
The first two can be fixed to work almost like real tibia 10.98, and the fixes are different things. The third I don't know how to solve.
My guess is that creatures that aren't the local player are being drawn with wrong position or wrong speed and then when the creature reach the next tile position on server side the creature position on client side is refreshed (you can see that Troll's name and health bar teleports too, so its not a problem on skipping frames, its skipping positions) without the sprite reaching it.
I've seen that the information sent from server to client is just the oldPos and the newPos, on client the sprites are rendered using the oldPos + newPos + gettingStepDuration() + totalPixelsWalked (something like that) and I verified the getStepDuration() formula from client sources and server sources and they look almost the same thing... I'm kind of lost here
Edit: I've counted frames and it looks like 5 frames are being used and then the creature teleports to the next tile and reset to the first frame.
To Reproduce See monsters or players walking on screen
Expected behavior A smooth and continuous movement without skipping positions.
Environment
- Latest OTClient
- Protocol 10.98
- Windows 10
Additional context
- https://github.com/edubart/otclient/issues/937
- https://otland.net/threads/animations-lets-give-it-a-try.262781/
- https://github.com/otland/otclient/compare/master...otland:WalkAnimation?expand=1 @ninjalulz solution for local player walking animation (I changed it a little to my client)
I fixed the local player walking and idle animation issue using ninjalulz's solution and fixed the pushing diagonal laggy issue (https://i.gyazo.com/412d93e4a799cdc93fd098c04001d7e2.mp4) setting the factor from getStepDuration() (in creature.cpp in client sources) to 1.
I think I found the bug.
creature.cpp:
I changed the return value of this function to 80% of the original value.
The factor is commented to solve the pushing diagonal laggy issue.
This line interval = std::ceil(interval / (50 * 1.f)) * 50;
uses 50
cause I use TFS 1.3.
int Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir)
{
int speed = m_speed;
if(speed < 1)
return 0;
if(g_game.getFeature(Otc::GameNewSpeedLaw))
speed *= 2;
int groundSpeed = 0;
Position tilePos;
if(dir == Otc::InvalidDirection)
tilePos = m_lastStepToPosition;
else
tilePos = m_position.translatedToDirection(dir);
if(!tilePos.isValid())
tilePos = m_position;
const TilePtr& tile = g_map.getTile(tilePos);
if(tile) {
groundSpeed = tile->getGroundSpeed();
if(groundSpeed == 0)
groundSpeed = 150;
}
int interval = 1000;
if(groundSpeed > 0 && speed > 0)
interval = 1000 * groundSpeed;
if(g_game.getFeature(Otc::GameNewSpeedLaw) && hasSpeedFormula()) {
int formulatedSpeed = 1;
if(speed > -m_speedFormula[Otc::SpeedFormulaB]) {
formulatedSpeed = std::max<int>(1, (int)floor((m_speedFormula[Otc::SpeedFormulaA] * log((speed / 2)
+ m_speedFormula[Otc::SpeedFormulaB]) + m_speedFormula[Otc::SpeedFormulaC]) + 0.5));
}
interval = std::floor(interval / (double)formulatedSpeed);
}
else
interval /= speed;
if(g_game.getClientVersion() >= 900)
interval = std::ceil(interval / (50 * 1.f)) * 50;
//float factor = 3;
//if(g_game.getClientVersion() <= 810)
// factor = 2;
//interval = std::max<int>(interval, g_game.getServerBeat());
//if(!ignoreDiagonal && (m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast ||
// m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast))
// interval *= factor;
if (this->isLocalPlayer()) {
return interval;
}
return (int)interval*0.8f;
}
My updateWalkAnimation function based on ninjalulz fix for walking and idle animations
void Creature::updateWalkAnimation(int totalPixelsWalked)
{
// update outfit animation
if(m_outfit.getCategory() != ThingCategoryCreature)
return;
int footAnimPhases = getAnimationPhases() - 1; //returns 8
float footDelay = getStepDuration(true) / footAnimPhases; //varies with the g round
// since mount is a different outfit we need to get the mount animation phases
if(m_outfit.getMount() != 0) {
ThingType *type = g_things.rawGetThingType(m_outfit.getMount(), m_outfit.getCategory());
footAnimPhases = type->getAnimationPhases() - 1;
footDelay = getStepDuration(true) / footAnimPhases;
}
if (totalPixelsWalked >= 32 && !m_walkFinishAnimEvent) {
m_footStep = 0;
auto self = static_self_cast<Creature>();
m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] {
if (!self->m_walking || self->m_walkTimer.ticksElapsed() >= self->getStepDuration(true)) {
self->m_walkAnimationPhase = 0;
}
self->m_walkFinishAnimEvent = nullptr;
}, std::min<int>(footDelay, 200));
}
if (footAnimPhases == 0) {
m_walkAnimationPhase = 0;
}
else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= footDelay && totalPixelsWalked < 32) {
m_footStep++;
m_walkAnimationPhase = (m_footStep % footAnimPhases);
m_footStepDrawn = false;
m_footTimer.restart();
}
else if(m_walkAnimationPhase == 0 && totalPixelsWalked < 32) {
m_walkAnimationPhase = (m_footStep % footAnimPhases);
}
}
Videos https://streamable.com/2gq1h https://streamable.com/j679m
Conclusion Client creature speed values are treated different from server creature speed values or the getStepDuration is wrong on client or server sources.
@GustavoContreiras I tested, and it was perfect! Thank you very much, brother, for sharing the content. For more people like you! Thanks!!!
Hey, nice that you found a fix, is that related to https://github.com/otland/otclient/pull/45? If not, can you please submit pull request with your fixes so we can review them?
Hey, nice that you found a fix, is that related to #45? If not, can you please submit pull request with your fixes so we can review them?
I think it's related. I'm not coding for OTClient has more then 1 year.. you're free to make the commit with my fix
for me it's a little suspicious that we always getStepDuration(true)
ignore diagonal when we calculate animation speed.
Anyway I don't think that updateWalkAnimation
is related to the non smooth diagonal movement. At least it shouldn't. After all it only decides which part of the sprite to show, not where on the screen it should be. If position update is somehow related to animation frames, then something else is wrong.
int footAnimPhases = getAnimationPhases() - 1; //returns 8
That's not true. It can return 1, any even number between 2 and 8 maybe more. And also 0 for some broken things.
@nekiro https://github.com/otland/otclient/pull/50