【问题标题】:How can I check if my 2D character is in the air in Unity2D?如何在 Unity2D 中检查我的 2D 角色是否在空中?
【发布时间】:2020-02-23 11:56:25
【问题描述】:

所以我试图让我的 2D 角色跳跃。 如果我在地面上跑步,它可以完美运行,但是当我撞到墙壁时,它就会出现问题:我什至可以在空中跳跃。 我试过用 bool 变量解决这个问题,但没有奏效。 我想过检查玩家是否在空中,然后将 is_on_ground 变量设置为 false。 显然,玩家只有在地面上时才应该跳跃。 我的代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerMovement : MonoBehaviour
{
    private bool canJump = false;
    public SpriteRenderer sr;
    private bool facingRight;
    private Animator animator;
    private bool is_on_ground;
    public Button leftBtn;
    public Button rightBtn;
    public Button jumpBtn;
    public float max_velocity;
    public float velocity;
    public float jump_scalar;
    private Rigidbody2D rb;
    private float x_movement;
    private Vector2 movement;
    void Start() {
        canJump = true;
        facingRight = true;
        animator = gameObject.GetComponent<Animator>();
        leftBtn.onClick.AddListener(moveLeft);
        rightBtn.onClick.AddListener(moveRight);
        jumpBtn.onClick.AddListener(jump);
        rb = gameObject.GetComponent<Rigidbody2D>();
    }
    private void FixedUpdate() {
        if (rb.velocity.magnitude < max_velocity) {
            movement = new Vector2(x_movement, 0);
            rb.AddForce(movement * velocity);
        }
    }
    private void OnCollisionEnter2D(Collision2D collision) {
        if (CollisionIsWithGround(collision)) {
            animator.SetBool("isJumping", false);
            canJump = true;
        }
        if (collision.collider.tag == "wall") {
            canJump = false;
        }
        is_on_ground = true;

    }
    private void OnCollisionExit2D(Collision2D collision) {
        if (!CollisionIsWithGround(collision)) {
            is_on_ground = false;
        }
        if (collision.collider.tag == "wall") {
            is_on_ground = true;
            canJump = true;
        }
    }
    private bool CollisionIsWithGround(Collision2D collision) {
        bool is_with_ground = false;
        foreach (ContactPoint2D c in collision.contacts) {
            Vector2 collision_direction_vector = c.point - rb.position;
            if(collision_direction_vector.y < 0) {
                is_with_ground = true;
            }
        }
        return is_with_ground;
    }
    public void moveLeft() {
        if (is_on_ground) {
            animator.SetBool("isJumping", false);
        }
        animator.SetBool("isRunning", true);
        sr.flipX = true;
        facingRight = false;
        x_movement = -1;
    }
    public void onRelease() {
        animator.SetBool("isRunning", false);
        x_movement = 0;
        if(is_on_ground) {
            animator.SetBool("isJumping", false);
            rb.velocity = Vector3.zero;
        }
    }
    public void moveRight() {
        if (is_on_ground) {
            animator.SetBool("isJumping", false);
        }
        if (!facingRight) {
            sr.flipX = false;
            facingRight = true;
            animator.SetBool("isRunning", true);
        } else {
            animator.SetBool("isRunning", true);
        }
        x_movement = 1;
    }
    public void jump() {
        if(is_on_ground) {
            if (canJump) {
                animator.SetBool("isJumping", true);
                Vector2 jumpForce = new Vector2(0, jump_scalar * 100);
                rb.AddForce(jumpForce);
            }
        }
    }
}

the problem looks like this

【问题讨论】:

    标签: c# unity3d 2d


    【解决方案1】:

    除了直接向下进行光线投射,您还可以在玩家的脚周围投射一个圆圈。

    您需要添加一个空的地面检查游戏对象作为玩家的子对象,并将其变换放置在玩家的脚下。接下来,您需要在检查器中为m_WhatIsGround LayerMask 定义哪些层算作地面。

    然后在FixedUpdate() 中检查地面检查变换是否在到地面的某个半径范围内。

    // A mask determining what is ground to the character
    [SerializeField] private LayerMask m_WhatIsGround;
    
    // A position marking where to check if the player is grounded.
    [SerializeField] private Transform m_GroundCheck;
    
    // Radius of the overlap circle to determine if grounded
    const float k_GroundedRadius = 0.3f;
    
    private void FixedUpdate() {
        is_on_ground = false;
    
        // The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
        // This can be done using layers instead but Sample Assets will not overwrite your project settings.
        Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
        for (int i = 0; i < colliders.Length; i++) {
            if (colliders[i].gameObject != gameObject) {
                is_on_ground = true;
            }
        }
    }
    

    这个方法的教程可以在Brackey's video找到。

    【讨论】:

      【解决方案2】:

      您可以在每个FixedUpdate 中对地板执行Physics2d.Raycast。当到最近对象的范围小于 0.01 或类似的值时,您将测试它是否是地板,如果是,则设置 is_on_ground = true,如果不是,则执行 is_on_ground = false

      示例:

      float raycastDistance = 0.05f;
      RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up, raycastDistance);
      if (hit.collider != null && hit.transform.gameObject.layer == LayerMask.NameToLayer("ground"))
          is_on_ground = true;
      } else {
          is_on_ground = false;
      }
      

      这应该可行。您显然必须在本例中定义一个名为 ground 的层并将其添加到每个 ground。

      【讨论】:

      • 你能告诉我更多关于如何在这里使用它的信息吗?
      • @Chr 添加了一个示例
      • is_on_ground 变量现在一直保持为假。
      • hit.transform.gameObject.layer 给了我玩家的层。
      • @Chr 你必须从角色的底部执行光线投射。例如,您可以添加一个直接位于脚下的子对象。您从其位置执行光线投射。该对象不应该有一个 colider。
      猜你喜欢
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-28
      • 2011-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多