该脚本使立方体“粘”到它与之碰撞的任何物体上。问题在于,当它以相对较高或中等的速度运行时(或者当设备本身速度较慢时),立方体往往会“进入”它与之碰撞的物体,然后粘在上面。我必须进行哪些更改才能解决此问题?
为了让这个脚本工作,一个游戏对象必须有 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;
}
以下是 Unity 编辑器的一些屏幕截图:
最佳答案
这是游戏工程中众所周知的一类问题,您会很高兴知道解决方案相对简单。您会很高兴听到类似但更复杂的问题实际上以相同的方式解决。我会试着解释一下。
现在事情来了。经常会出现以下问题...
So I'm working on GTA. I have a humanoid, H, running around. She approaches vehicle V. She opens the door and gets in and drives off. After that everything goes to hell in Mecanim and all the code stops working. What to do?
令人惊讶的是,在游戏中完成的方式是:
令人惊讶的是:那时你实际上换了完全不同的模型!!!!!!
你在游戏中有 H 和 V。但是然后你有一个动画(比如说)让 H 爬到 V。但是,你真的摧毁了 H 和 V 的游戏对象,而你实例化(或只是唤醒)一个全新的、完全不同的游戏对象 ,即 D(“一位女士驾驶的汽车”)。
(如果你仔细想想,你会发现,当你这样做时,你仔细调整了 D 中的所有东西,以便它 匹配 帧中“刚刚发生的事情”,与两者有关H 和 V。例如,从字面上看,您将汽车 V 的变换、扭曲等复制到新的 car-inside-D,如果女士 H 具有 SmearedMakeupEffect,则将相同的 SmearedMakeupEffect 放在 Lady-in-D ,您将所有骨骼放置相同,依此类推。)
另一个简单的例子是,你经常有人问,“我的角色 C 被杀了,我想让它变成布娃娃,怎么做?”事实上,您只需切换到一个全新的游戏对象,您已经为游戏的那段时间设置好了。事实上,如果你在游戏中有一个角色 A(“Arnie”),那么你有 4 或 5 个“不同的 As”坐在舞台外是很正常的,所以,有“布娃娃 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;
这就是你真正需要做的。第 1 步,您的脚本必须有
public bool
像这样 [System.NonSerialized] public bool isConnectedNow;
第 2 步,这里是 MyScript
继续击球立方体,首先我们将单元测试您的 isConnectedNow
bool 正在工作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);
}
}
附加、调试和运行。使小立方体粘住并从大立方体上取下.. 观察控制台。有用?所以将此添加到 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;
}
现在像这样在 MyScript 中的 Update() 中调用它 void Update()
{
Debug.Log("I am " yourScript.isConnectedNow ? "free" : "stuck");
if (yourScript.isConnectedNow) DistanceCorrectionX();
}
现在实际播放并坚持下去。现在,由于它在 Update
中运行只是在播放时查看检查器 MyScript
和 调整正确XDistance的值以获得您想要的确切外观。当您决定一个值时,取消播放并将其作为您希望的最终值。接下来,在
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
}
}
依此类推,您需要做“许多小事”。也不要忘记,绝大多数情况下您可能想要制作击中对象 的 child 大对象,看你的情况。 (当然,他们会作为一个整体一起走动。)
请注意,在上面的定位代码中,为了教学清晰,我只是将其显示为位置,而不是本地位置。如果你想让它们四处乱飞,旋转等等,你可以让击中对象成为另一个的 child ,你可以使用
localPosition
以同样的方式。享受。
关于c# - 正确制作 GameObject “attach”?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35754290/