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

Beste Umsetzung mit Scriptable Objects

Recommended Posts

Liebe Community meine Fragen beziehen sich auf Scriptable Objects und ich hoffe Ihr könnt Sie mir beantworten.

Ist es sinnvoll Scriptable Objects für Achievements / Items / Rassen von Charakteren zu verwenden?

Meine Idee ist:

Achievements per Scriptable Objects anzulegen mit Werten wie:

Icon/Titel/Beschreibung/Prefab

Das Prefab nenn ich Achievement und setze ein Skript welches Icon/Titel/Beschreibung vom Scriptable Object ladet.

Danach erstell ich ein leeres Gameobject mit einem Skript, welches ein Parent Gameobject nimmt und in diesen per Schleife die Scriptable Objects als Gameobject während des Spiels anzeigt.

Mein jetztiges Problem ist nur ich bekomm die Inhalte von Titel/Beschreibung nicht in das Prefab.

Bitte um jegliche Verbesserungsvorschläge :)

Share this post


Link to post
Share on other sites
vor 4 Stunden schrieb F1R3ON:

Ist es sinnvoll Scriptable Objects für Achievements / Items / Rassen von Charakteren zu verwenden?

Die sind generell überall da eine Überlegung wert, wo du Daten hast, die nicht speziell an bestimmte Objekte gebunden sind. Damit sind Items, Achievements und Charaktereigenschaften sehr gute Beispiele für Dinge, bei denen man gut ScriptableObjects benutzen kann.

vor 4 Stunden schrieb F1R3ON:

Mein jetztiges Problem ist nur ich bekomm die Inhalte von Titel/Beschreibung nicht in das Prefab.

Naja, du ziehst das Achievement-SO aus den Assets in deine Komponente, nachdem du ein Feld dafür gemacht hast:

[SerializeField]
private Achievement achievement;

bzw.

[SerializeField]
private Achievement[] achievements;

für mehrere.

Dann greifst du halt drauf zu:

someTextComponent.text = achievement.title;

 

  • Thanks 1

Share this post


Link to post
Share on other sites

Das versteh ich, dass man eine Referenz benötigt. Nur sagen wir ich hab 3 Scriptable Objects und 1 Prefab, das Prefab wird in einer Schleife 3x wiederholt und in einem Scrollview angezeigt. Dann seh ich ja theroethisch immer nur die Daten des 1 Scriptable Objects auf dem Prefab 3 mal? Wie kann ich das Problem am besten lösen :/?

 

EDIT:

Ich hab es jetzt so hinbekommen:

1x Gameobject mit einen Skript, welches durch das Skript eine Referenz auf ScriptableObjects hat als Beispiel 3x ScriptableObjects 1x Gameobject - Viewport/Content als Parent um Gameobjects darin zu erzeugen.

Im Skript benütze ich eine for-Schleife.

for(int x=0;x<testObjects.Length;x++)

{

Gameobject xyz = In...

xyz.GetComponentInChildren<TMP_Text>().text = testObjects[x].Title;

}

Share this post


Link to post
Share on other sites

Ah ja, genau so macht man das. Nach dem Instantiate die Instanz initialisieren. Siehe auch hier.

Share this post


Link to post
Share on other sites

Hab leider dennoch ein Problem mit Scriptable Objects ^^"

"Ich bekomm es nicht hin während der Laufzeit den Bool zu ändern und das in der Liste von LoadAchievement nur das jeweilige Freigeschalten wird."

Bzw. wenn man ein Achievement freischaltet soll das jeweilige Gameobject seine Color ändern das klappt aber nicht während der Laufzeit nur wenn man die Szene neustartet.

Ich bin mir nicht sicher ob das wirklich der richtige Ansatz bei den Scriptable Objects ist bin für jegliche Verbesserungsvorschläge offen auch bei den for-Schleifen ob da nicht foreach besser wäre?

AchievementObject welches für ScriptableObjects

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

[CreateAssetMenu(fileName = "NewAchievement", menuName = "Achievement/Create Achievement", order = 1)]
public class AchievementObject : ScriptableObject
{
    [SerializeField]
    private Sprite icon;

    [SerializeField]
    private string title;

    [SerializeField]
    private string description;

    [SerializeField]
    private int progValue;

    [SerializeField]
    private bool unlocked;

    [SerializeField]
    private Image unlockedImage;

    public Sprite Icon
    {
        get { return icon; }
    }

    public string Title
    {
        get { return title; }
    }

    public string Description
    {
        get { return description; }
    }

    public bool Unlocked
    {
        get { return unlocked; }
        set { unlocked = value; }
    }

    public void SaveAchievement(bool value)
    {
        unlocked = value;
    }
}

 

AchievementManager

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

public class AchievementManager : MonoBehaviour
{
    [SerializeField]
    private AchievementObject[] achievementObject;

    [SerializeField]
    private GameObject prefabAchievement;

    [SerializeField]
    private GameObject prefabAchievementUnlocked;

    [SerializeField]
    private GameObject visualAchievement;

    [SerializeField]
    private GameObject parentPanel;

    [SerializeField]
    private GameObject parentVisual;

    private static AchievementManager instance;

    public static AchievementManager Instance
    {
        get
        {
            if (instance == null)
            {
                instance = GameObject.FindObjectOfType<AchievementManager>();
            }
            return AchievementManager.instance;
        }
    }

    void Start()
    {        
        LoadAchievement();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Y))
        {
            EarnAchievement("AAA");
        }

        if (Input.GetKeyDown(KeyCode.X))
        {
            EarnAchievement("BBB");
        }
    }

    public void LoadAchievement()
    {
        for (int x = 0; x < achievementObject.Length; x++)
        {
            GameObject achievement = Instantiate(prefabAchievement, new Vector3(0, 0, 0), Quaternion.identity);

            if (achievementObject[x].Unlocked)
            {
                achievement.GetComponent<Image>().color = prefabAchievementUnlocked.GetComponent<Image>().color;
            }

            achievement.transform.SetParent(parentPanel.transform);
            achievement.transform.GetChild(0).GetComponent<Image>().sprite = achievementObject[x].Icon;
            achievement.transform.GetChild(1).GetComponent<TMP_Text>().text = achievementObject[x].Title;
        }
    }

    public void EarnAchievement(string title)
    {
        for (int x = 0; x < achievementObject.Length; x++)
        {
            if (title == achievementObject[x].Title && !achievementObject[x].Unlocked)
            {
                achievementObject[x].SaveAchievement(true);

                GameObject achievement = Instantiate(visualAchievement);
                Sprite icon = achievementObject[x].Icon;

                SetVisualInfo(parentVisual, achievement, icon, title);

                StartCoroutine(FadeAchievement(achievement));
            }
        }
    }

    public void SetVisualInfo(GameObject parent, GameObject achievement, Sprite icon, string title)
    {
        achievement.transform.SetParent(parent.transform);
        achievement.transform.GetChild(0).GetComponent<Image>().sprite = icon;
        achievement.transform.GetChild(1).GetComponent<TMP_Text>().text = title;
    }

    private IEnumerator FadeAchievement(GameObject achievement)
    {
        CanvasGroup canvasGroup = achievement.GetComponent<CanvasGroup>();

        float rate = 1.0f / 2;

        int startAlpha = 0;
        int endAlpha = 1;

        for (int i = 0; i < 2; i++)
        {
            float progress = 0.0f;

            while (progress < 1.0)
            {
                canvasGroup.alpha = Mathf.MoveTowards(startAlpha, endAlpha, progress);
                progress += rate * Time.deltaTime;
                yield return null;
            }

            yield return new WaitForSeconds(2);
            startAlpha = 1;
            endAlpha = 0;
        }

        Destroy(achievement);
    }
}

Ich hoffe mir kann jemand weiterhelfen, das hinzubekommen mit Unlock x.x und den Freischalten der Farbe für das jeweilge Achievement, welches den Bool auf True hat.

Ist die vorgehensweiße auch gut für später wenn man die Daten in eine Binäre Datei schreiben möchte?

Anbei auch das Projekt:

https://we.tl/t-0KKyg2Ugsy

Share this post


Link to post
Share on other sites

Für solche Sachen sind Events ganz gut. Du kannst z.B. in dein Achievement-SO ein Event einbauen:

public event Action onChangeUnlockStatus;

Und dann dieses Event im richtigen Moment auslösen:

public void Unlock()
{
  unlocked = true;
  onChangeUnlockStatus?.Invoke();
}

Objekte, die auf das Event reagieren sollen, tragen sich dort ein, sobald sie zum reagieren bereit sind:

public void Initialize(Achievement achievement)
{
  titleText.text = achievement.title;
  descriptionText.text = achievement.description;
  
  achievement.onChangeUnlockStatus += OnChangeUnlockStatus;
}

private void OnChangeUnlockStatus()
{
  if (achievement.unlocked)
  {
    // change image or background color
  }
}

Und sie tragen sich wieder aus, wenn sie zerstört werden:

achievement.onChangeUnlockStatus -= OnChangeUnlockStatus;

Der Ablauf ist also:

  1. Anzeige-GO wird initialisiert (setzt Text und Beschreibung usw.) und trägt eine Reaktion (Methode "OnChangeUnlockStatus") beim Event ein.
  2. Achievement wird freigeschaltet
  3. Alle im Event eingetragenen Reaktionen werden ausgelöst
  4. Anzeige-GO verändert sich

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...