c# - Unity 2d 游戏中奇怪的碰撞错误

标签 c# unity3d collision-detection

Github Repository (Scripts folder, has all code in .cs files)

我在 unity 中遇到了这个奇怪的碰撞错误,这是它的 gif:

GIF

重新创建:例如,在 gif 中,我同时按下 向左箭头向上箭头 直到速度恢复正常,然后我明白了卡在 block 中的原因。

我以前在 XNA 中做游戏时用我自己的碰撞算法遇到过这种情况,希望这不会在 Unity 中发生。

这是播放器脚本PlayerMovement:

using UnityEngine;
using UnityEngine.UI;

namespace Assets.Scripts
{
    public enum Directions
    {
        Back,
        Left,
        Front,
        Right,
        Idle = -1
    }

    public class PlayerMovement : MonoBehaviour
    {
        #region Public Members

        /// <summary>
        /// Maximum speed of the player (Accelerated to over a period of time)
        /// </summary>
        public float speed;

        /// <summary>
        /// Debug UI.Text element
        /// </summary>
        public Text debugText;

        #endregion

        #region Constants

        /// <summary>
        /// Constant for decaying the velocity on updates
        /// </summary>
        private const float VELOCITY_DECAY_FACTOR = 0.85f;

        /// <summary>
        /// Constant to convert normal speed sizes to fit the scale
        /// Of UnityEngine.Vector2
        /// </summary>
        private const float HUMAN_TO_VECTOR_SCALE_FACTOR = 850f;

        /// <summary>
        /// Constant to set the base speed of the player animation
        /// </summary>
        private const float BASE_ANIM_SPEED = 0.7f;

        /// <summary>
        /// Constant to slightly reduce the animation speed after 
        /// It is multiplied by the velocity of the player
        /// </summary>
        private const float POST_VELOCITY_MULTIPLICATION_ANIM_SPEED_FACTOR = 0.5f;

        /// <summary>
        /// Constant to set the animation speed
        /// </summary>
        private const float ANIM_SPEED_MODIFIER = BASE_ANIM_SPEED * POST_VELOCITY_MULTIPLICATION_ANIM_SPEED_FACTOR;

        /// <summary>
        /// Epsilon before velocity zerofication
        /// </summary>
        private const float VELOCITY_EPSILON = 0.1f;

        #endregion

        #region Private Members

        private Rigidbody2D rb2D;
        private Vector2 velocity;
        private Animator animator;
        private Directions dir = Directions.Idle;

        #endregion

        #region Game Loop Methods

        private void Awake()
        {
            animator = GetComponent<Animator>();
            rb2D = GetComponent<Rigidbody2D>();
        }

        private void FixedUpdate()
        {
            float vertical = Input.GetAxisRaw("Vertical");
            float horizontal = Input.GetAxisRaw("Horizontal");
            UpdateVelocity(horizontal, vertical);
            UpdateAnimation(horizontal, vertical);
            UpdateMovment();
        }

        #endregion

        #region Animation Methods

        private void UpdateAnimation(float horizontal, float vertical)
        {
            UpdateAnimation(new Vector2(horizontal, vertical));
        }

        private void UpdateAnimation(Vector2 input)
        {
            Directions direction;

            if (input.y > 0)
                direction = Directions.Back;
            else if (input.y < 0)
                direction = Directions.Front;
            else if (input.x > 0)
                direction = Directions.Right;
            else if (input.x < 0)
                direction = Directions.Left;
            else
                direction = Directions.Idle;

            SetDirection(direction);
        }

        private void SetDirection(Directions value)
        {
            animator.SetInteger("Direction", (int)value);
            dir = value;
        }

        #endregion

        #region Movement Methods

        private void UpdateMovment()
        {
            rb2D.MovePosition(rb2D.position + velocity * Time.fixedDeltaTime);
            KinematicsDebugPrints();
            ApplySpeedDecay();
        }

        private string GetDebugPrintDetails()
        {
            return string.Format("HOR : {0}\nVER : {1}\nDIR : {2}:{3}\nX : {4}\nY : {5}",
                velocity.x,
                velocity.y,
                animator.GetInteger("Direction").ToString().PadLeft(2),
                (Directions)animator.GetInteger("Direction"),
                rb2D.position.x,
                rb2D.position.y);
        }

        private void KinematicsDebugPrints()
        {
            var details = GetDebugPrintDetails();
            debugText.text = details;
            Debug.Log(details);
        }

        private void UpdateVelocity(float horizontal, float vertical)
        {
            if (vertical != 0)
                velocity.y += Mathf.Sign(vertical) * speed / HUMAN_TO_VECTOR_SCALE_FACTOR;
            if (horizontal != 0)
                velocity.x += Mathf.Sign(horizontal) * speed / HUMAN_TO_VECTOR_SCALE_FACTOR;
            animator.speed = ANIM_SPEED_MODIFIER * velocity.MaxOfXandY() ;
        }

        private void ApplySpeedDecay()
        {
            if (velocity == Vector2.zero) return;

            velocity *= VELOCITY_DECAY_FACTOR;
            velocity = velocity.ZerofiyTinyValues(0.1f);
        }

        #endregion
    }
}

这是当前的播放器对象:

player

这是墙对象(除图像外,所有墙的预制件都相同:

WALL

这是我的另一个错误的 gif:

bug two

这是碰撞框和圆圈的样子:

new collision boxes

这是检查员的详细信息

new inspector


所以在与 Hamza Hasan 交谈后,他帮助我将所有外墙盒式碰撞器变成了四个连续碰撞器,每侧一个(顶部、底部、左侧、右侧)。

它的代码在 BoardManagerCreateWallsColliders 方法中的脚本。

这是当前场景在场景编辑器中的样子:

new scene editor

最佳答案

您遇到的现象是由您的角色的矩形碰撞器与下一砖墙的底部边缘碰撞引起的。这个“错误”在物理引擎中很常见。这是由一些计算错误引起的,应该是可以预料到的。这就是为什么大多数游戏都有角色的边界椭圆,因为椭圆没有角或边。

消除这种突然停止的一种方法是确保所有相邻的墙砖都表示为单个碰撞器(矩形或多边形)。这需要一个单独的逻辑,在加载关卡后从障碍物中创建碰撞器,并且必须在每次更改关卡(打开门等...)后更新碰撞器

解决这个问题的一个更简单的方法是改变角色的碰撞器。如果您的角色的矩形形状不是必需的,我建议您使用以下形状的碰撞器:

capsule shaped collider

或者如果矩形是必不可少的,你可以用圆圈来扩展角:

enter image description here

关于c# - Unity 2d 游戏中奇怪的碰撞错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34457613/

相关文章:

c# - 如何为 C++ 代码(为树程序使用大量指针)创建一个 dll,以便它可以在 ASP.Net Web 应用程序中引用

c# - 无法将源类型 system.nullable 转换为目标类型 int

c# - 使用 SteamVR 交互系统时如何获取 Controller 输入

c# - 在 AddComponent 上调用函数(字符串变量)

java - 矩形之间的碰撞检测 libgdx

c# - 无法从 App.config 读取 key

c# - 无法使用 3 层架构添加/更新

database - 如何提高我的 Unity 项目的安全性?

javascript - 球之间的碰撞检测javascript

ios - 如何在 SpriteKit 中检测不同类型的碰撞