今天的视频有点绕,脑子转了好久,所以详细记录一下编程逻辑,供日后参考
视频
功能:
我们需要播放离开的动画
掉落武器
对最高分的选手进行追踪
server离开游戏时,所有玩家全部踢掉
client离开游戏,就自己滚蛋
我们在BlasterCharacter的新建变量,用于判断角色是否是离开游戏的状态变量
bool bLeftGame = false;
同时我们需要声明一个委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnLeftGame);
并且在private里定义委托变量用于绑定
FOnLeftGame OnLeftGame;
我们还要在BlasterCharacter新建serverRPC,以帮助client端玩家通知server断开连接
UFUNCTION(Server,Reliable)
void ServerLeaveGame();
我们继续在BlasterGameMode.cpp新建方法
void PlayerLeftGame(class ABlasterPlayerState* PlayerLeaving);
我们原先BlasterCharacter的Elim()和MulticastElim()方法需要添加Character的bLeftGame进行判断,所以重构
void Elim(bool bPlayerLeftGame);
UFUNCTION(NetMulticast, Reliable)
void MulticastElim(bool bPlayerLeftGame);
然后我们在ServerLeaveGame中调用BlasterGameMode的方法PlayerLeftGame
void ABlasterCharacter::ServerLeaveGame_Implementation()
{
ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode();
BlasterPlayerState = BlasterPlayerState == nullptr ? GetPlayerState() : BlasterPlayerState;
if (BlasterGameMode && BlasterPlayerState)
{
BlasterGameMode->PlayerLeftGame(BlasterPlayerState);
}
}
我们在MulticastElim方法添加,这样我们可以在计时器结束后,进行bLeftGame判定,以取消重生玩家
bLeftGame = bPlayerLeftGame; //最重要
然后我们在ElimTimerFinished()结束后,判断玩家是否离开游戏,离开的话调用委托OnLeftGame.Broadcast()
void ABlasterCharacter::ElimTimerFinished()
{
ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode();
if (BlasterGameMode && !bLeftGame)
{
BlasterGameMode->RequestRespawn(this, Controller);
}
if (bLeftGame && IsLocallyControlled())
{
OnLeftGame.Broadcast();
}
}
我们的playerGameMode也需要知道playerstate以对最高分玩家进行更新
所以我们在BlasterCharacter里开始传递数值
GameMode我们重构PlayerLeftGame方法,添加参数
void PlayerLeftGame(class ABlasterPlayerState* PlayerLeaving);
然后我们写PlayerLeftGame函数
void ABlasterGameMode::PlayerLeftGame(ABlasterPlayerState* PlayerLeaving)
{
//调用elim,传递true值进去
if (PlayerLeaving == nullptr) return;
ABlasterGameState* BlasterGameState = GetGameState();
if (BlasterGameState && BlasterGameState->TopScoringPlayers.Contains(PlayerLeaving))
{
BlasterGameState->TopScoringPlayers.Remove(PlayerLeaving);
}
ABlasterCharacter* CharacterLeaving = Cast(PlayerLeaving->GetPawn());
if (CharacterLeaving)
{
CharacterLeaving->Elim(true);
}
}
目前所有代码执行逻辑是,我们BlasterCharacter的ServerLeaveGame执行,然后我们进入到BlasterGameMode,调用BlasterCharacter的Elim()方法,Elim()调用MulticastElim网络多播,设置
bLeftGame = true,在计时器结束后,ElimTimerFinished()判断是否离开游戏,然后播放委托OnLeftGame.Broadcast()
我们需要在ReturnToMainMenu进行委托函数构造
首先是ReturnButtonClicked()
我们要对BlasterCharacter进行判断,通过controller获取pawn属性。当他离开了游戏,BlasterCharacter为Nullptr,就重新设置button为true状态,否则serverLeaveGame(),这个方式是serverRPC
void UReturnToMainMenu::ReturnButtonClicked()
{
ReturnButton->SetIsEnabled(false);
UWorld* World = GetWorld();
if (World)
{
APlayerController* FirstPlayerController = World->GetFirstPlayerController();
if (FirstPlayerController)
{
ABlasterCharacter* BlasterCharacter = Cast(FirstPlayerController->GetPawn());
if (BlasterCharacter)
{
BlasterCharacter->ServerLeaveGame();
}
else
{
ReturnButton->SetIsEnabled(true);
}
}
}
}
OnPlayerLeftGame这样写
void UReturnToMainMenu::OnPlayerLeftGame()
{
if (MultiplayerSessionsSubsystem)
{
MultiplayerSessionsSubsystem->DestroySession();
}
}
最后我们梳理一下逻辑,一旦在ReturnToMainMenu按下了绑定的按钮,ReturnButtonClicked()执行,ServerRPC:ServerLeaveGame()调用,然后我们进入到BlasterGameMode,调用BlasterCharacter的Elim()方法,Elim()调用MulticastElim网络多播,设置
bLeftGame = true,在计时器结束后,ElimTimerFinished()根据bLeftGame判断是否离开游戏,然后播放委托OnLeftGame.Broadcast(),执行OnPlayerLeftGame(),然后进入OnDestroySession方法,最后因为我们是客户端,执行GameMode为nullptr方法,返回主菜单PlayerController->ClientReturnToMainMenuWithTextReason(FText());
最后我们绑定一下
最后我们把计时器放在MulticastElim下,这样计时功能就也能在client上执行了,就是server调用了Elim,然后elim通过multicast传给所有客户端和服务器
回顾一下RPC