Projectile类型武器的ServerRewind
不同
因为Projectile是一个抛物线,所以不能再使用射线检测,而是通过检测projectile对象碰撞来造成伤害
所以对于抛物线轨迹,为了能够在服务器上模拟,需要传递起点和初始速度
所以还有一点不同就是这个Projectile对象的复制问题在开启SSR之后
Add
对于开放了Projectile的速度和最大速度在蓝图中可编辑的实现,当我们修改开放的这个speed,但是对应在projectile运动组件里面的速度并没有发生变化。所以需要用到后期编辑功能
重写PostEditProperty()
//.h
#if WITH_EDITOR
virtual void AProjectileBulletActor::PostEditChangeProperty(FPropertyChangedEvent& Event) override
#endif
//.cpp
#if WITH_EDITOR
void PostEditChangeProperty(FPropertyChangedEvent& Event)
{
Super::PostEditChangeProperty(Event);
//根据发生变化的事件获取属性然后获取其对应的名字
FName PropertyName = Event.Property != nullptr ? Event.Property->GetFName() : NAME_None;
if (PropertyName == GET_MEMBER_NAME_CHECKED(AProjectileBulletActor, InitialSpeedForBullet))//AProjectileBulletActor, InitialSpeedForBullet 追踪类和改变的变量
{
if (ProjectileMovementComp)
{
ProjectileMovementComp->MaxSpeed = InitialSpeedForBullet;
ProjectileMovementComp->InitialSpeed = InitialSpeedForBullet;
}
}
}
#endif
开启SSR之后的产生子弹属性
这次选择了使用在一个武器上挂载两种类型的子弹,它们的参数都是一致的只是有一个是不可复制的,有一个是可以复制的
而对于是否开启ServerSideRewind。在武器和子弹上都添加了这样一个bool值
分析
服务器和客户端#
对于服务器来说,其上的角色要么是自己控制,要么不是自己控制的但是是权威的
-
当是服务器并且是本地控制,然后武器开启了ServerSideRewind功能,只需要产生一个可复制的不需要ServerSideRewind功能的子弹就可以了
-
当是服务器但不是本地控制,然后客户端上的武器开启了ServerSideRewind功能,此时客户端上会生成一个不可复制具备SSR功能的子弹,然后该攻击就会和之前做HitScan一样,通过SSR来分析伤害,所以在服务器上只需要生成一个不可复制,不具有SSR功能的子弹。
-
当是客户端并且是本地控制的,武器开启了SSR功能,其产生的子弹就是一个生成一个不可复制具备SSR功能的子弹,利用SSR来进行伤害判定
-
当是客户端但不是本地控制的,武器开启了SSR功能,而在本地客户端会通过MulticastRPC,直到其他客户端产生了攻击,所以为了在本地显示,会产生一个不可复制的不使用SSR功能的子弹,相当于只是视觉演示
-
如果是服务器,武器没有开启SSR,那么不论是不是本地控制,都会产生一个可复制不具备SSR的子弹
-
如果是客户端,武器没有开启SSR,那么不论是不是本地控制,都不会产生,因为会通过服务器返回复制的子弹
修改
之前没有SSR功能相当于就是通过RPC然后向服务器发送通知,服务器执行,所以在Fire的时候需要检测当前是不是在服务器上
现在具有了SSR功能,那么在客户端上也可以实现命中检测了,所以对于Fire中命中和伤害的检测就需要更改了
if(//当前武器开启了SSR)
{
if(//在服务器上)
{
if(//本地控制,在服务上生成可复制的不具备SSR功能的子弹)
{
//注意,需要将子弹的伤害设置为武器的伤害,因为为了和下方的伤害值相同,之后子弹的伤害都通过武器来设置
}
else
{
//由其他客户端生成,在服务器上生成不可复制,具备SSR的子弹
//伤害会通过SSR来计算,服务器上产生的子弹不会对伤害造成影响
}
}
else // 客户端
{
if(//本地控制)
{
//在客户端上生成 不可复制,但具备SSR功能的子弹
//由于具备SSR,那么需要在服务器上验证轨迹击中,需要传递初始位置和初始速度,方便计算
//对于伤害值,需要将子弹的伤害设置为武器伤害
}
else // 其他客户端生成
{
// 在当前客户端生成 不可复制,不具备SSR
// 即该子弹不参与伤害计算,所以不需要设置参数
}
}
}
else //不是SSR功能
{
if(//在服务器上)
{
//生成可复制的,不具有SSR的功能
//同样将伤害设置为武器伤害
}
else
{
//不产生
}
}
ServerSideRewind
基本上仍然是ServerSideRewind主函数,然后ConfirmHit检测验证Hit,最后再来一个用于服务器执行的ApplyDamage函数
ServerSideRewind主函数
FServerSideRewindResult ProjectileServerSideRewind(AXCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize100& InitialVelocity, float HitTime);
该函数还是主要就是用来获得检测击中结果
ConfirmHit函数
FServerSideRewindResult ProjectileConfirmHit(const FFramePackage& Package, AXCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize100& InitialVelocity, float HitTime);
用来确认是否击中,主要方法和之前的一样,区别就是hit结果是通过路径预测返回的,通过传入的TraceStart和InitialVelocity
FPredictProjectilePathParams PathParams;
PathParams.bTraceWithCollision = true;
PathParams.MaxSimTime = MaxRecordTime;
PathParams.LaunchVelocity = InitialVelocity;
PathParams.StartLocation = TraceStart;
PathParams.SimFrequency = 15.f;
PathParams.ProjectileRadius = 5.f;
PathParams.TraceChannel = ECC_HitBox; // 检测的type
PathParams.ActorsToIgnore.Add(GetOwner());
FPredictProjectilePathResult PathResult;
UGameplayStatics::PredictProjectilePath(this, PathParams, PathResult);
服务器执行伤害逻辑
void ServerProjectileScoreRequest_Implementation(AXCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize100& InitialVelocity, float HitTime)
和之前的类似,但之前的函数都是用在武器的Fire函数中,现在这个函数将用在子弹的OnHit事件里面,因为只有OnHit触发时间相当于是客户端正确击打的时间
那么首先就是检测当前的该子弹的拥有者是否在服务器上
如果在服务器上,并且当前子弹没有开启SSR,那么进行ApplyDamage的操作
如果不在,说明是本地客户端且开启了SSR,就可以调用上面的函数来执行伤害的判定和施加
这两种情况,是根据上面的Fire会对子弹产生影响分析出来的
粗略的判断是否应当由服务器施加伤害
首先如果说是在服务器上
没有开启 SSR功能 那么肯定是服务器进行ApplyDamage的操作
其次如果当前角色是本地控制的(即当前角色是服务器自身的角色),那么无论是否开启了SSR,服务器是都需要进行ApplyDamage操作
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律