2015-11-21 8 views
7

Ich möchte Parenting vermeiden: "Es ist ein bisschen unsicher, obwohl Parenting Collider seltsame Ergebnisse, wie zufälliges Teleportieren oder Objekt beginnen können, sich verrückt zu bewegen und zu drehen usw." - Samed Tarık ÇETİN: comment.Collision Issues

+0

haben Sie versucht, eine übergeordnete Stelle dieser Art und Weise zu befestigen. Ich habe noch nie so etwas gemacht, aber ich habe im Internet gesucht und etwas gefunden, das deiner Situation ähnlich ist http://answers.unity3d.com/questions/55068/change-parent-of-gameobject-c.html. –

+0

Ja, ich habe es schon ausprobiert und ich bekomme immer wieder unerwartete Ergebnisse. Ich möchte Elternschaft vermeiden. "Es ist ein bisschen unsicher, aber Parenting Collider können seltsame Ergebnisse verursachen, wie zufälliges Teleportieren oder Objekte, die sich wahnsinnig bewegen und rotieren usw." - Samed Tarık ÇETİN: [Kommentar] (http://gamedev.stackexchange.com/questions/106270/how-can-i-make-a-gameobject-stick-to-another-gameobject-after-ith-has-collided # comment194060_106275) –

+0

Haben Sie versucht, nach dem Erkennen des Colliders des Kindes nur den Elternwert zu skalieren? Wie wenn (Kollisionsbedingung) {transform.parent.localScale ++}? –

Antwort

0

Änderung global

protected Collider stuckTo = null;  

///// Collider anstelle Aufgabe verwandeln. Sie könnten eine bessere Lösung bekommen.Informieren Sie mich, wenn es funktioniert oder gibt einen Fehler, da ich nicht versucht habe, wenn es funktioniert, würde ich gerne wissen.

void OnCollisionEnter(Collision col) 
{ 
    rb = GetComponent<Rigidbody>(); 
    rb.isKinematic = true; 

    if(stuckTo == null || stuckTo != col.gameObject.transform) 
     offset = col.collider.bounds.center - transform.position; 

    stuckTo = col.collider; 
} 
    public void LateUpdate() 
    { 
     if (stuckTo != null) 
      { 

     Vector3 distance=stuckTo.bounds.extents + GetComponent<Collider>().bounds.extents; 
     transform.position = stuckTo.bounds.center + distance; 

      } 
} 
+1

Nichts hat sich geändert. –

+1

Ich habe vergessen, offset.edited meine Antwort zu aktualisieren. Wenn es funktioniert, werde ich versuchen, den Code besser zu machen. –

+1

'' Fehler CS0103: Der Name 'col 'existiert nicht im aktuellen Kontext' 'ERROR in dieser Zeile:' offset = col.collider.bounds.center - transform.position; ' –

0

Vergewissern Sie sich, dass Sie die stuckTo Transformations Skalierung (derjenige, der die Collider an hat) und nicht von seinen Eltern oder das wird nicht funktionieren.

wenn die stuckTo 's Skala gleichmäßig ist:

protected Transform stuckTo = null; 
protected Vector3 originalPositionOffset = Vector3.zero; 
protected Vector3 positionOffset = Vector3.zero; 
protected Vector3 originalScaleOfTheTarget = Vector3.zero; 

public void LateUpdate() 
{ 
    if (stuckTo != null){ 
     positionOffset *= stuckTo.localScale.x; 
     transform.position = stuckTo.position - positionOffset; 
    } 
} 

void OnCollisionEnter(Collision col) 
{ 
    rb = GetComponent<Rigidbody>(); 
    rb.isKinematic = true; 

    if(stuckTo == null 
     || stuckTo != col.gameObject.transform){ 
     originalScaleOfTheTarget = col.gameObject.transform.localScale; 

     originalPositionOffset = col.gameObject.transform.position - transform.position; 
     originalPositionOffset /= originalScaleOfTheTarget.x; 
    } 

    stuckTo = col.gameObject.transform; 
} 

aber wenn die stuckTo' s Skala nicht einheitlich ist:

protected Transform stuckTo = null; 
protected Vector3 originalPositionOffset = Vector3.zero; 
protected Vector3 positionOffset = Vector3.zero; 
protected Vector3 originalScaleOfTheTarget = Vector3.zero; 

public void LateUpdate() 
{ 
    if (stuckTo != null){ 
     positionOffset.x = originalPositionOffset.x * stuckTo.localScale.x; 
     positionOffset.y = originalPositionOffset.y * stuckTo.localScale.y; 
     positionOffset.z = originalPositionOffset.z * stuckTo.localScale.z; 

     transform.position = stuckTo.position - positionOffset; 
    } 
} 

void OnCollisionEnter(Collision col) 
{ 
    rb = GetComponent<Rigidbody>(); 
    rb.isKinematic = true; 

    if(stuckTo == null 
     || stuckTo != col.gameObject.transform){ 
     originalScaleOfTheTarget = col.gameObject.transform.localScale; 

     originalPositionOffset = col.gameObject.transform.position - transform.position; 
     originalPositionOffset.x /= originalScaleOfTheTarget.x; 
     originalPositionOffset.y /= originalScaleOfTheTarget.y; 
     originalPositionOffset.z /= originalScaleOfTheTarget.z; 
    } 

    stuckTo = col.gameObject.transform; 
} 

Aber wenn auch noch - warum bist du nach ÇETİNs Rat Mann? Es ist absolut sicher für Eltern-Collider und Starrkörper und buchstäblich alles, solange Sie wissen, was Sie tun. Nur Eltern Ihre klebrigen verwandeln unter dem Ziel und Bam! Wenn etwas schief geht, entfernen Sie einfach Ihre Starrkörperkomponente oder deaktivieren Sie Ihre Beschleunigerkomponente.

+0

Vielen Dank für Ihre Antwort! Du hast gesagt: "Achte darauf, dass du das Steigen skalierst, um zu transformieren." Was meintest du genau? –

+0

Betrachten Sie einen Fall: huckedTo hat eine Elterntransformation. Wenn Sie das übergeordnete Element skalieren, kann das visuelle die selbe sein wie das Skalieren des stuckTo transform. Die tatsächliche Größe von stuckTo ändert sich jedoch nicht. Stellen Sie sicher, dass Sie stuckTo skalieren, nicht die Eltern. –

1

Ihre Grundidee richtig ist, können Sie den Code leicht, dies zu unterstützen modifiziert werden.

Hier ist der Trick: anstatt Ihr Objekt an das Objekt zu kleben, mit dem es kollidierte, erstellen Sie ein Dummy-Spielobjekt, nennen wir es "Leim", am Kollisionspunkt und kleben Sie Ihr Objekt an den Leim. Das Klebeobjekt wird dann auf das Objekt übertragen, mit dem wir kollidiert sind.

Da Leim nur ein Dummy-Objekt mit nur Komponenten-Transformation und einige Skript ist, gibt es kein Problem mit der Elternschaft.

Achten Sie auch darauf, dass es nicht wirklich wichtig ist, an welchem ​​Kontaktpunkt wir den Klebstoff herstellen, falls wir mehrere Kontaktpunkte haben, und es ist auch einfach, diese auf Rotationsbewegungen zu erweitern, siehe unten.

So bei der Kollision, das einzige, was wir jetzt tun, ist ein Klebstoff zu erstellen. Hier ist der Code:

void CreateGlue(Vector3 position, GameObject other) { 
    // Here we create a glue object programatically, but you can make a prefab if you want. 
    // Glue object is a simple transform with Glue.cs script attached. 
    var glue = (new GameObject("glue")).AddComponent<Glue>(); 

    // We set glue position at the contact point 
    glue.transform.position = position; 

    // This also enables us to support object rotation. We initially set glue rotation to the same value 
    // as our game object rotation. If you don't want rotation - simply remove this. 
    glue.transform.rotation = transform.rotation; 

    // We make the object we collided with a parent of glue object 
    glue.transform.SetParent(other.transform); 

    // And now we call glue initialization 
    glue.AttachObject(gameObject); 
} 

void OnCollisionEnter(Collision col) 
{ 
    // On collision we simply create a glue object at any contact point. 
    CreateGlue(col.contacts[0].point, col.gameObject); 
} 

Und hier ist, wie Glue.cs Skript aussieht, wird es behandeln LateUpdate und ändern transform.

public class Glue : MonoBehaviour { 

    protected Transform stuckTo = null; 
    protected Vector3 offset = Vector3.zero; 

    public void AttachObject(GameObject other) 
    { 
     // Basically - same code as yours with slight modifications 

     // Make rigidbody Kinematic 
     var rb = other.GetComponent<Rigidbody>(); 
     rb.isKinematic = true; 

     // Calculate offset - pay attention the direction of the offset is now reverse 
     // since we attach glue to object and not object to glue. It can be modified to work 
     // the other way, it just seems more reasonable to set all "glueing" functionality 
     // at Glue object 
     offset = transform.position - other.transform.position; 

     stuckTo = other.transform; 
    } 

    public void LateUpdate() 
    { 
     if (stuckTo != null) { 
      // If you don't want to support rotation remove this line 
      stuckTo.rotation = transform.rotation; 

      stuckTo.position = transform.position - transform.rotation * offset; 
     } 
    } 

    // Just visualizing the glue point, remove if not needed 
    void OnDrawGizmos() { 
     Gizmos.color = Color.cyan; 
     Gizmos.DrawSphere(transform.position, 0.2f); 
    } 
} 

Auch darauf achten, dass nur die Objekte, Elternschaft, wie es hier vorgeschlagen wurde, werden Sie in einigen zusätzlichen Schwierigkeiten geraten, weil die Skalierung Eltern auch Kinder skaliert, so dass Sie das Kind wieder Skala wieder auf seinen ursprünglichen müssen Größe. Das Problem ist, dass diese Skalierungsoperationen relativ zu verschiedenen Ankerpunkten sind, also müssen Sie auch zusätzliche Anpassungen in der Objektposition vornehmen. Kann aber getan werden.

Ich habe auch ein kleines Beispielprojekt erstellt, siehe hier (Unity v5.2.f3): https://www.dropbox.com/s/whr85cmdp1tv7tv/GlueObjects.zip?dl=0

P.S. Ich sehe, dass du Transformation und Starrkörper-Semantik mischt, da es auf kinematischen starren Körpern gemacht wird, ist das keine große Sache, sondern nur ein Vorschlag: denke darüber nach, ob du wirklich feste Körper an Objekten haben musst, die bereits "festgeklebt" sind - Entfernen oder deaktivieren Sie den Starrkörper, anstatt ihn kinematisch zu machen.

+0

Hallo! Vielen Dank für Ihre Antwort. Es scheint ein Problem bei der Implementierung Ihres Codes in meinem eigenen Projekt zu geben. Wenn das GameObject kollidiert, wird "Kleber" tatsächlich erzeugt, aber nicht auf der ** "Kante" **, mit der es kollidierte. Es ist in der Mitte geschaffen und daher kann es nicht gesehen werden, weil es drinnen eingedrungen ist. –

+0

Das ist seltsam. Im Grunde wird Kleber dort erzeugt, wo Sie sagen, er soll erstellt werden. Im obigen Beispiel setze ich einfach seine Position auf den ersten Kollisionspunkt, der col.contacts [0] .point ist. Sie haben nicht zufällig vergessen, die Leimposition nach der Erstellung auf den Kollisionspunkt zu setzen (wie im Beispiel in CreateGlue()). Wenn das nicht der Fall ist, dann kann ich nur daran denken, dass der Kollisionspunkt nicht auf der Oberfläche ist, was sehr unwahrscheinlich ist, im Grunde sollte die Physik-Engine damit umgehen ... –

+0

Nevermind, ich habe die Ursache des Problems gefunden Ich werde es dir später erzählen. Noch wichtiger: Ihr Code sorgt dafür, dass das GameObject bei einer Kollision angehängt wird, bleibt aber nicht angehängt, wenn sich die Skalierung ständig ändert ... –

1

Was Sie tun möchten, ist über den Kollisionspunkt zu skalieren. Sie können dies erreichen, indem Sie den Pivotpunkt auf den Kollisionspunkt setzen, wenn Sie das Objekt skalieren, das basierend auf dem Pivot skaliert wird. Der beste Weg, dies zu simulieren, ist die Verwendung von Sprites in Unity.

Scaling About Pivot Point

im Bild oben, hat die linke obere Steige einen Drehpunkt in der Mitte, so dass, wenn man es entlang der X-Skala, skaliert sie zu diesem Punkt, es ist Breite beiden Seiten des Drehpunktes zunehmender . Wenn der Pivot-Punkt jedoch wie im unteren linken Bild auf die Seite eingestellt ist, kann er beim Skalieren nur nach links verlängert werden (es sei denn, Sie skalieren natürlich negativ).

Jetzt ist das Problem, dass Sie den Drehpunkt des Netzes nicht einfach ändern können, so dass es eine Reihe von verschiedenen Umgehungslösungen dafür gibt. Ein solcher Ansatz besteht darin, das Netz an ein leeres neues gameObject anzuhängen und die lokale Transformation des Netzes in Bezug auf das übergeordnete Element anzupassen, wobei das Bewegen des Netzdrehpunkts simuliert wird.

Der folgende Code bestimmt den Kollisionspunkt. Da es mehrere Kollisionspunkte geben kann, erhalte ich den durchschnittlichen Kollisionspunkt von allen. Dann verschiebe ich die Mutter des Netzes zum Kollisionspunkt und stelle die lokale Position des Netzes so ein, dass die Seite des Würfels an diesem Punkt positioniert wird. Dies dient dazu, den Drehpunkt des Netzes auf den Kollisionspunkt zu setzen.

Jetzt, wenn Sie skalieren, wird es über den Kollisionspunkt skalieren, genau wie im obigen Bild.

public MeshRenderer _meshRenderer; 
public float _moveXDirection; 
public Rigidbody _rigidBody; 
public Transform _meshTransform; 
public bool _sticksToObjects; 
public ScalingScript _scalingScript; 

protected Transform _stuckTo = null; 
protected Vector3 _offset = Vector3.zero; 

void LateUpdate() 
{ 
    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; 

    // Enable the scaling script 
    if (_scalingScript != null) 
    { 
     _scalingScript.enabled = true; 
    } 
} 

Hier ist ein Beispiel-Projekt mit dem oben genannten Code: https://www.dropbox.com/s/i6pdlw8mjs2sxcf/CubesAttached.zip?dl=0

+0

Könnten Sie bitte Erstellen Sie ein anderes einfaches Projekt, damit ich besser verstehen kann, wie Ihr Code funktioniert? Die aktuelle zeigt nicht klar Ihren Code ... –

+1

Entschuldigung, ich bin mir nicht sicher, was passiert ist, aber sieht aus wie meine Änderungen an der Szene wurden nicht gespeichert. Ich habe das Projekt neu hochgeladen und es sollte nun funktionieren, wo zwei Würfel kollidieren, einer an dem anderen klebt und anfängt, auf und ab zu skalieren, während sich der andere Würfel entlang der x-Position bewegt. Ich werde versuchen, eine detailliertere Erklärung mit einigen Diagrammen in ein bisschen hinzuzufügen, sobald ich eine Chance habe. – Benzino

+0

Ihr Code passt nicht sehr gut zu meinem Skalierungsskript, das in meiner bearbeiteten Frage erwähnt wird. Können Sie Ihr Antwort- und Unity-Projekt mit einem eigenen Skalierungsskript aktualisieren? –