Bevor du anfängst
Stellen Sie sicher, dass Sie ein C++-basiertes Unreal Engine Projekt haben.
Diese Seite ist die Fortsetzung von First-Person Kamera, Mesh und Animation hinzufügen; Sie können diese Seite jedoch unabhängig vom Rest der Tutorial-Serie Ein erstes First-Person-Abenteuerspiel programmieren abschließen, wenn Sie nur etwas über datengesteuertes Gameplay lernen möchten.
Datenorganisation in Spielen
Die Art und Weise, wie Sie Daten organisieren und darstellen, ist ein wichtiger Teil des Spieldesigns. Interaktionsfähige Gegenstände können sehr unterschiedliche Eigenschaften haben und im Spiel oder nur als Daten existieren. Sie könnten diese Daten repräsentieren, indem Sie separate Klassen und Blueprints für jeden Objekttyp erstellen und die Daten über verschiedene Actors verteilen und kommunizieren. Dies wird jedoch ineffizient, wenn Ihr Spiel und die Menge der gespeicherten Daten wächst.
Ein besserer Ansatz ist Datengesteuertes Spiel. Anstatt Werte fest zu codieren, organisieren Sie die Daten an einem zentralen Ort, der von den Systemen in Ihrem Spiel verwaltet wird. Mit datengesteuertem Gameplay können Sie laden, was Sie brauchen, wenn Sie es brauchen. Beispiel verwenden viele Spiele Tabellenkalkulationsdokumente, um Dialoge zu organisieren, da es für ein System einfacher ist, eine bestimmte Dialogzeile zu finden, anstatt potenziell Hunderte von Zeilen in jedem Charakter zu speichern.
In diesem Abschnitt erfahren Sie, wie Sie diese Methode verwenden, um benutzerdefinierte Gegenstände zu erstellen.
Elemente für Datengesteuertes Spiel
Bevor Sie anfangen, grundlegende Gegenstände zu erstellen, ist es wichtig zu überlegen, was einen „Gegenstand“ definiert. Da ein Gegenstand alles sein kann, womit ein Spieler interagiert, sollte er über einen minimalen Satz von Eigenschaften verfügen, die für jeden Typ von Gegenstand gültig sind. Sie richten das in einer Gegenstanddatenstruktur ein. Sie sollten auch einen zentralen Ort haben, um diese Gegenstandsdaten zu organisieren und anzuzeigen. Dafür nutzen Sie ein Datentabellen Asset.
Ihre Gegenstanddatenstruktur agiert als Vorlage, die den Datentyp Ihres Gegenstands definiert, und Ihre Datentabelle und Daten-Assets speichern dann die tatsächlichen Dateneinträge auf der Grundlage Ihrer Struktur.
Das folgende Diagramm zeigt die vier Datengesteuerte Spiel-Elemente, die Sie in diesem Teil des Tutorial erstellen werden. Sobald Sie alle vier Elemente eingerichtet haben, werden Sie sich dieses Diagramm noch einmal genauer ansehen, um das Erarbeitete zusammenzufassen.
Zunächst erstellen Sie zwei Dateien, um Ihre Gegenstandsdaten zu definieren:
ItemData.h: Ein Container für die Gegenstanddatenstruktur-Deklaration (FItemData).ItemDefinition.h: Eine Klasse, die Daten vonUDataAssetübernimmt, damit Ihre Gegenstand-Daten im Unreal Editor genutzt werden können.
Die Gegenstanddatenstruktur übernimmt nicht von UObject und kann in einem Level nicht instanziert werden. Sie benötigen daher ebenfalls die Daten-Asset-Klasse, um im Editor zu Referenz und zu verwenden.
Anschließend erstellen Sie im Unreal Editor eine Datentabelle und eine Daten-Asset-Instanz basierend auf ItemDefinition.
Definieren Sie Ihre Gegenstanddaten
Ihre Item-Datenstruktur definiert die Daten oder Eigenschaften, die jeder Gegenstand in der Datentabelle haben sollte, und verhält sich wie die Spalten der Tabelle.
Ihre Gegenstanddatenstruktur wird die folgenden Eigenschaften haben:
ID: Ein einzigartiger Name für den Gegenstand, nützlich bei der späteren Referenzierung von Tabellenzeilen.
Gegenstandstyp: Der Typ dieses Gegenstandes (in diesem Fall definieren Sie die Werkzeug- und Verbrauchsgegenstände-Typen).
Gegenstandstext: Textdaten über den Gegenstand, einschließlich Name und Beschreibung.
Gegenstandsbasis: Das ItemDefinition-Daten-Asset, das mit diesem Gegenstand assoziiert ist.
Wenn Sie Ihre eigenen Tabellenfelder (Spalten) erstellen möchten, beachten Sie, dass Daten-Tabellenfelder beliebige Typen sein können, die mit UPROPERTY() kompatibel sind.
Erstellen Sie einen Header-Datei Container für die Struktur
Richten Sie einen neuen Ordner und eine neue Header-Datei (.h) ein, um Ihre Gegenstanddatenstruktur-Definition zu speichern.
Sie können die FItemData-Struktur in ItemDefinition.h erstellen, aber das Speichern der Struktur in einer separaten Datei hilft bei der Organisation Ihrer Datenelemente und ermöglicht die Wiederverwendung.
Befolgen Sie diese Schritte, um eine Header-Datei als Container für Ihre Gegenstandsdatenstruktur einzurichten:
Gehen Sie im Unreal Editor zu Werkzeuge > Neue C++-Klasse.
Wählen Sie im Fenster Parent Klasse auswählen Keine als Parent-Klasse und klicken dann auf Weiter.
Klicken Sie neben Pfad auf das Ordnersymbol. Erstellen Sie in Ihrem Ordner
Source/[ProjectName]einen neuen Ordner namensData, um diese Klasse zu speichern.Geben Sie der Klasse den Namen
ItemDataund klicken Sie auf Create Class.Falls die Unreal Engine Ihre neuen Klassendateien nicht automatisch öffnet, öffnen Sie Ihr Projekt und
ItemData.hin Visual Studio.Löschen Sie den gesamten Text in
ItemData.cpp, dann speichern und schließen Sie die Datei. Sie werden sie nicht benutzen.In
ItemData.h, löschen Sie alles unter der#include “CoreMinimal.h”Zeile.Der Header
CoreMinimal.henthält grundlegende Typen wieFName,FStringund andere Typen, die Sie zur Definition Ihrer Daten benötigen.Fügen Sie am Anfang von
ItemData.h, l#pragma onceund die folgenden Include-Anweisungen hinzu:#include “Engine/DataTable.h”: Erforderlich, damit Ihre Struktur vonFTableRowBaseübernimmt.#include “ItemData.generated.h”: Erforderlich für das Unreal Header Tool. Achten Sie darauf, dass diese Include-Anweisung zuletzt kommt, damit Ihr Code richtig kompiliert werden kann.
C++#pragma once #include "CoreMinimal.h" #include "Engine/DataTable.h" #include "ItemData.generated.h"Fügen Sie eine Vorwärts-Deklaration für eine Klasse namens
UItemDefinitionhinzu. Dies wird das Daten-Asset sein, mit dem Sie im Editor arbeiten können.C++class UItemDefinition;
Gegenstandseigenschaften definieren
Es gibt keine vorhandenen Variablentypen für einen Artikeltyp und Textdaten, so dass Sie diese definieren müssen.
Führen Sie die folgenden Schritte aus, um ein um ein Gegenstandstyp Enum zu definieren:
Erstellen Sie eine neue
enum class, die alle möglichen Gegenstand -Typen auflistet. In diesem Tutorial werden Sie Werkzeuge und Verbrauchsgegenstände erstellen.Nennen Sie die Enum Klasse
EItemTypeund geben Sie ihr den Typuint8. Fügen Sie das MakroUENUM()darüber ein, um dieses Enum im Unreal Header Tool zu bestimmen.C++// Defines the type of the item. UENUM() enum class EItemType : uint8 { };Fügen Sie zwei benutzerdefinierte Werte zu diesem Enum hinzu:
Tool, Hinzufügen einesUMETA()Makro mitDisplayName = “Tool”Consumable, Hinzufügen einesUMETA()Makros mitDisplayName = “Consumable”
C++// Defines the type of the item. UENUM() enum class EItemType : uint8 { Tool UMETA(DisplayName = "Tool"), Consumable UMETA(DisplayName = "Consumable") };
Diese Gegenstandstypen sind benutzerdefiniert und nicht in der Unreal Engine eingebaut; Sie können also, nachdem Sie die Grundlagen gelernt haben, alles erstellen, was Sie möchten! (Möglicherweise ein QuestItem, eine Currency oder ein Disguise?)
Gehen Sie folgendermaßen vor, um eine Gegenstandstext-Struktur zu definieren:
Nach
EItemTypeerstellen Sie eine neue Struktur namensFItemTextmit einemUSTRUCT()Makro. Diese Struktur enthält Textdaten über Ihren Gegenstand.C++// Contains textual data about the item. USTRUCT() struct FItemText { };Innerhalb von
FItemTextfügen Sie das MakroGENERATED_BODY()hinzu.Fügen Sie dann zwei
FText-Eigenschaften namensNameundDescriptionhinzu, um den Namen und die Beschreibung für diesen Gegenstand zu speichern. Fügen Sie das MakroUPROPERTY()zu jedem mitEditAnywhereals Argumente hinzu.C++// Contains textual data about the item. USTRUCT() struct FItemText { GENERATED_BODY() // The text name of the item. UPROPERTY(EditAnywhere) FText Name;
Erstellen Sie die Gegenstandsdaten Struktur
Nachdem Sie nun die Voraussetzungsdeklarationen hinzugefügt haben, erstellen Sie die Gegenstandsdaten Struktur mit den Eigenschaften Ihres Gegenstands darin. Diese Eigenschaften werden die Felder in Ihrer Daten-Tabelle.
Definieren Sie eine Struktur namens FItemData, die von FTableRowBase übernimmt. Fügen Sie den public Bezeichner hinzu, damit er überall sichtbar ist, und fügen Sie GENERATED_BODY() für das Unreal Header Tool hinzu.
// Defines a basic item that can be used in a data table.
USTRUCT()
struct FItemData : public FTableRowBase
{
GENERATED_BODY()
};FTableRowBase ist eine von der Unreal Engine bereitgestellte Basis Struktur, mit der Sie Ihre benutzerdefinierten USTRUCTs in einem Daten-Tabellen Asset verwenden können. Unreal verwendet sie, um zu wissen, wie die Zeilenstruktur zu serialisieren ist, um das Importieren und Exportieren von Daten aus CSV/JSON-Dateien zu unterstützen und um Typsicherheit beim Abrufen von Daten aus der Tabelle zu gewährleisten.
Fügen Sie in der FItemData-Struktur die folgenden Deklarationen hinzu:
Ein
FNamenamensID. Jede Zeile in einer Daten-Tabelle benötigt einen assoziiertenFName,zur Referenz.Ein
EItemType enummit dem NamenItemType. Dies ist das Enum der Gegenstandstypen, die Sie zuvor deklariert haben.Eine
FItemText-Struktur mit dem NamenItemText. Das ist die Struktur der Textdaten, die Sie vorher deklariert haben.
Fügen Sie das Makro UPROPERTY() zu jeder Deklaration mit den Argumenten EditAnywhere und Category = „Item Data“ hinzu.
// The ID name of this item for referencing in a table row.
UPROPERTY(EditAnywhere, Category = "Item Data")
FName ID;
// The type of the item.
UPROPERTY(EditAnywhere, Category = "Item Data")
EItemType ItemType;
// Text struct including the item name and description.
UPROPERTY(EditAnywhere, Category = "Item Data")
Fügen Sie eine weitere Deklaration hinzu: Ein TObjectPtr zu einer UItemDefinition mit dem Namen ItemBase. Geben Sie ihm das gleiche Makro UPROPERTY wie den anderen Eigenschaften in der Struktur.
// The Data Asset item definition associated with this item.
UPROPERTY(EditAnywhere, Category = "Item Data")
TObjectPtr<UItemDefinition> ItemBase;TObjectPtr ist ein Smart Pointer-Typ in der Unreal Engine, der einen sicherere Möglichkeit darstellt, um UObjectabgeleitete Typen zu referenzieren. Es ist ein editorfähiger, Garbage Collection-sicherer Ersatz für rohe UObject-Pointers. Das ist eine Hard-Referenz, so dass das Objekt zur Laufzeit geladen bleibt.
Im nächsten Schritt erstellen Sie eine UDataAsset-Klasse mit dem Namen ItemDefinition. In Ihrer Daten-Tabelle verwenden Sie das Feld ItemBase, um ItemDefinition-Daten-Asset-Instanzen zu referenzieren.
Ihre Struktur FItemData sollte nun so aussehen:
// Defines a basic item that can be used in a data table.
USTRUCT()
struct FItemData : public FTableRowBase
{
GENERATED_BODY()
// The ID name of this item for referencing in a table row.
UPROPERTY(EditAnywhere, Category = "Item Data")
FName ID;
Speichern Sie Ihren Code.
Erstellen Sie eine DataAsset-Gegenstands-Definition
Bisher haben Sie Ihre Gegenstandsdaten, oder die Datentypen, die in Ihrer Daten-Tabelle auftauchen, definiert. Als Nächstes implementieren Sie die Klasse UItemDefinition, für die Sie eine Vorwärts-Deklaration ItemData.h erstellt haben.
Diese Klasse übernimmt von UDataAsset und ist daher ein UObject, d. h. Sie können Instanzen davon direkt im Editor erstellen und verwenden, ohne Code zu durchlaufen. Sie füllen Ihre Daten-Tabelle mit Instanzen Ihrer UItemDefinition-Klasse auf.
Um Ihre Klasse ItemDefinition DataAsset (ItemDefinition.h) zu erstellen, gehen Sie wie folgt vor:
Gehen Sie im Unreal Editor zu Werkzeuge > Neue C++-Klasse.
Klicken Sie im Fenster Parent-Klasse auswählen auf Alle Klassen.
Suchen und wählen Sie DataAsset als Parent-Klasse und klicken dann auf Weiter.
Geben Sie der Klasse den Namen
ItemDefinition(entsprechend der Vorwärts-Deklaration, die Sie inItemData.herstellt haben), und klicken Sie dann auf Klasse erstellen.
VS sollte automatisch Ihre neue Klasse .h und .cpp öffnen Dateien. Wenn nicht, aktualisieren Sie VS und öffnen Sie die Dateien manuell. Sie werden lediglich in der .h Datei arbeiten, so dass Sie die Datei .cpp schließen können, falls gewünscht.
Fügen Sie in ItemDefinition.h, ein Include für ItemData.h hinzu, da Sie die in dieser Datei deklarierten Eigenschaften ItemType und ItemText wiederverwenden möchten.
#include "CoreMinimal.h"
#include "Data/ItemData.h"
#include "ItemDefinition.generated.h"Fügen Sie in ItemDefinition.h im Makro UCLASS() oberhalb der Klassendefinition die Bezeichner BlueprintType und Blueprintable hinzu, um diese Klasse als Basisklasse für die Erstellung von Blueprints auszuweisen.
// Defines a basic item with a static mesh that can be built from the editor.
UCLASS(BlueprintType, Blueprintable)
class FIRSTPERSON_API UItemDefinition : public UDataAsset
{
GENERATED_BODY()
public:
// Default constructor for the class.
UItemDefinition();
};Kopieren Sie im öffentlichen Abschnitt die Deklarationen FName ID, EItemType ItemType und FItemText ItemText aus ItemData.h.
Ihre Item-Definition erhält dieselben Daten wie die FItemData-Struktur, so dass Sie nicht auf die Originaltabelle verweisen müssen, wenn Sie Informationen über den Gegenstand erhalten möchten.
public:
// The ID name of this item for referencing in a table row.
UPROPERTY(EditAnywhere, Category = "Item Data")
FName ID;
// The type of this item.
UPROPERTY(EditAnywhere, Category = "Item Data")
EItemType ItemType;
Nach ItemText deklarieren Sie ein TSoftObjectPtr des Typs UStaticMesh mit dem Namen WorldMesh. Sie verwenden dieses statische Mesh, um den Gegenstand in der Welt anzuzeigen.
TSoftObjectPtr ist ein spezieller Typ von Schwacher Pointer, der als String-Darstellung eines Pfads für ein Asset dient und nur bei Bedarf geladen wird. Normalerweise wird bei der Deklaration einer UObject Pointer-Eigenschaft, die auf ein Asset verweist,, dieses Asset geladen, wenn das Objekt, das die Eigenschaft enthält, geladen wird. Dies könnte dazu führen, dass beim Spielstart alle Assets geladen werden, was einen enormen Overhead und eine Verlangsamung zur Folge hätte. TSoftObjectPtr ist nützlich für große Assets wie Meshs, die nur auf Anfrage geladen werden sollen. Weitere Informationen finden Sie unter Asynchronous Asset Loading.
Fügen Sie das gleiche UPROPERTY(EditAnywhere, Category = “Item Data”)-Makro zu dieser Eigenschaft hinzu.
// Text struct including the item name and description.
UPROPERTY(EditAnywhere, Category = "Item Data")
FItemText ItemText;
// The Static Mesh used to display this item in the world.
UPROPERTY(EditAnywhere, Category = "Item Data")
TSoftObjectPtr<UStaticMesh> WorldMesh;
Datentabellenzeilen ähneln CSV-Zeilen und sind für die Aufnahme von Textdaten gedacht, nicht für die Speicherung kompletter Assets. Zur Optimierung der Datenverwaltung empfehlen wir, Informationen wie das Mesh eines Gegenstands, das Material und die Animationen in einem DataAsset zu bündeln, da dies der zentrale Ort ist, an dem alle Daten zu einem bestimmten Gegenstand gespeichert sind. Die statische Mesh Eigenschaft des Items befindet sich also hier in UItemDefinition anstatt in der FItemData- Struktur.
Ihre vollständige UItemDefinition-Klasse sollte nun folgendermaßen aussehen:
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Data/ItemData.h"
#include "ItemDefinition.generated.h"
/**
* Defines a basic item with a static mesh that can be built from the editor.
Speichern Sie Ihren Code und kompilieren Sie ihn mit Visual Studio.
Erstellen Sie eine Daten-Asset-Instanz
Mit der Definition der Gegenstandsdaten (FItemData Struktur aus ItemData.h) und der Item-Definition (UItemDefinition Klasse) definiert, haben Sie alle Stücke, die Sie benötigen, um Ihre Gegenstandsinstanzen und Datentabelle zu erstellen.
Erstellen Sie zuerst ein Daten-Asset für einen neuen Projektil-Aufnahmegegenstand, erstellen Sie dann eine Datentabelle und füllen Sie diese mit den Informationen Ihres Daten-Assets.
Gehen Sie folgendermaßen vor, um ein Daten-Asset-Gegenstand aus Ihrer ItemDefinition -Klasse zu erstellen:
Gehen Sie im Inhaltsbrowser zu Inhalt > FirstPerson, klicken Sie auf Hinzufügen oder klicken Sie mit der rechten Maustaste auf einen leeren Bereich in der Anlagenansicht und wählen Sie Neuer Ordner aus, und bennnen Sie ihn
Data.Hier speichern und organisieren Sie die Datenbestände in Ihrem Spiel.
Klicken Sie im Ordner
Dataauf Hinzufügen oder klicken Sie mit der rechten Maustaste auf einen leeren Bereich in der Anlagenansicht und wählen Sie Sonstiges > Daten-Asset aus.Stellen Sie sicher, dass Sie die Option Daten-Asset mit dem Kreisdiagramm-Symbol auswählen.
Wählen Sie im Fenster Klasse für Daten-Asset-Instanz auswählen die Item-Definition (die C++ Klasse, die Sie zuvor definiert haben) und klicken dann auf Auswählen. Geben Sie dem neuen Daten-Asset den Namen
DA_Pickup_001.Mit einem Doppelklick auf
DA_Pickup_001wird es geöffnet. Im Details-Panel sehen Sie alle Eigenschaften, die Sie inItemDefinition.hdefiniert haben.Geben Sie
pickup_001als ID ein.Richten Sie den Gegenstandstyp auf Verbrauchsgegenstand ein.
Erweitern Sie Gegenstandstext und geben Sie irgendeinen Namen und eine Beschreibung ein.
Legen Sie das Welt-Mesh auf
SM_FoamBulletfest.Klicken Sie auf Speichern nahe der oberen linken Ecke des Fensters, um Ihr Daten-Asset zu speichern.
Definieren Sie eine Daten-Tabelle
Da Sie nun mindestens ein Daten-Asset haben, mit dem Sie eine Daten-Tabelle auffüllen können, können Sie die Tabelle erstellen!
Jede Zeile in der Daten-Tabelle ist eine ausgefüllte Instanz Ihrer ItemData-Struktur.
Um eine Daten-Tabelle zu erstellen, gehen Sie folgendermaßen vor:
Klicken Sie im Inhaltsbrowser in Ihrem Ordner
Datamit der rechten Maustaste auf einen leeren Bereich und wählen Sie Sonstiges > Daten-Tabelle.Im Fenster Zeilenstruktur auswählen wählen Sie ItemData (die
FItemDataStruktur, die Siein ItemData.hdefiniert haben), und klicken Sie dann auf OK.Nennen Sie die neue Tabelle
DT_PickupData, und öffnen Sie sie mit einem Doppelklick.
Ihre Datentabelle ist am Anfang leer. Allerdings werden Sie die Eigenschaften, die Sie in FItemData definiert haben, als Überschriften am oberen Rand der Tabelle sehen und eine zusätzliche Spalte mit dem Namen Row Name.
Gehen Sie folgendermaßen vor, um Ihr Abholpunkt-Daten-Asset als Zeile in die Tabelle einzufügen:
Klicken Sie auf Hinzufügen , um eine neue Zeile in Ihre Tabelle einzufügen. Der DataTable-Editor listet die Zeileneinträge im linken oberen Panel auf der Registerkarte Daten-Tabelle auf.
Machen Sie einen Doppelklick auf den Zeilennamen
NewRowund ändern Sie ihnpickup_001(die ID Ihres Daten-Assets).Verwenden Sie einen beliebigen
FNameals den Zeilennamen; um jedoch den Verweis auf die Zeile im Code zu erleichtern, sollten Sie den Zeilennamen mit der ID des Daten-Assets übereinstimmen lassen.Geben Sie im Panel Zeilen-Editor dieselben Werte ein, die Sie im Daten-Asset
DA_Pickup_001in den Feldern ID, Gegenstandstyp und Gegenstandstext festgelegt haben.Legen Sie die Gegenstandsbasis auf Ihr
DA_Pickup_001Daten-Asset fest.Speichern Sie Ihre Daten-Tabelle.
Und das war‘s schon! Schauen Sie sich das Diagramm der datengesteuerten Spiel-Elemente, die Sie in diesem Schritt erstellt haben, noch einmal an und sehen Sie, wie sie alle miteinander verbunden sind:
Sie haben eine Datentabelle erstellt, die ihre Spalten aus Ihrer FItemData-Struktur bezieht. Sie haben die Tabelle mit einer Zeile gefüllt, die die Daten aus der von Ihnen erstellten Daten-Asset-Instanz vom Typ Verbrauchsgegenstand ItemDefinition enthält, und haben den Pointer ItemBase verwendet, um auf das Daten-Asset selbst zu verweisen. Zuletzt hat Ihre Daten-Asset-Instanz ihre Eigenschaften aus der von Ihnen erstellten Parent-Klasse UItemDefinition Daten-Asset erhalten.
Als Nächstes
Im nächsten Abschnitt erfahren Sie, wie Sie diese Item-Definition erweitern, um eine benutzerdefinierte Abholpunktklasse zu erstellen und diese in Ihrem Level zu instantiieren.
Vollständiger Code
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "ItemData.generated.h"
class UItemDefinition;
/**
* Defines the type of the item.
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Data/ItemData.h"
#include "ItemDefinition.generated.h"
/**
* Defines a basic item with a static mesh that can be built from the editor.