【发布时间】:2012-01-16 06:05:08
【问题描述】:
我正在使用 SDL 库在 C++ 中编写一个简单的 roguelike 游戏,但在屏幕上移动我的角色时遇到了一些问题。每次需要渲染一帧时,我都会使用 update() 函数更新精灵的位置,如果玩家静止不动,该函数不会执行任何操作。为了发出移动命令,从而启动动画,我使用 step() 函数,每次玩家从一个瓷砖移动到另一个瓷砖时只调用一次。收到“向上”命令后,游戏表现良好,角色在一秒钟内平稳移动到新位置。然而,在下达“下”命令的时候,他以大约一半的速度移动,显然一秒过去后,他瞬间被“传送”到了最终位置,突然闪烁了一下。运动的代码基本相同,但在一种情况下,增量运动与 y 位置相加,在另一种情况下被减去。也许位置是整数而增量是双精度的事实会引起问题? sum 和 subract 的行为是否不同(可能是不同的舍入)?以下是相关代码(见长见谅):
void Player::step(Player::Direction dir)
{
if(m_status != STANDING) // no animation while standing
return;
switch(dir)
{
case UP:
if(m_currMap->tileAt(m_xPos, m_yPos - m_currMap->tileHeight())->m_type == Tile::FLOOR)
{
// if next tile is not a wall, set up animation
m_status = WALKING_UP;
m_yDelta = m_currMap->tileHeight(); // sprite have to move by a tile
m_yVel = m_currMap->tileHeight() / 1000.0f; // in one second
m_yNext = m_yPos - m_currMap->tileHeight(); // store final destination
}
break;
case DOWN:
if(m_currMap->tileAt(m_xPos, m_yPos + m_currMap->tileHeight())->m_type == Tile::FLOOR)
{
m_status = WALKING_DOWN;
m_yDelta = m_currMap->tileHeight();
m_yVel = m_currMap->tileHeight() / 1000.0f;
m_yNext = m_yPos + m_currMap->tileHeight();
}
break;
//...
default:
break;
}
m_animTimer = SDL_GetTicks();
}
void Player::update()
{
m_animTimer = SDL_GetTicks() - m_animTimer; // get the ms passed since last update
switch(m_status)
{
case WALKING_UP:
m_yPos -= m_yVel * m_animTimer; // update position
m_yDelta -= m_yVel * m_animTimer; // update the remaining space
break;
case WALKING_DOWN:
m_yPos += m_yVel * m_animTimer;
m_yDelta -= m_yVel * m_animTimer;
break;
//...
default:
break;
}
if(m_xDelta <= 0 && m_yDelta <= 0) // if i'm done moving
{
m_xPos = m_xNext; // adjust position
m_yPos = m_yNext;
m_status = STANDING; // and stop
}
else
m_animTimer = SDL_GetTicks(); // else update timer
}
编辑:我删除了一些变量,只留下了经过的时间、速度和最终位置。现在它移动没有闪烁,但向下和向右移动明显比向上和向左移动慢。仍然想知道为什么...
编辑 2: 好的,我知道为什么会这样了。正如我首先想到的那样,当涉及到和和减法时,从双精度到整数有不同的舍入。如果我执行这样的演员:
m_xPos += (int)(m_xVel * m_animTimer);
动画速度一样,问题就解决了。
【问题讨论】:
-
可能是错误的,但是在
Player::update中,在WALKING_DOWN的情况下,两行不应该使用+=而不是-=吗?我只是猜测WALKING_DOWN应该与WALKING_UP完全相反。不确定这是否与您的问题有关。 -
@KenWayneVanderLinde m_yDelta 变量存储要步行到达该位置的剩余像素,因此在这两种情况下都应该递减。
-
m_yPos、m_yVel和m_animTimer的类型是什么?而且,我认为m_animTimer应该始终更新,否则您将在下次调用update时获得虚假价值。 -
@Banthar
m_yPos是一个整数,如m_animTimer,而m_yVel是一个双精度数。m_animTimer会在玩家处于移动状态的每一帧中更新。仅当WALKING_DOWN状态为当前状态时才会显示问题,因此我认为计时器不是问题。 -
如果
m_yDelta实际上是在一秒钟内完成的步骤,并且速度包含在该计算中,则更好的方法是。然后,您通过将 delta 乘以 animTimer 来更新m_yPos,并且 delta 永远不会改变。那将是每秒一个恒定的步骤。 (免责声明:我可能在这里说了一些废话,我现在有点困。)