Jump to content
Unity Insider Forum

Trigger / Collider C#


Rokks

Recommended Posts

Moinsen,

 

ich habe ein Testfeld mit 3 x 3 einfachen Cubes.

Jedes Cube hat ein separates Triggerfeld an den Seiten "A" bis "D". Ausgenommen der Ober- und Unterseite. Berührungen werden in den Variablen SideA bis SideD mit true/false gesetzt.

 

Um zu überprüfen, an welchen Seiten eine Berührung vorliegt, löst "OnTriggerStay" aus.

Angedacht ist, dass ich aus dem Testfeld einfache Cubes entferne und die dadurch nun unberührten Seiten auf "false" gesetzt werden.

Lohnt es, an dieser Stelle zusätzlich "OnTriggerExit" anzuführen, oder reicht "OnTriggerStay" vollkommen aus?

Es sollen bisweilen keinerlei Cubes neu gesetzt werden können, nur entfernen.

 

public string wallSide; //Welche Triggerseite meldet Kontakt

void OnTriggerStay(Collider col) {
//Wenn Collider-Layer == 10 (Trigger)
if (col.gameObject.layer == 10) {
 if (wallSide == "A") {
  //Seite-A -> Seite-C
  if (!transform.GetComponentInParent<WallState>().WallSiteA && col.gameObject.tag == "WallChild3") {
transform.GetComponentInParent<WallState>().WallSiteA = true;
  } else if (transform.GetComponentInParent<WallState>().WallSiteA && col.gameObject.tag != "WallChild3") {
transform.GetComponentInParent<WallState>().WallSiteA = false;
  }
 }
 if (wallSide == "B") {
  //Seite-B -> Seite-D
  if (!transform.GetComponentInParent<WallState>().WallSiteB && col.gameObject.tag == "WallChild4") {
		 transform.GetComponentInParent<WallState>().WallSiteB = true;
  } else if (transform.GetComponentInParent<WallState>().WallSiteB && col.gameObject.tag != "WallChild4") {
transform.GetComponentInParent<WallState>().WallSiteB = false;
  }
 }
 if (wallSide == "C") {
  //Seite-C -> Seite-A
  if (!transform.GetComponentInParent<WallState>().WallSiteC && col.gameObject.tag == "WallChild1") {
transform.GetComponentInParent<WallState>().WallSiteC = true;
  } else if (transform.GetComponentInParent<WallState>().WallSiteC && col.gameObject.tag != "WallChild1") {
transform.GetComponentInParent<WallState>().WallSiteC = false;
  }
 }
 if (wallSide == "D") {
  //Seite-D -> Seite-B
  if (!transform.GetComponentInParent<WallState>().WallSiteD && col.gameObject.tag == "WallChild2") {
transform.GetComponentInParent<WallState>().WallSiteD = true;
  } else if (transform.GetComponentInParent<WallState>().WallSiteD && col.gameObject.tag != "WallChild2") {
transform.GetComponentInParent<WallState>().WallSiteD = false;
  }
 }
}
}
}

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich hab mal versucht, das aufzudröseln, komme aber mit deiner Logik nicht klar. Ich denke, dass jeder deiner 3x3 Cubes insgesamt vier Collider als Trigger hat, auf jeder Seite einen? Und du willst anhand der OnTriggerStay rausfinden, wo ein Nachbarcube vorhanden ist und wo nicht? Oder sind das keine Collider, sondern andere GameObjekte? Wenn es GameObjekte sind, dann hat wohl jedes davon dieses Script und die Variable WallSide wird schon im Inspector gesetzt? Sonst ergibt das für mich keinen Sinn.

 

Wenn ich das richtig interpretiere, wirst du OnTriggerExit brauchen. Wenn du einen Cube entfernst, wird einfach OnTriggerStay nicht mehr aufgerufen und du kannst nicht darauf reagieren.

 

In deinem Code sehe ich aber noch ein paar Probleme:

 

OnTriggerStay wird Du rufst in jedem Frame für jeden Trigger, der in einem anderen Trigger steckt, mindestens drei mal GetComponentInParent auf. Das ist ziemlicher Overkill und drückt die Performance gewaltig. Was mich auch durcheinander bringt, du bezeichnest die Variable als WallSiteA, den Collider allerdings mit WallChild3. Warum nicht WallChildC?

 

Wenn ich alles richtig interpretiert habe, sollte das so auch gehen:

 

private WallState m_WallState;

void Start()
{
   m_WallState = (WallState)GetComponentInParent<WallState>();
}

void OnTriggerStay(Collider col)
{
   if (wallSide == "A") {
    if (col.gameObject.tag == "WallChild3")
	    m_WallState.WallSiteA = true;
   }
   if (wallSide == "B") {
    if (col.gameObject.tag == "WallChild4")
	    m_WallState.WallSiteB = true;
   }
}

void OnTriggerExit()
{
   if (wallSide == "A") {
    m_WallState.WallSiteA = false;
   if (wallSide == "B") {
    m_WallState.WallSiteB = false;
}

 

Ist natürlich nicht getestet und ich kann mich bei meinen Annahmen irren. Für eine bessere Lösung bräuchte ich mehr Code. Aber so würde ich vorgehen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Okay, das mit dem vorherigen setzen der Variable im Start() leuchtet ein.

Sagt OnTriggerStay aber nicht auch aus, dass ein Object im Trigger solange erkannt bleibt,wie er sich in diesem befindet?

Wäre OnTriggerExit somit nicht überflüssig?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich hab das Thema jetzt nur überflogen, aber: Ohne OnTriggerExit setzt ja am Ende keiner mehr den Wert auf false.

 

Was dagegen etwas überflüssi aussieht, ist OnTriggerStay - OnTriggerEnter würde vermutlich dasselbe Ergebnis bringen, und dafür nicht in jedem FixedUpdate passieren.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Bei näherer Überlegen ist da was wahres dran :)

Dank Hrungdak's Anregung, Get-Variablen bereits im Start() zu setzen, spare ich mir nicht nur viel getickere sondern auch einiges an Performance. Hatte mich bereits gewundert, wieso ab und an meine Gizmos und Drawlines verrückt gespielt haben :)

 

Ich danke.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Awake() wird noch vor Start() ausgeführt,soweit habe ich das verstanden. Ist der Unterschied der Variablenzuweisung so drastisch spürbar/messbar?

 

Bei vielen Objekten mit vielen Zugehörigkeiten und Anforderungen könnt ich mir das zumindest schon vorstellen, dass hier mal eine ms dort mal eine ms am ende zu Sekunden führen können.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Awake wird ausgeführt nachdem das Objekt Instanziiert wurde. Start wird ausgeführt wenn das Objekt Enabled wird/ist und wenn ich mich nicht irre sogar erst dann wenn der Part von Unity der grade den Code ausführt der das Objekt instanziierte fertig ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ob Awake() oder Start() hat erst mal nichts mit Performance zu tun. Nur mit dem Ausführungszeitpunkt. Das einzige, was die Performance beeinflusst, ist, wenn Objekte zwar instanziiert, aber nicht aktiviert werden. Start() wird erst bei der Aktivierung ausgeführt.

 

Guter Link, was wann wo ausgeführt wird und die Zusammenhänge:

 

http://docs.unity3d.com/Manual/ExecutionOrder.html

Link zu diesem Kommentar
Auf anderen Seiten teilen

Der Grund, warum du Awake für Variablenzuweisungen benutzen willst, ist schlicht, dass du in Start schon Dinge passieren lassen willst. Wenn diese Dinge nun von anderen Objekten abhängen und diese Objekte dafür bestimmte Werte schon gesetzt haben müssen, dann sollten diese in Awake schon gesetzt worden sein, damit sie in Start auf jeden Fall schon da sind.

Z.B.:

public class Fountain : MonoBehaviour
{
 private ParticleSystem waterSplash;

 void Awake()
 {
waterSplash = GetComponent<ParticleSystem>();
 }

 public void TurnOn()
 {
waterSplash.Play();
 }
}

 

public class FountainManager : MonoBehaviour
{
 [serializeField]
 private Fountain[] fountains;

 public Start()
 {
   //Schalte zufällig einen der Brunnen an
fountains[Random.Range(0, fountains.Length)].TurnOn();
 }
}

 

Wäre der Code in Fountain.Awake jetzt stattdessen in Start, könnte es sein, dass Start von FountainManager zuerst ausgeführt würde. Ergebnis wäre dann eine NullReferenceException anstatt eines angeschalteten Brunnens.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...