打开主角类,生成枪的代码逻辑在游戏开始函数里

所以在生成之前,我们需要判断该对象是否在服务器端(服务器端视角)

void ASCharacter::BeginPlay()
{Super::BeginPlay();DefaultsFOV = CameraComp->FieldOfView;//判断是否在服务器端if (Role == ROLE_Authority){//设置生成参数,当生成的actor碰到了其他物体,也要生成FActorSpawnParameters Parameters;Parameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;//生成武器actor(类型、位置、方向、参数),并且其地址赋予到指针上CurrentWeapen1 = GetWorld()->SpawnActor<ASWeapen>(StartWeapen, FVector::ZeroVector, FRotator::ZeroRotator, Parameters);//设置武器的位置与骨骼的插槽中,并设置主人if (CurrentWeapen1){CurrentWeapen1->SetOwner(this);CurrentWeapen1->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, WeaponAttachSoketName);}}//受伤自定义事件绑定HealthComp->OnHealthChanged.AddDynamic(this, &ASCharacter::OnHealthChanged);}

编译一下,看看是什么效果

我们发现,左边的有武器,右边的没有武器

 所以我们要让武器可以进行网络复制

打开武器类,在构造函数中进行设置

 //设置可以进行网络复制SetReplicates(true);

编译,然后打开枪的蓝图,打上勾

这一次他们都有枪了

 

现在枪虽然是有了,左边的玩家可以开枪,但是右边的角色不可以开枪

这是因为右边角色,指向武器的指针是空的

所以我们要让武器指针可以同步,这样就可以同步了

 //目前玩家手中的武器UPROPERTY(Replicated)class ASWeapen * CurrentWeapen1;

要实现网络同步,必须还要有一个函数,这个函数定义在actor类里面

我们将其复制到玩家类里面

 //用于网络同步的函数void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

导入头文件

#include "Net/UnrealNetwork.h"

定义这个函数

void ASCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{Super::GetLifetimeReplicatedProps(OutLifetimeProps);//同步给所有的客户端和服务器DOREPLIFETIME(ASCharacter, CurrentWeapen1);
}

测试,两个角色都可以打枪了,但是互相看不见。

下面解决这个问题。

==========================================

给武器类添加成员函数serverfire()

 UFUNCTION(Server, Reliable, WithValidation)void ServerFire();

然后实现该函数的方式比较特殊

void ASWeapen::ServerFire_Implementation()
{Fire();
}bool ASWeapen::ServerFire_Validate()
{return true;
}

然后我们修改一下Fire()函数

void ASWeapen::Fire()
{//如果不是服务器,就执行ServerFire()if (Role < ROLE_Authority){ServerFire();return;}//创建一个撞击句柄,用来获取弹道相关信息FHitResult Hit;//弹道的起点,我们设置为角色眼睛的位置AActor * MyOwner = GetOwner();if (MyOwner){  //位置FVector EyeLocation;//方向FRotator EyeRotator;//得到眼睛的位置和角度MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotator);//弹道的终点就是起点+方向*10000FVector TraceEnd = EyeLocation + (EyeRotator.Vector() * 1000);//弹道特效的结束点FVector TraceEndPoint = TraceEnd;//设置碰撞通道为可见性通道FCollisionQueryParams  QueryParams;//让射线忽略玩家和枪QueryParams.AddIgnoredActor(MyOwner);QueryParams.AddIgnoredActor(this);//符合追踪设为true,可以让射击更加精准QueryParams.bTraceComplex = true;//返回命中目标的表面材质QueryParams.bReturnPhysicalMaterial = true;//在创建一个单轨迹线来计算弹道//LineTraceSingleByChannel击中物体返回trueif (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON, QueryParams)){//命中对象AActor * HitActor = Hit.GetActor();//实际的伤害float ActualDamage = BaseDamage;//得到命中物体表面材质EPhysicalSurface SurfaceType = UPhysicalMaterial::DetermineSurfaceType(Hit.PhysMaterial.Get());//如果命中的是头部表面材质,伤害变成四倍if (SurfaceType == SURFACE_FLESHVULNERABLE){ActualDamage *= 4;}//造成点伤害ApplyPointDamage//参数分别为命中对象、基础伤害、射击方向、命中信息(命中句柄)、MyOwner->GetInstigatorController(暂时不了解)//this(射击者) 和伤害类型 UGameplayStatics::ApplyPointDamage(HitActor, ActualDamage, EyeRotator.Vector(), Hit, MyOwner->GetInstigatorController(), this, DamageType);//根据材质的不同,进行不同的处理UParticleSystem * SelectedEffect = nullptr;switch (SurfaceType){//这两种情况是一个效果case SURFACE_FLESHDEFAULT:case SURFACE_FLESHVULNERABLE:SelectedEffect = FleshImpactEffect;break;default:SelectedEffect = DefaultImpactEffect;break;}//生成特效在命中点//ImpactEffect:特效 ImpactPoint:打击点 Rotation():打击方向if (SelectedEffect){UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, Hit.ImpactPoint, Hit.ImpactNormal.Rotation());}//命中的时候,修改弹道特效的终点TraceEndPoint = Hit.ImpactPoint;}//方便debug//DrawDebugLine(GetWorld(), EyeLocation, TraceEnd, FColor::Red, false, 1, 0, 1);//射击特效PlayFireEffects(TraceEndPoint);//最后开火的时间FireLastTime = GetWorld()->TimeSeconds;}}

编译,测试,服务器端开火,客户端看不到(不管控制哪个角色,都是在服务器端看到开火)

修改一下代码,我们把return去掉

编译测试

服务器端开火,客户端看不到;客户端开火,同时可以看到

 

给角色蓝图添加两个节点

===========================================

目前

操作客户端,两端都能看到特效

操作服务器端,客户端看不到特效

在武器类的头文件中,创建结构体

USTRUCT()
struct FHitScanTrace
{GENERATED_BODY()
public://弹道的目的坐标UPROPERTY()FVector_NetQuantize TraceTo;//子弹数目:为了让该结构体内容发生变化,结构体才被不断得被网络复制UPROPERTY()uint8 BrustCounter;};

创建该类中的结构体成员变量,和对应的网络复制函数

 //网络射击信息UPROPERTY(ReplicatedUsing = OnRep_HitScanTrace)FHitScanTrace HitScanTrace;//网络复制函数UFUNCTION()void OnRep_HitScanTrace();

当结构体内容发生改变的时候,就会自动调用网络复制函数

在fire函数里面,更新网络射击信息

     //更新网络射击信息if (Role == ROLE_Authority){//子弹数量++HitScanTrace.BrustCounter++;//更新弹道目的坐标HitScanTrace.TraceTo = TraceEndPoint;}
void ASWeapen::Fire()
{//如果不是服务器,就执行ServerFire()if (Role < ROLE_Authority){ServerFire();}//创建一个撞击句柄,用来获取弹道相关信息FHitResult Hit;//弹道的起点,我们设置为角色眼睛的位置AActor * MyOwner = GetOwner();if (MyOwner){ //位置FVector EyeLocation;//方向FRotator EyeRotator;//得到眼睛的位置和角度MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotator);//弹道的终点就是起点+方向*10000FVector TraceEnd = EyeLocation + (EyeRotator.Vector() * 1000);//弹道特效的结束点FVector TraceEndPoint = TraceEnd;//设置碰撞通道为可见性通道FCollisionQueryParams  QueryParams;//让射线忽略玩家和枪QueryParams.AddIgnoredActor(MyOwner);QueryParams.AddIgnoredActor(this);//符合追踪设为true,可以让射击更加精准QueryParams.bTraceComplex = true;//返回命中目标的表面材质QueryParams.bReturnPhysicalMaterial = true;//在创建一个单轨迹线来计算弹道//LineTraceSingleByChannel击中物体返回trueif (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON, QueryParams)){//命中对象AActor * HitActor = Hit.GetActor();//实际的伤害float ActualDamage = BaseDamage;//得到命中物体表面材质EPhysicalSurface SurfaceType = UPhysicalMaterial::DetermineSurfaceType(Hit.PhysMaterial.Get());//如果命中的是头部表面材质,伤害变成四倍if (SurfaceType == SURFACE_FLESHVULNERABLE){ActualDamage *= 4;}//造成点伤害ApplyPointDamage//参数分别为命中对象、基础伤害、射击方向、命中信息(命中句柄)、MyOwner->GetInstigatorController(暂时不了解)//this(射击者) 和伤害类型 UGameplayStatics::ApplyPointDamage(HitActor, ActualDamage, EyeRotator.Vector(), Hit, MyOwner->GetInstigatorController(), this, DamageType);//根据材质的不同,进行不同的处理UParticleSystem * SelectedEffect = nullptr;switch (SurfaceType){//这两种情况是一个效果case SURFACE_FLESHDEFAULT:case SURFACE_FLESHVULNERABLE:SelectedEffect = FleshImpactEffect;break;default:SelectedEffect = DefaultImpactEffect;break;}//生成特效在命中点//ImpactEffect:特效 ImpactPoint:打击点 Rotation():打击方向if (SelectedEffect){UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, Hit.ImpactPoint, Hit.ImpactNormal.Rotation());}//命中的时候,修改弹道特效的终点TraceEndPoint = Hit.ImpactPoint;}//方便debug//DrawDebugLine(GetWorld(), EyeLocation, TraceEnd, FColor::Red, false, 1, 0, 1);//射击特效PlayFireEffects(TraceEndPoint);//更新网络射击信息if (Role == ROLE_Authority){//子弹数量++HitScanTrace.BrustCounter++;//更新弹道目的坐标HitScanTrace.TraceTo = TraceEndPoint;}//最后开火的时间FireLastTime = GetWorld()->TimeSeconds;}}

定义网络复制函数,让其执行射击特效

void ASWeapen::OnRep_HitScanTrace()
{//调用射击特效PlayFireEffects(HitScanTrace.TraceTo);
}

此时,网络射击信息结构体变量还没有实现网络的复制共享,我们让其共享。

创建复制成员变量的函数

void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

定义这个函数

void ASWeapen::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{Super::GetLifetimeReplicatedProps(OutLifetimeProps);//同步给所有的客户端和服务器(DOREPLIFETIME_CONDITION不用同步给自己)DOREPLIFETIME_CONDITION(ASWeapen, HitScanTrace,COND_SkipOwner);
}

编译,测试

发现服务器端射击的时候,客户端可以看到弹道的特效,但看不到击中特效

============================================

现在解决一下这个问题

为网络射击结构体添加表面材质成员变量

 //表面材质UPROPERTY()TEnumAsByte<EPhysicalSurface> SurfaceType;

在fire函数里面为其赋值

     //更新网络射击信息if (Role == ROLE_Authority){//子弹数量++HitScanTrace.BrustCounter++;//更新弹道目的坐标HitScanTrace.TraceTo = TraceEndPoint;//更新击中物体的材质HitScanTrace.SurfaceType = SurfaceType;}

我们为击中特效的生成做成一个函数

 //击中特效void PlayImpactEffects(EPhysicalSurface SurfaceType , FVector ImpactPoint);

定义这个函数

void ASWeapen::PlayImpactEffects(EPhysicalSurface SurfaceType , FVector ImpactPoint)
{//根据材质的不同,进行不同的处理UParticleSystem * SelectedEffect = nullptr;switch (SurfaceType){//这两种情况是一个效果case SURFACE_FLESHDEFAULT:case SURFACE_FLESHVULNERABLE:SelectedEffect = FleshImpactEffect;break;default:SelectedEffect = DefaultImpactEffect;break;}//生成特效在命中点//ImpactEffect:特效 ImpactPoint:打击点 Rotation():打击方向if (SelectedEffect){//计算枪口位置FVector MuzzleLocation = MeshComponent->GetSocketLocation("MuzzleSocket");//射击方向向量 = 打击点-枪口FVector ShotDirection = ImpactPoint - MuzzleLocation;UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, ImpactPoint, ShotDirection.Rotation());}
}

完善一下复制函数内容函数

void ASWeapen::OnRep_HitScanTrace()
{//调用射击特效PlayFireEffects(HitScanTrace.TraceTo);//生成命中特效PlayImpactEffects(HitScanTrace.SurfaceType, HitScanTrace.TraceTo);
}

完善fire函数

void ASWeapen::Fire()
{//如果不是服务器,就执行ServerFire(),服务器端就有响应if (Role < ROLE_Authority){ServerFire();}//创建一个撞击句柄,用来获取弹道相关信息FHitResult Hit;//弹道的起点,我们设置为角色眼睛的位置AActor * MyOwner = GetOwner();//击中物体的材质EPhysicalSurface SurfaceType = EPhysicalSurface::SurfaceType_Default;if (MyOwner){  //位置FVector EyeLocation;//方向FRotator EyeRotator;//得到眼睛的位置和角度MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotator);//弹道的终点就是起点+方向*10000FVector TraceEnd = EyeLocation + (EyeRotator.Vector() * 1000);//弹道特效的结束点FVector TraceEndPoint = TraceEnd;//设置碰撞通道为可见性通道FCollisionQueryParams  QueryParams;//让射线忽略玩家和枪QueryParams.AddIgnoredActor(MyOwner);QueryParams.AddIgnoredActor(this);//符合追踪设为true,可以让射击更加精准QueryParams.bTraceComplex = true;//返回命中目标的表面材质QueryParams.bReturnPhysicalMaterial = true;//在创建一个单轨迹线来计算弹道//LineTraceSingleByChannel击中物体返回trueif (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON, QueryParams)){//命中对象AActor * HitActor = Hit.GetActor();//实际的伤害float ActualDamage = BaseDamage;//得到命中物体表面材质EPhysicalSurface SurfaceType = UPhysicalMaterial::DetermineSurfaceType(Hit.PhysMaterial.Get());//如果命中的是头部表面材质,伤害变成四倍if (SurfaceType == SURFACE_FLESHVULNERABLE){ActualDamage *= 4;}//造成点伤害ApplyPointDamage//参数分别为命中对象、基础伤害、射击方向、命中信息(命中句柄)、MyOwner->GetInstigatorController(暂时不了解)//this(射击者) 和伤害类型 UGameplayStatics::ApplyPointDamage(HitActor, ActualDamage, EyeRotator.Vector(), Hit, MyOwner->GetInstigatorController(), this, DamageType);//生成命中特效PlayImpactEffects(SurfaceType, Hit.ImpactPoint);//命中的时候,修改弹道特效的终点TraceEndPoint = Hit.ImpactPoint;}//方便debug//DrawDebugLine(GetWorld(), EyeLocation, TraceEnd, FColor::Red, false, 1, 0, 1);//射击特效PlayFireEffects(TraceEndPoint);//更新网络射击信息if (Role == ROLE_Authority){//子弹数量++HitScanTrace.BrustCounter++;//更新弹道目的坐标HitScanTrace.TraceTo = TraceEndPoint;//更新击中物体的材质HitScanTrace.SurfaceType = SurfaceType;}//最后开火的时间FireLastTime = GetWorld()->TimeSeconds;}}

编译,测试,两边特效同步了

============================

现在是死亡不同步

打开生命值组件

首先在游戏开始函数里判断当前是否是服务器,如果是服务器,才绑定受伤

// Called when the game starts
void USHealthComponent::BeginPlay()
{Super::BeginPlay();//这就意味着客户端不会响应受伤事件if (GetOwnerRole() == ROLE_Authority){AActor * Owner = GetOwner();//将该函数绑定在角色的受伤事件上if (Owner){Owner->OnTakeAnyDamage.AddDynamic(this, &USHealthComponent::HandleTakeAnyDamage);}}Health = DefaultHealth;}

在构造函数中设为可网路复制

USHealthComponent::USHealthComponent()
{// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features// off to improve performance if you don't need them.PrimaryComponentTick.bCanEverTick = true;DefaultHealth = 100;//网络复制SetIsReplicated(true);
}

将其中的生命值成员变量声明为网路可复制

 //当前生命值UPROPERTY(Replicated, BlueprintReadOnly, Category = "HealthComponent")float Health;

并定义和声明相关同步函数

     //用于网络同步的函数void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
#include "Net/UnrealNetwork.h"
void USHealthComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{Super::GetLifetimeReplicatedProps(OutLifetimeProps);//同步给所有的客户端和服务器DOREPLIFETIME(USHealthComponent, Health);
}

打开角色类,将该变量设为网络可复制

 //是否死亡UPROPERTY(Replicated, BlueprintReadOnly, Category = "Player")bool bDied;

网络同步函数中,也进行同步一下

void ASCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{Super::GetLifetimeReplicatedProps(OutLifetimeProps);//同步给所有的客户端和服务器DOREPLIFETIME(ASCharacter, CurrentWeapen1);DOREPLIFETIME(ASCharacter, bDied);
}

测试

同时倒地

18uec++多人游戏【服务器为两个角色发枪,并能在线开枪】相关推荐

  1. 高性能游戏服务器架构设计,一种高性能大型多人在线角色扮演游戏服务器架构设计.doc...

    一种高性能大型多人在线角色扮演游戏服务器架构设计 一种高性能大型多人在线角色扮演游戏服务器架构设计摘要:大型多人在线角色扮演游戏(Massively Multiplayer Online Role P ...

  2. 角色在服务器正在维护,魔兽怀旧服:服务器再次崩溃,角色全部消失,需要维护14个小时...

    前言:怀旧服服务器因为玩家数量太多,稳定性一直是一个问题,因为服务器崩溃已经不是一次两次了,就在昨天夜里又再次发生了,并且这次更加严重.昨天晚上有熬夜的玩家,都经历了服务器的再次崩溃,所有玩家的人物角 ...

  3. 魔兽怀旧服服务器周2维护一次吗,魔兽怀旧服:服务器再次崩溃,角色全部消失,需要维护14个小时...

    原标题:魔兽怀旧服:服务器再次崩溃,角色全部消失,需要维护14个小时 前言:怀旧服服务器因为玩家数量太多,稳定性一直是一个问题,因为服务器崩溃已经不是一次两次了,就在昨天夜里又再次发生了,并且这次更加 ...

  4. 服务器向客户机发信息,服务器如何主动给客户端发消息

    服务器如何主动给客户端发消息 内容精选 换一换 当出现以下问题时,可以参考本章节排查解决.可以直接访问后端业务,但是无法通过负载均衡访问后端业务.通过私网IP可以访问负载均衡,但是公网IP无法访问负载 ...

  5. android转服务器吗,王者荣耀角色迁移iOS区可以转安卓区吗 王者荣耀角色迁移iOS区转安卓区详情...

    王者荣耀角色迁移iOS区可以转安卓区吗?王者荣耀在王者营地中推出角色迁移功能,角色迁移上线后不少玩家都在问iOS区可以转安卓区的问题,下面小编带来了王者荣耀角色迁移iOS区转安卓区详情,一起来看看吧. ...

  6. 王者荣耀服务器什么时候增加人数,王者荣耀服务器连续两天崩!春节每人游戏时间暴涨75%,玩家要背锅?...

    原标题:王者荣耀服务器连续两天崩!春节每人游戏时间暴涨75%,玩家要背锅? 相信在这个特殊的春节,游戏就成了没有办法出门的大家选择最多的消遣方式. 但就是在这样的时间,王者荣耀的服务器连着两天崩溃,被 ...

  7. 角色所在服务器正在维护,梦幻西游角色所在服务器,角色所在服务器如何删除...

    超级金柳露和金柳露的作用都是一样的,梦幻西游角色忘记哪个服务器了那就是重置召唤兽的属性.技能,只不过超级金柳露是给参战等级在95级以上的召唤兽使用的,所以它的价格就会比较高,任务中大家获得超级金柳露都 ...

  8. 服务器管理器角色怎么修复,服务器管理器打开角色、功能出错

    一.错误提示 windows 2008系统,打开服务器管理器打开角色.功能出错,界面如下图所示: 查看日志,发现两条常见的错误日志: 1.在 Windows Modules Installer 服务意 ...

  9. MYSQL注入天书之服务器(两层)架构

    Background-6 服务器(两层)架构 首先介绍一下29,30,31这三关的基本情况: 服务器端有两个部分:第一部分为tomcat为引擎的jsp型服务器,第二部分为apache为引擎的php服务 ...

最新文章

  1. 轻松上云系列之一:本地数据迁移上云
  2. 设计模式复习-享元模式
  3. 5月22日 格式与布局
  4. javah找不到类文件
  5. 多生产者-多消费者问题
  6. java初始化虚拟机错误_VM初始化期间发生错误;无法为对象堆保留足够的空间;无法创建Java虚拟机...
  7. vijos 1057 盖房子 dp 最大子正方形
  8. nand flash驱动编写步骤
  9. C++冒泡排序(包含初级、正宗及改进三种实现)
  10. python 字典(数据结构)
  11. 单片机炫彩灯实训报告_单片机实验报告——流水灯
  12. 电脑上的ppt做不了计算机考试,ppt在有的电脑上打不开怎么办
  13. 用STM32F407开发板实现4G模块L610发送短信功能
  14. 使用AndroidStudio开发一个简易的音乐播放器
  15. 高速公路匝道口事故何时了?
  16. kali安装软件源软件
  17. [导入]【沈殿霞张曼玉经典爆笑鬼片】《双肥临门》【国语DVD中字】
  18. revit二开之过滤族(Family)
  19. 一文看懂RabbitMQ
  20. 遥感处理平台的发展(ENVI与GEE的比较)

热门文章

  1. ESP32S蓝牙05
  2. 2020年三月计算机二级甘肃报名官网,2020年3月甘肃计算机二级考试报名时间
  3. gwen语音课_想学习Vuetify? 这是Gwen Faraday的免费15部分课程
  4. Java回炉学习(三)
  5. 华视电子web读取身份证信息
  6. 如何用公式编辑器快速打五角星符号
  7. 水星怎么设置网速最快_水星路由器怎么限制别人网速_水星怎么限制wifi网速?-192路由网...
  8. 光猫-新版水星路由器配置(WiFi连接不上后)
  9. 3D车道线检测能否成为自动驾驶的核心?盘一盘近三年的SOTA论文!
  10. WIN10装cygwin后,打开提示找不到mintty