2016-08-08 27 views
1

Szenario:Unity3D: in einem Zugriff auf transformiert eine Methode aus dem einzigen Skript zur Verfügung

Ich habe 10 Objekte in einer Szene. Jedem Objekt ist eine eindeutige Klasse zugeordnet. Wenn Sie auf ein Objekt klicken, müssen zwei Methoden aufgerufen werden.

  • Eine Methode in einem Skript, das an das angeklickte gameObject angehängt ist. (Um die Benutzeroberfläche des neu angeklickten Objekts zu aktivieren)
  • Eine Methode aus dem zuvor angeklickten gameObject. (Zum Deaktivieren des zuvor angeklickt Objekts UI)

Was ich getan habe:

if (Physics.Raycast(ray, out hit)) { 
hit.transform.GetComponent(hit.transform.name+"").Show_status (true); 
current_transform.GetComponent(current_transform.name+"").Show_status(false); 
current_transform = hit.transform; 
} 

Hier Ich versuche, das Script für den Zugriff mit der Zeichenfolge als das Skript nach dem Gameobject benannt selbst. Eine Methode namens "Show_status()" ist für alle Klassen verfügbar. Der obige Code erzeugt den folgenden Fehler.

„UnityEngine.Component‘ enthält keine Definition für `Show_status“

Auch wenn dies nicht möglich ist, die Art, wie ich es bin versucht, es wäre hilfreich, um einige zu nennen andere einfache Ansätze zur Lösung des Szenarios.

+1

GetComponent hat eine Form, die das Casting für Sie übernimmt, d. H. 'MyGameObject.GetComponent ()' – Cody

Antwort

2

Der Zugriff auf GameObject mit Namen ist langsam. hit.transform.name ist langsam und reserviert Speicher jedes Mal, wenn es aufgerufen wird. Getting Component nach String-Namen (GetComponent(string)) ist auch langsam.

Wenn dies nicht möglich ist, wie ich es versuche, wäre es hilfreich , einige andere einfache Ansätze zur Lösung des Szenarios zu erwähnen.

Dies kann problemlos mit einer Interface durchgeführt werden. Erstellen Sie ein einfaches Skript namens IClickableDies ist keine Klasse. Es ist eine Schnittstelle.

public interface IClickable 
{ 
    void Show_status(bool value); 
} 

Ihre 10 Scripts (Implementieren IClickable in jedem):

Script1 ObjectToClick1 genannt.

public class ObjectToClick1 : MonoBehaviour, IClickable 
{ 
    //Implement your interface function 
    public void Show_status(bool value) 
    { 
     //Your implementation here 
    } 
} 

Script2 genannt ObjectToClick2.

public class ObjectToClick2 : MonoBehaviour, IClickable 
{ 
    //Implement your interface function 
    public void Show_status(bool value) 
    { 
     //Your implementation here 
    } 
} 

Script3 genannt ObjectToClick3.

public class ObjectToClick3 : MonoBehaviour, IClickable 
{ 
    //Implement your interface function 
    public void Show_status(bool value) 
    { 
     //Your implementation here 
    } 
} 

...

...

Nun, für das Klicken Teil und Erfassen, welche Objekt geklickt wird:

public class ObjectTest : MonoBehaviour 
{ 
    Transform current_transform; 

    // Update is called once per frame 
    void Update() 
    { 
     if (Input.GetMouseButtonDown(0)) 
     { 
      //Raycast from mouse cursor pos 
      RaycastHit rayCastHit; 
      Ray rayCast = Camera.main.ScreenPointToRay(Input.mousePosition); 
      if (Physics.Raycast(rayCast, out rayCastHit)) 
      { 
       IClickable tempIClickable = rayCastHit.transform.GetComponent<IClickable>(); 
       if (tempIClickable != null) 
       { 
        tempIClickable.Show_status(true); 
        current_transform.GetComponent<IClickable>().Show_status(false); 
        current_transform = rayCastHit.transform; 
       } 
      } 
     } 
    } 
} 

Sie so viele wie möglich Schnittstelle hinzufügen können. Dies ist sehr flexibel und kann verwendet werden, um Arten von verfügbaren Feinden zu erkennen.

+0

Ja, das stimmt und wurde behoben. Danke, dass du das gesehen hast. – Programmer

1

Der Fehler sagt Ihnen genau, was falsch ist, die Unity Component Klasse hat keine Methode namens Show_status.

Sie müssen die von GetComponent zurückgegebene Component in Ihre benutzerdefinierte Klasse umwandeln. Beispiel:

CustomClass yourClass = hit.transform.GetComponent(hit.transform.name) as CustomClass; 

if(yourClass) { 
    yourClass.Show_status(true); 
} 

See: GameObject.GetComponent

+0

Die "CustomClass" ist unbekannt, bis der Spieler auf das GameObject klickt. Wir können jede mögliche Klasse irgendwo speichern und überprüfen. Aber ich suche nach einer einfacheren Lösung für das Problem. –

+2

Dann kommt es zu einem Design/Architektur-Problem in Ihrem Projekt. Brauchen Sie wirklich 10 völlig eindeutige Klassen (eine für jedes Objekt)? Es scheint, dass sie alle mindestens 'Show_status 'gemeinsam haben, also können Sie vielleicht identische Eigenschaften in eine Elternklasse kombinieren. Anschließend wird die Komponente in die übergeordnete Klasse umgewandelt und dann abhängig vom Status oder anderen Kriterien in die untergeordnete eindeutige Implementierung umgewandelt. Es ist schwer zu sagen, was die beste Strategie ist, ohne mehr über das Gesamtdesign zu wissen (was den Rahmen dieser Frage sprengen würde). – ssell

1

Sie müssen das Ergebnis der GetComponent() zu einer Klasse werfen ihre Methoden für den Zugriff auf - aber in Ihrer Situation, Sie wissen nicht, welches Skript an das Gameobject angebracht sein geklickt.

Dies ist einer der Fälle, in denen Vererbung eine mögliche Lösung bietet (die Alternative wäre, die Statusverfolgung zu einer separaten Komponente zu machen). Da Sie eine Methode haben, die mehreren Klassen gemeinsam ist, warum müssen sie nicht alle von einer Klasse erben, die diese Methode hat? Dann müssen Sie nicht unterscheiden, welche gerade auf das GameObject geklickt wird.

So Ihre Basisklasse könnte wie folgt aussehen:

public class StatusTracker : MonoBehaviour { 
    public virtual void Show_status(bool status){ 
     // Status-changing code 
    } 
} 

die Klassen Dann würden Sie eigentlich zu Ihrem Gameobjects befestigen als Komponenten von StatusTracker und die Form erben würde:

public class SpecializedStatusTracker : StatusTracker { 
    public override void Show_status(bool status){ 
     // Alternative status-changing code 
    } 
} 

Hinweis: Sie müssen Show_status() nur dann überschreiben, wenn Ihre Klasse es anders implementiert als das generische Show_status() - andernfalls müssen Sie die Methode in den untergeordneten Klassen nicht einmal definieren!

Anpassung Ihres Raycast Code entsprechend, können Sie werfen die zurück Component zu der übergeordneten Klasse StatusTracker (unter Verwendung der generische Variante von GetComponent()) etwa so:

if (Physics.Raycast(ray, out hit)) { 
    hit.transform.GetComponent<StatusTracker>().Show_status (true); 
    current_transform.GetComponent<StatusTracker>().Show_status(false); 
    current_transform = hit.transform; 
} 

hoffte, das hilft! Lass es mich wissen, wenn du irgendwelche Fragen hast.