C ++如何使速度在所有方向上相等?

时间:2013-07-17 11:04:05

标签: c++ sdl

我觉得这是一个难以表达的问题,所以我在这个图上说明了(我在C ++中使用SDL)。 每个方块代表屏幕上的一个像素,我希望红色像素以相同的速度移动而不管方向。

如果速度为8像素/秒,则在1秒后:

  • 如果用户输入正确或向下,则像素将到达标记为蓝色的位置
  • 如果用户输入正确且向下,则它将到达标记为绿色的位置。

pixels

在这两种情况下,像素都被移位了8个像素,但红色和蓝色之间的欧氏距离= 8.00,红色和绿色= 11.31。我希望像素到达黄色。

所以我试图通过声明一个恒定的速度来纠正这个问题,然后我将它除以实际的位移,给我一个数字,我用来多个X和Y坐标并沿着轨迹向后移动,限制了我的速度。 / p>

代码看起来像这样(我已经评论了感兴趣的领域):

float velX = 0, velY = 0, currentX, currentY;
int time = 0, speed = 300;

//Events
void handleInput(){
    if( event.type == SDL_KEYDOWN ){
        switch( event.key.keysym.sym ){
            case SDLK_UP: {velY -= speed;} break;
            case SDLK_DOWN: {velY += speed;} break;
            case SDLK_LEFT: {velX -= speed;} break;
            case SDLK_RIGHT: {velX += speed;} break;
        }
    }
    else if( event.type == SDL_KEYUP ){
        //do the opposite
    }
}

//Logic
void move(){

    //float dist = sqrt( (velX*velX) + (velY*velY) );
    //
    //if(dist > 0){
    //        velX *= speed / dist;
    //        velY *= speed / dist;
    //}

    currentX += velX * (get_delta_ticks(&time) / 1000.f);
    currentY += velY * (get_delta_ticks(&time) / 1000.f);
    set_delta_ticks(&time);
}

//Render
void Player::render(){
    apply_surface(currentX, currentY, spriteSheet, screen, &currentClip);
}

所以这是我的问题,我是编程游戏的新手,我不确定这是否是正确的运动方式..在某些方面似乎有点低效,我是否应该尝试推断基于的位置一个角度和斜边的长度相反?我不太了解三角学,但当然我很想学习。

5 个答案:

答案 0 :(得分:1)

将逻辑位置与显示位置分开。

逻辑位置可能需要使用浮点坐标,然后将它们四舍五入为显示位置的整数像素坐标。如果你想平滑运动,你甚至可以用它做抗锯齿。

所以:

  • 右边会有逻辑单位向量(x,y)=(1.0,0.0)
  • down将具有逻辑单元向量(x,y)=(0.0,-1.0)
  • down + right将具有逻辑单元向量(x,y)=(1/sqrt(2),-1/sqrt(2))

每隔1/8秒,将单位矢量添加到当前逻辑位置,然后选择要绘制的像素。显然,您可以选择不同的单位并更新频率,但这会给出您要求的数字。

答案 1 :(得分:0)

我会从不同的用户控件开始:即绝对速度和方向

给定速度velAbs和角度theta,你有

velX = velAbs * cos(theta);
velY = velAbs * sin(theta);

更新位置时,通常最方便的是分解X和Y分量中的绝对速度,更新给定时间间隔的X和Y位置dt

currentX = velX * dt;
currentY = velY * dt;

而对于碰撞影响计算,绝对速度更具相关性。

这样可以避免黄色/绿色问题,因为X和Y方向的最大油门都会让你变绿。只需让用户将油门从0设置为8并设置方向,然后您将变为黄色或蓝色。

答案 2 :(得分:0)

你需要在2D空间中获得速度。为了得到它,你必须以两种速度做一个sqrt。

curSpeed = sqrt( ( velX * velX ) + (velY * velY ) );

答案 3 :(得分:0)

重点是:您计算了8-x和8-y按键事件,这与v = sqrt(8 * 8 + 8 * 8)= 11.31的原点之间的距离最短,与您观察到的完全相同。

您应该知道,在您测量的时间内,可能会对8个(仅x或y)或16个(x加y)按键事件进行采样,从而产生不同的“速度”,其中speed = number_of_key_events / period_of_time

如果您想要前往“黄色”点,在您在一个基本方向上对8个按键进行采样的同一时间内,应该只有6个X键按下事件加上6个Y键按下事件

因此,您的代码没有任何问题,并且正如其他海报所指出的那样,您可以使用欧几里德距离除以采样周期来计算您的欧几里德速度,分别得到v = 8或v = 11.31。

答案 4 :(得分:0)

好吧,看起来大多数人都忘了模拟输入......

无论如何,它应该像这样工作:

velXvelY是[-1.0..1.0]范围内的浮点数。 在数字输入(键盘,dpad)的情况下,按“left”将velX设置为-1,按“right”将velX设置为1,等等。

但是,如果使用模拟摇杆,则放置浮点值,其中velX == 1.0对应于模拟摇杆的最右侧位置,velX == -1.0对应最左侧位置,依此类推。

maxSpeed是最大游戏移动速度,也是浮动。

考虑到所有这些,你可以像这样计算物体的下一个位置:

void move(){
    float curVelX = velX, curVelY = velY;
    float moveSquared = (curVelX*curVelX + curVelY*curVelY);
    if (moveSquared > 1.0f){
         float d = sqrtf(moveSquared);
         curVelX /= d;
         curVelY /= d;
    }
    currentX += curVelX * maxSpeed * (get_delta_ticks(&time) / 1000.f);
    currentY += curVelY * maxSpeed * (get_delta_ticks(&time) / 1000.f);
    set_delta_ticks(&time);
}
  

在各方面似乎有点低效,

看,你有一个对象。当你拥有成千上万的数量时,你就可以开始担心效率了。

  

我应该尝试根据角度和斜边的长度推断出位置吗?

如果您的物体类似于鱼雷并且可以慢慢地左/右转动并加速/减速(您可以稍微转向它并使其变得更快/更慢),那么您可能需要存储运动方向和线性移动速度。

如果你的物体是某种飞行球或滚球,它可以朝着它想要的任何方向前进,那么你应该使用类似于我所描述的方法。使用sqrtf具有单独的x / y速度并限制最大线速度。