LWJGL 3D运动搞砸了

时间:2015-01-07 02:03:06

标签: java opengl 3d lwjgl voxel

我正在尝试使用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会导致水平速度大幅增加等。

我有一种感觉,这可能是由于错过了弹出或推入矩阵,或忘记在某处初始化身份。任何帮助,将不胜感激。提前谢谢!

1 个答案:

答案 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();

第二种方法的优点是,如果您已经在堆栈上有一个矩阵(例如视图转换),它也可以正常工作,而第一种方法会重置所有先前的转换。

另请注意,转换按指定的相反顺序应用于顶点。因此,您的变换序列将首先平移顶点,然后应用偏航旋转,然后应用俯仰旋转。如果这就是你想要的,那一切都很好。否则,您需要撤消订单。