二维物体碰撞统一
2D Object Collison Unity
我正在 Unity 中开发一个简单的 2D 游戏,在处理碰撞时我遇到了 运行 问题。我有两个对象,一棵树和一个玩家。树不会移动,并由一些精灵和多边形碰撞器表示。玩家使用自定义脚本(不是角色控制器)移动,并附有 kinematic Ridgidbody 和多边形对撞机。
我的预期行为是让玩家 'collide' 与树并被树挡住,因此 none 的物体可以移动。但是,这似乎不是一种简单的方法。
将树的 RidgidBody 组件设置为 'static' 或 'dynamic' 不会检测到碰撞。我考虑过让玩家成为一个 'dynamic' 刚体,但是 unity docs 建议动态刚体不应该被它们的变换组件移动,这就是我当前系统的工作方式。此外,将其设置为动态会导致玩家无缘无故冻结的意外行为,并且由于不会对玩家对象应用任何物理,这似乎是一个糟糕的动态用例。不过我可能是错的。
我可能会使用脚本在触发碰撞事件时以某种方式锁定玩家位置,但这看起来很老套。谁能提供一些有关如何处理此问题的见解?
显然 2D 碰撞有一点问题。这里有一些方法可以避免这个问题。基本上不是依赖碰撞器,它使用光线投射来检查玩家试图移动的地方是否有障碍物
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Player : MovingObjects {
protected override void AttemptMove<T> (int xDir, int yDir)
{
base.AttemptMove<T> (xDir, yDir);
RaycastHit2D hit;
}
protected override void onCantMove<T>(T component)
{
Wall hitwall = component as Wall;
hitwall.DamageWall (wallDamage);
}
// Update is called once per frame
void Update () {
int horizontal = 0;
int vertical = 0;
horizontal = (int)Input.GetAxisRaw ("Horizontal");
vertical = (int)Input.GetAxisRaw ("Vertical");
if (horizontal != 0)
vertical = 0;
if (horizontal != 0 || vertical != 0)
AttemptMove<Wall> (horizontal, vertical);
}
}
继承自:
using UnityEngine;
using System.Collections;
public abstract class MovingObjects : MonoBehaviour {
public float moveTime = 0.1f;
public LayerMask blockingLayer;
private BoxCollider2D boxCollider;
private Rigidbody2D rb2D;
private float inverseMoveTime;
protected virtual void Start()
{
boxCollider = GetComponent<BoxCollider2D> ();
rb2D = GetComponent <Rigidbody2D>();
inverseMoveTime = 1f / moveTime;
}
protected IEnumerator SmoothMovement(Vector3 end)
{
float sqrRemaininDistance = (transform.position - end).sqrMagnitude;
while (sqrRemaininDistance > float.Epsilon) {
Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime*Time.deltaTime);
rb2D.MovePosition(newPosition);
sqrRemaininDistance = (transform.position - end).sqrMagnitude;
yield return null;
}
}
protected bool Move(int xDir, int yDir, out RaycastHit2D hit)
{
Vector2 start = transform.position;
Vector2 end = start + new Vector2 (xDir, yDir);
boxCollider.enabled = false;
hit = Physics2D.Linecast (start, end, blockingLayer);
boxCollider.enabled = true;
if (hit.transform == null) {
StartCoroutine(SmoothMovement(end));
return true;
}
return false;
}
protected virtual void AttemptMove<T>(int xDir, int yDir)
where T : Component
{
RaycastHit2D hit;
bool canMove = Move (xDir, yDir, out hit);
if (hit.transform == null)
return;
Debug.Log ("Something hit", gameObject);
T hitComponent = hit.transform.GetComponent<T> ();
if (!canMove && hitComponent != null)
onCantMove (hitComponent);
}
protected abstract void onCantMove<T>(T component)
where T: Component;
}
该脚本属于Unity官网教程。一款名为 Rogue 的 2D 游戏。这是 link,以防您打算做类似的事情:
https://unity3d.com/es/learn/tutorials/projects/2d-roguelike-tutorial
我正在 Unity 中开发一个简单的 2D 游戏,在处理碰撞时我遇到了 运行 问题。我有两个对象,一棵树和一个玩家。树不会移动,并由一些精灵和多边形碰撞器表示。玩家使用自定义脚本(不是角色控制器)移动,并附有 kinematic Ridgidbody 和多边形对撞机。
我的预期行为是让玩家 'collide' 与树并被树挡住,因此 none 的物体可以移动。但是,这似乎不是一种简单的方法。
将树的 RidgidBody 组件设置为 'static' 或 'dynamic' 不会检测到碰撞。我考虑过让玩家成为一个 'dynamic' 刚体,但是 unity docs 建议动态刚体不应该被它们的变换组件移动,这就是我当前系统的工作方式。此外,将其设置为动态会导致玩家无缘无故冻结的意外行为,并且由于不会对玩家对象应用任何物理,这似乎是一个糟糕的动态用例。不过我可能是错的。
我可能会使用脚本在触发碰撞事件时以某种方式锁定玩家位置,但这看起来很老套。谁能提供一些有关如何处理此问题的见解?
显然 2D 碰撞有一点问题。这里有一些方法可以避免这个问题。基本上不是依赖碰撞器,它使用光线投射来检查玩家试图移动的地方是否有障碍物
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Player : MovingObjects {
protected override void AttemptMove<T> (int xDir, int yDir)
{
base.AttemptMove<T> (xDir, yDir);
RaycastHit2D hit;
}
protected override void onCantMove<T>(T component)
{
Wall hitwall = component as Wall;
hitwall.DamageWall (wallDamage);
}
// Update is called once per frame
void Update () {
int horizontal = 0;
int vertical = 0;
horizontal = (int)Input.GetAxisRaw ("Horizontal");
vertical = (int)Input.GetAxisRaw ("Vertical");
if (horizontal != 0)
vertical = 0;
if (horizontal != 0 || vertical != 0)
AttemptMove<Wall> (horizontal, vertical);
}
}
继承自:
using UnityEngine;
using System.Collections;
public abstract class MovingObjects : MonoBehaviour {
public float moveTime = 0.1f;
public LayerMask blockingLayer;
private BoxCollider2D boxCollider;
private Rigidbody2D rb2D;
private float inverseMoveTime;
protected virtual void Start()
{
boxCollider = GetComponent<BoxCollider2D> ();
rb2D = GetComponent <Rigidbody2D>();
inverseMoveTime = 1f / moveTime;
}
protected IEnumerator SmoothMovement(Vector3 end)
{
float sqrRemaininDistance = (transform.position - end).sqrMagnitude;
while (sqrRemaininDistance > float.Epsilon) {
Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime*Time.deltaTime);
rb2D.MovePosition(newPosition);
sqrRemaininDistance = (transform.position - end).sqrMagnitude;
yield return null;
}
}
protected bool Move(int xDir, int yDir, out RaycastHit2D hit)
{
Vector2 start = transform.position;
Vector2 end = start + new Vector2 (xDir, yDir);
boxCollider.enabled = false;
hit = Physics2D.Linecast (start, end, blockingLayer);
boxCollider.enabled = true;
if (hit.transform == null) {
StartCoroutine(SmoothMovement(end));
return true;
}
return false;
}
protected virtual void AttemptMove<T>(int xDir, int yDir)
where T : Component
{
RaycastHit2D hit;
bool canMove = Move (xDir, yDir, out hit);
if (hit.transform == null)
return;
Debug.Log ("Something hit", gameObject);
T hitComponent = hit.transform.GetComponent<T> ();
if (!canMove && hitComponent != null)
onCantMove (hitComponent);
}
protected abstract void onCantMove<T>(T component)
where T: Component;
}
该脚本属于Unity官网教程。一款名为 Rogue 的 2D 游戏。这是 link,以防您打算做类似的事情:
https://unity3d.com/es/learn/tutorials/projects/2d-roguelike-tutorial