本帖最后由 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
|