Unity3d 有人能解释一下Unity 2d碰撞检测是如何工作的以及为什么有时会失败吗?

Unity3d 有人能解释一下Unity 2d碰撞检测是如何工作的以及为什么有时会失败吗?,unity3d,collision-detection,vectormath,Unity3d,Collision Detection,Vectormath,我尝试从本次现场会话中调整2d platformer角色控制器: 进入二维自上而下的角色控制器。这似乎是可行的,但它可以移动到碰撞机与一些组合键按下,我不能真正找到,但它很容易做到这一点 问题是我不明白碰撞检测在这里是如何工作的,所以我不知道如何修复它。如果有人能解释这是怎么回事,我将不胜感激 谢谢:) 这是玩家的设置方式: 播放器控制器TopDown2D.cs: using System.Collections; using System.Collections.Generic; using

我尝试从本次现场会话中调整2d platformer角色控制器:

进入二维自上而下的角色控制器。这似乎是可行的,但它可以移动到碰撞机与一些组合键按下,我不能真正找到,但它很容易做到这一点

问题是我不明白碰撞检测在这里是如何工作的,所以我不知道如何修复它。如果有人能解释这是怎么回事,我将不胜感激

谢谢:)

这是玩家的设置方式:

播放器控制器TopDown2D.cs

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

public class PlayerControllerTopDown2D : PhysicsObject2D
{
    public float maxSpeed = 7;

    private SpriteRenderer spriteRenderer;
    private Animator animator;

    private bool facingUp, facingDown, facingLeft, facingRight;

    void Awake()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
        animator = GetComponent<Animator>();

        facingUp = true;
        facingDown = facingLeft = facingRight = false;
    }

    protected override void ComputeVelocity()
    {
        Vector2 move = Vector2.zero;

        move.x = Input.GetAxis("Horizontal");
        move.y = Input.GetAxis("Vertical");

        targetVelocity = move * maxSpeed;

        if (move.y > minMoveDistance && !facingUp)
        {
            clearOthersAndSet(0);
            // sprite rotation
        }

        if (move.y < -minMoveDistance && !facingDown)
        {
            clearOthersAndSet(1);
            // sprite rotation
        }

        if (move.x < -minMoveDistance && !facingLeft)
        {
            clearOthersAndSet(2);
            // sprite rotation
        }

        if (move.x > minMoveDistance && !facingRight)
        {
            clearOthersAndSet(3);
            // sprite rotation
        }


    }

    void clearOthersAndSet(int x)
    {
        switch (x)
        {
            case 0;
                facingUp = true;
                facingDown = facingLeft = facingRight = false;
                break;
            case 1:
                facingDown = true;
                facingUp = facingLeft = facingRight = false;
                break;
            case 2:
                facingLeft = true;
                facingUp = facingDown = facingRight = false;
                break;
            case 3:
                facingRight = true;
                facingUp = facingDown = facingLeft = false;
                break;
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysicsObject2D : MonoBehaviour
{
    protected Rigidbody2D rb2d;
    protected Vector2 velocity;
    protected Vector2 targetVelocity;

    protected ContactFilter2D contactFilter;
    protected RaycastHit2D[] hitBuffer = new RaycastHit2D[16];
    protected List<RaycastHit2D> hitBufferList = new List<RaycastHit2D>(16);


    protected const float minMoveDistance = 0.001f;
    protected const float shellRadius = 0.01f;

    protected bool hitSomething = false;


    void OnEnable()
    {
        rb2d = GetComponent<Rigidbody2D>();
    }

    void Start()
    {
        contactFilter.useTriggers = false;
        int layerMask = Physics2D.GetLayerCollisionMask(gameObject.layer);
        contactFilter.SetLayerMask(layerMask);
        contactFilter.useLayerMask = true;
    }

    void Update()
    {
        targetVelocity = Vector2.zero;
        ComputeVelocity();
    }

    protected virtual void ComputeVelocity()
    {

    }

    void FixedUpdate()
    {
        if (hitSomething)
        {
            targetVelocity = -targetVelocity * 5;
            hitSomething = false;
        }

        velocity.x = targetVelocity.x;
        velocity.y = targetVelocity.y;

        Vector2 deltaPosition = velocity * Time.deltaTime;

        Vector2 move = Vector2.right * deltaPosition.x;

        Movement(move, false);

        move = Vector2.up * deltaPosition.y;

        Movement(move, true);
    }

    void Movement(Vector2 move, bool yMovement)
    {
        float distance = move.magnitude;

        if (distance > minMoveDistance)
        {
            int count = rb2d.Cast(move, contactFilter, hitBuffer, distance + shellRadius);

            if (count > 0)
                hitSomething = true;
            else
                hitSomething = false;

            hitBufferList.Clear();
            for (int i = 0; i < count; i++)
            {
                hitBufferList.Add(hitBuffer[i]);
            }

            for (int i = 0; i < hitBufferList.Count; i++)
            {
                float modifiedDistance = hitBufferList[i].distance - shellRadius;
                distance = modifiedDistance < distance ? modifiedDistance : distance;
            }
        }

        rb2d.position = rb2d.position + move.normalized * distance;
    }
}
使用系统集合;
使用System.Collections.Generic;
使用UnityEngine;
公共类PlayerController TopDown2D:PhysicsObject2D
{
公共浮点数maxSpeed=7;
私人喷灌工;
私人动画师;
二等兵面朝上,面朝下,面朝左,面朝右;
无效唤醒()
{
spriteender=GetComponent();
animator=GetComponent();
facingUp=true;
facingDown=facingLeft=facingRight=false;
}
受保护的覆盖void ComputeVelocity()
{
向量2移动=向量2.0;
move.x=Input.GetAxis(“水平”);
move.y=Input.GetAxis(“垂直”);
targetVelocity=移动*最大速度;
if(move.y>minMoveDistance&&!facingUp)
{
clearOthersAndSet(0);
//精灵旋转
}
if(move.y<-minMoveDistance&&!facingDown)
{
clearOthersAndSet(1);
//精灵旋转
}
if(move.x<-minMoveDistance&!facingLeft)
{
clearOthersAndSet(2);
//精灵旋转
}
如果(move.x>minMoveDistance&&!facingRight)
{
clearOthersAndSet(3);
//精灵旋转
}
}
无效clearOthersAndSet(int x)
{
开关(x)
{
案例0;
facingUp=true;
facingDown=facingLeft=facingRight=false;
打破
案例1:
面朝下=正确;
facingUp=facingLeft=facingRight=false;
打破
案例2:
facingLeft=真;
facingUp=facingDown=facingRight=false;
打破
案例3:
facingRight=正确;
facingUp=facingDown=facingLeft=false;
打破
}
}
}
PhysicsObject2D.cs

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

public class PlayerControllerTopDown2D : PhysicsObject2D
{
    public float maxSpeed = 7;

    private SpriteRenderer spriteRenderer;
    private Animator animator;

    private bool facingUp, facingDown, facingLeft, facingRight;

    void Awake()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
        animator = GetComponent<Animator>();

        facingUp = true;
        facingDown = facingLeft = facingRight = false;
    }

    protected override void ComputeVelocity()
    {
        Vector2 move = Vector2.zero;

        move.x = Input.GetAxis("Horizontal");
        move.y = Input.GetAxis("Vertical");

        targetVelocity = move * maxSpeed;

        if (move.y > minMoveDistance && !facingUp)
        {
            clearOthersAndSet(0);
            // sprite rotation
        }

        if (move.y < -minMoveDistance && !facingDown)
        {
            clearOthersAndSet(1);
            // sprite rotation
        }

        if (move.x < -minMoveDistance && !facingLeft)
        {
            clearOthersAndSet(2);
            // sprite rotation
        }

        if (move.x > minMoveDistance && !facingRight)
        {
            clearOthersAndSet(3);
            // sprite rotation
        }


    }

    void clearOthersAndSet(int x)
    {
        switch (x)
        {
            case 0;
                facingUp = true;
                facingDown = facingLeft = facingRight = false;
                break;
            case 1:
                facingDown = true;
                facingUp = facingLeft = facingRight = false;
                break;
            case 2:
                facingLeft = true;
                facingUp = facingDown = facingRight = false;
                break;
            case 3:
                facingRight = true;
                facingUp = facingDown = facingLeft = false;
                break;
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysicsObject2D : MonoBehaviour
{
    protected Rigidbody2D rb2d;
    protected Vector2 velocity;
    protected Vector2 targetVelocity;

    protected ContactFilter2D contactFilter;
    protected RaycastHit2D[] hitBuffer = new RaycastHit2D[16];
    protected List<RaycastHit2D> hitBufferList = new List<RaycastHit2D>(16);


    protected const float minMoveDistance = 0.001f;
    protected const float shellRadius = 0.01f;

    protected bool hitSomething = false;


    void OnEnable()
    {
        rb2d = GetComponent<Rigidbody2D>();
    }

    void Start()
    {
        contactFilter.useTriggers = false;
        int layerMask = Physics2D.GetLayerCollisionMask(gameObject.layer);
        contactFilter.SetLayerMask(layerMask);
        contactFilter.useLayerMask = true;
    }

    void Update()
    {
        targetVelocity = Vector2.zero;
        ComputeVelocity();
    }

    protected virtual void ComputeVelocity()
    {

    }

    void FixedUpdate()
    {
        if (hitSomething)
        {
            targetVelocity = -targetVelocity * 5;
            hitSomething = false;
        }

        velocity.x = targetVelocity.x;
        velocity.y = targetVelocity.y;

        Vector2 deltaPosition = velocity * Time.deltaTime;

        Vector2 move = Vector2.right * deltaPosition.x;

        Movement(move, false);

        move = Vector2.up * deltaPosition.y;

        Movement(move, true);
    }

    void Movement(Vector2 move, bool yMovement)
    {
        float distance = move.magnitude;

        if (distance > minMoveDistance)
        {
            int count = rb2d.Cast(move, contactFilter, hitBuffer, distance + shellRadius);

            if (count > 0)
                hitSomething = true;
            else
                hitSomething = false;

            hitBufferList.Clear();
            for (int i = 0; i < count; i++)
            {
                hitBufferList.Add(hitBuffer[i]);
            }

            for (int i = 0; i < hitBufferList.Count; i++)
            {
                float modifiedDistance = hitBufferList[i].distance - shellRadius;
                distance = modifiedDistance < distance ? modifiedDistance : distance;
            }
        }

        rb2d.position = rb2d.position + move.normalized * distance;
    }
}
使用系统集合;
使用System.Collections.Generic;
使用UnityEngine;
公共类PhysicsObject2D:单行为
{
受保护的刚体2d rb2d;
保护矢量2速度;
保护矢量2目标速度;
受保护的ContactFilter2D contactFilter;
受保护的RaycastHit2D[]hitBuffer=新的RaycastHit2D[16];
受保护列表hitBufferList=新列表(16);
保护常数浮点最小移动距离=0.001f;
保护常数浮球半径=0.01f;
受保护的布尔值=假;
void OnEnable()
{
rb2d=GetComponent();
}
void Start()
{
contactFilter.useTriggers=false;
int layerMask=Physics2D.GetLayerCollisionMask(gameObject.layer);
contactFilter.SetLayerMask(layerMask);
contactFilter.useLayerMask=true;
}
无效更新()
{
目标速度=矢量2.0;
计算速度();
}
受保护的虚拟void ComputeVelocity()
{
}
void FixedUpdate()
{
如果(某事)
{
targetVelocity=-targetVelocity*5;
有些东西是假的;
}
速度.x=目标速度.x;
速度y=目标速度y;
Vector2 deltaPosition=速度*时间.deltaTime;
Vector2 move=Vector2.right*deltaPosition.x;
移动(移动,错误);
move=Vector2.up*deltaPosition.y;
移动(移动,真);
}
虚空移动(矢量2移动,布尔移动)
{
浮动距离=移动幅度;
如果(距离>最小移动距离)
{
int count=rb2d.Cast(移动、contactFilter、hitBuffer、距离+外壳半径);
如果(计数>0)
有些事是真的;
其他的
有些东西是假的;
hitBufferList.Clear();
for(int i=0;i
简化,unity以同步方式检查每一帧的碰撞(为了帧下降补偿),如果您的对象移动得很快(在短时间内覆盖了很长的距离),则您的对象有可能在碰撞检查和其他碰撞检查的时间间隔内通过墙。 在这方面做了很好的陈述和测试

如果您的对象正在通过一个对象,您要更改的第一件事是碰撞检测模式,当该模式设置为离散时,表示该对象正在以较低的速率检查碰撞

当您将其设置为“连续”时,对象会更频繁地检查碰撞。


因此,可能将检测模式从“离散”设置为“连续”就足以解决您的问题。

简化,如果您的对象移动速度快(短时间内覆盖了很长的距离),unity会以同步方式检查每一帧的碰撞情况(为了进行帧降补偿),你的物体有可能穿过那堵墙