通常,我会希望使用速度值(例如2.5)在基于像素的游戏中移动角色。但是,如果这样做,碰撞检测通常会更加困难。所以我最终做了这样的事情:
moveX(2);
if (ticks % 2 == 0) { // or if (moveTime % 2 == 0)
moveX(1);
}
每当我不得不写那封信时,我都会畏缩一次,是否有一种更清洁的方式来移动具有非整数速度值的角色,或者我会永远坚持这样做吗?
通常,我会希望使用速度值(例如2.5)在基于像素的游戏中移动角色。但是,如果这样做,碰撞检测通常会更加困难。所以我最终做了这样的事情:
moveX(2);
if (ticks % 2 == 0) { // or if (moveTime % 2 == 0)
moveX(1);
}
每当我不得不写那封信时,我都会畏缩一次,是否有一种更清洁的方式来移动具有非整数速度值的角色,或者我会永远坚持这样做吗?
Answers:
在过去,当人们仍在编写自己的基本视频例程以绘制线条和圆形时,使用Bresenham线条算法并不是没有听说过的。
布雷森纳姆解决了这个问题:您想在屏幕上画一条线,该线在dx
水平方向上移动像素,同时在dy
垂直方向上跨越像素。线条具有固有的“蓬松性”。即使您具有整数像素,您最终也会得到合理的倾斜度。
但是,该算法必须快速,这意味着它只能使用整数算法。它也没有任何乘法或除法,只有加法和减法就消失了。
您可以根据自己的情况进行调整:
“ x / y”不是屏幕上的位置,而是您的一个尺寸随时间变化的值。显然,如果您的精灵在屏幕上沿任意方向运行,则将有多个不来梅奔跑,其中2个用于2D,三个用于3D。
假设您要沿着一个轴从0到25的简单移动中移动角色。当它以速度2.5移动时,它将到达那里的第10帧。
这与从(0,0)到(10,25)的“画线”相同。抓住布雷森纳姆的线算法,让它运行。如果您做对了(并且在学习时会很快清楚地知道如何做对),那么它将为您生成11个“点”(0,0),(1,2),(2, 5),(3,7),(4,10)...(10,25)。
如果您搜索该算法并找到一些代码(维基百科上有相当大的条约),则需要注意以下几点:
dx
和dy
。但是,您对一种特定情况感兴趣(即,您永远不会有dx=0
)。dx
和dy
是积极的,消极的,以及是否abs(dx)>abs(dy)
与否。您当然也可以在这里选择所需的东西。您必须特别确保1
每个刻度线增加的方向始终是您的“时钟”方向。如果应用这些简化,结果的确将非常简单,并且完全摆脱了任何现实。
有一种很好的方法可以精确地执行您想要的操作。
除了float
速度之外,您还需要第二个float
变量,该变量将包含并累积实际速度和舍入速度之间的差。然后将这种差异与速度本身结合起来。
#include <iostream>
#include <cmath>
int main()
{
int pos = 10;
float vel = 0.3, vel_lag = 0;
for (int i = 0; i < 20; i++)
{
float real_vel = vel + vel_lag;
int int_vel = std::lround(real_vel);
vel_lag = real_vel - int_vel;
std::cout << pos << ' ';
pos += int_vel;
}
}
输出:
10 10 11 11 11 12 12 12 12 13 13 13 14 14 14 15 15 15 15 16
将浮点值用于移动,将整数值用于碰撞和渲染。
这是一个例子:
class Character {
float position;
public:
void move(float delta) {
this->position += delta;
}
int getPosition() const {
return lround(this->position);
}
};
移动时,您可以使用move()
累计小数位。但是通过使用该getPosition()
函数,碰撞和渲染可以处理积分位置。