如何防止玩家和物体在碰撞时抖动?

问题描述 投票:0回答:1

我的游戏的 2D 物理有问题。当玩家跳跃并与物体碰撞时,该物体会被稍微推入地面。如何防止碰撞体相互穿过?

Play Screen

我首先尝试将刚体设置更改为连续和插值,但它不起作用。然后我更改了 Unity 物理 2D 设置,例如接触偏移,但也不起作用。

这些是我的设置和玩家移动代码:

Player Rigidbody and Collider

Object Rigidbody and Collider

Physics 2D

using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

public class MovePlayer : MonoBehaviour
{
    public Rigidbody2D rb;
    Vector2 moveInput;
    public Animator anim;
    [SerializeField]
    float moveSpeed = 10f, acceleration = 1f, decceleration = -1f, velPower = 1f, jumpForce = 3f, coyoteTime = 0.1f, jumpInputBuffer = 0.1f, jumpCut = 1f;
    [SerializeField]
    float gravityScale = 6f, fallGravityMultiplier = 1.1f, jumpHangGravityThreshold = 0.1f, jumpHangGravityMultiplier = 0.8f, frictionAmount = 0.2f;
    [SerializeField]
    Vector2 groundChecksize = new Vector2(0.49f, 0.03f);

    public LayerMask ground;
    public GameObject groundCheckObject;
    
    PlayerAttack attackScript;

    float LastOnGroundTime = 0f, LastJumpPressed = 0f, LastMovePressed = 0f;
    float tmp = 1f;

    bool isJumping;
    bool isFacingRight = true;

    // Start is called before the first frame update
    void Start()
    {
        anim = this.GetComponent<Animator>();
        attackScript = this.GetComponent<PlayerAttack>();
    }


    // Update is called once per frame
    void Update()
    {
        LastOnGroundTime -= Time.deltaTime;
        LastJumpPressed -= Time.deltaTime;
        LastMovePressed -= Time.deltaTime;
        moveInput.x = Input.GetAxisRaw("Horizontal");
        moveInput.y = Input.GetAxisRaw("Vertical");
        if (moveInput.x != 0)
        {
            LastMovePressed = tmp;
        }
        if ((moveInput.x > 0f && isFacingRight == false) || (moveInput.x < 0f && isFacingRight == true))
        {
            FlipPlayer();
        }
        if(attackScript.isAttacking>=0)
        {
            moveInput.x = 0f;
        }
        groundCheck();

        if (isJumping && rb.velocity.y < 0) isJumping = false;

        if (Input.GetKeyDown(KeyCode.Space))
        {
            LastJumpPressed = jumpInputBuffer;
        }

        if (Input.GetKeyUp(KeyCode.Space) && isJumping && rb.velocity.y > 1f)
        {
            rb.AddForce(jumpCut * Vector2.down * (rb.velocity.y < 2f ? rb.velocity.y - 1 : 1), ForceMode2D.Impulse);
        }

        if (LastOnGroundTime > 0 && LastJumpPressed > 0)
        {
            Jump();
        }
        if (rb.velocity.y < 0)
        {
            rb.gravityScale = gravityScale * fallGravityMultiplier;
        }
        else if (Mathf.Abs(rb.velocity.y) < jumpHangGravityThreshold)
        {
            rb.gravityScale = gravityScale * jumpHangGravityMultiplier;
        }
        else
        {
            rb.gravityScale = gravityScale;
        }
        if (Input.GetAxisRaw("Horizontal") == 0)
        {
            anim.SetBool("walk", false);
        }
        else
        {
            anim.SetBool("walk", true);
        }
        if (LastOnGroundTime > 0 && Input.GetAxisRaw("Horizontal") == 0)
        {
            float friction = Mathf.Min(Mathf.Abs(rb.velocity.x), Mathf.Abs(frictionAmount));
            friction *= Mathf.Sign(rb.velocity.x);
            rb.AddForce(Vector2.right * -friction, ForceMode2D.Impulse);
        }
    }

    private void FixedUpdate()
    {
        float targetSpeed = moveInput.x * moveSpeed;
        float speedDif = targetSpeed - rb.velocity.x;
        float accelRate = (Mathf.Abs(targetSpeed) > 0.01f) ? acceleration : decceleration;
        float movement = Mathf.Pow(Mathf.Abs(speedDif) * accelRate, velPower) * Mathf.Sign(speedDif);
        rb.AddForce(movement * Vector2.right);
    }

    void Jump()
    {
        LastOnGroundTime = 0;
        LastJumpPressed = 0;
        isJumping = true;
        float force = jumpForce;
        if (rb.velocity.y < 0)
        {
            force -= rb.velocity.y;
        }
        rb.AddForce(force * Vector2.up, ForceMode2D.Impulse);
    }

    void groundCheck()
    {
        if (Physics2D.OverlapBox(groundCheckObject.transform.position, groundChecksize, 0, ground))
        {
            LastOnGroundTime = coyoteTime;
        }
    }

    void FlipPlayer() //이동 방향에 맞게 플레이어를 반전
    {
        isFacingRight = !isFacingRight;
        Vector3 PlayerScale = transform.localScale;
        PlayerScale.x = PlayerScale.x * -1;
        transform.localScale = PlayerScale;
    }

    public void InitPlayer()
    {
        LastOnGroundTime = 0f; LastJumpPressed = 0f; LastMovePressed = 0f;
        isJumping = false;
        if(!isFacingRight)
        {
            FlipPlayer();
        }
    }

    private void OnDrawGizmosSelected()
    {
        Gizmos.DrawWireCube(groundCheckObject.transform.position, groundChecksize);
    }
}
unity-game-engine 2d game-physics collision
1个回答
0
投票

经过一些实验,我可以得出结论,原因很可能是由于处理

FixedUpdate()
内部的运动:

private void FixedUpdate()
{
    float targetSpeed = moveInput.x * moveSpeed;
    float speedDif = targetSpeed - rb.velocity.x;
    float accelRate = (Mathf.Abs(targetSpeed) > 0.01f) ? acceleration : decceleration;
    float movement = Mathf.Pow(Mathf.Abs(speedDif) * accelRate, velPower) * Mathf.Sign(speedDif);
    rb.AddForce(movement * Vector2.right);
}

我尝试将我的运动功能移动到固定更新中,它也会在对象之间出现故障并口吃,我只需将你的运动代码放在一个函数中:

private void Move() {
    float targetSpeed = moveInput.x * moveSpeed;
    float speedDif = targetSpeed - rb.velocity.x;
    float accelRate = (Mathf.Abs(targetSpeed) > 0.01f) ? acceleration : decceleration;
    float movement = Mathf.Pow(Mathf.Abs(speedDif) * accelRate, velPower) * Mathf.Sign(speedDif);
    rb.AddForce(movement * Vector2.right);
}

然后在更新函数内部调用它:

void Update() {
    Move()
    //...
}

我注意到的另一件事是你像我一样使用 rb.AddForce 而不是 rb.velocity 。我明白你为什么会使用它,但这也可能是另一个原因。

© www.soinside.com 2019 - 2024. All rights reserved.