Unity 2D 解決角色撞牆出現詭異的抖動


建立時間: 2022年7月14日 12:21
更新時間: 2022年8月20日 03:05

說明

預期角色撞到牆壁時,應該要被停止在邊界過不去才對
但在開發的過程中,角色會稍微跑進牆裡後又被擠出來
看起來就像是很詭異的抖動

抖動.gif

原因

Translate() 是位移指定單位個距離,如果放在 Update() 裡,導致
角色被位移進去牆壁,然後再被彈出來,一直重複這樣就會像畫面抖動的樣子

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Example : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKey(KeyCode.D))
        {
            transform.Translate(moveSpeed * Time.deltaTime, 0, 0);
        }
        else if (Input.GetKey(KeyCode.A))
        {
            transform.Translate(-moveSpeed * Time.deltaTime, 0, 0);
        }
    }
}

解決辦法

使用 velocity 用改面物體速度的方式,會更像物理世界的
物體等速一樣,因為這個很逼真,所以要注意一些細節,例如
摩擦力、移動鍵放開時,若要靜止,需讓角色 velocity 歸零

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

public class Example : MonoBehaviour
{
    /// <summary>
    /// 角色移動速度
    /// </summary>
    [SerializeField] float moveSpeed = 5f;
    /// <summary>
    /// 地板層用來判斷角色有沒有在地板
    /// </summary>
    [SerializeField] private LayerMask platformsLayerMask;
    /// <summary>
    /// 角色的碰撞器
    /// </summary>
    private BoxCollider2D boxCollider2D;
    /// <summary>
    /// 玩家原本的材質
    /// </summary>
    private PhysicsMaterial2D _playerMaterial;
    /// <summary>
    /// 無摩擦力材質
    /// </summary>
    private PhysicsMaterial2D zeroFriction;
    /// <summary>
    /// 角色剛體
    /// </summary>
    private new Rigidbody2D rigidbody2D;

    // Start is called before the first frame update
    void Start()
    {
        boxCollider2D = transform.GetComponent<BoxCollider2D>();
        rigidbody2D = transform.GetComponent<Rigidbody2D>();
        _playerMaterial = rigidbody2D.sharedMaterial;

        zeroFriction = new PhysicsMaterial2D();
        zeroFriction.name = "ZeroFriction";
        zeroFriction.friction = 0f;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.D))
        {
            rigidbody2D.velocity = new Vector2(moveSpeed, rigidbody2D.velocity.y);
        }
        else if (Input.GetKey(KeyCode.A))
        {
            rigidbody2D.velocity = new Vector2(-moveSpeed, rigidbody2D.velocity.y);
        }
        else
        {
            rigidbody2D.velocity = new Vector2(0f, rigidbody2D.velocity.y);
        }

        // 避免卡在牆壁
        if (!IsGrounded())
        {
            rigidbody2D.sharedMaterial = zeroFriction;
        }
        else
        {
            rigidbody2D.sharedMaterial = _playerMaterial;
        }
    }

    /// <summary>
    /// 角色是否站在平台上
    /// </summary>
    /// <returns>是否站在平台上</returns>
    private bool IsGrounded()
    {
        RaycastHit2D raycastHit2D = Physics2D.BoxCast(
            boxCollider2D.bounds.center,
            boxCollider2D.bounds.size,
            0f,
            Vector2.down,
            .1f,
            platformsLayerMask
        );

        return raycastHit2D.collider != null;
    }
}

結果如下

不抖動.gif

備註

遊戲是參考 GrandmaCan -我阿嬤都會 的 Youtube 影片教學做出來的,網址附在最下面參考連結
他的教學真的很棒,很適合初學者

參考

觀看次數: 1949
bugFixedUpdateunity抖動撞牆
按讚追蹤 Enjoy 軟體 Facebook 粉絲專頁
每週分享資訊技術

一杯咖啡的力量,勝過千言萬語的感謝。

支持我一杯咖啡,讓我繼續創作優質內容,與您分享更多知識與樂趣!