|
Plugins/ShooterTests内容/Maps/L_ShooterTest_AutoRun.umap以及L_ShooterTest_FireWeapon.umap-关卡蓝图空的
关卡功能
- 单人角色B_Hero_ShooterMannequin0在PlayerStart1生成,可进行武器射击。
- UI部分,15分得分显示,12分支倒计时,血量显示,炸弹,武器123,子弹-当前/总。
- 武器准星显示
- 世界场景设置里Default Gameplay Experience=B_BasicShooterTest(父类是LyraExperienceDefinition-PrimaryDataAsset),这个正常项目是没有的
编辑-项目设置-地图和模式
- 默认模式=B_LyraGameMode-父类是c++的LyraGame.LyraGameMode
- 默认pawn类=LyraCharacter
- HUD类=LyraHUD
- 玩家控制器类=LyraPlayerController
- 游戏状态类=LyraGameState
- 玩家状态类=LyraPlayerState
- 旁观者类=SpectatorPawn
按键输入wasd
同初始关卡
代码逻辑
先加载资源B_BasicShooterTest,加载完成后
角色生成:gamemode设置pawn=LyraCharacter,但是生成了B_Hero_ShooterMannequin0,查引用-HeroData_ShooterGame.Pawn Class-B_BasicShooterTest.Default Pawn Data
void ALyraGameMode::InitGameState()
ExperienceComponent->CallOrRegister_OnExperienceLoaded(FOnLyraExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded));
void ALyraGameMode::OnExperienceLoaded(const ULyraExperienceDefinition* CurrentExperience)
RestartPlayer(PC);
void AGameModeBase::RestartPlayer(AController* NewPlayer)
RestartPlayerAtPlayerStart(NewPlayer, StartSpot);
void AGameModeBase::RestartPlayerAtPlayerStart(AController* NewPlayer, AActor* StartSpot)
APawn* NewPawn = SpawnDefaultPawnFor(NewPlayer, StartSpot);
UFUNCTION(BlueprintNativeEvent, Category=Game)
APawn* SpawnDefaultPawnFor(AController* NewPlayer, AActor* StartSpot);
APawn* AGameModeBase::SpawnDefaultPawnFor_Implementation(AController* NewPlayer, AActor* StartSpot)
return SpawnDefaultPawnAtTransform(NewPlayer, Transform);
UFUNCTION(BlueprintNativeEvent, Category=Game)
APawn* SpawnDefaultPawnAtTransform(AController* NewPlayer, const FTransform& SpawnTransform);
//角色pawn生成
APawn* ALyraGameMode::SpawnDefaultPawnAtTransform_Implementation(AController* NewPlayer, const FTransform& SpawnTransform)
{
FActorSpawnParameters SpawnInfo;
SpawnInfo.Instigator = GetInstigator();
SpawnInfo.ObjectFlags |= RF_Transient; // Never save the default player pawns into a map.
SpawnInfo.bDeferConstruction = true;
if (UClass* PawnClass = GetDefaultPawnClassForController(NewPlayer))
{
if (APawn* SpawnedPawn = GetWorld()->SpawnActor<APawn>(PawnClass, SpawnTransform, SpawnInfo))
{
if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(SpawnedPawn))
{
if (const ULyraPawnData* PawnData = GetPawnDataForController(NewPlayer))
{
PawnExtComp->SetPawnData(PawnData);
}
else
{
UE_LOG(LogLyra, Error, TEXT(&#34;Game mode was unable to set PawnData on the spawned pawn [%s].&#34;), *GetNameSafe(SpawnedPawn));
}
}
SpawnedPawn->FinishSpawning(SpawnTransform);
return SpawnedPawn;
}
else
{
UE_LOG(LogLyra, Error, TEXT(&#34;Game mode was unable to spawn Pawn of class [%s] at [%s].&#34;), *GetNameSafe(PawnClass), *SpawnTransform.ToHumanReadableString());
}
}
else
{
UE_LOG(LogLyra, Error, TEXT(&#34;Game mode was unable to spawn Pawn due to NULL pawn class.&#34;));
}
return nullptr;
}
//HeroData_ShooterGame.Pawn Class
UClass* ALyraGameMode::GetDefaultPawnClassForController_Implementation(AController* InController)
{
if (const ULyraPawnData* PawnData = GetPawnDataForController(InController))
{
if (PawnData->PawnClass)
{
return PawnData->PawnClass;
}
}
return Super::GetDefaultPawnClassForController_Implementation(InController);
}
//B_BasicShooterTest.Default Pawn Data
const ULyraPawnData* ALyraGameMode::GetPawnDataForController(const AController* InController) const
{
// See if pawn data is already set on the player state
if (InController != nullptr)
{
if (const ALyraPlayerState* LyraPS = InController->GetPlayerState<ALyraPlayerState>())
{
if (const ULyraPawnData* PawnData = LyraPS->GetPawnData<ULyraPawnData>())
{
return PawnData;
}
}
}
// If not, fall back to the the default for the current experience
check(GameState);
ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>();
check(ExperienceComponent);
if (ExperienceComponent->IsExperienceLoaded())
{
const ULyraExperienceDefinition* Experience = ExperienceComponent->GetCurrentExperienceChecked();
if (Experience->DefaultPawnData != nullptr)
{
return Experience->DefaultPawnData;
}
// Experience is loaded and there&#39;s still no pawn data, fall back to the default for now
return ULyraAssetManager::Get().GetDefaultPawnData();
}
// Experience not loaded yet, so there is no pawn data to be had
return nullptr;
}
gamestate也有个类似的,比gamemode先调用
void ALyraPlayerState::PostInitializeComponents()
ExperienceComponent->CallOrRegister_OnExperienceLoaded(FOnLyraExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded));
void ALyraPlayerState::OnExperienceLoaded(const ULyraExperienceDefinition* /*CurrentExperience*/)
if (const ULyraPawnData* NewPawnData = LyraGameMode->GetPawnDataForController(GetOwningController()))
SetPawnData(NewPawnData);
UI生成:
- 利用控件反射器找到W_ScoreWidget_Elimination,引用查看器找到B_BasicShooterTest-Actions-(TagName=&#34;HUD.Slot.TeamScore&#34;)
- 查c++ Actions成员,断点ActivateListOfActions(CurrentExperience->Actions);
void ULyraExperienceManagerComponent::OnGameFeaturePluginLoadComplete(const UE::GameFeatures::FResult& Result)
OnExperienceFullLoadCompleted();
void ULyraExperienceManagerComponent::OnExperienceFullLoadCompleted()
auto ActivateListOfActions = [&Context](const TArray<UGameFeatureAction*>& ActionList)
{
for (UGameFeatureAction* Action : ActionList)
{
if (Action != nullptr)
{
//@TODO: The fact that these don&#39;t take a world are potentially problematic in client-server PIE
// The current behavior matches systems like gameplay tags where loading and registering apply to the entire process,
// but actually applying the results to actors is restricted to a specific world
Action->OnGameFeatureRegistering();
Action->OnGameFeatureLoading();
Action->OnGameFeatureActivating(Context);
}
}
};
ActivateListOfActions(CurrentExperience->Actions);
//断点Action->OnGameFeatureActivating(Context);
Action->OnGameFeatureActivating(Context);
void UGameFeatureAction_AddAbilities::OnGameFeatureActivating(FGameFeatureActivatingContext& Context)
Super::OnGameFeatureActivating(Context);
//这里完成了蓝图控件的加载FWorldDelegates::OnStartGameInstance.AddUObject
void UGameFeatureAction_WorldActionBase::OnGameFeatureActivating(FGameFeatureActivatingContext& Context)
{
GameInstanceStartHandles.FindOrAdd(Context) = FWorldDelegates::OnStartGameInstance.AddUObject(this,
&UGameFeatureAction_WorldActionBase::HandleGameInstanceStart, FGameFeatureStateChangeContext(Context));
// Add to any worlds with associated game instances that have already been initialized
for (const FWorldContext& WorldContext : GEngine->GetWorldContexts())
{
if (Context.ShouldApplyToWorldContext(WorldContext))
{
AddToWorld(WorldContext, Context);
}
}
}
if (Context.ShouldApplyToWorldContext(WorldContext))
if (WorldContext.ContextHandle == WorldContextHandle)
{
return true;
}
//不同类跳转到不同方法
void UGameFeatureAction_AddComponents::OnGameFeatureActivating(FGameFeatureActivatingContext& Context)
{
FContextHandles& Handles = ContextHandles.FindOrAdd(Context);
Handles.GameInstanceStartHandle = FWorldDelegates::OnStartGameInstance.AddUObject(this,
&UGameFeatureAction_AddComponents::HandleGameInstanceStart, FGameFeatureStateChangeContext(Context));
ensure(Handles.ComponentRequestHandles.Num() == 0);
// Add to any worlds with associated game instances that have already been initialized
for (const FWorldContext& WorldContext : GEngine->GetWorldContexts())
{
if (Context.ShouldApplyToWorldContext(WorldContext))
{
AddToWorld(WorldContext, Handles);
}
}
}
void UGameFeatureAction_WorldActionBase::OnGameFeatureActivating(FGameFeatureActivatingContext& Context)
{
GameInstanceStartHandles.FindOrAdd(Context) = FWorldDelegates::OnStartGameInstance.AddUObject(this,
&UGameFeatureAction_WorldActionBase::HandleGameInstanceStart, FGameFeatureStateChangeContext(Context));
// Add to any worlds with associated game instances that have already been initialized
for (const FWorldContext& WorldContext : GEngine->GetWorldContexts())
{
if (Context.ShouldApplyToWorldContext(WorldContext))
{
AddToWorld(WorldContext, Context);
}
}
}
角色射击:
断点ALyraGameMode::InitGame
void ALyraGameMode::HandleMatchAssignmentIfNotExpectingOne()
FPrimaryAssetId ExperienceId;
// see if the world settings has a default experience
if (!ExperienceId.IsValid())
{
if (ALyraWorldSettings* TypedWorldSettings = Cast<ALyraWorldSettings>(GetWorldSettings()))
{
ExperienceId = TypedWorldSettings->GetDefaultGameplayExperience();
ExperienceIdSource = TEXT(&#34;WorldSettings&#34;);
}
}
void ALyraGameMode::OnMatchAssignmentGiven(FPrimaryAssetId ExperienceId, const FString& ExperienceIdSource)
{
#if WITH_SERVER_CODE
if (ExperienceId.IsValid())
{
UE_LOG(LogLyraExperience, Log, TEXT(&#34;Identified experience %s (Source: %s)&#34;), *ExperienceId.ToString(), *ExperienceIdSource);
ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>();
check(ExperienceComponent);
ExperienceComponent->ServerSetCurrentExperience(ExperienceId);
}
else
{
UE_LOG(LogLyraExperience, Error, TEXT(&#34;Failed to identify experience, loading screen will stay up forever&#34;));
}
#endif
}
LogLyraExperience日志
LogLyraExperience: Identified experience LyraExperienceDefinition:B_BasicShooterTest (Source: WorldSettings)
LogLyraExperience: EXPERIENCE: StartExperienceLoad(CurrentExperience = LyraExperienceDefinition:B_BasicShooterTest, Server)
LogLyraExperience: EXPERIENCE: OnExperienceLoadComplete(CurrentExperience = LyraExperienceDefinition:B_BasicShooterTest, Server)最开始的日志
目录
Engine\Plugins\Experimental\BackChannel\Source\BackChannel\Private\Transport\BackChannelConnection.cpp
LogBackChannel: Listening on FBackChannelConnection Client Socket (localport: 2049)
Engine\Plugins\Experimental\RemoteSession\Source\RemoteSession\Private\RemoteSessionModule.cpp
LogRemoteSession: Started listening on port 2049断点UE_LOG(LogBackChannel, Log, TEXT(&#34;Listening on %s (localport: %d)&#34;)
- 在Engine\Plugins\Experimental\RemoteSession\Source\RemoteSession\Public\RomoteSession.h中定义了virtual void InitHost(const int16 Port=0) = 0;
- 查引用看堆栈dll-void FRemoteSessionModule::OnPIEStarted(bool bSimulating)-InitHost();
- void FRemoteSessionModule::StartupModule()-PostPieDelegate = FEditorDelegates::PostPIEStarted.AddRaw(this, &FRemoteSessionModule::OnPIEStarted);
- 2049是默认端口DefaultPort
断点void ULyraExperienceManagerComponent::StartExperienceLoad()-堆栈在dll里
将解决方案配置development edit改成DebugGame,启动报错-改成debuggame edit-可直接断点进入dll
//加载方法
const TSharedPtr<FStreamableHandle> BundleLoadHandle = AssetManager.ChangeBundleStateForPrimaryAssets(BundleAssetList.Array(), BundlesToLoad, {}, false, FStreamableDelegate(), FStreamableManager::AsyncLoadHighPriority);
//设置加载完成回调
FStreamableDelegate OnAssetsLoadedDelegate = FStreamableDelegate::CreateUObject(this, &ThisClass::OnExperienceLoadComplete);
TSharedPtr<FStreamableHandle> UAssetManager::ChangeBundleStateForPrimaryAssets
if (ReturnHandle->HasLoadCompleted())
{
FStreamableHandle::ExecuteDelegate(DelegateToCall);
}
加载插件
void ULyraExperienceManagerComponent::OnExperienceLoadComplete()
UGameFeaturesSubsystem::Get().LoadAndActivateGameFeaturePlugin(PluginURL, FGameFeaturePluginLoadComplete::CreateUObject(this, &ThisClass::OnGameFeaturePluginLoadComplete)); |
|