我找到了正式的团结培训https://www.youtube.com/watch?v=D5MqLcO6A8g 并找到bug。(看分数)
我花了大约2天时间修复它并失败了。 我找到了" DontGoThroughThings"脚本并尝试重写以在2D中使用。再次失败)
请帮助我!
这是重写脚本:
public LayerMask layerMask; //make sure we aren't in this layer
public float skinWidth; //probably doesn't need to be changed
private float minimumExtent;
private float partialExtent;
private float sqrMinimumExtent;
private Vector2 previousPosition;
private Rigidbody2D myRigidbody;
//initialize values
void Awake()
{
myRigidbody = GetComponent<Rigidbody2D>();
previousPosition = myRigidbody.position;
minimumExtent = Mathf.Min(Mathf.Min(GetComponent<Collider2D>().bounds.extents.x, GetComponent<Collider2D>().bounds.extents.y));
partialExtent = minimumExtent * (1.0f - skinWidth);
sqrMinimumExtent = minimumExtent * minimumExtent;
}
void FixedUpdate()
{
//have we moved more than our minimum extent?
Vector2 movementThisStep = myRigidbody.position - previousPosition;
float movementSqrMagnitude = movementThisStep.sqrMagnitude;
if (movementSqrMagnitude > sqrMinimumExtent)
{
float movementMagnitude = Mathf.Sqrt(movementSqrMagnitude);
//RaycastHit2D hitInfo;
//check for obstructions we might have missed
if (Physics2D.Raycast(previousPosition, movementThisStep, movementMagnitude, 0, layerMask.value))
myRigidbody.position = (movementThisStep/movementMagnitude)*partialExtent;
Debug.DrawLine(myRigidbody.position, myRigidbody.position - previousPosition, Color.green);
}
previousPosition = myRigidbody.position;
}
这是unitypackage https://www.dropbox.com/s/a3n1dalbc1k0k42/Hat%20Trick.unitypackage?dl=0
P.S。抱歉我的英文,谢谢你的帮助!!
答案 0 :(得分:1)
<强>解释强>
Unity中的连续碰撞检测不使用光线投射。结果,非常快速移动(和/或相对较小)的对象(现在让我们调用那种对象projectile
)仍然可以通过事物而不会检测到碰撞。着名的DontGoThroughThings组件修复了3D。有一些不一致,但如果你知道自己在做什么,就可以完成任务。
这是我对它的二维适应。
我添加了一些功能,使每个不擅长编码或游戏物理的人都更友好。
如何使用
OnTriggerEnter2D
事件。MessageName
变量)。我实际上建议,由于下面解释的警告。triggerTarget
变量确定它是否将消息发送给自身(如果你有一个附加到射弹的命中处理脚本),则命令被击中的对象(如果你有附加的命中处理)应该被射弹击中的物体,或两者的任何变化。momentumTransferFraction
变量进行调整。当两个物体碰撞时,产生的力是两个物体之间的动量传递(质量乘以速度)的结果。我这样做的方式非常简陋,并且缺少很多促成因素,但这足以使射弹对物体产生影响。就像在现实世界中一样,你的弹丸越快或越重,施加的力就越大。还有一些警告(大多数也适用于原始版本)
momentumTransferFraction
设置为1让子弹物理推动物体(通过将其所有动量施加到物体上)第一个命中对象)没有子弹受到影响。OnTriggerEnter2D
触发,或者(如果碰撞是不是触发器)对命中目标施加一个力(除了这个脚本所施加的力)。但是,由于这在某种程度上是随机的并且非常不一致,除了在您的射弹对撞机上打开IsTrigger
之外,我建议使用自定义消息名称来处理射弹撞击。这样,通过默认碰撞检测随机检测到的碰撞不会产生任何意外的副作用[请记住,对于这些类型的对象,默认碰撞检测不一致是添加此脚本的实际原因]。仅供参考:从Unity 5开始,防止默认碰撞检测的唯一两种方法是IgnoreCollision和IgnoreLayerCollision。<强>代码强>
using UnityEngine;
using System.Collections;
using System.Linq;
/// <summary>
/// 2D adaption of the famous DontGoThroughThings component (http://wiki.unity3d.com/index.php?title=DontGoThroughThings).
/// Uses raycasting to trigger OnTriggerEnter2D events when hitting something.
/// </summary>
/// <see cref="http://stackoverflow.com/a/29564394/2228771"/>
public class ProjectileCollisionTrigger2D : MonoBehaviour {
public enum TriggerTarget {
None = 0,
Self = 1,
Other = 2,
Both = 3
}
/// <summary>
/// The layers that can be hit by this object.
/// Defaults to "Everything" (-1).
/// </summary>
public LayerMask hitLayers = -1;
/// <summary>
/// The name of the message to be sent on hit.
/// You generally want to change this, especially if you want to let the projectile apply a force (`momentumTransferFraction` greater 0).
/// If you do not change this, the physics engine (when it happens to pick up the collision)
/// will send an extra message, prior to this component being able to. This might cause errors or unexpected behavior.
/// </summary>
public string MessageName = "OnTriggerEnter2D";
/// <summary>
/// Where to send the hit event message to.
/// </summary>
public TriggerTarget triggerTarget = TriggerTarget.Both;
/// <summary>
/// How much of momentum is transfered upon impact.
/// If set to 0, no force is applied.
/// If set to 1, the entire momentum of this object is transfered upon the first collider and this object stops dead.
/// If set to anything in between, this object will lose some velocity and transfer the corresponding momentum onto every collided object.
/// </summary>
public float momentumTransferFraction = 0;
private float minimumExtent;
private float sqrMinimumExtent;
private Vector2 previousPosition;
private Rigidbody2D myRigidbody;
private Collider2D myCollider;
//initialize values
void Awake()
{
myRigidbody = GetComponent<Rigidbody2D>();
myCollider = GetComponents<Collider2D> ().FirstOrDefault();
if (myCollider == null || myRigidbody == null) {
Debug.LogError("ProjectileCollisionTrigger2D is missing Collider2D or Rigidbody2D component", this);
enabled = false;
return;
}
previousPosition = myRigidbody.transform.position;
minimumExtent = Mathf.Min(myCollider.bounds.extents.x, myCollider.bounds.extents.y);
sqrMinimumExtent = minimumExtent * minimumExtent;
}
void FixedUpdate()
{
//have we moved more than our minimum extent?
var origPosition = transform.position;
Vector2 movementThisStep = (Vector2)transform.position - previousPosition;
float movementSqrMagnitude = movementThisStep.sqrMagnitude;
if (movementSqrMagnitude > sqrMinimumExtent) {
float movementMagnitude = Mathf.Sqrt(movementSqrMagnitude);
//check for obstructions we might have missed
RaycastHit2D[] hitsInfo = Physics2D.RaycastAll(previousPosition, movementThisStep, movementMagnitude, hitLayers.value);
//Going backward because we want to look at the first collisions first. Because we want to destroy the once that are closer to previous position
for (int i = 0; i < hitsInfo.Length; ++i) {
var hitInfo = hitsInfo[i];
if (hitInfo && hitInfo.collider != myCollider) {
// apply force
if (hitInfo.rigidbody && momentumTransferFraction != 0) {
// When using impulse mode, the force argument is actually the amount of instantaneous momentum transfered.
// Quick physics refresher: F = dp / dt = m * dv / dt
// Note: dt is the amount of time traveled (which is the time of the current frame and is taken care of internally, when using impulse mode)
// For more info, go here: http://forum.unity3d.com/threads/rigidbody2d-forcemode-impulse.213397/
var dv = myRigidbody.velocity;
var m = myRigidbody.mass;
var dp = dv * m;
var impulse = momentumTransferFraction * dp;
hitInfo.rigidbody.AddForceAtPosition(impulse, hitInfo.point, ForceMode2D.Impulse);
if (momentumTransferFraction < 1) {
// also apply force to self (in opposite direction)
var impulse2 = (1-momentumTransferFraction) * dp;
hitInfo.rigidbody.AddForceAtPosition(-impulse2, hitInfo.point, ForceMode2D.Impulse);
}
}
// move this object to point of collision
transform.position = hitInfo.point;
// send hit messages
if (((int)triggerTarget & (int)TriggerTarget.Other) != 0 && hitInfo.collider.isTrigger) {
hitInfo.collider.SendMessage(MessageName, myCollider, SendMessageOptions.DontRequireReceiver);
}
if (((int)triggerTarget & (int)TriggerTarget.Self) != 0) {
SendMessage(MessageName, hitInfo.collider, SendMessageOptions.DontRequireReceiver);
}
}
}
}
previousPosition = transform.position = origPosition;
}
}
答案 1 :(得分:0)
以下是我重写此脚本的2D版本(适用于Unity 4.6):
using UnityEngine;
using System.Collections;
public class DontGoThroughThings : MonoBehaviour
{
public delegate void CollidedDelegate(Collider2D collider);
public event CollidedDelegate Collided;
public LayerMask layerMask; //make sure we aren't in this layer
public float skinWidth = 0.1f; //probably doesn't need to be changed
private float minimumExtent;
private float partialExtent;
private float sqrMinimumExtent;
private Vector2 previousPosition;
private Rigidbody2D myRigidbody;
//initialize values
void Awake()
{
myRigidbody = rigidbody2D;
previousPosition = myRigidbody.transform.position;
minimumExtent = Mathf.Min(BoundsOf(collider2D).extents.x, BoundsOf(collider2D).extents.y);
partialExtent = minimumExtent * (1.0f - skinWidth);
sqrMinimumExtent = minimumExtent * minimumExtent;
}
void FixedUpdate()
{
//have we moved more than our minimum extent?
Vector2 movementThisStep = (Vector2)myRigidbody.transform.position - previousPosition;
float movementSqrMagnitude = movementThisStep.sqrMagnitude;
if (movementSqrMagnitude > sqrMinimumExtent)
{
float movementMagnitude = Mathf.Sqrt(movementSqrMagnitude);
//check for obstructions we might have missed
RaycastHit2D[] hitsInfo = Physics2D.RaycastAll(previousPosition, movementThisStep, movementMagnitude, layerMask.value);
//Going backward because we want to look at the first collisions first. Because we want to destroy the once that are closer to previous position
for (int i = hitsInfo.Length-1; i >= 0; i--)
{
var hitInfo = hitsInfo[i];
if (hitInfo && hitInfo.rigidbody != rigidbody2D)
{
if (Collided != null)
{
Collided(hitInfo.collider);
}
}
}
}
previousPosition = myRigidbody.transform.position;
}
// compute bounds in local space
public static Bounds BoundsOf(Collider2D collider) {
var bounds = new Bounds();
var bc = collider as BoxCollider2D;
if (bc) {
var ext = bc.size * 0.5f;
bounds.Encapsulate(new Vector3(-ext.x, -ext.y, 0f));
bounds.Encapsulate(new Vector3(ext.x, ext.y, 0f));
return bounds;
}
var cc = collider as CircleCollider2D;
if (cc) {
var r = cc.radius;
bounds.Encapsulate(new Vector3(-r, -r, 0f));
bounds.Encapsulate(new Vector3(r, r, 0f));
return bounds;
}
// others :P
//Debug.LogWarning("Unknown type "+bounds);
return bounds;
}
// return bounds in world space
public static Bounds BoundsColliders(GameObject obj) {
var bounds = new Bounds(obj.transform.position, Vector3.zero);
var colliders = obj.GetComponentsInChildren<Collider2D>();
foreach(var c in colliders) {
var blocal = BoundsOf(c);
var t = c.transform;
var max = t.TransformPoint(blocal.max);
bounds.Encapsulate(max);
var min = t.TransformPoint(blocal.min);
bounds.Encapsulate(min);
}
return bounds;
}
}
如果它适合您,请告诉我。
谢谢, 利胆