【问题标题】:Unity Jumping Issue - Character won't jump if it walks to the platformUnity 跳跃问题 - 角色走到平台时不会跳跃
【发布时间】:2023-03-09 06:33:01
【问题描述】:

(这是一个 2D 项目)

我有一个跳跃问题,如果我的角色走进 X 平台,她不会跳跃,但是当她跳到 X 平台上时,她可以进行跳跃。

对于平台我目前正在使用 2 个 Box Collider 2D(其中一个已选中“触发”)

对于角色我目前正在使用 2 个 Box Collider 2D(其中一个已选中“is trigger”)和 Rigidbody 2D。

下面是我目前正在尝试使用的跳跃和接地代码。

{
    public float Speed;
    public float Jump;
    bool grounded = false;

    void Start()
    {
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.UpArrow))
        {
            if (grounded)
            {
                GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, Jump);
            }
        }
    }

    void OnTriggerEnter2D()
    {
        grounded = true;
    }

    void OnTriggerExit2D()
    {
        grounded = false;
    }
}

问题出现在每个平台的同一部分。 (每个方块代表一个平台精灵,它们具有完全相同的特征,因为我复制粘贴了它们中的每一个)。请查看此链接上的照片:https://imgur.com/a/vTmHw

【问题讨论】:

标签: unity3d


【解决方案1】:

这是因为您的方格有单独的对撞机。想象一下:

有两个块:AB。你站在区块A。现在您尝试在B 街区行走。一旦你的Rigidbody2D 碰撞器接触到块B,你的角色就会得到一个事件OnTriggerEnter2D(...)。现在你声称,你是接地的。
但是,此时您仍在与块A 发生碰撞。一旦你的Rigidbody2D 不再与块A 碰撞,你的角色就会收到OnTriggerExit2D(...)。现在你声称,你不再接地。但实际上,你还是在与区块B发生碰撞。

解决方案

您可以使用byte 类型变量,而不是使用bool 变量来检查是否接地,称为collisionsCounter

  • 输入触发器后 - 增加计数器。
  • 退出触发器后 - 减少计数器。

做一些检查以确保您确实在对撞机上方!

现在,一旦你需要检查你的角色是否接地,你就可以使用

if (collisionsCounter > 0)
{
    // I am grounded, allow me to jump
}

编辑

实际上,在进一步研究问题之后,我意识到您有完全不必要的对撞机(我说的是触发器)。删除那些。现在每个对象只有一个对撞机。但是要获得碰撞的调用,您需要进行更改:

  • OnTriggerEnter2D(...)OnCollisionEnter2D(Collision2D)
  • OnTriggerExit2D(...)OnCollisionExit2D(Collision2D)

最终代码

[RequireComponent(typeof(Rigidbody2D))]
public sealed class Character : MonoBehaviour
{
    // A constant with tag name to prevent typos in code
    private const string TagName_Platform = "Platform";



    public float Speed;
    public float Jump;

    private Rigidbody2D myRigidbody;
    private byte platformCollisions;



    // Check if the player can jump
    private bool CanJump
    {
        get { return platformCollisions > 0; }
    }



    // Called once the script is started
    private void Start()
    {
        myRigidbody = GetComponent<Rigidbody2D>();
        platformCollisions = 0;
    }

    // Called every frame
    private void Update()
    {
        // // // // // // // // // // // // // //
        // Need to check for horizontal movement
        // // // // // // // // // // // // // //

        // Trying to jump
        if (Input.GetKeyDown(KeyDode.UpArrow) && CanJump == true)
            Jump();
    }

    // Called once Rigidbody2D starts colliding with something
    private void OnCollisionEnter2D(Collision2D collision)
    {
        if(collision.collider.tag == TagName_Platform)
            platformCollisions++;
    }

    // Called once Rigidbody2D finishes colliding with something
    private void OnCollisionExit2D(Collision2D collision)
    {
        if(collision.collider.tag == TagName_Platform)
            platformCollisions--;
    }



    // Makes Character jump
    private void Jump()
    {
        Vector2 velocity = myRigidbody.velocity;
        velocity.y = Jump;
        myRigidbody.velocity = velocity;
    }
}

这里可能有一些小错误,因为所有代码都是在记事本中输入的...

【讨论】:

  • 我有两个盒子碰撞器的原因是,如果我只使用一个并激活触发器,我的角色就​​会通过它。我实际上在一些教程中看到了它,他们使用了两个,它工作得很好,不知道为什么它对我的不起作用。关于如何只使用 ONE box collider 并让我的角色不掉下来,你还有什么其他技巧吗?
  • 单个块使用 2 个对撞机非常好(在性能方面没有那么多)。我的意思是你的每个平台都有一组单独的对撞机。当你从一个平台到另一个平台时,进入和退出的事情就会发生。
  • @EricAhn 编辑了我对这两个问题的答案(跳跃和对撞机计数)
  • Svedas 对不起,我在这方面真的很陌生,当我尝试使用 OnCollisionEnter2D(Collision2D) 和 OnCollisionExit2D(Collision2D) 时,最后一个括号出现错误“二维物理回调函数返回的碰撞详细信息. 需要标识符。”
  • @EricAhn 该错误表明您没有在方法中为 Collision2D 参数指定名称。所以 OnCollisionEnter2D(Collision2D) 应该类似于 OnCollisionEnter2D(Collision2D collisionVariableName)。想想更能描述变量名称的东西。 OnCollisionExit2D(...) 也是如此。
【解决方案2】:

我认为这里有几个问题。

首先,使用Triggers 来检查这种类型的碰撞可能不是最好的方法。我建议不要使用触发器,而是使用OnCollisionEnter2D()Triggers 只是检测两个物体的碰撞空间是否相互重叠,而正常的碰撞会像两个固体物体一样碰撞每个 otehr。看起来好像你正在检测你是否已经降落在地板上,你不想像Triggers那样从地板上摔下来。

其次,我建议使用AddForce 而不是GetComponent&lt;Rigidbody2D&gt;().velocity

您的最终脚本可能如下所示:

public class PlayerController : MonoBehaviour 
{         
     public float jumpForce = 10.0f;     
     public bool isGrounded;
     Rigidbody2D rb;

     void Start()
     {
         rb = GetComponent<Rigidbody2D>();
     }

     void OnCollisionEnter2D(Collision2D other)
     {
         // If we have collided with the platform
         if (other.gameObject.tag == "YourPlatformTag")
         {
             // Then we must be on the ground
             isGrounded = true;
         }
     }

     void Update()
     {
         // If we press space and we are on the ground
         if(Input.GetKeyDown(KeyCode.Space) && isGrounded)
         {     
             // Add some force to our Rigidbody
             rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);

             // We have jumped, we are no longer on the ground
             isGrounded = false;
         }
     }
}

【讨论】:

  • “YourPlatformTag”是指我所有平台的母亲吗?或者你的意思是每个孩子的名字?对不起,我是新手。并感谢我什至没有问过的提示(不是讽刺),所有提示都有帮助:)
  • 对于每个平台,如果您查看检查器,右上角有一个标签选项。在这里,您可以创建自己的标签并将其应用于所有平台 :-) 所以您可以创建一个名为“Platform”并将“YourPlatformTag”更改为“Platform”
  • 您的代码非常有用,非常感谢 :) 但我仍然想弄清楚为什么触发器跳转仅在同一平台的特定部分上不起作用,我可能不得不在未来? (我不知道)
  • 也许您的角色不只是与一个平台发生碰撞,还是同时与多个平台发生碰撞?在您的帖子中,您没有检查碰撞的内容,它基本上是whatever we collide with, set grounded to false。也许它混淆了grounded = truegrounded = false 两种状态?
  • 我明白了,谢谢伙计,我不想利用你的帮助,但你知道为什么我的角色卡在一边吗?我可以理解为什么,但我不知道如何解决它.. imgur.com/a/J0iF9
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多