|
任何c++函數你要用在BP(blueprint),你一定要寫在class裡面。這個class一定要有UCLASS()宣告這個class一定要有GENERATED_BODY()巨集宣告你要在BP裡面呼叫的函數一定要在函數宣告前宣告UFUNCTION
而這個函數一定要在Public:之下
像是這樣 UFUNCTION(BlueprintCallable, Category = OpenCV|ImageProcess )
BlueprintCallable表示你可以控制他什麼時候執行
BlueprintPure你不能確定他在什麼時候執行,但他就是會執行,而且你不能用他來修改任何狀態承上,如果你的函數是不需要 class instance 的函數你還是要宣告在class裡,然後定義成static
純函數可以用 BlueprintCallable 也可以用 BlueprintPure在給BP呼叫的函數的參數部份,只要是class 只能用有UCLASS()宣告的class而且一定要用指標參數的部份不能用int, short, char, double 你只能用 int8, int16, int32, uint 16, float來取代他們所有的函數不能用一樣的名字,你可以使用
UFUNCTION(BlueprintCallable, meta = (DisplayName = SmoothingEach5 (ueLine array) ), Category = Line )
DisplayName 這個屬性來修正在ue4裡面顯示的名字
Category 可以用 | 來做子集UFUNCTION(BlueprintCallable, Category = OpenCV|CurveExtraction ) bool SetPicture(UueMat* umat);复制代码
陣列的部份你只能用TArray YourClass* 來傳入,也不能用 typedef 來定義別名
你不能用std::vectorUFUNCTION(BlueprintCallable, meta = (FriendlyName = SmoothingEach5 (ueLine array) ), Category = Line ) static TArray UueLine* SmoothingEach5_Array(const TArray UueLine* cvp, float centroidRadio = 1.0, int32 repeat = 1);复制代码
當你想做出一個大家都能存取的變數時,請在變數宣告前面加上
UPROPERTY(BlueprintReadWrite) or UPROPERTY(BlueprintReadOnly)
class應該要使用指標,使用NewObject Class () 來new。UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Mat ) UTexture2D* MyTexture2D;复制代码
當你想要輸出多個變數時,在參數宣告使用非const 的 reference 變數來輸出。UFUNCTION(BlueprintCallable, Category = Test ) static bool TestOut2(TArray UTexture2D* t1, TArray UTexture2D* t2);复制代码
UENUM(BlueprintType)enum class EMyEnum : uint8{ BranchA, BranchB};复制代码在ue4.8版中更新後
TEnumAsByte EMyEnum 不在需要,要改成 EMyEnum UFUNCTION(BlueprintCallable, Category = Stuff , Meta = (ExpandEnumAsExecs = Branches )) void DoSomeBranch(int32 SomeInput, EMyEnum Branches);复制代码void AMyActor::DoSomeBranch(int32 SomeInput, EMyEnum Branches){ if (SomeInput == 1) { Branches = EMyEnum::BranchA; } else { Branches = EMyEnum::BranchB; }}复制代码
BlueprintNativeEvent 新增內建的事件,但實作由C++來實作
一般用在Actor裡UFUNCTION(BlueprintNativeEvent, Category = Switch Functions ) void OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult SweepResult);复制代码值的注意的是,實作的函數名是 XXXX_Implementation 在執行時會自動呼叫void AMyActor::OnOverlapBegin_Implementation(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult SweepResult){ if (OtherActor (OtherActor != this) OtherComp) { ToggleLight(); }}复制代码
BlueprintImplementableEvent 在c++中只寫宣告,給blueprint實作的事件
一般用在Actor裡,你的Function 會多一個可以OverideUFUNCTION(BlueprintImplementableEvent, Category = Tracking) void IsActorInJunction(AActor* Actor, bool Result);复制代码
比如我在Tick 中呼叫了這個函數// Called every framevoid AMyActor::Tick( float DeltaTime ){ Super::Tick( DeltaTime ); bool res; IsActorInJunction(this, res);}复制代码看的出來就一般的C++函數呼叫,但是我在code中沒有寫他的實作
在UE4裡面我也只拉了一個print string hello當實作
變數開關的設定 UPROPERTY( Category=Location, EditAnywhere ) uint32 bUseOffset : 1; UPROPERTY(Category = Location, EditAnywhere, meta = (EditCondition = bUseOffset )) FVector Offset;复制代码
實作PostEditChangeProperty函數
virtual void PostEditChangeProperty(FPropertyChangedEvent PropertyChangedEvent) override;
這個函數將在每次變數在editor內被修改時呼叫
函數最後要加
Super:: PostEditChangeProperty(PropertyChangedEvent);
可以用下面的code來判斷是哪個成員被改動FName PropertyName = (PropertyChangedEvent.Property != nullptr) PropertyChangedEvent.Property- GetFName() : NAME_None; if((PropertyName == GET_MEMBER_NAME_CHECKED(AHeroCharacter, Skill_LevelCDs))) {}复制代码
TArray改動就實作PostEditChangeChainProperty函數
virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent PropertyChangedEvent) override;
可以用下面的code來判斷是哪個成員被改動const FName TailPropName = PropertyChangedEvent.PropertyChain.GetTail()- GetValue()- GetFName(); static FName Mobility_NAME(TEXT( CDs )); if (TailPropName == Mobility_NAME) {}复制代码也可以用下面方法得到改動的 indexint32 index = PropertyChangedEvent.GetArrayIndex(TEXT( Meshes ));复制代码
實作PostInitProperties函數
virtual void PostInitProperties() override;
這個函數將在每次變數在初始化時呼叫
函數最前面要加
Super:: PostInitProperties();
參考:
https://answers.unrealengine.com ... pdates-in-code.html //for regular properties: void ACustomClass::PostEditChangeProperty(struct FPropertyChangedEvent e) { FName PropertyName = (e.Property != NULL) e.Property- GetFName() : NAME_None; if (PropertyName == GET_MEMBER_NAME_CHECKED(UCustomClass, PropertyName)) { //various uproperty tricks, see link } Super::PostEditChangeProperty(e); } //for TArrays: void ACustomClass::PostEditChangeChainProperty(struct FPropertyChangedChainEvent e) { int32 index = e.GetArrayIndex(TEXT( Meshes )); //checks skipped UStaticMesh *mesh = Meshes[index]; //changed mesh Super::PostEditChangeChainProperty(e); }复制代码
有人反應說怎麼動態呼叫BP的函數
而且是沒在C++宣告的
查了一下終於查了到
就是使用 CallFunctionByNameWithArguments 這個函數
我只知道傳基本型態 int32 float FString 之類的方法
其它參數怎麼傳請看 Engine/Source/Runtime/CoreUObject/Private/UObject/ScriptCore.cpp
我是從這裡學來的 https://answers.unrealengine.com ... -c.htmlsort=oldest
主要就是 你的函數要格式化成 functionname parameter1 parameter2 ...
第一個是函數名 第二個是參數一表示成字串的方式 以此類推
這邊我有做了一個小測試 證明是可行的void XXXXX::TestCallFunctionByName(FString str){ FOutputDeviceNull ar; this- CallFunctionByNameWithArguments(*str, ar, NULL, true);}复制代码
要在begin play加,在建構式加會沒反應
Component- OnClicked.AddDynamic(this, AYourActor::OnMouseClicked);
傳入參數請參考標頭檔
然後在cpp實作建構式
這是將預設的subobject移除的建構式AFightCharacter::AFightCharacter(const FObjectInitializer ObjectInitializer) : Super(ObjectInitializer.DoNotCreateDefaultSubobject(ACharacter::MeshComponentName)){}复制代码這是將預設的建構式AHeroCharacter::AHeroCharacter(const FObjectInitializer ObjectInitializer) : Super(FObjectInitializer::Get()){}复制代码之後可以用
以Decal 為例,宣告在classUPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly) UDecalComponent* SelectionDecal;复制代码建構式可以設定像這樣AHeroCharacter::AHeroCharacter(const FObjectInitializer ObjectInitializer) : Super(FObjectInitializer::Get()){ PrimaryActorTick.bCanEverTick = true; SelectionDecal = ObjectInitializer.CreateDefaultSubobject UDecalComponent (this, TEXT( SelectionDecal0 )); SelectionDecal- SetWorldLocation(FVector(0, 0, -90)); // FRotator = rotation Y Z X SelectionDecal- SetWorldRotation(FQuat(FRotator(90, 0, 0))); SelectionDecal- SetWorldScale3D(FVector(10, 50, 50)); SelectionDecal- AttachParent = GetCapsuleComponent();}复制代码初始化後設定位置、旋轉、縮放,並Attach 不然會在世界座標 (0, 0, 0) 的位置如何在任何地方拿到HUD跟ControllerAMyHUD * hud = Cast AMyHUD (UGameplayStatics::GetPlayerController(this, 0)- GetHUD());复制代码GetWorld()- GetFirstPlayerController()复制代码
旋轉常要你填FQuat
可以用FRotator去初始化
三個變數等於editor裡 Y Z X方向的旋轉SelectionDecal- SetWorldRotation(FQuat(FRotator(90, 0, 0)));复制代码
網路連線
首先是函數成員
所有要同步的UPROPERTY要加 Replicated
像這樣UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Hero , Replicated) FVector ThrowDestination;复制代码並加入同步代碼void AYourActor::GetLifetimeReplicatedProps(TArray FLifetimeProperty OutLifetimeProps) const{ Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(AHeroCharacter, ThrowDestination);}复制代码範例二UPROPERTY(Transient, ReplicatedUsing = OnRep_PosChange) FVector CurrentPosition;复制代码Transient 是不能序列化的意思。
ReplicatedUsing 是同步請用這個函數UFUNCTION() void OnRep_PosChange();复制代码類似這樣voidAYourActor::OnRep_PosChange(){ SetActorLocation(CurrentPosition);}复制代码再來是函數
有分Server在Call的,這個函數會同步到所有ClientUFUNCTION(Server, Reliable, WithValidation) void ServerSetLocation(FVector location);复制代码只有Client在Call 的,這個函數在Server上不會執行UFUNCTION(Client, Reliable, WithValidation) void ClientSetLocation(FVector location);复制代码但你的函數就會分成兩個實作
一個加 _Validate 回傳 bool
一個加 _Implementation 不回傳bool AYourActor::ServerSetLocation_Validate(FVector location){ return true;}void AYourActor::ServerSetLocation_Implementation(FVector location){ CurrentPosition = location; SetActorLocation(location);}复制代码在這些 Actor裡面可以用if (Role == ROLE_Authority)复制代码或if (GEngine- GetNetMode(GetWorld()) == ENetMode::NM_Client)复制代码來判斷是不是在Server還是Client
最重要的要在Controller裡面將大家的Owener設成自己
這個動作在Server會做 Client不會做,這樣就可以同步了。for(TActorIterator AActor ActorItr(GetWorld()); ActorItr; ++ActorItr) { if(*ActorItr != this) { ActorItr- SetOwner(this); } }复制代码
剩下各種規則細節詳見官網
可編輯 唯讀
EditAnywhere, VisibleAnywhere在editor
BlueprintReadWrite, BlueprintReadOnly在blueprint連連看
BlueprintAssignable 看不太懂要使用的場合,好像也是要給Actor用的
就給有用過的人分享經驗吧
楼主讲解的不错,赞一个!
能补充讲解下事件函数(BlueprintImplementableEvent / BlueprintNativeEvent)和 事件调度器(BlueprintAssignable)的蓝图暴露方法就更好了。
|
|