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

时间:2015-12-24 20:25:43

标签: c# unity3d collision-detection

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

我在团结中有这个奇怪的碰撞错误,这里是它的一个gif:

GIF

重新创建:例如,在gif中,我按向左箭头向上箭头直到速度标准化,我得到一些为什么卡在一个块中。< / p>

当我在XNA中进行游戏时,我之前已经使用了自己的碰撞算法,希望在Unity中不会发生这种情况。

这是播放器脚本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 } }

CreateWallsColliders

这是当前的玩家对象:

player

这是墙面物体(除了图像之外,所有墙壁的预制都是相同的:

WALL

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

bug two

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

new collision boxes

这是检查员的详细信息

new inspector

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

它的代码位于var RepeatModule = React.createClass({ getInitialState: function() { return { items: [] } }, render: function() { var listItems = this.props.items.map(function(item) { return ( <li key={item.name}> <a href={item.link}>{item.name}</a> </li> ); }); return ( <div> <ul> {listItems} </ul> </div> ); } }); 方法的BoardManager脚本中。

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

new scene editor

2 个答案:

答案 0 :(得分:7)

您遇到的现象是由角色的矩形对撞机与下一个墙砖的底边碰撞引起的。这个&#39; bug&#39;在物理引擎中很常见。它是由一些计算错误引起的,应该是预期的。这就是为什么大多数游戏都有角色的边界椭圆,因为椭圆没有角落或边缘。

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

解决问题的一种更简单的方法是更改​​角色的对撞机。如果角色的矩形形状不是必需的,我建议您使用以下形状的对撞机:

capsule shaped collider

或者如果矩形是必不可少的,你可以用圆圈延伸角落:

enter image description here

答案 1 :(得分:3)

好吧,首先将输入代码从FixedUpdate移到Update,否则会导致应用程序出现滞后行为。第二件事是你可以通过Friction = 0Bounciness = 0创建PhysicsMaterial2D并将其附加到播放器以及Material中的墙壁对撞机来实现此目的。希望这会对你有所帮助。

修改

这里有一个替代解决方案,而不是每个块使用1个盒子对撞机,每侧仅使用1个对撞机。总共有4个碰撞者。

以下是代码,您可以将其添加到BoardManager课程中。并在SetUpScene方法结束时调用它,您可以进一步修改它。

void CreateWallsColliders ()
        {
            GameObject colliders = new GameObject ("Colliders");
            colliders.transform.position = Vector3.zero;

            GameObject leftCollider = new GameObject ("LeftCollider");
            leftCollider.transform.position = Vector3.zero;
            BoxCollider2D bcLeftCollider = leftCollider.AddComponent<BoxCollider2D> ();
            leftCollider.transform.parent = colliders.transform;

            GameObject rightCollider = new GameObject ("RightCollider");
            rightCollider.transform.position = Vector3.zero;
            BoxCollider2D bcRightCollider = rightCollider.AddComponent<BoxCollider2D> ();
            rightCollider.transform.parent = colliders.transform;

            GameObject topCollider = new GameObject ("TopCollider");
            topCollider.transform.position = Vector3.zero;
            BoxCollider2D bcTopCollider = topCollider.AddComponent<BoxCollider2D> ();
            topCollider.transform.parent = colliders.transform;

            GameObject bottomCollider = new GameObject ("BottomCollider");
            bottomCollider.transform.position = Vector3.zero;
            BoxCollider2D bcBottomCollider = bottomCollider.AddComponent<BoxCollider2D> ();
            bottomCollider.transform.parent = colliders.transform;

            // Assuming 15 x 15 tiles. Make it dynamic if you need.
            // Assuming -1 and 15 are the limits on both sides

            int rows = 15;
            int cols = 15;

            int lowerLimit = -1;
            int upperLimit = 15;

            leftCollider.transform.position = new Vector3 (lowerLimit, rows / 2);
            leftCollider.transform.localScale = new Vector3 (1, cols, 1);

            rightCollider.transform.position = new Vector3 (upperLimit, rows / 2);
            rightCollider.transform.localScale = new Vector3 (1, cols, 1);

            topCollider.transform.position = new Vector3 (cols / 2, upperLimit);
            topCollider.transform.localScale = new Vector3 (rows, 1, 1);

            bottomCollider.transform.position = new Vector3 (cols / 2, lowerLimit);
            bottomCollider.transform.localScale = new Vector3 (rows, 1, 1);
        }