奇怪的行为更新精灵位置

Pie*_*ice 6 c++ sdl

我正在使用SDL库在C++中编写一个简单的roguelike游戏,我在屏幕上移动我的角色时遇到了一些问题.每次需要渲染帧时,我都会使用update()函数更新精灵的位置,如果玩家静止不动,则不会执行任何操作.为了发出移动命令,从而开始动画,我使用每个玩家从一个瓦片移动到另一个瓦片时只调用一次的step()函数.在接收到"向上"命令时,游戏表现良好并且角色在一秒内平稳地移动到新位置.然而,当给出"向下"命令时,他以大约一半的速度移动,并且显然在经过一秒之后,他立即被"传送"到最终位置,突然闪烁.移动的代码基本相同,但是在一种情况下,delta移动被加到y位置,在另一种情况下被减去.也许这个位置是一个整数并且delta是一个双倍的事实会导致问题?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
}
Run Code Online (Sandbox Code Playgroud)

编辑:我删除了一些变量,只剩下经过的时间,速度和最终位置.现在它移动时没有闪烁,但向下和向右移动明显慢于向上和向左移动.还在想为什么......

编辑2:好的,我弄清楚为什么会这样.正如我所假设的那样,当涉及到求和减法时,有一个从double到integer的不同舍入.如果我执行这样的演员:

m_xPos += (int)(m_xVel * m_animTimer);
Run Code Online (Sandbox Code Playgroud)

动画速度是一样的,问题解决了.

bre*_*anw 3

考虑以下:

#include <iostream>

void main()
{
    int a = 1, b = 1;
    a += 0.1f;
    b -= 0.1f;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

当a和b被赋值时,在float到int的隐式转换过程中,小数点之后的所有内容都将被截断而不是四舍五入。该程序的结果是:

1
0
Run Code Online (Sandbox Code Playgroud)

您说过 m_yPos 是整数,m_yVel 是双精度数。Player::update考虑如果 的结果m_yVel * m_animTimer小于 1会发生什么。在UP这种情况下,结果将是你的精灵向下移动一个像素,但在这种DOWN情况下,你的精灵根本不会移动,因为如果你添加的值小于 1为整数时,什么也不会发生。尝试将您的位置存储为双精度数,并且仅在需要将它们传递给绘图函数时将它们转换为整数。

为了确保在转换期间进行舍入而不是截断,可以采用的一个技巧是在分配给整数期间始终将浮点值添加 0.5。

例如:

double d1 = 1.2;
double d2 = 1.6;
int x = d1 + 0.5;
int y = d2 + 0.5;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,x 将变为 1,而 y 将变为 2。