本帖最后由 damody 于 2018-1-22 08:38 编辑  
 
大家好 教學之前先打一下廣告 
https://www.patreon.com/nobu_game 
小的我在做一套開源的信長重製 
如果這篇教學有幫助到你請幫忙訂閱個1元謝謝。 
有需要源代碼的可以去上面的網站有下載連結 
2018年1月4日的進度影片 
 
 
加入uproject產生sln方法。 
 
uproject要怎麼產生指定 visual studio版本的專案檔呢? 
這問題來自我灌了vs2017後,他預設產生的專案版本就會到2017 
可是我要2015時怎麼辨? 
你需要這樣下指令 重點在後面的 -2015,要2013就是 -2013 
[mw_shl_code=bash,true]UnrealBuildTool.exe -projectfiles -project="uproject路徑" -game -engine -progress -2015[/mw_shl_code] 
實際範例會像這樣 
[mw_shl_code=bash,true]C:\Program Files\Epic Games\UE_4.18\Engine\Binaries\DotNET\UnrealBuildTool.exe  -projectfiles -project="C:/Unreal Projects/AON/AON.uproject" -game -engine -progress -2015[/mw_shl_code] 
 
1. 任何c++函數你要用在BP(blueprint),你一定要寫在class裡面,不能寫成獨立的函數。 
2. 這個class一定要有UCLASS()宣告 
3. 這個class一定要有 GENERATED_BODY() 巨集宣告 
   或是 GENERATED_UCLASS_BODY() 
   這兩個宣告決定於你的初始化函數方式 
   如果你有 U????Component 的初始化需求就會用 GENERATED_UCLASS_BODY() 
   沒有的話就預設的 GENERATED_BODY() 就可以了 
[mw_shl_code=cpp,true]// in .h file 
UCLASS() 
class MOBA_API AHeroCharacter : public ACharacter 
{ 
        GENERATED_UCLASS_BODY() 
public: 
        // Called when the game starts or when spawned 
        virtual void BeginPlay() override; 
        // Called every frame 
        virtual void Tick(float DeltaTime) override; 
     // 選人的地版光環 
        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Interaction") 
        UDecalComponent * SelectionDecal; 
}; 
 
// in .cpp file 
AHeroCharacter::AHeroCharacter(const FObjectInitializer& ObjectInitializer) 
        : Super(FObjectInitializer::Get()) 
{ 
    ObjectInitializer.CreateDefaultSubobject<UDecalComponent>(this, TEXT("SelectionDecal0")); 
  
    CreateDefaultSubobject<UParticleSystemComponent>(TEXT("BulletParticle0")); 
}[/mw_shl_code] 
 
[mw_shl_code=cpp,true]// in .h file 
UCLASS() 
class MOBA_API ABasicCharacter : public ACharacter 
{ 
        GENERATED_BODY() 
 
public: 
        // Sets default values for this character's properties 
        ABasicCharacter(); 
        // Called when the game starts or when spawned 
        virtual void BeginPlay() override; 
        // Called every frame 
        virtual void Tick(float DeltaTime) override; 
}; 
 
// in .cpp file 
ABasicCharacter::ABasicCharacter() 
{ 
         // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it. 
        PrimaryActorTick.bCanEverTick = true; 
}[/mw_shl_code] 
 
4. 你要在BP裡面呼叫的函數一定要在函數宣告前宣告UFUNCTION 
 
而這個函數一定要在c++ class public: 之下 
像是這樣 UFUNCTION(BlueprintCallable, Category = "OpenCV|ImageProcess") 
BlueprintCallable與BlueprintPure 都會把這個c++函數標記給藍圖呼叫 
BlueprintCallable 表示你可以從藍圖控制他什麼時候執行 
BlueprintPure 你不能確定他在什麼時候執行,但他就是會執行,而且你不能用他來修改任何狀態 
 
5. 承上,如果你的函數是不需要 class instance 的函數你還是要宣告在class裡,然後定義成static 
純函數可以用 BlueprintCallable 也可以用 BlueprintPure 
 
6. 在給BP呼叫的函數的參數部份,只要是class 只能用有UCLASS()宣告的class而且一定要用指標不能直接傳整個物件 
參數的部份不能用int, short, char, double 你只能用 int32, float來取代他們 
目前可以用的內建型態為 
[mw_shl_code=cpp,true]uint32:1 // bitfields same as bool 
bool 
int32 
float 
FString 
FVector 
FRotator[/mw_shl_code] 
 
在C++14已經標準化的情況下 
建議在class inline初始化 
像下面這樣  
[mw_shl_code=cpp,true]UCLASS() 
class MOBA_API AHeroCharacter : public ACharacter 
{ 
        GENERATED_UCLASS_BODY() 
public: 
    // ... 
    // 基礎魔法受傷倍率 
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MOBA") 
        float BaseMagicInjuredRatio = 1; 
        // 基礎物理受傷倍率 
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MOBA") 
        float BasePhysicsInjuredRatio = 1; 
        // 基礎裝甲 
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MOBA") 
        float BaseArmor = 2; 
        // 基礎攻擊力 
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MOBA") 
        float BaseAttack = 80; 
        // 基礎移動速度 
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MOBA") 
        float BaseMoveSpeed = 300; 
}[/mw_shl_code]  
7. 陣列的部份你只能用TArray<YourClass*> 來傳入,也不能用 typedef 來定義別名 
你不能用std::vector 
 
[mw_shl_code=cpp,true]// TArray 可以使用所有基本型態 繼承UObject的物件一定要用物件指標 
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "MOBA") 
TArray<float> LevelProperty_Attack; 
// TMap 可以包上面的基本型態 但不能包TArray 繼承UObject的物件一定要用物件指標 
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Current", Replicated) 
TMap<EHeroBuffState, bool> BuffStateMap;[/mw_shl_code] 
 
  
 
8. 所有的函數不能用一樣的名字,如果是C++重載同名函數時,你可以使用 meta DisplayName 來更改名字 
 
[mw_shl_code=cpp,true] 
UFUNCTION(BlueprintCallable, meta = (DisplayName = "SmoothingEach5 (Vector2D array)"), Category = "Line") 
static TArray<FVector2D>   SmoothingEach5(const TArray<FVector2D>& data, float centroidRadio = 1.0f, int32 repeat = 1); 
 
UFUNCTION(BlueprintCallable, meta = (DisplayName = "SmoothingEach5 (LineV2)"), Category = "Line") 
static ULineV2 * SmoothingEach5(const ULineV2* ul, float centroidRadio = 1.0f, int32 repeat = 1); 
[/mw_shl_code] 
 
DisplayName 這個屬性來修正在ue4裡面顯示的名字 
Category 可以用 | 來做子集 
[mw_shl_code=cpp,true]UFUNCTION(NetMulticast, WithValidation, Reliable, BlueprintCallable, Category = "MOBA|Server") 
void ServerPlayAttackStartSFX();[/mw_shl_code] 
  
 
9. 當你想要輸出多個變數時,在參數宣告使用非const 的 reference 變數來輸出。 
```clike= 
UFUNCTION(BlueprintCallable, Category = "Test") 
static bool TestOut2(TArray<UTexture2D*>& t1, TArray<UTexture2D*>& t2); 
``` 
 
10. 當你想要輸出多個執行分支時,參考以下的方法 
[mw_shl_code=cpp,true]// .h 
UFUNCTION(BlueprintCallable, Category = "Stuff", Meta = (ExpandEnumAsExecs = "Branches")) 
void DoSomeBranch(int32 SomeInput, EMyEnum& Branches); 
 
// .cpp 
void ASkillSplineActor: oSomeBranch(int32 SomeInput, EMyEnum& Branches) 
{ 
        if (SomeInput == 1) 
        { 
                Branches = EMyEnum::BranchA; 
        } 
        else 
        { 
                Branches = EMyEnum::BranchB; 
        } 
}[/mw_shl_code] 
  
 
11. BlueprintNativeEvent 新增內建的事件,但實作由C++來實作 一般用在Actor裡 
 
[mw_shl_code=cpp,true]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) 
    { 
 
    } 
}[/mw_shl_code] 
 
12. BlueprintImplementableEvent 在c++中只寫宣告,給blueprint實作的事件 
一般用在Actor裡,你的Function 會多一個可以Overide 
[mw_shl_code=cpp,true]UFUNCTION(BlueprintImplementableEvent, Category = "MOBA") 
void OnHit(AHeroCharacter* caster, AHeroCharacter* target);[/mw_shl_code] 
  
 
  
 
13. 變數開關的設定 
使用 meta = (EditCondition = "bYourVariable") 可以控制 
我這邊用 SkillType 去改變 UseDirectionSkill 來開關 IsFixdLength, SkillLength, MinimalLength 這三個設定 
[mw_shl_code=cpp,true]UPROPERTY(Category = "SkillHint", EditAnywhere, BlueprintReadOnly) 
ESkillHintEnum SkillType; 
 
UPROPERTY(Category = "SkillHint", EditAnywhere, BlueprintReadOnly) 
FVector SkillPos; 
 
UPROPERTY(Category = "SkillHint", VisibleAnywhere, BlueprintReadOnly) 
uint32 UseDirectionSkill: 1; 
 
UPROPERTY(Category = "SkillHint", VisibleAnywhere, BlueprintReadOnly) 
uint32 UseRangeSkill: 1; 
 
// 是否固定長度 
UPROPERTY(Category = "FlySkill", EditAnywhere, BlueprintReadOnly, meta = (EditCondition = "UseDirectionSkill")) 
uint32 IsFixdLength: 1; 
 
// 技能最遠距離 
UPROPERTY(Category = "FlySkill", EditAnywhere, BlueprintReadOnly, meta = (EditCondition = "UseDirectionSkill")) 
float SkillLength; 
 
// 技能最短距離 
UPROPERTY(Category = "FlySkill", EditAnywhere, BlueprintReadOnly, meta = (EditCondition = "UseDirectionSkill")) 
float MinimalLength; 
 
// 法術直徑 
UPROPERTY(Category = "FlySkill", EditAnywhere, BlueprintReadOnly, meta = (EditCondition = "UseRangeSkill")) 
float SkillDiameter; 
 
// 施法距離 
UPROPERTY(Category = "FlySkill", EditAnywhere, BlueprintReadOnly, meta = (EditCondition = "UseRangeSkill")) 
float SkillCastRadius; 
 
// 技能最小施法距離 
UPROPERTY(Category = "FlySkill", EditAnywhere, BlueprintReadOnly, meta = (EditCondition = "UseRangeSkill")) 
float MinimalCastRadius;[/mw_shl_code] 
  
 
  
 
14. 各種UPROPERTY meta 介紹 
    在變數加上 meta = (MakeEditWidget = true)  
    如果這個變數適合在3d場景中編輯,那他就會可以編輯 
    不是每種型態都可以 
[mw_shl_code=cpp,true]UPROPERTY(Category = "MOBA", EditAnywhere, BlueprintReadWrite, meta = (MakeEditWidget = true)) 
FVector Direction;[/mw_shl_code] 
  
 
ExposeOnSpawn 在Spawn Actor時可以強制得到輸入 
[mw_shl_code=cpp,true]UPROPERTY(BlueprintReadWrite, Category = "Variable", Meta = (ExposeOnSpawn = true)) 
FVector Location1; 
 
UPROPERTY(BlueprintReadWrite, Category = "Variable", Meta = (ExposeOnSpawn = true)) 
FVector Location2;[/mw_shl_code] 
 
一般的 actor 
  
特製的 
  
 
各種Edit Visible 選項 
[mw_shl_code=cpp,true]// Edit 
UPROPERTY(EditAnywhere, Category = "Edit") 
int32 EditAnywhere; 
UPROPERTY(EditDefaultsOnly, Category = "Edit") 
int32 EditDefaultsOnly; 
UPROPERTY(EditInstanceOnly, Category = "Edit") 
int32 EditInstanceOnly; 
UPROPERTY(EditAnywhere, AdvancedDisplay, Category = "Edit") 
int32 AdvancedDisplay1; 
 
// Visible 
UPROPERTY(VisibleAnywhere, Category = "Visible") 
int32 VisibleAnywhere; 
UPROPERTY(VisibleDefaultsOnly, Category = "Visible") 
int32 VisibleDefaultsOnly; 
UPROPERTY(VisibleInstanceOnly, Category = "Visible") 
int32 VisibleInstanceOnly; 
UPROPERTY(VisibleAnywhere, AdvancedDisplay, Category = "Visible") 
int32 AdvancedDisplay2; 
 
UPROPERTY(EditAnywhere, Category = "Variable", Meta = (MultiLine = true)) 
FString StringData; 
UPROPERTY(EditAnywhere, Category = "Variable", Meta = (UIMin = 5, UIMax = 100)) 
int32 minmax; 
 
UPROPERTY(EditAnywhere, EditFixedSize, Category = "EditFixedSize") 
TArray<FName> EditFixedSize; 
UPROPERTY(EditAnywhere, Category = "EditFixedSize") 
TArray<FName> NoEditFixedSize;[/mw_shl_code] 
 
這邊是在Actor Editor裡 
  
這邊是在Level Editor裡 
  
EditFixedSize則可以限制TArray不能增減,但可以修改裡面元素的內容 
 
15. 當你想要在editor改變後變數自動更新可以這樣做 
    實作PostEditChangeProperty函數 
    virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; 
    這個函數將在每次變數在editor內被修改時呼叫 
    函數最後要加 
    Super:: PostEditChangeProperty(PropertyChangedEvent); 
     
    TArray改動就實作PostEditChangeChainProperty函數 
    virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) override; 
    可以用下面的code來判斷是哪個成員被改動 
     
    由於只能在editor裡使用所以要用#if WITH_EDITOR包起來 
    不然打包會失敗 
[mw_shl_code=cpp,true]// .h 
#if WITH_EDITOR 
        virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; 
 
        virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) override; 
#endif // WITH_EDITOR 
 
// .cpp 
// .h 
#if WITH_EDITOR 
    virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; 
 
    virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) override; 
#endif // WITH_EDITOR 
 
// .cpp 
#if WITH_EDITOR 
 
void AHeroCharacter: ostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) 
{ 
    //Get the name of the property that was changed 
    FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None; 
     
    if((PropertyName == GET_MEMBER_NAME_CHECKED(AHeroCharacter, Skill_LevelCDs))) 
    { 
        Skill_BaseCD.SetNum(Skill_LevelCDs.Num()); 
    } 
     
    Super: ostEditChangeProperty(PropertyChangedEvent); 
} 
 
void AHeroCharacter: ostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) 
{ 
    const FName TailPropName = PropertyChangedEvent.PropertyChain.GetTail()->GetValue()->GetFName(); 
     
    static FName Mobility_NAME(TEXT("CDs")); 
    if(TailPropName == Mobility_NAME) 
    { 
        for(int32 i = 0; i < Skill_LevelCDs.Num(); ++i) 
        { 
            if(Skill_LevelCDs.CDs.Num() > 0) 
            { 
                Skill_BaseCD = Skill_LevelCDs[0]; 
                Skill_MaxCD = Skill_BaseCD; 
            } 
        } 
    } 
    Super: ostEditChangeChainProperty(PropertyChangedEvent); 
} 
#endif // WITH_EDITOR 
     
// 例子2 
#if WITH_EDITOR 
 void ACustomClass: ostEditChangeProperty(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: ostEditChangeProperty(e); 
} 
 
//for TArrays: 
void ACustomClass: ostEditChangeChainProperty(struct FPropertyChangedChainEvent& e) 
{ 
    // 也可以用下面方法得到改動的TArray index 
    int32 index = e.GetArrayIndex(TEXT("Meshes")); //checks skipped 
    UStaticMesh *mesh = Meshes[index]; //changed mesh 
    Super: ostEditChangeChainProperty(e); 
} 
#endif // WITH_EDITOR 
[/mw_shl_code] 
 
也可以實作 PostInitProperties 函數 
virtual void PostInitProperties() override; 
這個函數將在每次變數在初始化時呼叫 
函數最前面要加 
Super:: PostInitProperties(); 
[mw_shl_code=cpp,true]// .h 
#if WITH_EDITOR 
    virtual void PostInitProperties() override; 
#endif 
// .cpp 
#if WITH_EDITOR 
void ASkillHintActor: ostInitProperties() 
{ 
    Super: ostInitProperties(); 
    UpdateLength(); 
} 
#endif // WITH_EDITOR[/mw_shl_code] 
可以參考 
https://answers.unrealengine.com ... pdates-in-code.html 
 
16. 怎麼在C++呼叫沒在C++宣告的BP的函數 
 
使用 CallFunctionByNameWithArguments 這個函數 
我只知道傳基本型態 int32 float FString 之類的方法 
其它參數怎麼傳請看 Engine/Source/Runtime/CoreUObject/Private/UObject/ScriptCore.cpp 
參考 https://answers.unrealengine.com ... -c.html?sort=oldest  
主要就是 你的函數要格式化成 functionname parameter1 parameter2 ... 
第一個是函數名 第二個是參數一表示成字串的方式 以此類推 
當你有一個函數叫做 Hello 接受一個 int32 的參數 
你可以這樣呼叫 "Hello 42" 
比較重要的是你必需對正確的Actor使用 CallFunctionByNameWithArguments 
[mw_shl_code=cpp,true]void XXXXX::TestCallFunctionByName(FString str) 
{ 
    FOutputDeviceNull ar; 
    this->CallFunctionByNameWithArguments(*str, ar, NULL, true); 
}[/mw_shl_code] 
 
17. Component的事件觸發 
所有事件的綁定都要在BeginPlay()加,在建構式加會沒反應 
Generate Overlap Events 要打勾才會有 Overlap 事件 
  
 
[mw_shl_code=cpp,true]// 建構式中 
// ECR_Block 碰撞 觸發碰撞事件 
// ECR_Overlap 重疊但不碰撞 觸發重疊事件 
// ECR_Ignore 不碰撞且不觸發任何事件 
CapsuleComponent->SetCollisionResponseToChannel(ECC_Visibility, ECR_Ignore); 
CapsuleComponent->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore); 
CapsuleComponent->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Ignore); 
CapsuleComponent->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Ignore); 
CapsuleComponent->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap); 
CapsuleComponent->SetCollisionResponseToChannel(ECC_PhysicsBody, ECR_Ignore); 
CapsuleComponent->SetCollisionResponseToChannel(ECC_Vehicle, ECR_Ignore); 
CapsuleComponent->SetCollisionResponseToChannel(ECC_Destructible, ECR_Ignore); 
 
// in BeginPlay() 
Component->OnClicked.AddDynamic(this, &AYourActor::OnMouseClicked); 
CapsuleComponent->OnComponentBeginOverlap.AddDynamic(this, &AYourActor::OnBeginOverlap); 
 
// in AYourActor.h 
UFUNCTION() 
void OnMouseClicked(UPrimitiveComponent* ClickedComp, FKey ButtonPressed); 
 
UFUNCTION() 
void OnBeginOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,  
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); 
```[/mw_shl_code] 
函數宣告請參考標頭檔 
[mw_shl_code=cpp,true]/** 
 * Delegate for notification of blocking collision against a specific component.   
 * NormalImpulse will be filled in for physics-simulating bodies, but will be zero for swept-component blocking collisions.  
 */ 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FiveParams( FComponentHitSignature, UPrimitiveComponent*, HitComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, FVector, NormalImpulse, const FHitResult&, Hit ); 
/** Delegate for notification of start of overlap with a specific component */ 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams( FComponentBeginOverlapSignature, UPrimitiveComponent*, OverlappedComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, int32, OtherBodyIndex, bool, bFromSweep, const FHitResult &, SweepResult); 
/** Delegate for notification of end of overlap with a specific component */ 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams( FComponentEndOverlapSignature, UPrimitiveComponent*, OverlappedComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, int32, OtherBodyIndex); 
/** Delegate for notification when a wake event is fired by physics*/ 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FComponentWakeSignature, UPrimitiveComponent*, WakingComponent, FName, BoneName); 
/** Delegate for notification when a sleep event is fired by physics*/ 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FComponentSleepSignature, UPrimitiveComponent*, SleepingComponent, FName, BoneName); 
/** Delegate for notification when collision settings change. */ 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FComponentCollisionSettingsChangedSignature, UPrimitiveComponent*, ChangedComponent); 
 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FComponentBeginCursorOverSignature, UPrimitiveComponent*, TouchedComponent ); 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam( FComponentEndCursorOverSignature, UPrimitiveComponent*, TouchedComponent ); 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( FComponentOnClickedSignature, UPrimitiveComponent*, TouchedComponent , FKey, ButtonPressed); 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( FComponentOnReleasedSignature, UPrimitiveComponent*, TouchedComponent, FKey, ButtonReleased); 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( FComponentOnInputTouchBeginSignature, ETouchIndex::Type, FingerIndex, UPrimitiveComponent*, TouchedComponent ); 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( FComponentOnInputTouchEndSignature, ETouchIndex::Type, FingerIndex, UPrimitiveComponent*, TouchedComponent ); 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( FComponentBeginTouchOverSignature, ETouchIndex::Type, FingerIndex, UPrimitiveComponent*, TouchedComponent ); 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams( FComponentEndTouchOverSignature, ETouchIndex::Type, FingerIndex, UPrimitiveComponent*, TouchedComponent );[/mw_shl_code] 
 
18. 如何在任何地方拿到HUD跟Controller 
[mw_shl_code=cpp,true]AMyHUD * hud = Cast<AMyHUD>(UGameplayStatics::GetPlayerController(this, 0)->GetHUD()); 
 
GetWorld()->GetFirstPlayerController()[/mw_shl_code] 
 
19. 旋轉常要你填 FRotator 
    可以用 FQuat 去初始化 
    三個變數等於editor裡 Y Z X方向的旋轉 
    FVector可以用Rotation()得到方向 
    GetActorRotation() 可以得到Actor的旋轉 
[mw_shl_code=cpp,true]SelectionDecal->SetWorldRotation(FQuat(FRotator(90, 0, 0))); 
 
FVector dir = MousePos - PlayerPos; 
dir.Z = 0; 
SetActorRotation(dir.Rotation());[/mw_shl_code] 
 
20. 網路連線同步 
如果一個Actor要能被同步 
那他Replicates要打勾 
  
寫在c++裡就是 bReplicates 在建構式為 true 
[mw_shl_code=cpp,true]AHeroSkill::AHeroSkill() 
{ 
            bReplicates = true; 
}[/mw_shl_code] 
下面講的功能 
cpp檔要先include 
[mw_shl_code=cpp,true]#include "UnrealNetwork.h"[/mw_shl_code] 
 
要同步的UPROPERTY要加 Replicated 
[mw_shl_code=applescript,true]// .h 
// .h 
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hero", Replicated) 
FVector ThrowDestination; 
 
// .cpp 
void AYourActor::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const 
{ 
     Super::GetLifetimeReplicatedProps(OutLifetimeProps); 
     DOREPLIFETIME(AHeroCharacter, ThrowDestination); 
} 
[/mw_shl_code] 
 Transient 是不能序列化的意思。 
 ReplicatedUsing 是同步請用這個函數 
[mw_shl_code=cpp,true]// .h 
UPROPERTY(Transient, ReplicatedUsing = OnRep_PosChange) 
FVector CurrentPosition; 
 
UFUNCTION() 
void OnRep_PosChange(); 
 
// .cpp 
 
void  AYourActor::OnRep_PosChange() 
{ 
        SetActorLocation(CurrentPosition); 
}[/mw_shl_code] 
 
請先參考下面文檔 
https://docs.unrealengine.com/la ... orking/Actors/RPCs/ 
https://docs.unrealengine.com/la ... ors/RPCs/index.html 
 
> 基本上我們可以得知 
> 想要在Client呼叫一個函數同步到所有的機器上 
> 這個函數的的Actor的owner必需是local controller 
 
最簡單的方法就是直接寫在local controller了 
因為多人遊戲中的actor除非你的所有權不轉移 不然就不能分享控制單位 
如果有這層考慮的話底層邏輯會變的很複雜 
而所有的同步函數一定要加 WithValidation  
以官方的條件同步範例來看 
 
SomeRPCFunction_Validate 會在Server端被呼叫 
如果回傳 true 就會被RPC到所有機器 
如果你是在 SomeRPCFunction_Implementation 做判斷的話 
那就會是RPC先呼叫,到了目標機器上再做處理 
會浪費網路資源 
 
一般的RPC是不保證一定會執行的 
加上 Reliable 保證一定要執行 
有些有時效性的函數就是時間過了再執行也來不及的函數 
就建議不要加了 
 
[mw_shl_code=cpp,true] 
// .h 
UFUNCTION( Server, Reliable, WithValidation ) 
void SomeRPCFunction( int32 AddHealth ); 
// .cpp 
bool SomeRPCFunction_Validate( int32 AddHealth ) 
{ 
    if ( AddHealth > MAX_ADD_HEALTH ) 
    { 
        return false;                       // This will disconnect the caller 
    } 
    return true;                              // This will allow the RPC to be called 
} 
 
void SomeRPCFunction_Implementation( int32 AddHealth ) 
{ 
    Health += AddHealth; 
} 
 
``` 
在Actor裡可以用 
```clike 
if (Role == ROLE_Authority) 
{ 
    // 在Server端 
} 
 
if (GEngine->GetNetMode(GetWorld()) == ENetMode::NM_ListenServer 
    ||GEngine->GetNetMode(GetWorld()) == ENetMode::NM_DedicatedServer)) 
{ 
    // 在Server端 
} 
[/mw_shl_code] 
 
21. 當你需要動態產生 Actor 但想要從藍圖指定Class時 
請用 TSubclassOf<AYourClass> 
像下面這樣就可以在編輯器裡面選擇你要的類或衍生類 
 
[mw_shl_code=cpp,true]// 技能提示 
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "MOBA") 
TSubclassOf<ASkillHintActor> HintActor; 
     
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MOBA") 
TArray<TSubclassOf<AHeroSkill>>        Skill_Classes; 
 
// 在需要用的時候 
ASkillHintActor* CurrentSkillHint = GetWorld()->SpawnActor<ASkillHintActor>(HintActor);[/mw_shl_code] 
TSubclassOf<ASkillHintActor> HintActor; 
  
TArray<TSubclassOf<AHeroSkill>>        Skill_Classes; 
  
 
22.  一些內建基本功能介紹 
> 各種字串轉換 
https://wiki.unrealengine.com/St ... s:_FString_to_FName,_FString_to_Int32,_Float_to_FString 
> TArray 
https://docs.unrealengine.com/la ... chitecture/TArrays/ 
https://docs.unrealengine.com/la ... /TArrays/index.html 
> TMap 
https://docs.unrealengine.com/la ... ure/TMap/index.html 
https://docs.unrealengine.com/la ... ure/TMap/index.html 
> Timers 
https://docs.unrealengine.com/la ... rchitecture/Timers/ 
https://docs.unrealengine.com/la ... e/Timers/index.html 
 
23. debug 印字串 
[mw_shl_code=cpp,true]#include "Engine.h" 
     
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Cyan, 
                            FString::Printf(TEXT("Server OnRMousePressed1 %f %f"), pos.X, pos.Y));[/mw_shl_code] 
 
24.  給UE4 C++初學者的話 
下面這三個官方基礎教學請一定要看過 可以更快上手 
我只是把官方的功能大概整理一下而已。 
https://docs.unrealengine.com/la ... ickStart/index.html 
https://docs.unrealengine.com/la ... utorials/index.html 
https://docs.unrealengine.com/la ... itecture/index.html 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 |