【问题标题】:Unity3D - Preventing 3D Character from Changing Direction Mid-airUnity3D - 防止 3D 角色在空中改变方向
【发布时间】:2017-09-12 08:31:30
【问题描述】:

我是一名学习电子游戏编程的二年级学生,我一直在为这个问题苦苦挣扎一段时间,我想知道你们是否可以就如何解决这个问题提出最好的建议。

我有一个 3D 角色,他能够行走、奔跑、跳跃、二段跳和旋转以面对光标。但是,我注意到了一种错误,即我的角色能够控制其在半空中的移动。

例如,如果你按住左键 Shift + W 奔跑然后跳跃,你可以停止向前移动,然后在半空中开始向左扫射.

这是我的代码:

void Update ()
{
    // Turns off all animations while in the air
    if (isInAir)
    {
        animator.SetBool("Running", false);
        animator.SetBool("Walking", false);
    }

    if (Input.GetKey(KeyCode.W))
    {
        // If the character is not in the air then turn on the walk animation
        if (!isInAir)
        {
            animator.SetBool("Walking", true);
        }
        transform.Translate(Vector3.forward * movementSpeed * Time.deltaTime);
    }
    else if (Input.GetKey(KeyCode.S))
    {
        // If the character is not in the air then turn on the walk animation
        if (!isInAir)
        {
            animator.SetBool("Walking", true);
        }
        transform.Translate(Vector3.back * movementSpeed * Time.deltaTime);
    }

    if (Input.GetKey(KeyCode.A))
    {
        // If the character is not in the air then turn on the walk animation
        if (!isInAir)
        {
            animator.SetBool("Walking", true);
        }
        transform.Translate(Vector3.left * movementSpeed * Time.deltaTime);
    }
    else if (Input.GetKey(KeyCode.D))
    {
        // If the character is not in the air then turn on the walk animation
        if (!isInAir)
        {
            animator.SetBool("Walking", true);
        }
        transform.Translate(Vector3.right * movementSpeed * Time.deltaTime);
    }

    if (Input.GetKey(KeyCode.LeftShift))
    {
        // If the character is not in the air then turn on the run animation 
        //  and change the character's movementSpeed
        if (!isInAir)
        {
            movementSpeed = runSpeed;
            animator.SetBool("Running", true);
        }
    }
    else
    {
        // If the character is not in the air then reset their movement speed
        //  and turn off the run animation.
        if (!isInAir)
        {
            movementSpeed = walkSpeed;
            animator.SetBool("Running", false);
        }
    }

    // When a key is released, turn off the movement animations
    // This does not cause an issue since each movement if statement turns the animation back on
    if (Input.GetKeyUp(KeyCode.W) || Input.GetKeyUp(KeyCode.S) || Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.D))
    {
        animator.SetBool("Walking", false);
        animator.SetBool("Running", false);
    }
    #endregion

    // Jumping
    if (Input.GetButtonDown("Jump") && jumpCounter != 2)
    {
        jumpCounter++;
        isInAir = true;
        myRigidbody.AddForce(new Vector3(0, jumpForce));
        if (jumpCounter == 1)
        {
            firstJumpStamp = Time.time;
        }
    }

    if(Physics.Raycast(groundCheckRay, groundCheckRayDistance) && Time.time > firstJumpStamp + 0.5f)
    {
        jumpCounter = 0;
        isInAir = false;
    }
}

我已删除所有与角色移动无关的代码。

有人可以就我可以用来完成这项工作的方法给我一个建议吗?

我不是要代码来解决这个问题,只是一个建议......

我觉得我需要自己学习这个,我只需要有人指出我正确的方向。

如果您不理解部分代码,请随时问我,我很乐意向您展示我正在尝试用它做什么。 :) 例如,也许您知道编写某些行的更好方法。

(我确实尽量避免使用Input.GetAxis,因为当我没有 100% 控制它时,我发现它更难移动)

【问题讨论】:

  • 你的扫射代码在哪里?
  • 它只是检查 Input.GetKey(KeyCode.A) 和 KeyCode D,然后向左或向右翻译字符。该代码位于 S 检查的正下方

标签: c# unity3d 3d


【解决方案1】:

我可以建议您重新评估您的要求并将其与您所写的内容进行比较。您所描述的内容与您在代码中所做的内容之间存在细微差别。首先是您希望该角色能够向左或向右移动,而不是同时移动这两个,与向前和向后相同。

为了解决这个问题,您可以使用 Input.GetAxis 代替您现在使用的 Input.GetKey


我可以建议的第二件事是使用本地Vector3 计算力,然后将其应用于您的角色。然后,您可以根据 Vector3 值设置动画变量。


您的主要问题在于所使用的运动技术。由于您决定使用Transform.Translate 而不是使用Rigidbody 来移动角色,因此您必须计算帧上的位置增量。
假设您的角色将从[ x:1.00f, y: 0.00f, z: 1.00f ] 的位置开始并在框架1 上向[ x: 0.30f, y: 0.00f, z: 0.70f ] 方向移动,然后它决定跳跃。那你要做的就是抢到之前的位置 (帧更改前的那个)将是[ x:1.00f, y: 0.00f, z: 1.00f ],然后从您当前的位置([ x:1.30f, y: 0.00f, z: 1.70f ])中减去它。这将返回一个等于前一个位置增量([ x: 0.30f, y: 0.00f, z: 0.70f ])的向量。现在只需简单地将这个位置添加到当前位置,它应该保持相同的路线(方向)。
这不包括摩擦力,因此您的角色在半空中时将始终以相同的速度沿相同的方向移动。

即使您没有要求提供代码,但用简单的英语描述它要容易得多(至少对我来说:))所以,这里有一个示例代码:

// value indicating what was the position before change
Vector3 previousPosition;

void Update ()
{
    // get user input as a vector
    Vector3 horizontal = Vector3.right * Input.GetAxis("horizontal");
    Vector3 vertical = Vector3.forward * Input.GetAxis("vertical");

    bool isRunning = Input.GetKey(KeyCode.LeftShift);
    float speedModifier = isRunning ? runSpeed : walkSpeed;

    // add these inputs together
    Vector3 currentVelocity = (horizontal + vertical);

    // check if player is in mid air
    if (IsInAir)
    {
        // if it is, get the previous and current positions
        // add calculate the distance between frames
        // and normalize it to get the movement direction
        Vector3 currentPosition = transfor.position;
        Vector3 direction = (currentPosition - previousPosition).Normalize();
        // apply movement direction to the "currentVelocity"
        currentVelocity = direction * speedModifier * Time.deltaTime;
    }
    else
    {
        // user is not in mid air so you can just calculate
        // the position change
        currentVelocity = currentVelocity.Normalize() * speedModifier * Time.deltaTime;

        if ( currentVelocity != Vector3.zero )
        {
            animator.SetBool("walking", !isRunning);
            animator.SetBool("running", isRunning);
        }
    }

    // current position ( before changes )
    // should be copied to a previous position
    // to calculate it in the next frame update
    previousPosition = currentPosition;

    // do the translation
    transform.Translate(currentVelocity);
}

附加信息: 我仍然强烈建议您从Transform.Translate 切换到Rigidbody,并在角色在半空中时“重新使用”它的速度。这将不需要您计算每帧的位置增量,使其更易于使用。

【讨论】:

  • 这段代码看起来非常专业。我印象深刻!我从来不知道你可以在 Unity 中做很多事情。谢谢您的帮助!我还没有尝试过,但看起来它肯定会对我有所帮助。 :) 至于我作业的要求,很简单: - 让角色前后移动 - 让角色左右扫射 - 让角色双跳 - 让角色奔跑 - 让角色能够转身 他们'是简单化的要求。我只是为了我自己的学习利益而尝试添加更多内容。 :) 再次感谢您!
  • @PierreGravelle 感谢您的反馈。此外,此代码不包含跳转逻辑,因为您原始代码中使用的逻辑没问题,所以我决定不重写它。如果某些东西没有按预期工作,请随时发表评论,我会修复它,目前我在没有测试的情况下写了这个(我在办公室,工作:))所以如果我应该修复任何东西,请告诉我。
  • 好的,谢谢。我注意到一些拼写错误,但自从我注意到它们以来,它们并不是什么大问题。 :) 到目前为止,我看到的唯一问题是速度修饰符的内联 if 语句在应该是 walkSpeed 时使用了移动速度。我知道我从来没有在代码中显示我的变量声明,所以这是我的错哈哈。我没有将您的答案标记为已接受的答案,因为我不想阻止其他程序员也发布他们的建议。
【解决方案2】:

我认为您需要将transform 移动到if。因为现在您正在以任何一种方式移动对象,只是不更新​​布尔值。
例如:

if (Input.GetKey(KeyCode.W))
    {
        // If the character is not in the air then turn on the walk animation
        if (!isInAir)
        {
            animator.SetBool("Walking", true);
            transform.Translate(Vector3.forward * movementSpeed * Time.deltaTime); //<-- New line
        }
        //transform.Translate(Vector3.forward * movementSpeed * Time.deltaTime); //<-- Removed line
    }

你需要对所有动作都这样做ifs

【讨论】:

  • 我在问这个问题之前试过这个,它不起作用,因为一旦你跳跃,你的动作就不会被保存。你只是停在半空中,不能再动了。我正在尝试做的是在没有用户输入的情况下在半空中保持运动。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多