我尝试通过此实时会话改编2d平台游戏角色控制器:https://www.youtube.com/watch?v=wGI2e3Dzk_w&list=PLX2vGYjWbI0SUWwVPCERK88Qw8hpjEGd8
进入2d自上而下的字符控制器。似乎可行,但是可以通过我无法真正发现的某些按键组合进入对撞机,但很容易实现。
问题是我不知道冲突检测在这里实际上是如何工作的,所以我不知道如何解决它。我很高兴有人可以解释它的工作原理。
谢谢:)
这是播放器的设置方式: Player Inspector
PlayerControllerTopDown2D.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;
}
}
}
PhysicsObject2D.cs :
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;
}
}
答案 0 :(得分:1)
简化,统一检查以检测每一帧,如果您的物体运动很快(在短时间内覆盖很长的距离),那么在碰撞检查间隙之间的确切时间里,您的物体就有可能穿过墙壁还有一个。 并对此thread进行了测试。
如果您的对象正在通过一个对象,则要更改的第一件事是碰撞检测模式,当该模式设置为离散模式时,您就说该对象正在检查碰撞率较低。
因此将检测模式从“离散”设置为连续可能足以解决您的问题。
答案 1 :(得分:1)
1)将重要的实体(例如玩家)的碰撞检测模式设置为“连续”。
2)使用rb2d.MovePosition();
进行移动。
3)一帧中不要多次呼叫rb2d.MovePosition()
。
这3项组合可以使您的移动和碰撞检测工作正常。 我不会质疑您的其余代码,但这是我的一般性建议
Vector2 MovementDirection; //Assuming this is assigned in Update() from Input
public float MaxSpeed;
void FixedUpdate()
{
Vector2 finalMoveDir = MovementDirection.normalized * MaxSpeed;
//
//any additional changes to the final direction should happen here
//
finalMoveDir *= Time.deltaTime;
rb2d.MovePosition((Vector2)transform.position + finalMoveDir);
}
答案 2 :(得分:0)
正如Matheus所建议的,我将对撞机模式更改为连续模式,但是问题仍然存在。我确实找到了实现这一目标的方法。
为完成这项工作,我删除了PhysicsObject2D.cs的第38行:
targetVelocity = -targetVelocity * 5;
在此位置,我按向左+向下,然后播放器将向上移动到盒对撞机中。玩家一开始不在其他对撞机内。
当物体重叠时,允许它们在内部自由移动,但移动速度慢得多,方向相反,按向上移动向下,按左箭头向右移动。