Jump to content
Unity Insider Forum
Sign in to follow this  
Hans Ulrich

Menü beim ansehen eines Objektes

Recommended Posts

Hallo Community,

ich bin neu hier im Forum und versuche mich zur Zeit an der Unity Engine. Und zwar bastel ich zur Zeit an einem GUI. Dabei möchte ich, wenn ich mich zu einem Objekt bewege (Beispielsweise eine Kiste), dass dann ein Feld aufploppt, in dem Informationen über das Objekt stehen.

Zum Beispiel: Kiste steht auf einer Fläche, Spieler läuft in die Nähe von ihr und schaut sie an. Dann öffnet sich das Feld wo drin steht: Name des Objektes, Größe des Objektes usw...

Leider habe ich diesbezüglich nie etwas gefunden im Netz, sondern nur allgemein, wie man eine GUI erstellt.

Würde mich freuen wenn mir geholfen werden würde :) 

Liebe Grüße 

Share this post


Link to post
Share on other sites

Gibt da mehrere Wege... willst du, dass das GUI in der 3D-Welt schwebt (wie in Borderlands) oder eher, dass es auf einer festen Position auf dem Bildschirm aufploppt?

Share this post


Link to post
Share on other sites
vor 16 Minuten schrieb Sascha:

Gibt da mehrere Wege... willst du, dass das GUI in der 3D-Welt schwebt (wie in Borderlands) oder eher, dass es auf einer festen Position auf dem Bildschirm aufploppt?

Vielen Dank für die Antwort. Ich würde es bevorzugen, wenn es eine feste Position am Bildschirm hätte :)

Share this post


Link to post
Share on other sites

Ist etwas schwer, zu erraten, wodran es hapert.

  1. Dass du die Kiste anschaust, machst du mit einem Raycast von der Kamera weg.
  2. Dass das Objekt, das vom Raycast getroffen wurde, von Interesse ist (also zu den Objekten gehört, wegen denen das Info-Panel aufgeht), definierst du am besten mit einer entsprechenden Komponente auf dem Objekt.
  3. Was in dem Panel steht, sollte als Datensatz auf der Komponente stehen, sodass du einfach die Daten vom getroffenen Objekt auslesen und an das UI weitergeben kannst.
  4. Beim Weitergeben der Daten an das UI gibt es mehrere Wege. Es wäre hier vermutlich in Ordnung, ein Pseudo-Singleton zu nutzen, um die Daten über einen statischen Weg weiterzugeben.

Sollte irgendetwas davon (zu) unklar sein (mein Geld liegt auf Punkt 4. :)), dann sag Bescheid und ich erzähle ein bisschen was ;)

Share this post


Link to post
Share on other sites

Hey @Hans Ulrich - es gibt verschiedene Möglichkeiten, dies zu erreichen. Eine Variante hat Sascha bereits genannt: Raycasting. Du schickst per Mausklick einen "unsichtbaren Strahl" von der aktiven Kamera aus in die Szene. Dieser Strahl kann dann z.B basierend auf den Objekten die er trifft, verschiedene logische Abläufe ausführen. Sollte es sich bei dem Objekt was du angeklickt hast z.B um eine Kiste handeln, möchtest du die Informationen in einem seperaten UI-Panel angezeigt bekommen. Wie mein Vorgänger bereits erwähnt hat, könntest du in diesem Falle einfach ein Panel einblenden, was dann die Informationen aus dem "Kisteninhalt-Script" für dich ausliest und visualisiert.

Neben dem Raycasting könntest du ua. auch mit Distanz oder Triggern arbeiten, wenn dein Spiel eher auf Tastaturnavigation aufbaut. Die Funktion Vector3.Distance(float a, float b) returned einen Float, dessen Wert die exakte Distanz zwischen Punkt A und B ist. Du könntest also permanent prüfen, ob die Distanz zwischen der Kiste und dem Player einer gewissen Reichweite (Range) entspricht. Sollte dies gegeben sein, könntest du ebenfalls ein Panel einblenden und auch hier die Daten ans Panel transferieren. Ob du dafür eine extra Taste drücken müsst, oder ob es sich direkt öffnet wenn du in Reichweite bist, liegt dabei ganz bei dir.


Für die Trigger-Variante würdest du dem Objekt einfach einen Collider geben und ihn als Trigger kennzeichnen. Dann schreibst du deine Logik in der OnTriggerEnter oder OnTriggerStay Function, die auf der Kiste in einem Script liegt. Die Funktion prüft dann permanent, ob du dich noch im Radius des Triggers befindest. Anmerkung für diese Lösung: OnTriggerStay könnte Mucken machen und nur dann feuern, wenn du dich bewegst. Um dies zu vermeiden, ändere den sleeping Mode vom RigidBody. Nur als letzten Tipp.

Das wären drei simple Lösungen, die dich an dein Ziel bringen könnten. Solltest du nicht wissen, wie du allgemein eine Verbindung zwischen GUI und Script herstellen kannst, würde ich dir raten, zunächst einmal das Grundkonzept von Referenzen zu verinnerlichen um zu verstehen, wie du die Werte von Feldern, bzw. von Objekten quer durch dein Projekt schicken kannst. Hoffe, ich habe dich nicht zu sehr verwirrt :D 

 

Share this post


Link to post
Share on other sites

Wow! Erstmal vielen vielen Dank für eure Hilfe von euch beiden! Das hilft mir schon deutlich mehr, als ich vorher mit gedacht hatte! 

Ich werde es mal versuchen, die permanente Position des Spielers abzufragen und bei der Nähe zu einem Objekt wird das Panel dann eingeblendet. 

 

Woran es bei mir genau noch hapert: Ich finde bei keinem Tutorial die Möglichkeit, Informationionen aus dem Objekt auszulesen. Kennt ihr da Tricks, oder gar Tutorials? Zur Erstellung von GUIs gibt's ja massenweise Tipps, aber nicht, wie man Infos, beispielsweise über die Größe des Objektes ausliest und in das Panel schreibt. 

@Sascha

Am 27.3.2020 um 19:12 schrieb Sascha:

 

  1. Was in dem Panel steht, sollte als Datensatz auf der Komponente stehen, sodass du einfach die Daten vom getroffenen Objekt auslesen und an das UI weitergeben kannst. 

Und genau da Rätsel ich gerade wie ich die Daten auslesen könnte :D

@Maurice94

Du  hast mich nicht verwirrt, ganz im Gegenteil sogar :)

Share this post


Link to post
Share on other sites

@Hans Ulrich Grüß Gott.

Nur mal angenommen du hast irgendwo in deiner Szene ein Gameobjekt rumstehen. Dieses Objekt soll eine Kiste darstellen, deren Inhalt von Wert X ist. Diese Kiste ist jedoch nicht die einzige Kiste, die du in der Szene rumstehen hast. Du hast vielleicht noch 2 weitere Kisten unter einem Felsen, eine im Wasser, eine auf einer Wolke und weiß der Henker wo nicht noch alles. Ich weiß nicht, ob du es schon gemacht hast, oder wie breit dein Wissensstand generell gefächert ist - aber du musst jetzt eine neue Klasse schreiben (einen neuen Script anlegen) und diesen Script dann als Komponente auf deine Kiste legen. Du könntest deine Klasse z.B wie folgt schreiben:
 

using UnityEngine;
using UnityEngine.UI;
using System;

public class Schatztruhe : MonoBehaviour {
		
		public int GoldWert;

}


Wenn du nun einen derartigen Script als Komponente auf deine Kiste legst, wird der Script immer als eine eigene Instanz der Klasse behandelt. Heißt, auch wenn du 10 dieser Scripts auf 10 verschiedenen Kisten liegen hast, kannst du bei jeder Instanz den GoldWert individuell für das Objekt im Inspector festlegen. Das würde nicht für statische Klassen funktionieren, aber davon ist jetzt nicht die Rede.

Mit diesem Wissen könntest du nun also Gebrauch von den Methoden OnTriggerEnter / OnTriggerExit machen - diese Methoden feuern, wann immer du den Trigger betrittst / verlässt:

using UnityEngine;
using UnityEngine.UI;
using System;

public class Schatztruhe : MonoBehaviour {
		
		public int GoldWert;
  		public GameObject infoPanel; // Referenz zu deinem Panel
 		public Text infoText; // Referenz zu deinem Text

  		void OnTriggerEnter()
        { infoPanel.SetActive(true); infoText.text = GoldWert.ToString(); }
  
  		void OnTriggerExit()
        { infoPanel.SetActive(false); infoText.text = string.Empty; }
  
}

Und schon hättest du auf relativ einfache Art und Weise die Informationen deiner Kiste in dein Panel übertragen. Das hier sollte dir auf jeden Fall einen Einblick gewähren :D 
 

Share this post


Link to post
Share on other sites

Vielen Dank für die wirklich große Hilfe von euch!! :D

 

Ich werde die Tage jetzt mal ein wenig basteln und meinen Gehirnschmalz mit euren Hilfestellungen in Wallungen bringen. Ich berichte, wenn ich Erfolg hatte, oder ich kläglich am scheitern bin. 

 

Bis die Tage dann und danke nochmal!! :)

Share this post


Link to post
Share on other sites

Das heißt ja, dass bei jeder Schatztruhe die Referenz auf das Panel gesetzt sein muss. Und das kann man dann ohne weiteres nicht einmal einmalig im Prefab abhaken, weil das Panel ja Teil der Szene ist. @Maurice94 du erwähnst am Rande, dass das auch anders geht, aber ich würde gerne sehr deutlich von dieser Herangehensweise abraten.

@Hans Ulrich Daten auslesen ist sehr einfach: Du schreibst den Namen der Variable (bzw. Eigenschaft), die die Daten von Interesse enthält, dahin, wo die Daten erwartet werden.

So kannst du z.B. einen Wert von einer Variable in eine andere kopieren:

variableDieWertBekommt = variableDieAusgelesenWird;

Du kannst auch eine Methode aufrufen und den Wert einer Variable als Parameter übergeben:

MethodeDieAufgerufenWird(variableDessenWertUebergebenWird);

Innerhalb dieser Methode kannst du dann wieder dieselben zwei Dinge mit dem Wert machen:

public void MethodeDieAufgerufenWird(ParameterTyp parameterName)
{
  variableDieWertBekommt = parameterName;
  AndereMethode(parameterName);
}

Wenn du also eine Schatztruhe hast, dann bekommt die eine Komponente, auf der für alle Datenpunkte je eine Variable vorhanden ist (solange da nicht lauter gleichartige Datenpunkte sind, dann gibt's ne Sammlung):

public class InfoPanelObject : MonoBehaviour
{
  public string title;
  public int price;
}

Und wenn du deinen Raycast machst, schaust du, ob du ein Objekt getroffen hast, das so eine Komponente hat:

if (Physics.Raycast(ray, out var hit, ...))
{
  var infoPanelObject = hit.gameObject.GetComponent<InfoPanelObject>();
  if (infoPanelObject) // Wenn die Komponente existiert
  {
    Debug.Log(infoPanelObject.title + " wurde gefunden!");
  }
}

Hier wird die title-Variable der gefundenen Komponente ausgelesen und in Debug.Log reingesteckt. Stattdessen kannst du die Daten jetzt an dein Panel weitergeben, und den Titel z.B. der "text"-Eigenschaft eines UI-Texts zuweisen. Wenn du dich mit dem Pseudo-Singleton-Pattern noch nicht auseinandersetzen willst, dann kannst du fürs Erste auch deine Panel-Objekte über den Inspektor an das Raycast-Script zuweisen:

public Text titleText;

private void Update()
{
  var ray = ...;
  if (Physics.Raycast(ray, out var hit, ...))
  {
    var infoPanelObject = hit.gameObject.GetComponent<InfoPanelObject>();
    if (infoPanelObject) // Wenn die Komponente existiert
    {
      titleText.text = infoPanelObject.title;
    }
  }
}

Eigentlich ist es aber noch besser, wenn du deinem Panel ein Extrascript gibst, das die verschiedenen Elemente zusammenfasst:

public class InfoPanel : MonoBehaviour
{
  public Text titleText;
  public Text priceText;

  public void Display(InfoPanelObject infoPanelObject)
  {
    titleText.text = infoPanelObject.title;
    priceText.text = infoPanelObject.price + "";
  }
}

Und dann im Raycast-Script:

public InfoPanel panel;

private void Update()
{
  var ray = ...;
  if (Physics.Raycast(ray, out var hit, ...))
  {
    var infoPanelObject = hit.gameObject.GetComponent<InfoPanelObject>();
    if (infoPanelObject) // Wenn die Komponente existiert
    {
      panel.Display(infoPanelObject); // <-- !!
    }
  }
}

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...