【问题标题】:LWJGL 3D Movement messed upLWJGL 3D 运动搞砸了
【发布时间】:2015-01-07 02:03:05
【问题描述】:

我正在尝试仅使用 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()方法的输入导致随机方向的抖动和奇怪的移动,其速度基于偏航和俯仰的变化,同时按住 W + A 或 W + D 会导致水平速度大幅增加,等等。

我有一种感觉,这可能是由于缺少矩阵中的弹出或推送,或者忘记在某处初始化身份。任何帮助,将不胜感激。提前致谢!

【问题讨论】:

    标签: java opengl 3d lwjgl voxel


    【解决方案1】:

    操作旧版 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();
    

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

    另请注意,转换以与指定相反的顺序应用于顶点。所以你的变换序列将首先平移顶点,然后应用偏航旋转,然后是俯仰旋转。如果这就是你想要的,一切都很好。否则,您需要颠倒顺序。

    【讨论】:

    • 我想我应该包括这个,很抱歉我没有,但是调用这个的方法,Main.render(),确实同时调用了glPushMatrix()和@987654328 @ 之前和之后(分别)Player.render() 方法,所以我没有更接近弄清楚这一点。
    猜你喜欢
    • 1970-01-01
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    相关资源
    最近更新 更多