我正在尝试使用LWJGL和Slick-util创建一个3D游戏,我打算将它作为第一人称游戏,所以我需要一种方法来使用3D运动来导航地图。我有一个位置Vector3f
和另一个向量acc
来存储加速度。我已经设置了以下方法,所有方法(在另一个类中)绑定到W,A,S和D:
public void walkForward()
{
acc.x += walkSpeed * (float) Math.sin(Math.toRadians(yaw)); // Calculations for 3D Movement (please correct me if wrong)
acc.z -= walkSpeed * (float) Math.cos(Math.toRadians(yaw));
}
public void walkBackward()
{
acc.x -= walkSpeed * (float) Math.sin(Math.toRadians(yaw));
acc.z += walkSpeed * (float) Math.cos(Math.toRadians(yaw));
}
public void strafeLeft()
{
acc.x += walkSpeed * (float) Math.sin(Math.toRadians(yaw - 90));
acc.z -= walkSpeed * (float) Math.cos(Math.toRadians(yaw - 90));
}
public void strafeRight()
{
acc.x += walkSpeed * (float) Math.sin(Math.toRadians(yaw + 90));
acc.z -= walkSpeed * (float) Math.cos(Math.toRadians(yaw + 90));
}
walkSpeed
是正浮点数。此外,在我的move()
方法中,实际处理了移动,我有以下内容:
void move()
{
acc.y = 0.0f; // Keep the player's height stable, for testing purposes.
getPosition().x += acc.x; // Add current velocity to the position.
getPosition().y += acc.y;
getPosition().z += acc.z;
if(acc.x > 0.0f) // Gradually bring player's velocity to 0.
acc.x -= 0.01f;
else if(acc.x < 0.0f)
acc.x += 0.01f;
if(acc.y > 0.0f)
acc.y -= 0.01f;
else if(acc.y < 0.0f)
acc.y += 0.01f;
if(acc.z > 0.0f)
acc.z -= 0.01f;
else if(acc.z < 0.0f)
acc.z += 0.01f;
}
最后,在render()
方法中,实际上对游戏进行了转换,我有这个:
public void render()
{
move();
glRotatef(pitch, 1.0f, 0.0f, 0.0f);
glRotatef(yaw, 0.0f, 1.0f, 0.0f);
glTranslatef(-position.x, -position.y, -position.z);
}
预期结果:普通3D运动,适当的定向运动等
实际结果:玩家在一般方向上移动,速度根据偏航和俯仰而变化,释放所有键(调试确认正在接收到walk()
方法的NO输入导致随机方向的抖动和奇怪的移动,其速度根据偏航和俯仰而变化,保持W + A或W + D会导致水平速度大幅增加等。
我有一种感觉,这可能是由于错过了弹出或推入矩阵,或忘记在某处初始化身份。任何帮助,将不胜感激。提前谢谢!
答案 0 :(得分:0)
操纵传统OpenGL矩阵堆栈的方法(如glRotatef()
和glTranslatef()
)将指定的转换与当前在矩阵堆栈上的转换连接起来。由于您从未重置/恢复转换,因此每次调用render()
时都会连续进行更多转换。
要避免这种情况,您可以在开始应用当前转换之前重置转换:
glLoadIdentity();
glRotatef(pitch, 1.0f, 0.0f, 0.0f);
glRotatef(yaw, 0.0f, 1.0f, 0.0f);
glTranslatef(-position.x, -position.y, -position.z);
或在开始时保存前一个矩阵,并在结束时恢复它:
glPushMatrix();
glRotatef(pitch, 1.0f, 0.0f, 0.0f);
glRotatef(yaw, 0.0f, 1.0f, 0.0f);
glTranslatef(-position.x, -position.y, -position.z);
glPopMatrix();
第二种方法的优点是,如果您已经在堆栈上有一个矩阵(例如视图转换),它也可以正常工作,而第一种方法会重置所有先前的转换。
另请注意,转换按指定的相反顺序应用于顶点。因此,您的变换序列将首先平移顶点,然后应用偏航旋转,然后应用俯仰旋转。如果这就是你想要的,那一切都很好。否则,您需要撤消订单。