一、上周工作问题的解决
a) 观看模式已经成功合并到主项目当中,统一了一些公用变量。
b) 给用户一个准备的时间,准备动作做好之后说出开始指令后再开始学习。
c) 创建一个UserCharacter作为观看视角,设置类默认值locked to HMD为false以取消VR头盔对视角的控制。
二、回放系统测试
FirstPerson模板上的回放系统测试
首先新建一个FirstPerson的blueprint项目,我这里命名为ReplayTest.创建完成后打开ReplayTest/Config/DefaultEngine.ini,在文件最后添加如下语句然后保存。这个语句的作用就是允许使用DemoNetDriver这个录像功能。
[/Script/Engine.GameEngine]
+NetDriverDefinitions=(DefName="DemoNetDriver",DriverClassName="/Script/Engine.DemoNetDriver",DriverClassNameFallback="/Script/Engine.DemoNetDriver")
然后我们需要将所有Map里所有能移动的actor的Static Mesh Replicate Movement属性设置为true:
完成之后打开blueprint文件“FirstPersonProjectile”,将其类默认值值中的“Replicates”与“Replicate Movement”属性都设为true:
完成后打开blueprint文件“FirstPersonCharacter”,同样将“Replicates”与“Replicate Movement”属性设为true。然后找到“InputAction Fire”这个自定义事件,在该事件旁边创建一个自定义事件命名为“Server_Fire”,然后将该事件的属性设置为如图所示:
然后再在蓝图中做一些改动:
接下来我们需要把UE4中的录制与回放方法提供给蓝图以便我们在蓝图中调用。首先创建一个新的C++类,选择父类为GameInstance:
我这里命名为MyGameInstance,创建后会自动打开Visual Studio,先在项目中找到名为“ReplayTest.Build.cs”的C#文件,(注意第一个.前面的字符串为项目名称),打开该文件并添加语句:
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Json" });
添加后的文件内容如下:
然后我们再打开之前创建的MyGameInstance.h文件,首先添加include语句:
#include "NetworkReplayStreaming.h"
注意有些include语句必须放在所有include的最前面或者最后面,如果之后编译出错可以根据错误提示调整其位置。然后我们来添加所需的函数:
public:
/** Start recording a replay from blueprint. ReplayName = Name of file on disk, FriendlyName = Name of replay in UI */
UFUNCTION(BlueprintCallable, Category = "Replays")
void StartRecordingReplayFromBP(FString ReplayName, FString FriendlyName);
/** Start recording a running replay and save it, from blueprint. */
UFUNCTION(BlueprintCallable, Category = "Replays")
void StopRecordingReplayFromBP();
/** Start playback for a previously recorded Replay, from blueprint */
UFUNCTION(BlueprintCallable, Category = "Replays")
void PlayReplayFromBP(FString ReplayName);
/** Start looking for/finding replays on the hard drive */
UFUNCTION(BlueprintCallable, Category = "Replays")
void FindReplays();
/** Apply a new custom name to the replay (for UI only) */
UFUNCTION(BlueprintCallable, Category = "Replays")
void RenameReplay(const FString &ReplayName, const FString &NewFriendlyReplayName);
/** Delete a previously recorded replay */
UFUNCTION(BlueprintCallable, Category = "Replays")
void DeleteReplay(const FString &ReplayName);
virtual void Init() override;
private:
// for FindReplays()
TSharedPtr<INetworkReplayStreamer> EnumerateStreamsPtr;
FOnEnumerateStreamsComplete OnEnumerateStreamsCompleteDelegate;
void OnEnumerateStreamsComplete(const TArray<FNetworkReplayStreamInfo>& StreamInfos);
// for DeleteReplays(..)
FOnDeleteFinishedStreamComplete OnDeleteFinishedStreamCompleteDelegate;
void OnDeleteFinishedStreamComplete(const bool bDeleteSucceeded);
protected:
UFUNCTION(BlueprintImplementableEvent, Category = "Replays")
void BP_OnFindReplaysComplete(const TArray<FS_ReplayInfo> &AllReplays);
最后再在文件开始处添加语句:
USTRUCT(BlueprintType)
struct FS_ReplayInfo
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadOnly)
FString ReplayName;
UPROPERTY(BlueprintReadOnly)
FString FriendlyName;
UPROPERTY(BlueprintReadOnly)
FDateTime Timestamp;
UPROPERTY(BlueprintReadOnly)
int32 LengthInMS;
UPROPERTY(BlueprintReadOnly)
bool bIsValid;
FS_ReplayInfo(FString NewName, FString NewFriendlyName, FDateTime NewTimestamp, int32 NewLengthInMS)
{
ReplayName = NewName;
FriendlyName = NewFriendlyName;
Timestamp = NewTimestamp;
LengthInMS = NewLengthInMS;
bIsValid = true;
}
FS_ReplayInfo()
{
ReplayName = "Replay";
FriendlyName = "Replay";
Timestamp = FDateTime::MinValue();
LengthInMS = 0;
bIsValid = false;
}
};
那么MyGameInstance.h文件就已经全部写好了,再贴一下完整代码:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "NetworkReplayStreaming.h"
#include "MyGameInstance.generated.h"
USTRUCT(Bluep