同步系列2-玩家姓名的同步


游戏角色在游戏开始后在头上显示自己的名字,方便玩家辨认队友,这个名字可以由玩家自己设置

1
2
UPROPERTY(EditAnywhere, Category = "Player Name")
FString LocalPlayerName = TEXT("Unknown Player");

然后在角色蓝图中设置玩家姓名,我这里是在蓝图中直接设置的,后面也可以放给UI让玩家在进入游戏之前自己设置自己的名字或者后面加入账号功能后跟账号绑定。

image-20230419225939177

直接放最后运行的效果

image-20230419230147754

在BeginPlay中再初始化玩家名称是为了等角色所有的信息都加载好了比如控制器,避免无效。用到了两个函数,老样子一个ServerRPC一个ClientRPC。

1
2
3
4
5
6
7
8
9
10
11
12
void ABlasterCharacter::BeginPlay()
{
Super::BeginPlay();
ServerSetPlayerName(LocalPlayerName);
ServerSetMaterial();
}

UFUNCTION(Client, Reliable)
void ClientSetName(const FString& Name);

UFUNCTION(Server, Reliable)
void ServerSetPlayerName(const FString& PlayerName);

两个函数都是用const FString&传参,减少一次拷贝构造的消耗,来看具体实现。

1
2
3
4
5
6
7
8
9
10
11
void ABlasterCharacter::ServerSetPlayerName_Implementation(const FString& PlayerName)
{
APlayerController* PlayerController = Cast<APlayerController>(GetController());
if (PlayerController)
{
// 在服务端设置玩家名称 Set player name in server
PlayerController->PlayerState->SetPlayerName(PlayerName);
// 调用ClientSetPlayerName函数在客户端设置玩家名称 use ClientSetPlayerName to set player name in client
ClientSetName(PlayerName);
}
}

通过调用控制器的玩家状态的设置玩家姓名函数,传入玩家名字,同理客户端也是,注释部分有解释。ClientRPC部分如下:

1
2
3
4
5
6
7
8
9
void ABlasterCharacter::ClientSetName_Implementation(const FString& Name)
{
//设置玩家名称 Set Player Name
APlayerController* PlayerController = Cast<APlayerController>(GetController());
if (PlayerController->PlayerState)
{
PlayerController->PlayerState->SetPlayerName(Name);
}
}

那么这样就可以实现开局同步玩家姓名的功能了。光说同步差点忘了说在哪显示了…因为显示都是在用户界面上操作的,你建好你自己的Widet类,然后加上这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void UOverheadWidget::ShowPlayerName(APawn *InPawn)
{
APlayerState* PlayerState = InPawn->GetPlayerState();

// 获取玩家名字
if ( PlayerState != nullptr)
{
FString PlayerName = PlayerState->GetPlayerName();
// 这里可以根据需要将 FString 转换为 std::string 或其他类型
// ...
FString LocalRoleString = FString::Printf(TEXT("%s"), *PlayerName);
SetDisplayText(LocalRoleString);
}
}

这个是用来显示最后的玩家姓名的,或许我应该设置个保底…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void UOverheadWidget::ShowPlayerName(APawn *InPawn)
{
APlayerState* PlayerState = InPawn->GetPlayerState();
// 获取玩家名字
if ( PlayerState != nullptr)
{
FString PlayerName = PlayerState->GetPlayerName();
// 这里可以根据需要将 FString 转换为 std::string 或其他类型
// ...
FString LocalRoleString = FString::Printf(TEXT("%s"), *PlayerName);
SetDisplayText(LocalRoleString);
}
else
{
FString LocalRoleString = FString::Printf(TEXT("Unknown Player"));
SetDisplayText(LocalRoleString);
}
}

这样就算没能拿到玩家姓名也能设置个未知玩家在头上摆着。最后在角色蓝图里调一下就行。

image-20230419231922218


文章作者: John Doe
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 John Doe !
  目录