Jump to content
Unity Insider Forum

Waffen/Werkzeuge als ScritableObjects -> wie ausrüsten?


Saiirex

Recommended Posts

Hallo, ich wusste nicht genau was ich als Titel wählen sollte, ich hoffe es ist okay.

Hier mal die Erklärung:

In meinem 3D Spiel habe ich z.B. eine Machete als Waffe und eine Axt sowieso eine Hacke. Ich möchte ein ScriptableObject erstellen (z.B. "Tool"), dort möchte ich verschiedene Variablen zuweisen wie z.B.

Schaden gegen über Tieren
Schaden gegen über Bäumen
Schaden gegen über Steinen
usw...

Außerdem halt die Icons für diese Items usw.

Die Frage ist, wie genau kann ich dann zwischen diesen Dingen wecheln? Also z.B. dass wenn ich die Taste "1" drücke, dass dann die Machete ausgerüstet wird (und das 3D-Modell in der Hand gehalten wird) und genau so bei der Taste 2, 3 usw?

 

Die zweite Frage ist:

Solche Dinge sind ja theorteisch Items, Dinge wie Steine, Tränke etc. sind ja auch Items. Soll ich eine Basisklasse "Item" (ScriptableObject) erstellen oder verschiedene Klassen dafür erstellen? Wie funktioniert sowas dann mit dem Inventar? Wo ich z.B. eine Liste von Typ "item" habe?


Ich hoffe die Fragen sind verständlich :D

Link zu diesem Kommentar
Auf anderen Seiten teilen

Tag auch!

ScriptableObjects kannst du prima referenzieren. Wenn du gleich mehrere Referenzierst, hast du eine Auswahl:

public Tool[] tools;
private currentToolIndex;

// Praktische Property, um das aktuelle Tool zu bekommen
public Tool currentTool
{
  get { return tools[currentToolIndex]; }
}

void Update()
{
  // Hier currentToolIndex ändern, um Werkzeug zu wechseln, z.B.
  if(Input.GetKeyDown(KeyCode.1))
  {
    currentToolIndex = 1;
  }
  // Das geht aber noch besser als mit vielen Ifs.
  // Falls du dafür einen Denkanstoß möchtest, sag bescheid.
  
  if(Input.GetMouseButtonDown(0))
  {
    // Mach was mit currentTool, z.B.
    Debug.Log(currentTool.name + ": " + currentTool.damageToAnimals);
  }
}

Wenn du statt eines Arrays eine Liste hast, kannst du leicht Elemente hinzufügen oder entfernen. Damit kannst du dann bauen, dass Werkzeuge aufgenommen und fallengelassen werden können.

using System.Collections.Generic;
private List<Tool> tools;
private currentToolIndex;

// Praktische Property, um das aktuelle Tool zu bekommen
public Tool currentTool
{
  get { return tools[currentToolIndex]; }
}

public void AddTool(Tool tool)
{
  tools.Add(tool);
}

public void DropCurrentTool()
{
  tools.RemoveAt(currentToolIndex);
}

AddTool ruft dann irgendein anderes Script auf. Zum Beispiel ein Loot-Kisten-Skript:

public Tool[] tools;

public void TakeItems(ToolCarrier carrier)
{
  foreach(var tool in tools)
  {
    carrier.AddTool(tool);
  }
}

Hab für das Beispiel das obige Script mal ToolCarrier genannt. TakeItems wird von dem Script aufgerufen, das die Kiste aktiviert.

Alternativ kannst du auch auf ein Prefab eines am Boden liegenden Werkzeugs ein Script wie dieses hier packen:

public Tool tool;

public PickupItem(ToolCarrier carrier)
{
  carrier.AddItem(tool);
  Destroy(gameObject);
}

Hoffe, die Beispiele helfen etwas.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hier mal ein kleines Beispiel für die Verwendung von SO.

Basisklasse:

using UnityEngine;
 
[CreateAssetMenu]
public class ItemType : ScriptableObject {
    public string name;
    public Sprite icon;
    public float cost;
    public float weight;
    public float durability;
    public GameObject itemPrefab; 
    //etc.
}

Subklasse:

using UnityEngine;
 
[CreateAssetMenu]
public class WeaponType : ItemType {
    public bool oneHanded;
    public float damage;
}

Einfaches Inventar:

using UnityEngine;
public System.Collections.Generic;
 
public class Inventory : MonoBehaviour {
 
    [System.Serializable]
    public class Slot {
        public ItemType itemType;
        public int amount;
    }
 
    public List<Slot> slots;
}

 

Wichtig zu erwähnen ist noch folgendes:
SOs sind eigentlich nur "dumme Datencontainer" die "Initialwerte" für Instanzen beschreiben denen das SO zugeordnet wurde, das eigentliche Verhalten (beispielsweise einer Waffe) sollte von einer weiteren MonoBehaviour-Unityklasse übernommen werden.  Die Werte des SO werden in die Startwerte der Waffeninstanz dieser Klasse übernommen:

using UnityEngine;
 
public class Weapon : MonoBehaviour {
    public WeaponType weaponSO;
    private bool oneHanded;
    private float damage;
    public float currentDurability;

   void Start()  {
      oneHanded = weaponSO.oneHanded;
      damage = weaponSO.getDamage(this.gameObject);
      currentDurability = weaponSO.durability;
   }
}


Ebenfalls sollten instanzspezifische Werte nicht in den SOs abgelegt werden. Ein Beispiel hierfür wäre die aktuelle (Rest-)Haltbarkeit der Waffe.
Man kann zwar sogenannte Delegate-Methoden ebenfalls in den SOs anlegen, aber diese sollten sich dann grundsätzlich auf die Werte der SOs beziehen und nicht primär auf die Werte der aktuellen "Item-Instanz" in der Szene. SOs gelten eben für alle Instanzen in der Szene und das sollte man im Hinterkopf behalten.
(natürlich kann man die aktuelle Instanz einer Delegatemethode übergeben, um damit die aktuellen Werte der Instanz in der Delegatemethode zu verwenden)

Ein Beispiel für eine Delegatemethode innerhalb eines SO. Ich übergebe hier die aktuelle GameObjekt-Instanz aus der Szene. Man könnte nun hier Werte aus der Instanz auslesen und diese der Methode übergeben. Ich habe es mal exemplarisch der "Durability" gemacht.

using UnityEngine;
 
[CreateAssetMenu]
public class WeaponType : ItemType {
    public bool oneHanded;
    public float damage;

    public float getDamage(GameObject currentInstance) {
       // Here you can do something with the "currentInstance"
       // like get some data values from a component that is attached to the gameObject
       float currentDurabilty = durability;
       Weapon weapon = currentInstance.GetComponent<Weapon>();
       if (weapon!=null) currentDurabilty = weapon.currentDurabilty;

       if (currentDurabilty == 0) return 0; // 0 damage if the weapon has no more durability
         
       if (onHanded) {         
          return damage;
       } else {
          return damage*1.5f;
       }
    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...