【问题标题】:Unity2D not checking conditions properlyUnity2D 没有正确检查条件
【发布时间】:2020-06-14 17:26:59
【问题描述】:

我在这么短的时间内问了这么多 Unity 问题,我非常感谢所有回答的人。我不知道为什么我总是面临这样的问题,而我在网上看到的任何答案都无法帮助我。好的,这是我的问题:

if (Input.GetKey(KeyCode.Q) && (rightHit.collider != null || leftHit.collider != null) && groundHit.collider == null)

如果我按住任何墙上的 Q 按钮,Update 函数中的这行代码会检查每一帧。如果条件满足,那么

void Grapple()
    {
        if (wallGrapple) 
        {
            x = 0f;
            rb.gravityScale = 0;
            rb.velocity = new Vector2(speed * x, speed * y);
            if (Input.GetKeyDown(KeyCode.Space)) { jumpRequest = true; }

        }
    }

这个函数被调用,它允许玩家根据垂直轴输入(输入 y 变量)在墙上粘贴和滑动。现在的问题是,如果我只在墙上按 Q 一次,它就会留在墙上,即使它应该被按住以便调用 Graapple() [我使用 Input.GetKey 而不是 Input.GetKeyDown] 和即使在 if 行中,我也能够在墙壁上方滑动(就像有一些看不见的墙壁一样),正在检查检测墙壁的条件。

我已经玩了大约 30-45 分钟,但我无法破解它。我想到的另一个解决方法是使用协程,但我不知道如何使用,因为我没有找到任何关于它如何工作以及应该如何使用的基本解释。这是完整的代码,

using System.Collections;
using System.Collections.Generic; 
using UnityEngine;
using UnityEngine.SocialPlatforms;

public class Move : MonoBehaviour
{
    [SerializeField] private LayerMask groundMask;
    [SerializeField] private LayerMask Wall;

    [Header("Horizontal")]
    public float x;
    float dirX;
    public float speed;
    float initialSpeed;
    [SerializeField] [Range(0, 1)] float LerpConstant;
    public float dashForce = 100f;
    public bool canDash;
    public bool dashRequest;
    [Header("Vertical")]
    public float y;
    public bool canJump;
    public bool jumpRequest;
    public float initialJumpForce;
    public float jumpForce;
    public bool canWallJump;
    public float modifiedJumpForce;
    public float sideJumpForce;
    public bool wallGrapple;
    [Header("Other")]
    public Rigidbody2D rb;
    public float gScale = 10f;
    BoxCollider2D boxcollider;


    RaycastHit2D groundHit;
    RaycastHit2D leftHit;
    RaycastHit2D rightHit;


    // Start is called before the first frame update
    void Start()
    {
        rb = gameObject.GetComponent<Rigidbody2D>();
        boxcollider = gameObject.GetComponent<BoxCollider2D>();
        jumpForce = initialJumpForce;
        initialSpeed = speed;
        rb.gravityScale = gScale;

    }


    // Update is called once per frame
    void Update()
    {
        //Instant 1, 0, -1 inputs
        x = Input.GetAxisRaw("Horizontal");
        y = Input.GetAxisRaw("Vertical");
        if(x < 0) 
            { dirX = -1; } 
        else if(x > 0) 
            { dirX = 1; }
        if (Input.GetKeyDown(KeyCode.Space) && (canJump || canWallJump)) //for jumps
            { jumpRequest = true; } 
        if (Input.GetKey(KeyCode.Q) && (rightHit.collider != null || leftHit.collider != null) && groundHit.collider == null) //for wall grappling
            { wallGrapple = true; } 
        if (Input.GetKeyDown(KeyCode.LeftShift) && (canDash)) //for dashing
            { dashRequest = true; } 

        Detection();
        JumpDash();
        Grapple();
    }
    void FixedUpdate()
    {        
        Movement();
    }

    void Detection()
    {
        groundHit = Physics2D.BoxCast(boxcollider.bounds.center, boxcollider.bounds.size, 0f, Vector2.down, 0.1f, groundMask);
        if (groundHit.collider != null) //If player is on ground
        {
            canJump = true;
            canWallJump = false;
            canDash = false;
            jumpForce = initialJumpForce;
            sideJumpForce = 0;
            LerpConstant = 0.25f;
        }
        else if (groundHit.collider == null)//not on ground 
        {
            LerpConstant = 0.12f;
            canJump = false;
        }

        //Wall detection

        //Left wall
        leftHit = Physics2D.BoxCast(boxcollider.bounds.center, boxcollider.bounds.size, 0f, Vector2.left, 0.1f, Wall);
        if (leftHit.collider != null && groundHit.collider == null) //if player on left wall and not on ground
        {
            canWallJump = true;
            jumpForce = modifiedJumpForce;
            sideJumpForce = jumpForce;

        }
        //Right wall
        rightHit = Physics2D.BoxCast(boxcollider.bounds.center, boxcollider.bounds.size, 0f, Vector2.right, 0.1f, Wall);
        if (rightHit.collider != null && groundHit.collider == null) //if player on right wall and not on ground
        {
            canWallJump = true;
            jumpForce = modifiedJumpForce;
            sideJumpForce = -jumpForce; // negative of jump force to jump in left direction


        }

        if (rightHit.collider == null && leftHit.collider == null) //if both walls are not detected
        {
            canWallJump = false;
        }
    }

    void Movement()
    {
        Vector2 move = new Vector2(x * speed, rb.velocity.y);
        rb.velocity = Vector2.Lerp(rb.velocity, move, LerpConstant);
    }



    void JumpDash()
    {

        //Jump
        if (jumpRequest)
        {
            wallGrapple = false;
            rb.gravityScale = gScale;
            rb.AddForce(new Vector2(sideJumpForce * 2.1f, jumpForce), ForceMode2D.Impulse);
            speed = initialSpeed;
            jumpRequest = false; //setting jumpRequest to false after jumping to prevent unlimited jumps
            canDash = true;
        }

        /*if (dashRequest)
        {
            rb.velocity = Vector2.zero;
            rb.AddForce((dashForce, 0f), ForceMode2D.Impulse);
        }*/ //remember to put this code in later

    }

    void Grapple()
    {
        if (wallGrapple) 
        {
            x = 0f;
            rb.gravityScale = 0;
            rb.velocity = new Vector2(speed * x, speed * y);
            if (Input.GetKeyDown(KeyCode.Space)) { jumpRequest = true; }

        }
    }

}

附:我最初想使用 Space 本身而不是 Q 来进行摇杆和滑动,但是会弹出更多错误,例如不一致的墙壁跳跃,所以这就是我使用 Q 的原因。

https://streamable.com/3v6qrq

【问题讨论】:

  • 尽管有你的解释,我还是不明白你的问题……你的问题在哪里
  • 好的,我已经上传了一个显示问题的视频。我还希望当我按住 Q 而不是只按一次时,播放器会粘在墙上(并滑到墙上)。您还可以在视频中看到,即使 if 条件不允许,玩家也可以越过墙壁

标签: unity3d 2d


【解决方案1】:

你好像没有设置

wallGrapple = 假

代码中除跳转请求之外的任何位置。因此,由于它永远不会设置为 false,因此您的玩家将不断地进行擒抱。 或许你可以先在Update函数中设置为false,然后做key检测。

【讨论】:

  • 好吧,这几乎对我有用。现在,当我越过墙壁时,我的播放器就会不断上升。我在 update 函数中设置了 wallGrapple = false ,这应该意味着它一直是假的,只有在满足条件时才为真。我知道这是如何工作的,但是当条件不满足时,我以前的代码不应该自动将 wallGrapple 设置为 false 吗?还是在条件不再不满意时保持原样?
  • 否 - 您需要在某处明确设置 wallGrapple=false,无论是在更新或检测等开始时。
【解决方案2】:

我给你看一个协程示例代码 sn-p。 您可以从注释行中理解它并将其应用到您自己的代码中。

void Start()
{
    StartCoroutine("coroutineFunc");  // calling for example 
}

和协程函数是这样的:

IEnumerator coroutineFunc()
    {
         // before waiting... if u wanna try something
            yield return new WaitForSeconds(1); // waiting..

            // after waiting something what do you want



    }

【讨论】:

  • 协程在这种情况下究竟是如何工作的?据我了解,我知道调用协程会阻止除协程之外的所有代码运行,是吗?所以这意味着我可以在满足条件时调用协程,对吗?另外,在确切等待之前我们会放什么? (对不起,我很困惑,一个例子可以帮助我)。最后一件事是它会准确地检查条件吗(不像当前的代码没有正确检查条件)?
  • 使用字母 q 是有意义的。但是,您提出的问题非常具体,在这种情况下,您必须自己决定需要操作什么。我只能指导你。协程运行时,没有其他功能将起作用。查看您编写的条件并检查它们的调试和状态。如果您能进一步澄清问题,我将很乐意提供帮助。就个人而言,当我阅读您的问题时,我不需要协程。
  • 我希望这个评论现在可以澄清问题,即当我在墙上按 Q 时,它会粘住,即使我希望它只有在玩家按住 Q 时才会粘住(所以我用过if(Input.GetKey .....) 而不是 if(Input.GetKeyDown ....) 但它的行为仍然像 KeyDown) 并且当玩家卡在墙上时也能够在墙上滑动,这不应该是可能是因为如果条件是玩家只能在检测到墙壁时抓住/粘在墙上,所以当它越过墙壁时,条件变为假,但由于某种原因它仍然为真。
  • 好的,我也尝试过使用 IEnumerator 但我不知道我所做的是否正确。 IEnumerator Grapple() { x = 0f; rb.gravityScale = 0; rb.velocity = new Vector2(speed * x, speed * y); if (Input.GetKeyDown(KeyCode.Space)) { jumpRequest = true; } yield return null; } 代码显然可以工作,但我认为我没有正确使用它。而且,没有准确检测到 if 条件的问题仍然存在。
猜你喜欢
  • 2015-03-02
  • 2014-01-25
  • 2019-10-07
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-16
  • 1970-01-01
相关资源
最近更新 更多