ue4學(xué)習(xí)筆記

Unreal Engine 4 Scripting with C++ Cookbook 簡單筆記

  1. 主動刪除Object 內(nèi)存 調(diào)用 object->ConditionalBeginDestroy() 間隔一段時間后會被垃圾回收系統(tǒng)清除 也可以手動調(diào)用GetWorld()->ForceGarbageCollection(true) 來立即清空
    時間間隔的設(shè)置默認(rèn)是60s 位置在Epic Games\4.11\Engine\Config \BaseEngine.ini gc.TimeBetweenPurgingPendingKillObjects=60
    2.創(chuàng)建UStruct
    創(chuàng)建。h文件

pragma once

include "ColoredTexture.generated.h"

USTRUCT()
struct FColoredTexture
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = HUD)
UTexture* Texture;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = HUD)
FLinearColor Color;
};
3.創(chuàng)建Enum
UENUM()
enum Status
{
Stopped UMETA(DisplayName = "display Stopped"),
Moving,
Attacking
};
使用Enum
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Status")
TEnumAsByte<Status> status;
4.內(nèi)存管理
繼承自UObject的類型通過聲明UProperty 保存引用 會自動添加到GC系統(tǒng)中 可以自動刪除 或者通過AddToRoot 防止被自動刪除 需要刪除時 調(diào)用RemoveFromRoot自動被gc系統(tǒng)刪除
Actor 與 ActorComponent例外
非UObject類可以通過TSharedRef 或者 TWeakRef 智能指針來保存引用 智能指針智能不能保存UObject類型
TWeakPtr 不會保證引用會在內(nèi)存中保存 所有可以通過ptr.isValid() 來判斷指針指向的對象是否存在
TSharePtr 是線程安全的 不需要的畫可以使用TAutoPtr
TScopedPointer 作用域智能指針 確保指針會在作用域結(jié)束后才能刪除
如果使用TArray之類的容器保存UObject指針 需要將TArray聲明UPorperty()

5.控制Actor的生存時間 一種方式是通過調(diào)用延遲函數(shù) 在延遲回調(diào)里面通過actor->destroy() 破壞掉
GetWorldTimerManager().SetTimer(Timer, this,
&AUE4CookbookGameMode::DestroyActorFunction, 10)
還有一種方式是通過 設(shè)置setLifeSpan(10) 在10s后actor會調(diào)用自身的Destroy()刪除

  1. 沒有任何Component的actor是沒有任何意義的 既沒有transform也不能附加到其他的actor上
    為Actor添加Component的話 通過在Actor的構(gòu)造函數(shù)(必須要在構(gòu)造函數(shù)中)調(diào)用CreateDefaultSubobject 創(chuàng)建Component 測試發(fā)現(xiàn)當(dāng)將CreateDefaultSubobject創(chuàng)建的
    Component保存為UProperty是 名稱參數(shù)不起作用 實際在Editor中顯示的名稱與變量名稱一致
    加載StaticMesh資源 auto meshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("/Game/StarterContent/Props/SM_Bush"));
    其中路徑部分的game對應(yīng)的是Content文件夾 可以通過在資源右鍵 copyreference 獲得該資源的路徑

7.可以通過繼承自ActorComponent 重寫component類 可以通過GetOwner()獲得Component綁定的Actor
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) 其中ClassGroup指定 在Editor中 component的分類 meta 指定該Component是否可以被藍(lán)圖actor使用

  1. 代理與事件的區(qū)別 代理的調(diào)用可以在任何可以訪問到代理的類中進(jìn)行訪問 而事件 只可以在聲明事件的類中進(jìn)行訪問

9.在代碼中控制輸出 繼承Character類 在SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{中 調(diào)用PlayerInputComponent->BindAxis() 將在ProjectSetting、input中的動作名稱 綁定到自定義的函數(shù)上
同理可調(diào)用BindAction() 綁定動作按鍵

  1. 在代碼中動態(tài)的添加按鍵動作
    創(chuàng)建AxisKey FInputAxisKeyMapping forwardKey("Forward", EKeys::W, 1.0f)
    添加key GetWorld()->GetFirstPlayerController()->PlayerInput->AddAxisMapping(forwardKey)

  2. 創(chuàng)建接口類
    接口類指的是一組classs聲明 其中U開頭的類 繼承自UInterface I開頭的類是聲明實際接口方法的類
    創(chuàng)建MyInterface。h 寫出一下代碼
    // Fill out your copyright notice in the Description page of Project Settings.

pragma once

include "CoreMinimal.h"

include "MyInterface.generated.h"

/**

*/
UINTERFACE()
class UE4COOK_API UMyInterface:public UInterface
{

GENERATED_BODY()

};

class UE4COOK_API IMyInterface
{
GENERATED_BODY()
public:
virtual FString GetTestName();
};
創(chuàng)建MyInterface.cpp
// Fill out your copyright notice in the Description page of Project Settings.

include "MyInterface.h"

include "UE4Cook.h"

FString IMyInterface::GetTestName()
{
unimplemented();
return FString();
}

接口的使用 創(chuàng)建一個新的actor類 繼承該接口 并重寫GetTestName類
class UE4COOK_API ASingleInterfaceActor : public AActor, public IMyInterface
{
GENERATED_BODY()

public:
// Sets default values for this actor's properties
ASingleInterfaceActor();

protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;

public:
// Called every frame
virtual void Tick(float DeltaTime) override;
FString GetTestName() override;

};

檢測是否實現(xiàn)接口 可通過
obj->GetClass()->ImplementsInterface(UInterface::StaticClass());

如果要創(chuàng)建繼承的接口類 就要以UMyInterface為父類 IMyInterface為父類 按照上面的格式 重新添加接口類

12.創(chuàng)建一個被editor 藍(lán)圖識別的UObject類型
需要在UClass中 添加BlueprintType 表示該類可以被藍(lán)圖認(rèn)為是一種type類型 可以作為返回 和 輸入的節(jié)點

  1. 添加module的流程
    右鍵.uproject文件 添加新的模塊
    {
    "FileVersion": 3,
    "EngineAssociation": "4.16",
    "Category": "",
    "Description": "",
    "Modules": [
    {
    "Name": "UE4Cook",
    "Type": "Runtime",
    "LoadingPhase": "Default",
    "AdditionalDependencies": [
    "Engine",
    "CoreUObject"
    ]
    },
    {
    "Name": "UE4CookTestEditor", //新模塊名稱
    "Type": "Editor", //運行模式 Runtime 表示 既在editor模式下運行 又在發(fā)布版運行
    "LoadingPhase": "PostEngineInit", //模塊加載時機(jī)
    "AdditionalDependencies": [
    "Engine",
    "CoreUObject"
    ]
    }
    ]
    }
    添加配置文件
    在Source下 參照原有的文件接口 添加UE4CookTestEditor 文件夾 里面相應(yīng)創(chuàng)建xx.h xx.build.cs xx.cpp文件
    .build.cs
    using UnrealBuildTool;

public class UE4CookTestEditor : ModuleRules
{
public UE4CookTestEditor(ReadOnlyTargetRules Target) : base(Target)
{
PublicDependencyModuleNames.AddRange(new string[] {"Core", "CoreUObject", "Engine", "InputCore", "RHI","RenderCore", "ShaderCore" });
PublicDependencyModuleNames.Add("UE4Cook"); //主模塊
PrivateDependencyModuleNames.AddRange(new string[] {"UnrealEd" });
}
}

其中。h文件
#pragma once

include "CoreMinimal.h"

include "Engine.h"

include "ModuleManager.h"

include "UnrealEd.h" //為了使用Editor相關(guān)的函數(shù) 可以不加

class FUE4CookTestEditorModule: public IModuleInterface
{
};
.cpp文件

include "UE4CookTestEditor.h"

include "Modules/ModuleManager.h"

IMPLEMENT_PRIMARY_GAME_MODULE( FUE4CookTestEditorModule, UE4CookTestEditor); //此處的名稱要與。uproject中配置的名稱保持一致
添加完以上文件后 右鍵。uproject 重新生成vsstudio文件
編輯UE4CookTestEditor.Target.cs
using UnrealBuildTool;
using System.Collections.Generic;

public class UE4CookEditorTarget : TargetRules
{
public UE4CookEditorTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;

    ExtraModuleNames.AddRange( new string[] { "UE4CookTestEditor" } );
}

}

編譯程序并運行 點開/developTools/Modules 查看自定義的module是否正確添加

主要要點 一定要確保模塊名稱在文件名 。build.cs .h 。cpp中的一致性 模塊創(chuàng)建失敗多是由于名稱不一致引起的

  1. 添加工具ui到Editor中

editor的ui是通過TCommand的方式進(jìn)行聲明
在。build.cs中
publicDependencyModuleNames 添加Slate模塊

添加CookbookCommands.h

pragma once

include "Commands.h"

include "EditorStyleSet.h"

class FCookbookCommands : public TCommands<FCookbookCommands>
{
public:
FCookbookCommands() :TCommands<FCookbookCommands>(FName(TEXT("UE4_Cookbook")), //command 名稱
FText::FromString("Cookbook Commands"), // 提示信息
NAME_None, //配合提示信息的 參數(shù)
FEditorStyle::GetStyleSetName())
{};

virtual void RegisterCommands() override;
TSharedPtr<FUICommandInfo> myButton; 

};
添加CookbookCommands.cpp

include "UE4CookTestEditor.h"

include "Commands.h"

include "CookbookCommands.h"

void FCookbookCommands::RegisterCommands()
{

define LOCTEXT_NAMESPACE ""

UI_COMMAND(myButton, "Cookbook", "Demo Cookbook Toolbar command", EUserInterfaceActionType::Button, FInputGesture()); //創(chuàng)建button 保存到myButton中

undef LOCTEXT_NAMESPACE

}

在Editor module類中 重寫StartupModule ShutdownModule函數(shù) 在其中將之前定義的command 綁定到具體的事件和ui中
editor.h文件
// Fill out your copyright notice in the Description page of Project Settings.

pragma once

include "CoreMinimal.h"

include "Engine.h"

include "ModuleManager.h"

include "UnrealEd.h"

include "MainFrame.h" //需要在。build.cs中添加Mainframe模塊

include "CookbookCommands.h"

include "MultiBoxExtender.h"

class FUE4CookTestEditorModule: public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;

TSharedPtr<FExtender> ToolbarExtender; //菜單類 可以用來拓展右鍵菜單 和工具欄菜單
TSharedPtr<const FExtensionBase> Extension; //拓展類 存儲添加菜單的結(jié)果
//按鈕點擊事件
void MyButton_Clicked()
{
    TSharedPtr<SWindow> CookbookWindow = SNew(SWindow)
        .Title(FText::FromString(TEXT("Co Window")))
        .ClientSize(FVector2D(800, 400))
        .SupportsMaximize(false)
        .SupportsMinimize(false);

    IMainFrameModule& mainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>(TEXT("MainFrame"));
    if (mainFrameModule.GetParentWindow().IsValid())
    {
        FSlateApplication::Get().AddWindowAsNativeChild(CookbookWindow, mainFrameModule.GetParentWindow().ToSharedRef())
    }
    else
    {
        FSlateApplication::Get().AddWindow(CookbookWindow);
    }
};
//添加到工具欄的按鈕添加執(zhí)行函數(shù)
void AddToolbarExtension(FToolBarBuilder& builder)
{
    //創(chuàng)建按鈕圖標(biāo)
    FSlateIcon iconBrush = FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.ViewOptions", "LevelEditor.ViewOptions.Small");
    //添加按鈕 第一個參數(shù)是
    builder.AddToolBarButton(FCookbookCommands::Get().myButton, NAME_None, FText::FromString("btn"), FText::FromString("Click to display", iconBrush, NAME_None));
};

};

editor.cpp文件
// Fill out your copyright notice in the Description page of Project Settings.

include "UE4CookTestEditor.h"

include "Modules/ModuleManager.h"

include "ILevelEditor.h"

include "SlateBasics.h"

IMPLEMENT_GAME_MODULE(FUE4CookTestEditorModule, UE4CookTestEditor);

void FUE4CookTestEditorModule::StartupModule()
{
FCookbookCommands::Register(); //注冊自定義command
TSharedPtr<FUICommandList> CommandList = MakeShareable(new FUICommandList()); //創(chuàng)建commandlist 保存我們綁定的事件
//綁定按鈕事件 第一個參數(shù)是我們創(chuàng)建的按鈕 第二個參數(shù)是按鈕的執(zhí)行回調(diào) 第三個參數(shù)是執(zhí)行前的判斷回調(diào) 為true的畫才可以執(zhí)行按鈕事件 這里使用預(yù)定義的回調(diào) 始終返回true
CommandList->MapAction(FCookbookCommands::Get().myButton, FExecuteAction::CreateRaw(this, &FUE4CookTestEditorModule::MyButton_Clicked), FCanExecuteAction());
ToolbarExtender = MakeShareable(new FExtender()); //創(chuàng)建菜單類 可以用來拓展右鍵菜單 和工具欄菜單
//添加按鈕到工具欄 第一個參數(shù)是添加的位置 可以通過Editor Setting/ Generay / miscellaneous /display uiextension points 獲得菜單的位置 第二個參數(shù)是具體的位置在前
Extension = ToolbarExtender->AddToolBarExtension("Compile", EExtensionHook::Before, CommandList, FToolBarExtensionDelegate::CreateRaw(this,
&FUE4CookTestEditorModule::AddToolbarExtension));
//將工具欄添加到editor中
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);

}

void FUE4CookTestEditorModule::ShutdownModelu()
{
//模塊關(guān)閉時 移除拓展
ToolbarExtender->RemoveExtension(Extension.ToSharedRef());
Extension.Reset();
ToolbarExtender.Reset();
}

.build.cs
// Fill out your copyright notice in the Description page of Project Settings.

using UnrealBuildTool;

public class UE4CookTestEditor : ModuleRules

{
public UE4CookTestEditor(ReadOnlyTargetRules Target) : base(Target)
{
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "RHI", "RenderCore", "ShaderCore", "Slate", "SlateCore", "MainFrame", "EditorStyle", });
PublicDependencyModuleNames.Add("UE4Cook");
PrivateDependencyModuleNames.AddRange(new string[] { "UnrealEd" });

}

}

添加菜單按鈕
與普通按鈕不一樣的地方
1.在。h的Add函數(shù)中 調(diào)用builder.AddMenuEntry
2.在。cpp extender的extender->AddMenuExtension 變成AddMenuExtension
3.LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(ToolbarExtender);

添加窗口
可以通過windows/develop tools/widget reflector 點擊PickLiveWidget 獲得窗口層級
TSharedRef<SWindow> CookbookWindow = SNew(SWindow) //創(chuàng)建一個SWindow類型的Slate
.Title(FText::FromString(TEXT("Cookbook Window"))) //設(shè)置window的屬性
.ClientSize(FVector2D(800, 400))
.SupportsMaximize(false)
.SupportsMinimize(false)
[ //在【】中添加要拜訪到該slot的ui window只有能添加一個widget
SNew(SVerticalBox)
+ SVerticalBox::Slot() //通過重載運算符 + 獲得一個slot
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("Hello from Slate")))
]
];

    IMainFrameModule& mainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>(TEXT("MainFrame"));
    if (mainFrameModule.GetParentWindow().IsValid())
    {
        FSlateApplication::Get().AddWindowAsNativeChild(CookbookWindow, mainFrameModule.GetParentWindow().ToSharedRef());
    }
    else
    {
        FSlateApplication::Get().AddWindow(CookbookWindow);
    }

15 創(chuàng)建ue4可用的新的資源類型
創(chuàng)建繼承自UObject 自定義類
創(chuàng)建繼承自UFactory 的自定義類 重寫其中的FactoryCreateNew方法 在方法中創(chuàng)建我們自定義的類型
自定義的類型 可以通過在content中 右鍵 miscellaneous中查詢到
。cpp文件
// Fill out your copyright notice in the Description page of Project Settings.

include "CustomAssetFactory.h"

include "MyCustomAsset.h"

UCustomAssetFactory::UCustomAssetFactory():Super()
{
bCreateNew = true;
bEditAfterNew = true;
SupportedClass = UMyCustomAsset::StaticClass();
}

UObject* UCustomAssetFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn, FName CallingContext)
{
auto NewObjectAsset = NewObject<UMyCustomAsset>(InParent, InClass, InName, Flags);
return NewObjectAsset;
}

16 創(chuàng)建自定義資源的右鍵菜單
創(chuàng)建菜單類 繼承自FAssetTypeActions_Base
.h文件

pragma once

include "AssetTypeActions_Base.h"

class FMyCustomAssetActions :public FAssetTypeActions_Base
{
public:
virtual bool HasActions(const TArray<UObject>& InObjects)const override; //系統(tǒng)調(diào)用 確認(rèn)該類型是否有action
virtual void GetActions(const TArray<UObject
>& InObjects, FMenuBuilder& menuBuilder) override; //如果上面返回true 那么調(diào)用下面 添加菜單項
virtual FText GetName() const override; //資源在縮略圖模式下 鼠標(biāo)的tip提示
virtual UClass* GetSupportedClass() const override; //資源縮略圖的顏色
virtual FColor GetTypeColor() const override;
virtual uint32 GetCategories() override;

void MyCustomAssetContent_Clicked();

};
.cpp文件

include "UE4CookTestEditor.h"

include "MyCustomAssetActions.h"

include "MyCustomAsset.h"

bool FMyCustomAssetActions::HasActions(const TArray<UObject*>& InObjects) const
{
return true;
}

void FMyCustomAssetActions::GetActions(const TArray<UObject*>& InObjects, FMenuBuilder& menuBuilder)
{
menuBuilder.AddMenuEntry(FText::FromString("CustomAssetAction"),
FText::FromString("Action from Cook"),
FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.ViewOptions"),
FUIAction(FExecuteAction::CreateRaw(this, &FMyCustomAssetActions::MyCustomAssetContent_Clicked),
FCanExecuteAction())
);
}

uint32 FMyCustomAssetActions::GetCategories()
{
return EAssetTypeCategories::Misc;
}

FText FMyCustomAssetActions::GetName() const
{
return FText::FromString(TEXT("My Custom Asset"));
}

UClass* FMyCustomAssetActions::GetSupportedClass() const
{
return UMyCustomAsset::StaticClass();
}

FColor FMyCustomAssetActions::GetTypeColor() const
{
return FColor::Emerald;
}

void FMyCustomAssetActions::MyCustomAssetContent_Clicked()
{
TSharedRef<SWindow> CookbookWindow = SNew(SWindow)
.Title(FText::FromString(TEXT("Cookbook Window")))
.ClientSize(FVector2D(800, 400))
.SupportsMaximize(false)
.SupportsMaximize(false);
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>(TEXT("MainFrame"));
if (MainFrameModule.GetParentWindow().IsValid())
{
FSlateApplication::Get().AddWindowAsNativeChild(CookbookWindow, MainFrameModule.GetParentWindow().ToSharedRef());
}
else
{
FSlateApplication::Get().AddWindow(CookbookWindow);

}

}

在Editor Module startModule中

IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
auto Actions = MakeShareable(new FMyCustomAssetActions);
AssetTools.RegisterAssetTypeActions(Actions);
刪除的時候 在shutdownModule中
//刪除command
if (DisplayTestCommand)
{
IConsoleManager::Get().UnregisterConsoleObject(DisplayTestCommand);
DisplayTestCommand = nullptr;
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容