UE4 | Інвентар для Multiplayer #2 | Підключення Blueprint до C++
Список статей
UE4 | Інвентар для Multiplayer #1 | Сховище даних на DataAsset
UE4 | Інвентар для Multiplayer #2 | Підключення Blueprint до C++
UE4 | Інвентар для Multiplayer #3 | Структура взаємодії
У попередній статті я розповідав як створити DataAsset, і чому він такий хороший і зручний. Тут же ми розглянемо те, як отримати доступ до DataAsset, точніше до призначених у ньому даними, з Blueprint і C++.
Попутно ми відповімо на питання отримання доступу до будь-якого Blueprint з C++.
Із взаємодією Blueprints все досить прозоро.
Зважаючи на те, що ми закрили прямий доступ до нашої бази даних, ми не можемо просто так звернеться до неї з Blueprint. Зверніть увагу на protected: у коді нижче.
protected:
/* This is the main Database for all Items. It contains constant common variables */
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ItemsDatabase")
TMap<FGameplayTag, FItemsDatabase> ItemsDataBase;
Тобто наше сховище буде мабуть тільки в успадкованих класах, і це добре, тому що ми прописали функції для безпечного виклику даних.
/* Used in the widget */
UFUNCTION(BlueprintCallable, Category = "ItemDatabase")
FORCEINLINE UTexture2D * GetItemIconTexture(const FGameplayTag & ItemNameTag) const;
BlueprintCallable якраз і означає, що дана функція може бути використана в Blueprint. Якщо ви читали попередню статтю, то напевно помітили, що інші функції виклику такого атрибуту не мають. Так зроблено тільки тому, що викликаються ними дані на даний момент в Blueprint не знадобилися. Якщо комусь щось знати не потрібно — не поспішаємо про це повідомляти.
Наступний крок, це створення у кожному Blueprint змінної типу створеної нами бази даних (в моєму випадку це BP_DreampaxItemsDataAsset).
Після цього легко невимушено витягаємо призначену текстуру.
Тепер розглянемо як отримати доступ до інформації в C++.
Ми не можемо просто звернутися до класу DreampaxItemsDataAsset, оскільки він не містить ніякої інформації. Нам потрібно отримати доступ до BP_DreampaxItemsDataAsset.
Існує два основних метода як достукатися до Blueprint.
Спочатку розглянемо незручний спосіб підключення з використанням милиці ConstructorHelpers. В даному випадку це доступ до текстурою.
ASHUD::ASHUD(const class FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
/* You can use the FObjectFinder in C++ reference to content directly in code. Although it's advisable to avoid this and instead assign content through Blueprint child classes. */
static ConstructorHelpers::FObjectFinder<UTexture2D> HUDCenterDotObj(TEXT("/Game/UI/HUD/T_CenterDot_M.T_CenterDot_M"));
CenterDotIcon = UCanvas::MakeIcon(HUDCenterDotObj.Object);
}
Приклад взятий з чудового проекту EpicSurvivalGameSeries, ідеально відповідного для вивчення Multiplayer на C++. Автор поставив за мету показати якомога більше методів та прийомів програмування гри на C++.
Чому цей спосіб незручний? Та ж біда як і з DataTable — при зміні назви Blueprint або місця розташування, файл не знайдений.
Найкращим можна вважати метод в якому ми оголошуємо змінну в заголовочном файлі, для подальшого призначення її вже в наследованном Blueprint. Для прикладу вище це могло б виглядати так:
UPROPERTY(EditDefaultsOnly, Category = "AimPointer")
FCanvasIcon CenterDotIcon;
Набагато простіше, вірно?
Тепер, знаючи як отримати доступ до будь Blueprint, ми можемо без проблем підключити нашу базу даних.
UCLASS()
class ADreampaxGameMode : public AGameMode
{
GENERATED_BODY()
public:
ADreampaxGameMode(const FObjectInitializer & ObjectInitializer);
/////////////////////////////////////////////////////////////////////////////
//Data Bases
/////////////////////////////////////////////////////////////////////////////
public:
/* Connect data base in BP for items*/
UPROPERTY(EditDefaultsOnly, Category = "Database")
class UDreampaxItemsDataAsset * DreampaxItemsDataAsset;
FORCEINLINE UDreampaxItemsDataAsset * GetDreampaxItemsDataAsset() const;
Невеликий відступ для не профі на тему оголошення змінних
Як людина майже незнайомий з C++, я зламав чимало списів, намагаючись зрозуміти як правильно оголошувати кастомні змінні.
Якщо стоїть мета оголосити змінну створеного нами класу, як, наприклад
UDreampaxItemsDataAsset * DreampaxItemsDataAsset;
// або
class UDreampaxItemsDataAsset * DreampaxItemsDataAsset;
особисто мені якийсь час було незрозуміло коли потрібно застосовувати class, а коли ні.
Все виявилося до болю просто.
- Якщо не ставити class, то потрібно виконати включення #include “Data/DreampaxItemsDataAsset.h”, що містить оголошення цього класу.
- Якщо ставити class, то #include “Data/DreampaxItemsDataAsset.h” можна зробити уже .cpp.
- І ще одна опція попереднього пункту, якщо потрібно оголосити відразу багато змінних даного класу. Безпосередньо після усіх #include попередньо оголосити наш клас class UDreampaxItemsDataAsset;, а після оголошувати змінні вже без приставки class.
Який з цих способів правильний — не беруся сказати. Якщо хтось пояснить, буду вдячний.
Робимо змінну C++ класі ADreampaxGameMode, так як він видно тільки сервера, а все що пов’язано зі спауном об’єктів повинно йти тільки через сервер. Даний клас є батьком для BP_DreampaxGameMode, де ми підключимо наш BP_DreampaxItemsDataAsset.
Підключення BP_DreampaxItemsDataAsset
Тепер вся міць C++ може бути використана для роботи з даними нашої бази даних.
У наступній статті (нарешті!) ми поговоримо про створення інвентарю і дізнаємося чому нам ніяк не обійтися без вже створеного DataAsset.
Якщо є питання або побажання розкрити будь-який аспект детальніше, будь ласка пишіть в коментарях.