Unity2D - 验证 isGround 是不是正确
Posted
技术标签:
【中文标题】Unity2D - 验证 isGround 是不是正确【英文标题】:Unity2D - Verify if isGround is correctlyUnity2D - 验证 isGround 是否正确 【发布时间】:2021-12-09 18:03:19 【问题描述】:我有一个脚本可以检测玩家何时触摸名为“Ground”的图层,它运行良好,但我的问题是当我使用允许我跳过平台的“Platform Effector 2D”时。所以,当我的角色通过平台时,我的布尔“isGrounded”为真,但他实际上不在地面,发生的情况是我用来检查的点是与地面层的对象“碰撞” .
我觉得我解释的不是很好,所以我在 Youtube 上上传了一个未列出的视频来展示
www.youtube.com/watch?v=EQpF4iSNC0Yt
这是代码
[Header("Components")]
[HideInInspector]public Rigidbody2D _rb;
[Header("Layer Masks")]
[SerializeField] private LayerMask groundLayer;
[Header("Movement Variables")]
[SerializeField] private float _movementAcceleration;
[SerializeField] private float _maxMoveSpeed;
[SerializeField] private float _linearDrag;
[SerializeField] private float dashPower;
private float horizontalDirection;
private bool changingDirection => (_rb.velocity.x > 0f && horizontalDirection < 0f) || (_rb.velocity.x < 0f && horizontalDirection > 0f);
public bool isFalling => _rb.velocity.y < 0.0f;
private bool isRunning => horizontalDirection != 0;
[Header("Jump Variables")]
[SerializeField] private float jumpForce = 12f;
[SerializeField] private float airLinearDrag = 2.5f;
[SerializeField] private float fallMultiplier = 8f;
[SerializeField] private float lowJumpFallMultiplier = 5f;
private bool canJump => Input.GetButtonDown("Jump") && isGround;
[Header("Ground Colission Variables")]
[SerializeField] private float groundRayCastLenght;
private bool isGround;
private bool jumped;
private bool facinRight = true;
private Animator animator;
private SpriteRenderer sprite;
GameController controller;
public Transform groundCheck ;
public bool canPassThrough = false;
void Start()
sprite = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
_rb = GetComponent<Rigidbody2D>();
controller = FindObjectOfType<GameController>();
// Update is called once per frame
void Update()
Debug.Log(_rb.velocity.y);
isGround = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
horizontalDirection = GetInput().x;
if(canJump && !controller.gamePaused)
Jump();
if(Input.GetKeyDown(KeyCode.LeftShift))
ApplyDash();
setAnimations();
void FixedUpdate()
//CheckCollisions();
if(!controller.gamePaused)
//checkDirection();
MoveCharacter();
if(isGround)
jumped = false;
ApplyLinearDrag();
else
ApplyAirLinearDrag();
FallMultiplier();
private Vector2 GetInput()
return new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
private void MoveCharacter()
if(horizontalDirection < 0 && facinRight || horizontalDirection > 0 && !facinRight)
checkDirection();
Vector3 v = _rb.velocity;
_rb.AddForce(new Vector2(horizontalDirection* _movementAcceleration, 0f) );
if(Mathf.Abs(_rb.velocity.x) > _maxMoveSpeed)
v.x = Mathf.Sign(_rb.velocity.x) * _maxMoveSpeed;
_rb.velocity = v;
//_rb.velocity = new Vector2(Mathf.Sign(_rb.velocity.x) * _maxMoveSpeed, _rb.velocity.y );
private void CheckCollisions()
isGround = Physics2D.Raycast(transform.position * groundRayCastLenght, Vector2.down, groundRayCastLenght, groundLayer);
private void ApplyLinearDrag()
if(Mathf.Abs(horizontalDirection) < 0.4f || changingDirection)
_rb.drag = _linearDrag;
else
_rb.drag = 0f;
private void ApplyDash()
_rb.AddForce(new Vector2(horizontalDirection * dashPower, _rb.velocity.y));
void ApplyAirLinearDrag()
_rb.drag = airLinearDrag;
void Jump()
jumped = true;
if(horizontalDirection != 0)
_rb.velocity = new Vector2(_rb.velocity.x, 0f);
_rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
else
_rb.velocity = new Vector2(_rb.velocity.x, 0f);
_rb.AddForce(Vector2.up * jumpForce * 2f, ForceMode2D.Impulse);
void OnDrawGizmos()
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, transform.position + Vector3.down * groundRayCastLenght);
void FallMultiplier()
if(_rb.velocity.y < 0)
_rb.gravityScale = fallMultiplier;
else if(_rb.velocity.y > 0 && !Input.GetButtonDown("Jump"))
_rb.gravityScale = lowJumpFallMultiplier;
else
_rb.gravityScale = 1f;
void setAnimations()
animator.SetBool("Run", isRunning && isGround);
animator.SetBool("isGround", isGround);
animator.SetBool("Jump", jumped);
animator.SetBool("isFalling", isFalling);
animator.SetFloat("eixoY", Mathf.Abs(_rb.velocity.y));
void checkDirection()
facinRight = !facinRight;
transform.localScale = new Vector3( - transform.localScale.x, transform.localScale.y, transform.localScale.z);
void OnCollisionEnter2D(Collision2D other)
if(LayerMask.LayerToName(other.gameObject.layer) == "Ground") //check layer is ground
if (gameObject.GetComponent<Rigidbody2D>().velocity.y <= 0) //check velocity.y is 0
Debug.Log("in ground"); //debug console
canPassThrough = false;
else
Debug.Log("Not in ground");
canPassThrough = true;
【问题讨论】:
您是否还要在您的条件中添加对仅在角色处于跳跃状态时才为真的指示的依赖?因为实际上他正在接触地面,但既然你想让用户跳过一个平台,那么显然有一个案例需要更多关注。另外,您能否在问题中提供最少的代码和场景设置详细信息,以便我们进一步提供帮助。 我贴出了播放器代码 如何为玩家跳跃添加其他条件?因为当玩家在地面上时我设置为 false,但是当玩家通过平台时,变量 isground 检测到他在地面上,而实际上他不是 我认为你会从学习状态和状态机中受益。不需要包含所有内容的大型状态机,将状态机分解为重要的相关组件会有所帮助。有这么多结果。如果您有兴趣,Mit 有点冗长。但是您可能还可以找到其他更简单的方法。 依赖过多的bool
s 可能会导致许多边缘情况和错误以及(远远超过需要的)代码分支。如果您在阅读状态机后有任何困难,或者只是不知道如何应用它 lmk,我可以进一步解释。
【参考方案1】:
如果我们想在触摸的时候进行调试操作,我们可以通过检查在触摸的那一刻velocity.y是否为0来成功执行操作。
像这样:
private void OnCollisionEnter2D(Collision2D collision)
if(LayerMask.LayerToName(collision.gameObject.layer) == "Ground") //check layer is ground
if (gameObject.GetComponent<Rigidbody2D>().velocity.y <= 0) //check velocity.y is 0
Debug.Log("in ground"); //debug console
【讨论】:
是的,我已经尝试过了,但是我的 velocity.y 是个怪人,它在运行时会返回 2,我正在尝试解决这个问题 实际上它可以工作,但是当我跳跃并且玩家与平台碰撞但不在地面时,如果我跳跃并继续向一边走,我会出错,因为玩家从 -7 到 7,并且 de condicion ".velocity.y以上是关于Unity2D - 验证 isGround 是不是正确的主要内容,如果未能解决你的问题,请参考以下文章