Jump to content
Unity Insider Forum
Sign in to follow this  
Kojote

Static und Nicht Static

Recommended Posts

Grüße!

Ich hab ein kleines Scriptproblem. In einer Klasse habe ich eine statische Methode:

        public static Sprite MinimapSpriteIcon(int icon) {
            switch (icon) {
                case 0:
                    sprite = iconSprites[0];
                    break;
                case 1:
                    sprite = iconSprites[1];
                    break;
                case 2:
                    sprite = iconSprites[2];
                    break;
                case 3:
                    sprite = iconSprites[3];
                    break;
            }
            return sprite;
        }

Diese rufe ich von vielen anderen Scripts aus auf, um zu erfahren, welches Icon genutzt werden soll.

Problem ist, ich muss in dieser Klasse ja irgendwie die Sprites festlegen, was ich so mache:

        [Tooltip("Sprites für die Icons der Objekte.")]
        public Sprite[] iconSprites = new Sprite[0];
        public Sprite sprite;

Problem ist nun, "sprite" und "iconSprites" müssten auch Static sein, um sie in der Methode nutzen zu können. Mache ich dies jedoch, werden die Variablen nicht mehr im Inspector angezeigt. Gibt es da irgend eine Lösung um das Problem zu umgehen?

Grüße von Kojote

Share this post


Link to post
Share on other sites

Die einfachste Lösung: Übergib iconSprites als Parameter. Ich seh keinen Sinn dahinter, dass sprite überhaupt in der Methode ist, also nimm das am Besten raus.

public static Sprite MinimapSpriteIcon (int icon, Sprite[] iconSprites)
{
  // iconSprites[icon] macht genau das selbe wie dein switch statement....
  return (icon < iconSprites.Length) ? iconSprites[icon] : null;
}

Die Initialisierung von iconSprites da oben mit

public Sprite[] iconSprites = new Sprite[0];

Ist auch überflüssig. Unity initialisiert serialisierte Felder von selbst.

Falls dein Code ziemlich genau so aussieht, kannst du auch einfach direkt iconSprites[icon] wo auch immer machen, und dir die ganze Methode sparen.

Share this post


Link to post
Share on other sites

So richtig verstehe ich das nicht.

Ich habe eine Methode in einer Klasse:

    public class LD_Menue_Minimap_Icon : MonoBehaviour {

        public enum ic : short {
            Spieler=0,
            Mitspieler=1,
            Beute=2,
            Portal=3,
            KeineAuswahl=4
        };
        public ic icon = ic.KeineAuswahl;

        private Sprite iconSprite;


        private void Start() {
            if (icon == ic.KeineAuswahl) {
                Debug.Log("FEHLER: Für Objekt " + this.gameObject.name + " wurde kein Icon ausgewählt.");
                return;
            }
            iconSprite = LD_Menue_Minimap.MinimapSpriteIcon((int)icon);
            SpriteRenderer renderer = this.gameObject.AddComponent<SpriteRenderer>();
            renderer.sprite = iconSprite;
            this.gameObject.layer = LD_Menue_Minimap.MinimapLayer();
        }
    }

Hier hole ich mir das Icon.

In der zweiten Klasse sind die Sprites hinterlegt:

        [Tooltip("Sprites für die Icons der Objekte.")]
        public Sprite[] iconSprites; 

		public static Sprite MinimapSpriteIcon(int icon, Sprite[] iconSprites) {
            return (icon < iconSprites.Length) ? iconSprites[icon] : null;
        }

Wie funktioniert dies? Die Klasse die die Static Methode aufruft, kennt doch das Array iconSprites gar nicht.

Share this post


Link to post
Share on other sites

Achso, ja dann macht das mit dem Parameter natürlich keinen Sinn.

Also die lange Lösung lautet: Vermutlich ist static hier eben einfach nicht angebracht. Das ist halt eine Frage von Architektur.

Die kurze Lösung: Du kannst das ganze ein bisschen dribbeln, wenn du unbedingt willst, und halt ne separates statisches Feld anlegen und dann irgendwann iconSprites dem zuweisen. Z.B. in der Start Methode.

Share this post


Link to post
Share on other sites

Um das Problem zu lösen, kannst Du z.B. das Singleton Pattern nutzen. In deiner Sprite Klasse deklarierst Du eine statische Referenz auf sich selbst und setzt diese beim Start. Dann kannst Du von überall auf die eine Instanz zugreifen, ohne statische Dinge zu nutzen, bis auf die Referenz zum Objekt selbst.

Beispiel

//achtung: pseudo code, nicht funktionsfähig! :D

//das hier ist in deiner sprite klasse
private static DeineKlasse instance;

public static DeineKlasse Instance
{
	get
	{
		return instance;
	}
}

void Awake()
{
	//hier kann man noch prüfen, ob das singleton schon existiert, aber wir gehen mal davon aus, dass du es nur einmal in der szene hast ;)
	instance = this;
}

[SerializeField]
private Sprite[] sprites;

public Sprite MinimapSpriteIcon(int icon) 
{
	return sprites[icon];
}

//... irgendeine klasse
deinSprite = DeineKlasse.Instance.MinimapSpriteIcon(1)

 

  • Like 1

Share this post


Link to post
Share on other sites

@devandart Nur ein kleiner Hinweis:

private static DeineKlasse instance;

public static DeineKlasse Instance
{
	get
	{
		return instance;
	}
}

kann man ersetzen durch

public static DeineKlasse Instance { get; private set; }

Generell ist Singleton zu vermeiden, wenn's geht. In Unity ist es wegen der Serialisierung nicht-statischer Klassen weniger schlimm als überall anders, aber immer noch nicht gut. Es ist okay, sie zu benutzen, bis man etwas besseres findet. Das "Bessere" heißt dann in der Regel ScriptableObjects.

In diesem Fall geht es ja um eine Liste von Sprites. Warum müssen diese in der Scene (also auf einer Komponente auf einem GameObject) definiert sein? Eine Liste, die in den Assets liegt, wäre doch viel besser. Also ScriptableObject auf und los gehts:

using UnityEngine;

[CreateAssetMenu(menuName = "Game/Sprite List")]
public class SpriteList : ScriptableObject
{
  public Sprite[] sprites;
}

In den Assets Rechtsklick, so ein Ding erstellt und Sprites reingezogen. Name "Minimap Sprites".

Dann baust du deine Scripts um, die diese Sprites benutzen und machst

[SerializeField]
private SpriteList minimapSprites;

und ziehst das ScriptableObject "Minimap Sprites" da rein.

Dann benutzt du statt

MinimapSpriteManager.Instance.MinimapSpriteIcon[1];

das elegantere

minimapSprites.sprites[1];

und hast dadurch Modularität, Robustheit und andere Code-Qualitäten erhalten.

  • Like 2

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×