Jump to content
Unity Insider Forum

gezählte Items weiter verarbeiten


Brxn

Recommended Posts

Hi guys and girls,

 

versuche mich gerade an nem kleinem Sammelspiel, um n bisschen in´s coding rein zu kommen und zu lernen. hab dafür nen kleines Tutorial nachgearbeitet und das hier is mein Code bis jetzt:

 

using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine;
public class collect_pickup : MonoBehaviour
{
   public GameObject inventoryPanel;
   public GameObject[] inventoryIcons;
   public Text Score;
   void OnCollisionEnter(Collision collision)
   {
    //look through children for existing icon
    foreach (Transform child in inventoryPanel.transform)
    {
	    //if item is already in inventory
	    if (child.gameObject.tag == collision.gameObject.tag)
	    {
		    string c = child.Find("Text").GetComponent<Text>().text;
		    int tcount = System.Int32.Parse(c) + 1;
		    child.Find("Text").GetComponent<Text>().text = "" + tcount;
		    return;
	    }
    }
    GameObject i;
    if (collision.gameObject.tag == "pickup_1")
    {
	    i = Instantiate(inventoryIcons[0]);
	    i.transform.SetParent(inventoryPanel.transform);
    }
    else if (collision.gameObject.tag == "pickup_2")
    {
	    i = Instantiate(inventoryIcons[1]);
	    i.transform.SetParent(inventoryPanel.transform);
    }
    else if (collision.gameObject.tag == "pickup_3")
    {
	    i = Instantiate(inventoryIcons[2]);
	    i.transform.SetParent(inventoryPanel.transform);
    }
   }
}

 

funktioniert soweit auch prima. Mein Problem ist, dass ich den verschiedenen Items verschiedene Punkte zuweisen will, die in einem Textfeld als gesamte Score angegeben wird.

 

Also zum Beispiel Item_1 ist 10 Punkte wert, Item_:2 ist aber 25 Punkte werd usw. ..

Da ich ja die einzelnen Items schon zähle, bräuchte ich sie nur noch mit der Punktzahl multiplizieren und alle zusammen rechnen. Klang in der ersten Überlegung recht einfach, aber ich weiss nicht, wie ich das mit meinem bisherigen Code verschmelzen soll.

 

Gibts da ne Möglichkeit mit dem Code da oben ?

 

Grüße

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich denke, es ist leicht nachzuvollziehen, dass dein aktueller Weg nicht gerade vorteilhaft ist.

Wenn du 200 Items in deiner Szene hast musst du 200 Mal diese 4 Zeilen kopieren, die noch dazu alle fast gleich sind.

Und wenn du dann eines der Items ändern möchtest, musst du unter den 800 Zeilen das richtige Pickup raussuchen.

Ich habe seit einigen Jahren überhaupt keine Tags mehr in Verwendung, weil man nahezu alles, was man damit machen kann, ohne Tags besser machen kann.

 

Gegen derartige Code-Duplizierung helfen einfache Objekte. In diesem Fall, um mal ein paar Schritte zu überspringen, wäre eine Komponentenklasse sinvoll.

Du machst also ein neues Skript:

class Pickup : MonoBehaviour
{
 [serializeField]
 private GameObject _inventoryIcon;
 public GameObject inventoryIcon { get { return _inventoryIcon; } }
}

Das Skript kriegen alle deine Pickup-GameObjects.

Dein obiges Skript würde dann statt der if-Abfragen einfach nur noch folgendes tun:

var pickup = collision.gameObject.GetComponent<Pickup>();
if(pickup)
{
 var icon = Instantiate(pickup.inventoryIcon);
 icon.transform.SetParent(inventoryPanel.transform);
}

Damit würde dasselbe passieren wie jetzt auch schon, nur dass du, wenn ein neues Pickup eingebaut oder eines geändert werden soll, nicht mehr in den Code zu gehen brauchst. Du machst das neue Pickup-GameObject, packst die Pickup-Komponente drauf und ziehst das InventoryIcon in das Pickup. Fertig!

 

Wenn du jetzt Punkte einbauen willst, musst du nur eine Punktzahl in die Pickup-Klasse einbauen, z.B. so:

class Pickup : MonoBehaviour
{
 [serializeField]
 [Range(1,100)]
 private int _points;
 public int points { get { return _points; } }
}

Und dann kannst du in der anderen Klasse die Punkte auslesen und benutzen, wie du willst.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hey Sascha "alter" CodeGuru :P

 

ich hab versucht es echt zu verstehen und umzusetzen ... mit mäßigem Erfolg.

 

Ich habe ein neues Script mit dem Namen "Pickup" erstellt und folgenden Code reingeschrieben:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pickup : MonoBehaviour {

    [serializeField]
    private GameObject _inventoryIcon;
    public GameObject inventoryIcon { get { return _inventoryIcon; } }
   }

Dies habe ich meinen Objekten, die ich sammeln will, angehängt.

 

Jetzt wirds kniffelig für mich. Mein altes Script "collect_pickup" ändere ich wie folgt um?:

using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine;
public class Collect_Pickup1 : MonoBehaviour
{
   public GameObject inventoryPanel;
   public GameObject[] inventoryIcons;
   public Text Score;
   void OnCollisionEnter(Collision collision)
   {
    //look through children for existing icon
    foreach (Transform child in inventoryPanel.transform)
    {
	    //if item is already in inventory
	    if (child.gameObject.tag == collision.gameObject.tag)
	    {
		    string c = child.Find("Text").GetComponent<Text>().text;
		    int tcount = System.Int32.Parse(c) + 1;
		    child.Find("Text").GetComponent<Text>().text = "" + tcount;
		    return;
	    }
    }

    var pickup = collision.gameObject.GetComponent<Pickup>();
    if (pickup)
    {
	    var icon = Instantiate(pickup.inventoryIcon);
	    icon.transform.SetParent(inventoryPanel.transform);
    }
   }
}

 

Die Items verschwinden zwar noch, aber der Zähler und die Icons funktionieren irgendwie nicht mehr. Das mit dem weiterverarbeiten, habe ich erstmal noch nicht angegriffen :(

 

Grüße

Link zu diesem Kommentar
Auf anderen Seiten teilen

//e: Code repariert.

 

Also, deine Schleife arbeitet ja immer noch mit Tags. Die sollten wir komplett abschaffen :)

Wo ich noch nicht wirklich hintersteige ist, wie du dir das mit den Icons gedacht hast.

Instantiate ist nichts, was ich dafür benutzen würde, wenn nicht beliebig viele davon infrage kommen.

 

Wenn ich dich richtig verstehe, hast du n Pickups und für jedes davon ein InventoryIcon, das entweder gespawnt wurde oder eben noch nicht. Ich würde diese Icons als UI-Element bauen, die Fest in der UI verankert ist (du setzt die Positionen offenbar nicht dynamisch).

Diese kann man dann mit SetActive (oder im Editor mit dem Häckchen links neben dem Namen) an- und ausschalten.

Dann würde ich die Info, ob man ein Pickup schon hat, nicht im Vorhandensein der Objekte kodieren, sondern ganz simpel in einem Boolean-Array. Dass dieselbe Information doppelt vorhanden ist macht nichts, wenn dafür nicht mehrdeutige Semantik verwendet wird.

 

Also:

public GameObject[] inventoryIcons;

Da kommen jetzt keine Prefabs mehr rein, sondern die einzigartigen UI-Elemente.

Dazu kommt:

private bool[] pickupsAquired;

void Awake()
{
 pickupsAquired = new bool[inventoryItems.Length];
}

In diesem Moment würde ich dann z.B. nur noch eine Nummer im Pickup speichern:

class Pickup : MonoBehaviour
{
 [serializeField]
 private int _index;
 public int index { get { return _index; } }

 [serializeField]
 private int _points;
 public int points { get { return _points; } }
}

Und dann einfach:

void OnCollisionEnter(Collision collision)
{
var pickup = collision.gameObject.GetComponent<Pickup>();
if (pickup)
{
	if(!pickupAquired[pickup.number])
	{
		 pickupAquired[pickup.index] = true;
		 inventoryIcons[pickup.index].SetActive(true);
	}
	else
	{
		 score += pickup.points;
	}
}
}

 

Das ganze kann man immer noch ein bisschen eleganter machen, z.B. mit ScriptableObjects, aber das führt gerade zu weit.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Heyho, wenns um das Thema Coding geht, komm ich mir regelmäßig mal so richtig dumm vor :(

 

Also, ich versuche alles nochmal zu erklären, damit ihr ungefähr wisst, wie es im Moment aufgebaut ist.

Ja ich habe -n Pickups (vielleicht 5-7 oder so), diese hatte ich vorher mit Tags versehen, um sie in meinem Ursprungscode bei OnCollision identifizieren zu können. OnCollision wurde dann ein vorgefertigtes UI-prefab instantiated, um den Erfolg des Einsammelns zu repräsentieren. Soweit so logisch ^^ Das GuiPickup besteht aus einem Image und einem Textfelkd, indem die Anzahl der jeweiligen Items angezeigt wird.

 

Im Ur-Code hab ichs noch verstanden, wie was wo hochgezählt wurde und dann bei Bedarf angezeigt wird oder eben noch nicht. In deinem (Sascha) steig ich nich so ganz dahinter, is mir ein etwas komplizierteres Konzept, wenngleich es auch 1000x besser zu sein scheint.(Deine Erklärung macht schon Sinn)

 

"Pickup" Code ... hängt jetzt an jedem PickupObjekt

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pickup : MonoBehaviour
{

 [serializeField]
private int _index;
public int index { get { return _index; } }
[serializeField]
private int _points;
public int points { get { return _points; } }
}

 

Und dann kommt das Collect_Pickup Script, welches auf dem Player liegt:

using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine;
public class Collect_Pickup1 : MonoBehaviour
{
public GameObject inventoryPanel;
public GameObject[] inventoryIcons;
private bool pickupAquired;
public Text Score;

void Awake()
{
	pickupAquired = new bool[inventoryIcons.Length];
}
void OnCollisionEnter(Collision collision)
{
	var pickup = collision.gameObject.GetComponent<Pickup>();
	if (pickup)
	{
		if (!pickupAquired[pickup.number])
		{
			pickupAquired[pickup.number] = true;
			inventoryIcons[pickup.number].SetActive(true);
		}
		else
		{
			Score += pickup.points;
		}
	}
}
}

 

ich bekomm leider noch 2-3 Fehlermeldungen in der Konsole:

 

- Error CS0029 Cannot implicitly convert type 'bool[]' to 'bool' Jump´n Run Assets\Scripts\Collect_Pickup1.cs 17 Active

 

 

- Error CS1061 'Pickup' does not contain a definition for 'number' and no extension method 'number' accepting a first argument of type 'Pickup' could be found (are you missing a using directive or an assembly reference?) Jump´n Run Assets\Scripts\Collect_Pickup1.cs 26 Active

 

- Error CS0019 Operator '+=' cannot be applied to operands of type 'Text' and 'int' Jump´n Run Assets\Scripts\Collect_Pickup1.cs 33 Active

 

ich denke der letzte Fehler beruht darauf, dass ich nicht direkt das Textfeld vom GameObjekt Score anspreche und darein die Score schreibe. Bei den anderen 2 Fehlern steig ich nicht wirklich dahinter :(

 

Grüße

 

PS: Sascha du hattest in deinem CodeSnippet was von "inventoryItems" geschrieben, meintest du inventoryIcons ?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Huch ja, da haben sich einige Fehler eingeschlichen gestern abend. Es soll natürlich InventoryIcons heißen, und außerdem pickup.index, nicht pickup.number.

 

Du hast außerdem vergessen, pickupsAquired als Array zu definieren:

private bool[] pickupsAquired;

 

Was diese GUI-Prefabs angeht... Ich habe angenommen, dass das Icons sind, die für den Rest des Spiels angezeigt werden. Also wie ein Ausrüstungsgegenstand bei Zelda-Spielen - einmal eingesammelt, für immer im Inventar angezeigt. Und jedes Item hat seinen eigenen Slot in dem es entweder angezeigt wird oder eben noch nicht.

In diesem Fall hast du diese Objekte an einer bestimmten Position und sie werden nur einmalig instanziiert. Da würde ich keine Prefabs für nehmen, um sie einmalig aus den Assets in die Szene zu kopieren. Ich würde sie einfach im Editor in die UI setzen und nach Belieben an- und ausschalten.

 

Wo er jetzt noch meckert, ist die Zeile mit "Score +=". Du hast die Punktzahl immer aus dem String, der angezeigt wird, rausgeparst.

Ich empfehle, stattdessen eine zusätzliche Zahl zu speichern. Du rechnest dann nur mit dieser Zahl und schmeißt sie nach der Addition in den String.

private int score = 0;
[serializeField]
private Text scoreText;

score += pickup.score;
scoreText.text = score+" Punkte";

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hehe, daß mit den kleinen Fehlerchen dachte ich mir schon, war ja auch schon spät :D

 

Ok, langsam kommt Licht ins Dunkel meiner Schädeldecke.

So siehts jetzt aus:

using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine;
public class Collect_Pickup1 : MonoBehaviour
{
   public GameObject inventoryPanel;
   public GameObject[] inventoryIcons;
   private bool[] pickupAquired;
   private int score = 0;
   [serializeField]
   private Text scoreText;

   void Awake()
   {
    pickupAquired = new bool[inventoryIcons.Length];
   }
   void OnCollisionEnter(Collision collision)
   {
    var pickup = collision.gameObject.GetComponent<Pickup>();
    if (pickup)
    {
	    if (!pickupAquired[pickup.index])
	    {
		    pickupAquired[pickup.index] = true;
		    inventoryIcons[pickup.index].SetActive(true);
	    }
	    else
	    {
		    score += pickup.score;
		    scoreText.text = score + " Punkte";
	    }
    }
   }
}


 

Etwas hab ich aber noch immer nicht verstanden. Erstens meckert er rum :

 

.- Error CS1061 'Pickup' does not contain a definition for 'score' and no extension method 'score' accepting a first argument of type 'Pickup' could be found (are you missing a using directive or an assembly reference?) Jump´n Run Assets\Scripts\Collect_Pickup1.cs 36 Active

 

Und zweitens: wie sag ich dem jetzt, dass ItemTypNr1 sagen wir 10 punkte wert ist und ItemTypNr2 von mir aus 20 oder so ? Das finde ich nicht so richtig im Code ^^

Aber vielen Dank schonmal für dein Wissen!!

Grüße

Link zu diesem Kommentar
Auf anderen Seiten teilen

Die Fehlermeldung ist wieder von mir. Aber damit du das selber fixen kannst:

In einer Klasse steht

public int irgendwas;

oder, wie in unserem Fall eine Property (habe dazu gerade in einem anderen Thread etwas geschrieben)

private int _irgendwas;
public int irgendwas { get { return _irgendwas; } }

...dann kannst du in einer anderen Klasse auf "irgendwas" zugreifen:

int zahl = einPickup.irgendwas;

Ich beziehe mich auf die Property "points". Es muss also pickup.points heißen, nicht pickup.score, denn

public int score;

oder dergleichen gibt es in der Pickup-Klasse ja nicht. Deswegen meckert er.

 

Zum zweiten: Du hast doch die Pickup-Komponente auf deine Pickup-GameObjects gezogen. Dort kannst du jetzt jeweils einen Wert für index und points eingeben. Das geht durch das [serializeField].

Packe einfach mal folgendes in die OnCollisionEnter-Methode der anderen Klasse, in das if(pickup):

Debug.Log("Pickup gefunden! es hat die Nummer " + pickup.number + " und gibt " + pickup.points + " Punkte.");

Dann sammelst du die Pickups alle mal ein und achtest auf die Ausgaben in der Konsole.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hey Sascha,

 

es geht vorwärts !! :D

Die Items werden korrekt erkannt und auch die Punkte werden zusammengerechnet. Jedoch erst beim zweiten OnCollisionEnter.

Bei der ersten Collision verschwindet das Item wie gewünscht und auch in der Console kommt die Nachricht, aber erst wenn das Item respawnt und ich es erneut einsammle zählt er den Score mit.

 

Und das zweite Problem ist noch, dass meine GUI Bilder für das jeweilige Item nicht mehr spawnen (wo auch nochmal die einzelnen Items gezählt werden). Hab versucht in mein Collect_Pickup Script die Sprites für die InventoryIcons reinzuziehen, geht aber nicht, wohl weil die Sprites kein GameObject sind, sonder ... wer haette es gedacht ... ein Sprite.

An dem Sprite hängt aber noch ein Textfeld, wo die Anzahl der Items mitgezählt wurde.

 

Hier nochmal mein Stand in Sachen Scripts:

using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine;
public class Collect_Pickup1 : MonoBehaviour
{
public GameObject inventoryPanel;
public GameObject[] inventoryIcons;
private bool[] pickupAquired;
private int score = 0;
[serializeField]
private Text scoreText;

void Awake()
{
	pickupAquired = new bool[inventoryIcons.Length];
}
void OnCollisionEnter(Collision collision)
{
	var pickup = collision.gameObject.GetComponent<Pickup>();
	if (pickup)
	{
		Debug.Log("Pickup gefunden! es hat die Nummer " + pickup.index + " und gibt " + pickup.points + " Punkte.");
		if (!pickupAquired[pickup.index])
		{
		   pickupAquired[pickup.index] = true;
		   inventoryIcons[pickup.index].SetActive(true);
		}
		else
		{
			score += pickup.points;
			scoreText.text = score + " Punkte";
		}
	}
}
}

 

Und das Script für die collectable Items:

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pickup : MonoBehaviour
{

 [serializeField]
private int _index;
public int index { get { return _index; } }
[serializeField]
private int _points;
public int points { get { return _points; } }
}


 

 

Grüße

 

PS: wollte es halt so haben, dass die items angezeigt und gezählt werden (was ich vorher in den GUI prefabs hatte) zusätzlich die Score angezeigt wird, die sich aus den einzelnen Wertigkeiten und der Anzahl der Items ergibt. Und das ich Items auch wieder abziehen kann, per trigger oder so, was dann wiederum in einem niedrigeren Score endet.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Naja, ist schon ziemlich einleuchtend, dass das passiert. Steht ja auch da. Ich habe das aber nur von deiner Code-Funktionsweise kopiert :)

if (!pickupAquired[pickup.index])
{
   pickupAquired[pickup.index] = true;
   inventoryIcons[pickup.index].SetActive(true);
}
else
{
    score += pickup.points;
    scoreText.text = score + " Punkte";
}

Link zu diesem Kommentar
Auf anderen Seiten teilen

verstehe es nicht :(

 

ich geh mal den Teil durch, den du da als letztes gepostet hast.

 

Wenn pickupAquired nicht dem Array von pickup.index entspricht, dann ist pickupAquired(indexnummer) wahr und das inventoryIcon(indexnummer) wird angeschalten.

Ansonsten wird bei score der Wert des Pickups addiert und dann an das scoreText GUI Item weitergegeben.

 

OK, wenn ich´s nicht falsch verstanden habe, kann ich es etwas lesen, aber darin findet mein beschränkter Programmierkopf keine Lösung zu den oben genannten Problems :(

 

Hab die GUI Prefabs auch dierekt ins Panel gelegt und deaktiviert, hilft aber nix ...

Und ob das mit der score funktioniert, wenn ich Items wieder verbrauche, weiß ich auch gerade noch nicht ^^

 

Grüße

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn pickupAquired nicht dem Array von pickup.index entspricht, dann ist pickupAquired(indexnummer) wahr und das inventoryIcon(indexnummer) wird angeschalten.

Neee, das klingt falsch.

 

Hier wird in das Array geschaut.

if (!pickupAquired[pickup.index])
{

Es sieht etwa so aus:

[0,0,0,1,0,1,0]

Hier stehen die 0 für false, die 1 für true.

Das 0-te, 1-te und das 2-te Feld sind false und sagen damit aus: Die Items 0-2 sind nicht eingesammelt worden.

Das Item mit der Nummer 3 allerdings schon.

pickup.index sagt, welchen Index in diesem Array das eingesammelte Pickup hat.

Das Item weiß also über die Variable "index" selbst, welchen Index es hat, und die andere Klasse fragt nur danach.

Der Ausdruck

pickupAquired[pickup.index]

evaluiert durch Auslesen des Arrays zu true oder false, je nach dem, ob an der Stelle "pickup.index" true oder false steht.

Das ! negiert das, und das wird abgefragt. Semantisch verkleidet steht da also

"Wenn ich das Pickup mit dieser Nummer noch nicht eingesammelt habe"

 

Als nächstes wird ein Wert geändert. Hier entspricht nichts irgendetwas anderem (das darf man nicht wegen des = annehmen).

Links steht eine Variable (wobei es in diesem Fall ein Feld in einem Array ist) und rechts der Wert, der in die Variable geschrieben wird.

   pickupAquired[pickup.index] = true;

Beispiel:

pickupAquired ist [0, 1, 0]

pickup.index ist 2

Ergebnis:

pickupAquired ist [0, 1, 1]

 

Dann wird das im Array referenzierte InventoryIcon angeschaltet, wie du richtig gesagt hast.

   inventoryIcons[pickup.index].SetActive(true);

 

Dann steht als nächstes der "sonst"-Fall zum if.

}
else
{

Alles weitere passiert jetzt nur dann, wenn das Item bereits vorher schon einmal eingesammelt wurde, im Array an der untersuchten Stelle also true steht.

 

Hier findet jetzt die Erhöhung der Punktzahl statt. Da das an dieser Stelle steht, passiert es also nur, wenn der beschriebene sonst-Fall zutrifft.

	score += pickup.points;

 

Anschließend wird der Text des Text-Objekts auf die neue Punktzahl angepasst.

	scoreText.text = score + " Punkte";
}

 

Wenn du jetzt willst, dass die Punkte immer dazugerechnet werden, dann musst du die beiden letzten Zeilen, die sich auf die Punktzahl beziehen woanders hinschieben.

Vorher:

wenn(bedingung)
{
 Zeug();
}
sonst
{
 PunkteZeug();
}

 

Nachher:

wenn(bedingung)
{
 Zeug();
}
PunkteZeug();

Somit wird es unabhängig von der Bedingung immer ausgeführt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Echt riesig, dass Du dir die Zeit nimmst und es mir so toll erklärst. Danke!

Ich mache halt kleine Fortschritte aber immernoch Fortschritte :P

 

Aber wie oft ich jetzt ein Item eingesammelt habe ist nicht mehr erkennbar wa ?!

Weil das mit den Icons funzt jetzt nicht mehr, wo ich das ablesen konnte :(

Ich geh davon aus, dass ich den inventoryIcons noch den Index mitteilen muss, den Sie besitzen ? Obwohl die ja in dem Collect_Pickup Script in dem Array auch mit 0 beginnend indexiert wurden ... hm

Stehe schon wieder aufm Schlauch ^^

 

Grüße

Link zu diesem Kommentar
Auf anderen Seiten teilen

mhh, ok ... ich habe es zumindest theoretisch versucht da ein "zweites" Zählwerk einzubauen.

habe mir gedacht, dass wenn ich ein pickup aufnehme (der index wird ja mit übergeben) ich eine Variable erstelle (mit dem gleichen index) wo es dann hochgezählt wird. so habe ich dann n- Variablen, die mir die Anzahl der jeweils eingesammelten Items anzeigt.

Soweit so gut.

 

Ich hab es mal probiert:

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

public class Collect_Pickup1 : MonoBehaviour
{

   public GameObject inventoryPanel;
   public GameObject[] inventoryIcons;
   private bool[] pickupAquired;
   private int score = 0;
   [serializeField]
   private Text scoreText;
   private int[] pCount;    
   void Awake()
   {
    pickupAquired = new bool[inventoryIcons.Length];
    pCount = new int[inventoryIcons.Length];
   }

   void OnCollisionEnter(Collision collision)
   {
    var pickup = collision.gameObject.GetComponent<Pickup>();
    if (pickup)
    {
	    Debug.Log("Pickup gefunden! es hat die Nummer " + pickup.index + " und gibt " + pickup.points + " Punkte.");
	    pCount[pickup.index] = +1;
	    Debug.Log("blah " + pCount);

	    if (!pickupAquired[pickup.index])
	    {
		   pickupAquired[pickup.index] = true;
		   inventoryIcons[pickup.index].SetActive(true);
	    }
		    score += pickup.points;
		    scoreText.text = score+"";

    }
   }
}

 

In der Console gibt er mir "blah System.Int32[]" aus, also überhaupt nicht, was ich beabsichtigt habe. Ich denke der Gedanke an sich ist nicht sooo schlecht, die Umsetzung dafür wohl aber schon :(

 

Könnte mir einer dabei helfen ?

 

Grüße

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also, so ab 2-3 Arrays, die alle denselben Index haben, sollte man an einen eigenen Typ denken. In diesem Fall wohl eine weitere Komponente.

public class PickupDisplay : MonoBehaviour
{
 public int count { private set; get; }

 public void AddOne()
 {
   count++;
   gameObject.SetActive(true);
   // Weitere Dinge, wie z.B.
   // text = count+"";
 }
}

Diese Klasse packst du dann auf deine GameObjects in der GUI, die du anschaltest.

In deiner anderen Klasse, die du schon hast, nimmst du die Arrays raus und schreibst nur noch eines rein:

[serializeField]
private PickupDisplay[] pickupDisplays;

Jetzt kannst du abfragen, wie viele du schon hast:

pickupDisplays[pickup.index].count

oder eines hinzufügen:

pickupDisplays[pickup.index]AddOne();

 

Wichtig: Die Funktionalität ist jetzt ausgelagert.

Du rufst nur noch vom richtigen PickupDisplay AddOne auf und fertig.

   void OnCollisionEnter(Collision collision)
   {
	    var pickup = collision.gameObject.GetComponent<Pickup>();
	    if (pickup)
	    {
			    Debug.Log("Pickup gefunden! es hat die Nummer " + pickup.index + " und gibt " + pickup.points + " Punkte.");
			    pickupDisplays[pickup.index]AddOne();
	    }
   }

Jegliches setzen von Text oder dergleichen passiert in der PickupDisplay-Klasse, wie in den Kommentaren angedeutet.

 

Wenn gleichartige Pickups (also mit demselben Index) immer gleich viele Punkte geben, dann würde ich points auch aus der Pickup-Klasse nehmen.

Denn pro Pickup-Sorte kann es offenbar mehrere Pickups geben, aber nur ein PickupDisplay.

Wenn du also etwas hast, was alle Pickups derselben sorte gemein haben (wie die Punktzahl?), dann packe es in's PickupDisplay.

(Man kann sich ab dem Punkt streiten, ob man das noch "PickupDisplay" nennen sollte wenn es mehr tut als nur anzuzeigen, aber das ist ein anderes Problem).

 

Könnte (stumpfe Variante) so aussehen:

public class PickupDisplay : MonoBehaviour
{
 public int count { private set; get; }

 [serializeField]
 private int points; // Im Editor eintragen
 public int totalPoints { get { return count * points; } }

und in der anderen Klasse kannst du alle Punkte aller PickupDisplays aufaddieren:

public int GetTotalScore()
{
 var points = 0;
 foreach(var display in pickupDisplays)
 {
   points += display.totalPoints;
 }
 return points;
}

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 weeks later...

Heyho, ich bin´s schon wieder.

 

Klappt jetzt soweit ganz gut, wollte aber noch ne kleine Änderung vornehmen.

Und zwar funktioniert das alles nur bei Collision mit dem RigidBody. Das führt dazu, dass der Spieler jedesmal an nem Item abgebremst wird und neu beschleunigen muss. Hab versucht beides auf OnTrigger Enter umzustellen, funktioniert aber nicht komplett. De- und Respawn funktionieren aber er zählt dann keine Punkte mehr :( bin den Code durch gegenagen, finde aber nicht die Ursache dafür.

 

Kann ich nicht einfach:

void OnCollisionEnter(Collision col)
   {
    var pickup = col.gameObject.GetComponent<Pickup>();
    if (pickup)
    { ... usw...

in

void OnTriggerEnter()
   {
    var pickup = this.gameObject.GetComponent<Pickup>();
    if (pickup)
    { ... usw ...

umschreiben ?

 

Wieso nicht ?

 

Grüße

Link zu diesem Kommentar
Auf anderen Seiten teilen

Du hast col durch this ersetzt.

this referenziert das Objekt in dem wir gerade sind und kann in den meisten Fällen weggelassen werden.

Da könnte also auch stehen:

var pickup = gameObject.GetComponent<Pickup>();

Das bedeutet, dass du das GameObject, auf dem dieses Skript liegt, nach einer Pickup-Komponente fragst, und nicht das, womit es kollidiert ist.

 

Die Lösung: Auch OnTriggerEnter kann einen Parameter haben. Der ist dann aber nicht vom Typ Collision, sondern Collider.

Während in Collidion detaillierte Infos über die Kollision stehen, hat man in OnTriggerEnter also nur die Info, was man berührt hat. Reicht ja aber in diesem Fall.

void OnTriggerEnter(Collider other)
{
   var pickup = other.gameObject.GetComponent<Pickup>();

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...