Wie kann ich im UI Text Element die Anzahl Gegner anzeigen die noch vorhanden sind (mit Tag)?

...komplette Frage anzeigen

2 Antworten

Es gibt zu der Möglichkeit, die du mit dosenbiiir ausgetüftelt hast, noch eine weitere, die den einen oder anderen Vorteil bietet. Es hängt zwar stark von deiner Absich ab, wozu du die Enemies benutzt, aber sie sollte sehr viel effizienter sein.

Eine Sekunde ist eine sehr lange Zeit für einen Computer. Es laufen viele, viele Frames in dieser Zeit und in jeder dieser Frames rufst du in Update(), eine Funktion, die jedes Frame gerufen wird, die Funktion GameObject.FindGameObjectsWithTag(). Das ist eine sehr kostspielige Funktion, was Effizienz angeht. Zusätzlich, die Anzahl der Enemies ändert sich ja nicht mit jedem Update(), richtig ? Du musst also auch nicht immer Updaten.

Aber was nun ? Wir habe jetzt eine Klasse, die Daten über unsere GameObjecte, die Enemies sind, speichern soll. Warum also speichern wir unsere Enemies nicht auch dort, in einer List<GameObject> ?

public class MyEnemies : MonoBehaviour{
[SerializeField]
Text enemyCount;
// Eine Liste mit allen enemies
List<GameObject> enemies;

private void Awake(){
// falls die Liste noch nicht existiert, erstelle sie
if(enemies ==null){enemies = new List<GameObject>();}
}

private void Start(){
// falls bereits enemies existieren, finde sie
GameObject.FindGameObjectsWithTag("Enemy");
}
}

So, was haben wir jetzt gemacht ? Wenn unser Skript erzeugt wird, also startet, wird die Funktion Start() gerufen, um alle GameObjects mit dem Tag "Enemy" zu finden, die bereits existieren. Das passiert automatisch, kein Funktionsaufruf von uns nötig ( siehe Awake() und Update() ). Die ganze Funktion Start() kannst du weglassen, wenn es keine Enemies gibt, bevor das Skript enabled wird.

Aber jetzt die Magie: Wir benutzen Getter und Setter, um das Textfeld zu ändern, wenn sich die Liste ändert. Das ist auch als Property bekannt. Wenn wir beispielsweise enemyCount.text rufen, dann rufen wir eine Property der Klasse enemyCount, nämlich den Text.

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System;

public class MyEnemies : MonoBehaviour
{
[SerializeField]
Text enemyCount;
// Eine Liste mit allen enemies
private List enemies;

public List Enemies
{
get { return enemies;}
set {enemies = value;
enemyCount.text = "Enemies left: " + Convert.ToString(enemies.Count);
}
}

private void Awake( ){
// falls die Liste noch nicht existiert, erstelle sie
if( enemies == null ) { enemies = new List(); }
}
private void Start( ){
// falls bereits enemies existieren, finde sie
GameObject.FindGameObjectsWithTag("Enemy");
}
}

Einziger kleiner Nachteil, du musst deine GameObjects manuell zu der Liste hinzufügen. Das musst du dann da machen, wo du Instantinate() machst, beispielsweise:

GameObject enemy = Instantiate(enemyPrefab);
// sollte werden zu
MyEnemies.Add(Instantiate(enemyPrefab));

Es würde sich gegebenfalls empfehlen, MyEnemies zu einer statischen Klasse zu machen, da du ja nur ein Objekt dieser Art brauchst. Das wäre dann keine Monobehaviour mehr, du würdest also einfach die Klasse rufen, wie oben, und das Skript nicht mehr an ein GameObject anhängen, also:

public static class MyEnemies{
//...
}

Text speichert keinen Text, sondern lediglich den Text Component. Wie du in Unity (Inspector Fenster) ja sehen kannst hat der Text Component viele verschiedene Werte (Font-Style, Font-Size etc.). Die Variable Text kannst du also mit folgendem verändern:

Enemies_left.text = "Irgendein Text";

Des weiteren solltest du wenn möglich nicht "GameObject.FindGameObjectsWithTag" benutzen um alle deine Gegner zu finden, kannst du machen ist aber mehr performance lastig. Besser ist wenn du alle Gegner in eine Liste speicherst und darauf zugreifst.

PS: Schreib den Anfangsbuchstaben von Variablen am besten klein ;)

Dan6erbond 08.01.2017, 09:42

Du scheinst dich auszukennen, kannst du mir vielleicht bei einem anderen Script auch noch helfen? ;)

0
Dan6erbond 08.01.2017, 09:52
@Dan6erbond

mach ich es falsch oder funktioniert deine Methode nicht?:

using System.Collections; using System.Collections.Generic; using UnityEngine.UI; using UnityEngine; public class Enemy_Values : MonoBehaviour { public Text Enemies_left; // Use this for initialization void Start () { } // Update is called once per frame void Update () { GameObject[] Enemies = GameObject.FindGameObjectsWithTag ("Enemy"); int ENEMIES = Enemies.Length; Enemies_left.text = "Enemies left: " + ENEMIES; } }

0
Dan6erbond 08.01.2017, 09:52
@dosenbiiir
using System.Collections;

using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;

public class Enemy_Values : MonoBehaviour {

public Text Enemies_left;

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {

GameObject[] Enemies = GameObject.FindGameObjectsWithTag ("Enemy");
int ENEMIES = Enemies.Length;

Enemies_left.text = "Enemies left: " + ENEMIES;
}
}
0
dosenbiiir 08.01.2017, 10:01
@Dan6erbond

Also bei mir funktioniert dein Script. Was funktioniert bei dir denn nicht?

Hast du die Variable "Enemies_left" auch in Unity (Inspector) zugewiesen?

Und hast du deinen Gegnern auch den Tag zugewiesen?


0

Was möchtest Du wissen?