同步系列6-切换人称和视角旋转方式的同步


在射击游戏中,我想同时实现第一人称和第三人称的效果,这样在PVP模式中我希望是仅能第一人称,而在PVE模式中,使用第一人称增加代入感,或者使用第三人称纵览全局并获得更稳定的视角。

在第一人称中,我希望做到的效果是玩家角色随鼠标的移动进行旋转,同时将旋转的角度同步到其他客户端,使得其它角色也能看到你在旋转。

在第三人称中,因为我需要使用鼠标观察四周移动视角,所以实际上我并不希望角色随着鼠标的朝向移动,那样对于玩家来说是一个困扰。我希望的效果是,玩家随着键盘的控制方向移动,而不是鼠标,此时本地玩家A移动鼠标后,其他客户端的玩家并不会发现在他们的显示器上,玩家A控制的角色发生了旋转。但若此时玩家A在键盘上输入相反的方向进行位移,那么其他客户端的玩家应该发现在他们的显示器上,玩家A控制的角色发生了相反的旋转。

这两个效果是我今天想要完成的。

来,先绑定输入

1
2
//按V切换视角
EnhancedInputComponent->BindAction(IA_ChangeView, ETriggerEvent::Triggered, this, &ABlasterCharacter::InputShiftView);

直接看InputShiftView不墨迹

1
2
3
4
5
6
7
8
9
10
11
12
void ABlasterCharacter::InputShiftView(const FInputActionValue& InputValue)
{
//如果是服务端执行,就相当于调用一次本地客户端,然后直接return
if(HasAuthority())
{
//服务端的本地就是服务端自己的客户端
ClientChangeView();
return;
}
//如果是客户端执行,让服务端去改变,再传递给各个客户端来完成同步的效果
ServerChangeView();
}

然后再看ServerChangeView_Implementation

1
2
3
4
5
6
7
void ABlasterCharacter::ServerChangeView_Implementation()
{
//需要修改服务器上的版本,因为服务器上的版本是用来同步给别的客户端的,别的客户端不与正在执行动作的客户端通信,别的客户端拿的是服务端的数据
ChangeCameraView();
//再去让正在执行动作的客户端去真正实现功能
ClientChangeView();//注释此函数后,客户端角色能同步旋转但是不能改变视角,原因是没有收到Server发来的ClientChangeView()所以改变不了视角,但是和角色移动旋转相关的属性是默认实现网络同步的,是否旋转属性在上面Server端被修改的时候就被同步到客户端了,因此不需要Server发来的ClientChangeView()也改变了旋转。
}

ClientRPC直接执行ChangeCameraView使得在客户端执行业务逻辑

1
2
3
4
void ABlasterCharacter::ClientChangeView_Implementation()
{
ChangeCameraView();
}

最后由ChangeCameraView真正的直接去修改视角和控制旋转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void ABlasterCharacter::ChangeCameraView()
{
// 判断当前激活的摄像机,并切换到另一个摄像机
if (FollowCamera->IsActive())//切换到第三人称
{
FollowCamera->SetActive(false);
FollowCamera->Deactivate();
TPSCamera->SetActive(true);
TPSCamera->Activate();
GetCharacterMovement()->bOrientRotationToMovement = true;
bUseControllerRotationYaw = false;
}
else//切换到第一人称
{
TPSCamera->SetActive(false);
TPSCamera->Deactivate();
FollowCamera->SetActive(true);
FollowCamera->Activate();
GetCharacterMovement()->bOrientRotationToMovement = false;
bUseControllerRotationYaw = true;

}
}

到这逻辑就写完了,不过记得可以在角色构造里面自定义初始化一下关于视角的设置,设置成自己喜欢的方式就行,不一定要和我一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ABlasterCharacter::ABlasterCharacter()
{
PrimaryActorTick.bCanEverTick = true;

//创建第一人称摄像机
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
//摄像机绑到角色头部的骨骼插槽里
FollowCamera->SetupAttachment(GetMesh(), FName(TEXT("FollowCameraSocket")));

//创建第三人称摄像机
TPSCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("TPSCamera"));
TPSCamera->SetupAttachment(CameraBoom);

FollowCamera->bUsePawnControlRotation = true;

FollowCamera->SetActive(true);//激活第一人称摄像机,其实这个函数里面的实现就是下面Activate()
FollowCamera->Activate();//还是激活,我不知道不写这行只写上面的行不行,不过我看了SetActive没有网络同步的内容,但是Activate()里面有Broadcast广播,所以我觉得还是留着吧,你可以测试下
TPSCamera->SetActive(false);
TPSCamera->Deactivate();

}

与本篇无关的函数内容这里精简了,至于摄像机的位置大家自己摆一下,摄像机视角的变换和旋转同步问题到这里应该就解决了,至于第一人称视角容易和角色穿模的问题我们下篇再讨论有什么处理方式。最后放一张效果图

image-20230419234602363


  目录