让GameObject正确"附加"?

8 c# unity-game-engine

这个脚本使一个立方体"粘住"它碰撞的任何东西.问题在于,当它以相对较高或较高的速度运行时(或者当设备本身很慢时),立方体往往会"碰到"它碰到的东西,然后坚持下去.我需要做些什么改变才能解决这个问题?

为了使这个脚本工作,一个GameObject必须有bool _sticksToObjects = true;另一个bool _sticksToObjects = false;

我试图打开RigidbodyCollision Detection模式设置为ContinuousContinuous 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编辑器的一些屏幕截图:

在此输入图像描述

在此输入图像描述

在此输入图像描述

Fat*_*tie 6

这是游戏工程中众所周知的一类问题,您会很高兴知道解决方案相对简单.您会很高兴听到有类似但更复杂的问题以相同的方式实际解决.我会试着解释一下.

现在就是这样的.通常会出现以下问题......

所以我正在研究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"等等.

有趣的是,这里的"真实"解决方案是,

一旦他们成为一个新的联系的东西,摧毁他们两个并完全交换到一个新的游戏对象!

如果你制作游戏"直到你脸红了",那么这就是你当然会做的事情.即使它是一个简单的情况,从长远来看,它也更容易.毕竟,考虑发生这种情况时你必须做的所有事情:

  1. 使另一个人击中对象的孩子

  2. 关掉孩子的物理学

  3. 改变你的物理学对整个事物的工作方式

  4. 关闭或更改击中对象上的对撞机,可能使其成为整个对象的一部分

  5. 你可能会有一些新的"分离"物理学,它可以被淘汰 - 你必须把所有这些都打开

  6. 可能会改变声音效果,颜色等小问题

正如你所看到的那样,做这些事情是一项繁重的苦差事,事实上,它只是"更容易做到正确"并改为新模型.


所有这一切,我知道你想要一个快速脚本解决方案,你可以粘贴:)这里是......

第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以同样的方式使用它.请享用.