Inventarsystem · Teil 2 von 2 der Serie
Einfache UI für das Inventarsystem
So erstellst du eine Benutzeroberfläche für das Inventar in Unity

Nachdem du das Inventarsystem fertiggestellt hast, ist es Zeit für eine Benutzeroberfläche (UI), die den Spielenden das Inventar anzeigt. In diesem Tutorial erstellen wir mit dem UI Toolkit von Unity eine einfache Inventar-UI.
Für die UI brauchen wir drei Dateien: eine UXML-Datei für das Layout, eine USS-Datei für das Styling und ein C#-Skript für die Logik.
Die UXML-Datei
Erstelle im Unity Editor einen neuen Ordner namens UI im Ordner Scripts deines Projekts. Erstelle darin eine neue UXML-Datei namens InventoryUi.
Öffne die Datei InventoryUi.uxml und füge Folgendes ein:
<?xml version="1.0" encoding="utf-8"?>
<ui:UXML
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ui="UnityEngine.UIElements"
xmlns:uie="UnityEditor.UIElements"
xsi:noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd"
>
<Style src="project://database/Assets/Scripts/UI/InventoryUi/InventoryUi.uss"/>
<ui:VisualElement name="Container" class="Container">
<ui:VisualElement name="CollectibleItems" class="CollectibleItems">
<ui:VisualElement name="InventoryItem" class="InventoryItem">
<ui:Label text="99" name="ItemQuantity" class="ItemQuantity"/>
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement name="BuildableItems" class="BuildableItems">
<ui:VisualElement name="InventoryItem" class="InventoryItem">
<ui:Label text="99" name="ItemQuantity" class="ItemQuantity"/>
</ui:VisualElement>
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>Wie du siehst, importieren wir ein Stylesheet namens InventoryUi.uss, das wir im nächsten Schritt erstellen. Das Layout besteht aus einem Container mit zwei Bereichen: einem für Collectibles und einem für Buildables. Jeder Bereich enthält ein Inventarelement mit einem Label, das die Menge des Gegenstands anzeigt. Diese Elemente sind nur Platzhalter, die zur Laufzeit ersetzt werden.
Die USS-Datei
Erstelle im Ordner UI eine neue USS-Datei namens InventoryUi.uss.
Öffne die Datei InventoryUi.uss und füge Folgendes ein:
.Container {
bottom: 0;
left: 0;
right: 0;
height: 50px;
flex-direction: row;
align-items: center;
position: absolute;
}
.CollectibleItems {
height: 50px;
flex-direction: row;
width: 50%;
background-color: rgb(0, 0, 0);
margin-right: 5px;
}
.BuildableItems {
height: 50px;
flex-direction: row;
width: 50%;
background-color: rgb(0, 0, 0);
}
.InventoryItem {
width: 45px;
height: 45px;
margin-right: 5px;
position: relative;
background-size: contain;
}
.ItemQuantity {
position: absolute;
bottom: 1px;
right: 1px;
padding: 0px;
margin: 0px;
color: white;
font-size: 12px;
-unity-font-definition: resource("FlatSkin/Font/Roboto-Bold");
-unity-text-align: upper-right;
-unity-font-style: bold;
-unity-text-outline-width: 1px;
-unity-text-outline-color: rgb(0, 0, 0);
justify-content: flex-end;
align-self: flex-end;
align-content: flex-end;
align-items: flex-end;
height: 12px;
flex-direction: row;
flex-grow: 1;
}Du siehst, dass wir eine Leiste am unteren Rand mit zwei Bereichen bekommen. Jeder Bereich enthält Inventarelemente mit einem Mengen-Label in der unteren rechten Ecke.
Das Controller-Skript
Das UI-Controller-Skript enthält die Logik, die die UI aktualisiert, wenn Gegenstände zum Inventar hinzukommen oder daraus entfernt werden.
Erstelle im Ordner UI ein neues C#-Skript namens InventoryUi.
using UnityEngine;
using UnityEngine.UIElements;
public class InventoryUi : MonoBehaviour {
public static InventoryUi Instance;
public UIDocument uiDocument;
// the UI element references for the main container
// and the containers for the collectible- and buildable items
VisualElement rootElement;
VisualElement collectibleItemsContainer;
VisualElement buildableItemsContainer;
// the inventory references for the collectible- and buildable inventory
Inventory<
CollectibleInventoryItem,
CollectibleItem,
CollectibleItemType
> collectibleInventory;
Inventory<
BuildableInventoryItem,
BuildableItem,
BuildableItemType
> buildableInventory;
private void Awake() {
// set the singleton instance (very basic implementation)
Instance = this;
// initialize the UI references
rootElement = uiDocument.rootVisualElement.Q<VisualElement>(className: "Container");
collectibleItemsContainer = rootElement.Q<VisualElement>(name: "CollectibleItems");
buildableItemsContainer = rootElement.Q<VisualElement>(name: "BuildableItems");
}
// set the collectible inventory reference
// and subscribe to its events on withdraw and deposit items
public void SetCollectibleInventory(
Inventory<
CollectibleInventoryItem,
CollectibleItem,
CollectibleItemType
> _inventory
) {
collectibleInventory = _inventory;
collectibleInventory.OnItemDeposited += UpdateCollectibleItemsUi;
collectibleInventory.OnItemWithdrawn += UpdateCollectibleItemsUi;
collectibleItemsContainer.Clear();
UpdateCollectibleItemsUi(null);
}
// set the buildable inventory reference
// and subscribe to its events on withdraw and deposit items
public void SetBuildableInventory(
Inventory<
BuildableInventoryItem,
BuildableItem,
BuildableItemType
> _inventory
) {
buildableInventory = _inventory;
buildableInventory.OnItemDeposited += UpdateBuildableItemsUi;
buildableInventory.OnItemWithdrawn += UpdateBuildableItemsUi;
buildableItemsContainer.Clear();
UpdateBuildableItemsUi(null);
}
void UpdateCollectibleItemsUi(CollectibleInventoryItem changedItem) {
if(changedItem == null) {
foreach(CollectibleInventoryItem item in collectibleInventory.items) {
AddCollectibleInventoryElement(item);
}
return;
}
Label changedItemQuantityLabel = collectibleItemsContainer.Q<Label>(
name: "ItemQuantity_" + changedItem.Type.ToString()
);
if(changedItemQuantityLabel != null) {
int itemAmount = collectibleInventory.GetAmountOfItemType(changedItem.Type);
if(itemAmount > 0) {
changedItemQuantityLabel.text = collectibleInventory
.GetAmountOfItemType(changedItem.Type)
.ToString();
} else {
VisualElement itemElement = changedItemQuantityLabel.parent;
collectibleItemsContainer.Remove(itemElement);
}
return;
}
AddCollectibleInventoryElement(changedItem);
}
void UpdateBuildableItemsUi(BuildableInventoryItem changedItem) {
if(changedItem == null) {
foreach(BuildableInventoryItem item in buildableInventory.items) {
AddBuildableInventoryElement(item);
}
return;
}
Label changedItemQuantityLabel = buildableItemsContainer.Q<Label>(
name: "ItemQuantity_" + changedItem.Type.ToString()
);
if(changedItemQuantityLabel != null) {
int itemAmount = buildableInventory.GetAmountOfItemType(changedItem.Type);
if(itemAmount > 0) {
changedItemQuantityLabel.text = buildableInventory
.GetAmountOfItemType(changedItem.Type)
.ToString();
} else {
VisualElement itemElement = changedItemQuantityLabel.parent;
buildableItemsContainer.Remove(itemElement);
}
return;
}
AddBuildableInventoryElement(changedItem);
}
void AddCollectibleInventoryElement(CollectibleInventoryItem item) {
VisualElement itemElement = new VisualElement();
itemElement.name = "InventoryItem";
itemElement.AddToClassList("InventoryItem");
itemElement.style.backgroundImage = new StyleBackground(item.Icon);
Label itemQuantityLabel = new Label(
collectibleInventory.GetAmountOfItemType(item.Type).ToString()
);
itemQuantityLabel.name = "ItemQuantity_" + item.Type.ToString();
itemQuantityLabel.AddToClassList("ItemQuantity");
itemElement.Add(itemQuantityLabel);
collectibleItemsContainer.Add(itemElement);
}
void AddBuildableInventoryElement(BuildableInventoryItem item) {
VisualElement itemElement = new VisualElement();
itemElement.name = "InventoryItem";
itemElement.AddToClassList("InventoryItem");
itemElement.style.backgroundImage = new StyleBackground(item.Icon);
Label itemQuantityLabel = new Label(
buildableInventory.GetAmountOfItemType(item.Type).ToString()
);
itemQuantityLabel.name = "ItemQuantity_" + item.Type.ToString();
itemQuantityLabel.AddToClassList("ItemQuantity");
itemElement.Add(itemQuantityLabel);
buildableItemsContainer.Add(itemElement);
}
}Die Methoden AddCollectibleInventoryElement und AddBuildableInventoryElement erstellen neue UI-Elemente für die jeweiligen Inventargegenstände und fügen sie dem passenden Container hinzu. Die Methoden UpdateCollectibleItemsUi und UpdateBuildableItemsUi aktualisieren die UI, wenn Gegenstände zum Inventar hinzukommen oder daraus entfernt werden.
Wir könnten auch generische Methoden hinzufügen, um doppelten Code zu vermeiden, aber der Übersichtlichkeit halber lassen wir sie hier getrennt.
Hänge zum Schluss das Skript InventoryUi an ein neues GameObject in deiner Szene und füge ihm eine UIDocument-Komponente hinzu. Weise in der UIDocument-Komponente die Datei InventoryUi.uxml dem Feld Source Asset zu.
Du solltest nun diese Struktur in deinem Unity-Projekt haben:
Assets/
├── Objects/
│ ├── Collectibles/
│ │ ├── Wood.asset
│ │ ├── Stone.asset
│ │ ├── Iron.asset
│ │ ├── Silver.asset
│ │ └── Gold.asset
│ └── Buildables/
│ └── Storage.asset
└── Scripts/
├── Inventory/
│ ├── Inventory.cs
│ └── IInventoryItem.cs
├── Items/
│ ├── Collectibles/
│ │ ├── CollectibleItem.cs
│ │ ├── CollectibleItemType.cs
│ │ └── CollectibleInventoryItem.cs
│ └── Buildables/
│ ├── BuildableItem.cs
│ ├── BuildableItemType.cs
│ ├── BuildableInventoryItem.cs
│ └── Buildable.cs
├── Ui/
│ └── InventoryUi/
│ ├── InventoryUi.uss
│ ├── InventoryUi.uxml
│ └── InventoryUi.cs
└── PlayerController.cs