这个脚本使一个立方体"粘住"它碰撞的任何东西.问题在于,当它以相对较高或较高的速度运行时(或者当设备本身很慢时),立方体往往会"碰到"它碰到的东西,然后坚持下去.我需要做些什么改变才能解决这个问题?
为了使这个脚本工作,一个GameObject必须有bool _sticksToObjects = true;另一个bool _sticksToObjects = false;
我试图打开Rigidbody的Collision Detection模式设置为Continuous或Continuous Dynamic
我认为我的脚本取决于帧速率.这可能是问题所在.
正常"附加":
异常"附着":
Rigidbody _rigidBody;
Transform _meshTransform;
bool _sticksToObjects = true;
public Transform _stuckTo = null;
protected Vector3 _offset = Vector3.zero;
void Awake()
{
GameObject CubeMesh = GameObject.FindWithTag ("CubeMesh");
GameObject Cube = GameObject.FindWithTag ("Cube");
_rigidBody = Cube.GetComponent<Rigidbody> ();
_meshTransform = CubeMesh.GetComponent<Transform> ();
}
void Update()
{
if (_stuckTo != null)
{
transform.position = _stuckTo.position - _offset;
}
}
void OnCollisionEnter(Collision collision)
{
if (!_sticksToObjects) {
return;
}
_rigidBody.isKinematic = true;
// Get the approximate collision point and normal, as there
// may be multipled collision points
Vector3 contactPoint = Vector3.zero;
Vector3 contactNormal = Vector3.zero;
for (int i = 0; i < collision.contacts.Length; i++) {
contactPoint += collision.contacts [i].point;
contactNormal += collision.contacts [i].normal;
}
// Get the final, approximate, point and normal of collision
contactPoint /= collision.contacts.Length;
contactNormal /= collision.contacts.Length;
// Move object to the collision point
// This acts as setting the pivot point of the cube mesh to the collision point
transform.position = contactPoint;
// Adjust the local position of the cube so it is flush with the pivot point
Vector3 meshLocalPosition = Vector3.zero;
// Move the child so the side is at the collision point.
// A x local position of 0 means the child is centered on the parent,
// a value of 0.5 means it's to the right, and a value of -0.5 means it to the left
meshLocalPosition.x = (0.5f * contactNormal.x);
_meshTransform.localPosition = meshLocalPosition;
if (_stuckTo == null || _stuckTo != collision.gameObject.transform) {
_offset = collision.gameObject.transform.position - transform.position;
}
_stuckTo = collision.gameObject.transform;
}
Run Code Online (Sandbox Code Playgroud)
以下是Unity编辑器的一些屏幕截图:
这是游戏工程中众所周知的一类问题,您会很高兴知道解决方案相对简单.您会很高兴听到有类似但更复杂的问题以相同的方式实际解决.我会试着解释一下.
现在就是这样的.通常会出现以下问题......
所以我正在研究GTA.我有一个人形,H,跑来跑去.她接近车辆V.她打开车门进入并开走.之后,一切都在Mecanim中下地狱,所有代码都停止工作.该怎么办?
令人惊讶的是,游戏的方式是:
你在游戏中有H和V. 但是你有一个动画(比方说)让H爬到V.然后,你真的会破坏H和V的游戏对象,并且你实例化(或者只是唤醒)一个新的,完全不同的游戏对象,即D ("被一位女士驾驶的汽车").
(如果你考虑一下,你可以看到,当你这样做时,你仔细调整D中的所有东西,使它与帧中的"刚刚发生" 相匹配,与H和V相关.所以对于例如,从字面上看,你将汽车V的变换,扭曲等复制到新车里面D,如果女士H有SmearedMakeupEffect,你把同样的SmearedMakeupEffect放在D女士身上,你定位所有的骨头同样的,等等.)
另一个简单的例子就是,你经常让人们问,"我的角色C被杀了,我希望它成为一个布娃娃,怎么样?" 事实上,你只是换成了一个全新的游戏对象,你已经为游戏的那一段做好了准备.事实上,如果你在游戏中有一个角色A("Arnie"),那么你在舞台旁边有4或5个"不同的As"是正常的,所以,有"ragdoll A","A可以跳舞的人""A用武器".事实上,其中很多都是组合,你知道"A on the horse""A in the car"等等.
有趣的是,这里的"真实"解决方案是,
如果你制作游戏"直到你脸红了",那么这就是你当然会做的事情.即使它是一个简单的情况,从长远来看,它也更容易.毕竟,考虑发生这种情况时你必须做的所有事情:
使另一个人击中对象的孩子
关掉孩子的物理学
改变你的物理学对整个事物的工作方式
关闭或更改击中对象上的对撞机,可能使其成为整个对象的一部分
你可能会有一些新的"分离"物理学,它可以被淘汰 - 你必须把所有这些都打开
可能会改变声音效果,颜色等小问题
正如你所看到的那样,做这些事情是一项繁重的苦差事,事实上,它只是"更容易做到正确"并改为新模型.
所有这一切,我知道你想要一个快速脚本解决方案,你可以粘贴:)这里是......
第0步,您将创建"YourScript",它位于"主"立方体上.它会"抓住"另一个立方体移动.
YourScript看起来基本上就像这样......
[System.NonSerialized] public bool isConnectedNow;
void OnCollisionEnter(Collision collision)
GameObject theThingWeCaught = collision.gameObject
Debug.Log("We caught this thing .. " + theThingWeCaught.name)
// make it a child of us......
theThingWeCaught.transform.parent = transform
theThingWeCaught ... set kinematic
theThingWeCaught ... probably disable the rigidbody
theThingWeCaught ... probably disable the collider
isConnectedNow = true;
Run Code Online (Sandbox Code Playgroud)
这就是你所要做的一切.
第1步,你的脚本必须是public bool这样的
[System.NonSerialized] public bool isConnectedNow;
Run Code Online (Sandbox Code Playgroud)
第2步,这就是MyScript击中立方体,首先我们将对你的isConnectedNowbool工作进行单元测试
public Class MyScript:MonoBehaviour // attach to the "child" cube
{
public float correctXDistance;
public float correctYDistance;
public Transform bigCube;
public YourScript yourScript;
void Update()
{
string message = yourScript.isConnectedNow ? "free" : "stuck";
Debug.Log("I am " + message);
}
}
Run Code Online (Sandbox Code Playgroud)
附加,调试和运行.让小立方体棒并从大立方体中取出来.观察控制台.有用?所以添加这个MyScript
private void DistanceCorrectionX()
{
float xDistance = bigCube.position.x - transform.position.x;
float xSign = Mathf.Sign(xDistance);
float xDelta = Mathf.Abs(xDistance);
float closenessPercentage = (xDelta/correctXDistance)*100f;
if ( closenessPercentage<90f || closenessPercentage>110f)
{
// they are not close enough to quantize on this axis
// this comes in to play when you have multiple axes
return; // do nothing.
}
float xShouldBe = bigCube.position.x + xSign * correctXDistance;
Vector3 p = transform;
p.x = xShouldBe; // be careful it's .y, .z etc for other axes
transform.position = p;
}
Run Code Online (Sandbox Code Playgroud)
现在在MyScript中的Update()中调用它
void Update()
{
Debug.Log("I am " yourScript.isConnectedNow ? "free" : "stuck");
if (yourScript.isConnectedNow) DistanceCorrectionX();
}
Run Code Online (Sandbox Code Playgroud)
现在实际上玩,并坚持下去.现在,因为它Update只是在Play中查看Inspector,MyScript并调整correctXDistance的值以获得您想要的精确外观.当你决定一个值,unPlay并把它作为你想要的最终值.
接下来,DistanceCorrectionX简单地复制所有代码并再次为Y轴执行此操作DistanceCorrectionX.如果你也做Z,那就去做吧.
最后.请注意,你会有很多混乱的代码,比如这......
void Update()
{
// handle all the DistanceCorrectionX etc as seen above.
if (yourScript.isConnectedNow)
{
.. turn off the collider on me
}
else
{
.. turn on the collider on me
}
}
Run Code Online (Sandbox Code Playgroud)
等等,你需要做"很多小事".
不要忘记,绝大多数情况下,根据您的情况,您可能希望将击中物体作为大物体的孩子.(当然,他们会作为一个整体一起移动.)
请注意,在上面的定位代码中,我只是将其显示为位置,而不是本地位置,以获得教学清晰度.如果你想要它们四处乱窜,旋转等等,你就会让击球对象成为另一个对象的孩子,你会localPosition以同样的方式使用它.请享用.