UE4 多人网络对战游戏笔记

摘要:
1.向对象施加径向力以定义径向力:URadialForceComponent*RadicalForceComp;在构造函数中指定默认值:RadialForceComp=CreateDefaultSubobject(TEXT(“RadialForceComp”));RadialForceComp-˃设置附件(MeshComp);R

1.给物体施加一个径向力

定义一个径向力:

URadialForceComponent* RadialForceComp;

在构造函数里赋默认值:

RadialForceComp = CreateDefaultSubobject<URadialForceComponent>(TEXT("RadialForceComp"));
RadialForceComp->SetupAttachment(MeshComp);
RadialForceComp->Radius = 250.0f; //力影响的半径范围
RadialForceComp->bImpulseVelChange = true;//作用力速率变化为真
RadialForceComp->bAutoActivate = false;//prevent component from ticking, and only use fireImpulse() instead把自动激活关闭,用fireimpulse的方法来代替
RadialForceComp->bIgnoreOwningActor = true;//是否忽略自身

触发:

RadialForceComp->FireImpulse();

2.创建一个ActorComponent处理主角掉血事件

新建一个类 继承自UActorComponent:

class COOPGAME_API USHealthComponent : public UActorComponent

定义一个OnHealthChanged的事件:

UPROPERTY(BlueprintAssignable,Category = "Events")
FOnHealthChangedSignature OnHealthChanged;

在UCLASS的上面声明这个事件:

DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, USHealthComponent*, HealthComp, float, Health, float, HealthDelta, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);//定义一个动态、多播、委托、六个参数的事件

定义一个HandleTakeAnyDamage的事件来处理受到的伤害:

UFUNCTION()
void HandleTakeAnyDamage(AActor* DamagedActor ,float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);

将主角受到的伤害动态绑定到HandleTakeAnyDamage上:

AActor* MyOwner = GetOwner();

if (MyOwner)
{
MyOwner->OnTakeAnyDamage.AddDynamic(this, &USHealthComponent::HandleTakeAnyDamage);
}

实现HandleTakeAnyDamage方法:

void USHealthComponent::HandleTakeAnyDamage(AActor * DamagedActor, float Damage, const UDamageType * DamageType, AController * InstigatedBy, AActor * DamageCauser)
{
if (Damage <= 0.0f)
{
return;
}

//update helth clamped
Health = FMath::Clamp(Health - Damage, 0.0f, DefaultHealth);

UE_LOG(LogTemp, Warning, TEXT("Health Changed: %s"),*FString::SanitizeFloat(Health));

OnHealthChanged.Broadcast(this, Health, Damage, DamageType, InstigatedBy, DamageCauser);//将参数广播给OnHealthChanged
}

3.若要让服务器和客户端同时表现一样的效果,需要让服务器通知客户端该做什么,但代码依然在服务器端执行

将是否爆破的UPROPERTY加上ReplicatedUsing = OnRep_Exploded:

UPROPERTY(ReplicatedUsing = OnRep_Exploded)
bool bExploded;

定义一个事件OnRep_Exploded将上述实现

UFUNCTION()
void OnRep_Exploded();

在血量为0时,同时执行OnRep_Exploded() 函数,目的是为了让客户端表现和服务器端一样的状态:

void ASExplosiveBarrel::OnHealthChanged(USHealthComponent * OwningHealthComp, float Health, float HealthDelta, const UDamageType * DamageType, AController * InstigatedBy, AActor * DamageCauser)
{
if (bExploded)
{
return;
}
if (Health <= 0.0f)
{
bExploded = true;
OnRep_Exploded();
FVector BoostIntensity = FVector::UpVector * ExplosionImpulse;
MeshComp->AddImpulse(BoostIntensity, NAME_None, true);

UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ExplosionEffect, GetActorLocation());
MeshComp->SetMaterial(0, ExplodedMaterial);
RadialForceComp->FireImpulse();
}
}

void ASExplosiveBarrel::OnRep_Exploded()
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ExplosionEffect, GetActorLocation());
MeshComp->SetMaterial(0, ExplodedMaterial);
}

接下来记得在生命周期中复制bExploded给客户端,在cpp中引入头文件#include"Net/UnrealNetwork.h"后即可直接添加GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const 方法,后面的参数可保持不变:

void ASExplosiveBarrel::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);

DOREPLIFETIME(ASExplosiveBarrel,bExploded);
}

4.客户端服务器端同步

在构造函数中设置可重复为true:

SetReplicates(true);

定义一个服务器开火的事件,设置UFUNCTION里面的内容:

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

接着在cpp里添加服务器开火函数的_Implementation和_Validate,直接在ServerFire后添加(Validate有时候不需要):

void ASWeapon::ServerFire_Implementation()
{
Fire();
}

bool ASWeapon::ServerFire_Validate()
{
return true;
}

判断Role是否在服务器上:

if (Role < ROLE_Authority) //判断Role是否在服务器上
{
ServerFire(); //Role < ROLE_Authority,说明不在服务器上,让Server处理这个开火
}

else{}          //在服务器上,自己处理开火

源码贴:

1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #pragma once
4 
5 #include "CoreMinimal.h"
6 #include "GameFramework/Character.h"
7 #include"Public/SWeapon.h"
8 #include "SCharacter.generated.h"
9 
10 classUCameraComponent;
11 classUSpringArmComponent;
12 classASWeapon;
13 classUSHealthComponent;
14 
15 UCLASS()
16 class COOPGAME_API ASCharacter : publicACharacter
17 {
18 GENERATED_BODY()
19 
20 public:
21     //Sets default values for this character's properties
22 ASCharacter();
23 
24 protected:
25     //Called when the game starts or when spawned
26     virtual void BeginPlay() override;
27 
28     void MoveForward(floatvalue);
29 
30     void MoveRight(floatvalue);
31 
32     voidBeginCrouch();
33 
34     voidEndCrouch();
35 UFUNCTION(BlueprintImplementableEvent)
36     voidJumpFromAction();
37 
38     UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Components")
39     UCameraComponent*CameraComp;
40 
41     UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
42     USpringArmComponent*SpringArmComp;
43 
44     UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
45     USHealthComponent*HealthComp;
46 
47     boolbWantsToZoom;
48 
49 
50     UPROPERTY(EditDefaultsOnly, Category = "Player")
51     floatZoomedFOV;
52 
53     UPROPERTY(EditDefaultsOnly, Category = "Player",meta = (ClampMin = 0.1,ClampMax = 100))
54     floatZoomInterpSpeed;
55 
56     /*default FOV set during begin play*/
57     floatDefaultFOV;
58 
59     voidBeginZoom();
60 
61     voidEndZoom();
62 
63 UPROPERTY(Replicated)
64     ASWeapon*CurrentWeapon;
65 
66     UPROPERTY(EditDefaultsOnly,Category = "Player")
67     TSubclassOf<ASWeapon>StarterWeaponClass;
68 
69     UPROPERTY(VisibleDefaultsOnly,Category = "Player")
70 FName WeaponAttachSocketName;
71     voidStartFire();
72 
73     voidStopFire();
74 
75 UFUNCTION()
76     void OnHealthChanged(USHealthComponent* OwingHealthComp, float Health, float HealthDelta, const class UDamageType* DamageType, class AController* InstigatedBy, AActor*DamageCauser);
77 
78     UPROPERTY(Replicated,BlueprintReadOnly,Category = "Player")
79     boolbDied ;
80 public:    
81     //Called every frame
82     virtual void Tick(float DeltaTime) override;
83 
84     //Called to bind functionality to input
85     virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
86 
87     virtual FVector GetPawnViewLocation() const;
88     
89 };
SCharacter.h
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #include "Public/SCharacter.h"
4 #include"Camera/CameraComponent.h"
5 #include"GameFramework/SpringArmComponent.h"
6 #include"Components/CapsuleComponent.h"
7 #include"CoopGame/CoopGame.h"
8 #include"SHealthComponent.h"
9 #include"GameFramework/PawnMovementComponent.h"
10 #include"Net/UnrealNetwork.h"
11 
12 
13 //Sets default values
14 ASCharacter::ASCharacter()
15 {
16      //Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
17     PrimaryActorTick.bCanEverTick = true;
18 
19     SpringArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComp"));
20     SpringArmComp->bUsePawnControlRotation = true;
21     SpringArmComp->SetupAttachment(RootComponent);
22 
23     GetMovementComponent()->GetNavAgentPropertiesRef().bCanCrouch = true;
24 
25     GetCapsuleComponent()->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Ignore);
26 
27     HealthComp = CreateDefaultSubobject<USHealthComponent>(TEXT("HealthComp"));
28 
29     CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
30     CameraComp->bUsePawnControlRotation = true;
31     CameraComp->SetupAttachment(SpringArmComp);
32 
33     ZoomedFOV = 65.0f;
34     ZoomInterpSpeed = 20.0f;
35 
36     WeaponAttachSocketName = "WeaponSocket";
37 }
38 
39 //Called when the game starts or when spawned
40 voidASCharacter::BeginPlay()
41 {
42 Super::BeginPlay();
43     
44     DefaultFOV = CameraComp->FieldOfView;
45 
46     HealthComp->OnHealthChanged.AddDynamic(this, &ASCharacter::OnHealthChanged);
47 
48     if (Role ==ROLE_Authority) 
49 {
50 
51 FActorSpawnParameters SpawnParams;
52     SpawnParams.SpawnCollisionHandlingOverride =ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
53 
54     CurrentWeapon = GetWorld()->SpawnActor<ASWeapon>(StarterWeaponClass, FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);
55     if(CurrentWeapon) 
56 {
57         CurrentWeapon->SetOwner(this);
58         CurrentWeapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale,WeaponAttachSocketName);
59 }
60 
61 }
62 }
63 
64 void ASCharacter::MoveForward(floatvalue)
65 {
66     AddMovementInput(GetActorForwardVector()*value);
67 }
68 
69 void ASCharacter::MoveRight(floatvalue)
70 {
71     AddMovementInput(GetActorRightVector()*value);
72 }
73 
74 voidASCharacter::BeginCrouch()
75 {
76 Crouch();
77 }
78 
79 voidASCharacter::EndCrouch()
80 {
81 UnCrouch();
82 }
83 
84 
85 voidASCharacter::BeginZoom()
86 {
87     bWantsToZoom = true;
88 }
89 
90 voidASCharacter::EndZoom()
91 {
92     bWantsToZoom = false;
93 }
94 
95 voidASCharacter::StartFire()
96 {
97     if(CurrentWeapon) 
98 {
99         CurrentWeapon->StartFire();
100 }
101 }
102 
103 voidASCharacter::StopFire()
104 {
105     if(CurrentWeapon) 
106 {
107         CurrentWeapon->StopFire();
108 }
109 }
110 
111 void ASCharacter::OnHealthChanged(USHealthComponent* HealthComp, float Health, floatHealthDelta, 
112     const class UDamageType* DamageType, class AController* InstigatedBy, AActor*DamageCauser)
113 {
114     if (Health <= 0.0f && !bDied) 
115 {
116         bDied = true;
117         GetMovementComponent()->StopMovementImmediately();
118         GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
119 
120 DetachFromControllerPendingDestroy();
121 
122         SetLifeSpan(10.0f);
123 }
124 }
125 
126 //Called every frame
127 void ASCharacter::Tick(floatDeltaTime)
128 {
129 Super::Tick(DeltaTime);
130 
131     float TargetFOV = bWantsToZoom ?ZoomedFOV : DefaultFOV;
132 
133     float NewFOV = FMath::FInterpTo(CameraComp->FieldOfView, TargetFOV, DeltaTime, ZoomInterpSpeed);
134     CameraComp->SetFieldOfView(NewFOV);
135 
136 }
137 
138 //Called to bind functionality to input
139 void ASCharacter::SetupPlayerInputComponent(UInputComponent*PlayerInputComponent)
140 {
141 Super::SetupPlayerInputComponent(PlayerInputComponent);
142 
143     PlayerInputComponent->BindAxis("MoveForward", this, &ASCharacter::MoveForward);
144     PlayerInputComponent->BindAxis("MoveRight", this, &ASCharacter::MoveRight);
145 
146     PlayerInputComponent->BindAxis("LookUp", this, &ASCharacter::AddControllerPitchInput);
147     PlayerInputComponent->BindAxis("Turn", this, &ASCharacter::AddControllerYawInput);
148 
149     PlayerInputComponent->BindAction("Crouch", IE_Pressed,this, &ASCharacter::BeginCrouch);
150     PlayerInputComponent->BindAction("Crouch", IE_Released,this, &ASCharacter::EndCrouch);
151 
152     PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ASCharacter::JumpFromAction);
153 
154     PlayerInputComponent->BindAction("Zoom", IE_Pressed, this, &ASCharacter::BeginZoom);
155     PlayerInputComponent->BindAction("Zoom", IE_Released, this, &ASCharacter::EndZoom);
156 
157     PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ASCharacter::StartFire);
158     PlayerInputComponent->BindAction("Fire", IE_Released, this, &ASCharacter::StopFire);
159 }
160 
161 FVector ASCharacter::GetPawnViewLocation() const
162 {
163     if(CameraComp) 
164 {
165         return CameraComp->GetComponentLocation();
166 }
167 
168     returnFVector();
169 }
170 void ASCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
171 {
172 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
173 
174 DOREPLIFETIME(ASCharacter, CurrentWeapon);
175 DOREPLIFETIME(ASCharacter, bDied);
176 }
SCharacter.cpp
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #pragma once
4 
5 #include "CoreMinimal.h"
6 #include "GameFramework/Actor.h"
7 #include "SExplosiveBarrel.generated.h"
8 
9 classUSHealthComponent;
10 classURadialForceComponent;
11 classUParticleSystem;
12 UCLASS()
13 class COOPGAME_API ASExplosiveBarrel : publicAActor
14 {
15 GENERATED_BODY()
16     
17 public:    
18     //Sets default values for this actor's properties
19 ASExplosiveBarrel();
20 
21 protected:
22     //Called when the game starts or when spawned
23     virtual void BeginPlay() override;
24 
25     UPROPERTY(VisibleAnywhere,Category = "Components")
26     USHealthComponent*HealthComp;
27 
28     UPROPERTY(VisibleAnywhere, Category = "Components")
29     UStaticMeshComponent*MeshComp;
30 
31     UPROPERTY(VisibleAnywhere, Category = "Components")
32     URadialForceComponent*RadialForceComp;
33 
34 UFUNCTION()
35         void OnHealthChanged(USHealthComponent* OwningHealthComp, float Health, floatHealthDelta, 
36             const class UDamageType* DamageType, class AController* InstigatedBy, AActor*DamageCauser);
37 
38     UPROPERTY(ReplicatedUsing =OnRep_Exploded)
39         boolbExploded;
40 
41 UFUNCTION()
42         voidOnRep_Exploded();
43 
44     UPROPERTY(EditDefaultsOnly, Category = "FX")
45         floatExplosionImpulse;
46     UPROPERTY(EditDefaultsOnly, Category = "FX")
47         UParticleSystem*ExplosionEffect;
48     UPROPERTY(EditDefaultsOnly, Category = "FX")
49         UMaterialInterface*ExplodedMaterial;
50 
51 
52 public:    
53 
54 
55     
56     
57 };
SExplosiveBarrel.h
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #include "SExplosiveBarrel.h"
4 #include"SHealthComponent.h"
5 #include"Kismet/GameplayStatics.h"
6 #include"PhysicsEngine/RadialForceComponent.h"
7 #include"Components/StaticMeshComponent.h"
8 #include"Net/UnrealNetwork.h"
9 
10 
11 //Sets default values
12 ASExplosiveBarrel::ASExplosiveBarrel()
13 {
14      //Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
15     HealthComp = CreateDefaultSubobject<USHealthComponent>(TEXT("HealthComp"));
16     HealthComp->OnHealthChanged.AddDynamic(this, &ASExplosiveBarrel::OnHealthChanged);
17 
18     MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
19     RootComponent =MeshComp;
20 
21     RadialForceComp = CreateDefaultSubobject<URadialForceComponent>(TEXT("RadialForceComp"));
22     RadialForceComp->SetupAttachment(MeshComp);
23     RadialForceComp->Radius = 250.0f;
24     RadialForceComp->bImpulseVelChange = true;
25     RadialForceComp->bAutoActivate = false;//prevent component from ticking, and only use fireImpulse() instead
26     RadialForceComp->bIgnoreOwningActor = true;//ignore self
27 
28     ExplosionImpulse = 400;
29 
30     SetReplicates(true);
31     SetReplicateMovement(true);
32 
33 }
34 
35 //Called when the game starts or when spawned
36 voidASExplosiveBarrel::BeginPlay()
37 {
38 Super::BeginPlay();
39     
40 }
41 
42 void ASExplosiveBarrel::OnHealthChanged(USHealthComponent * OwningHealthComp, float Health, float HealthDelta, const UDamageType * DamageType, AController * InstigatedBy, AActor *DamageCauser)
43 {
44     if(bExploded) 
45 {
46         return;
47 }
48     if (Health <= 0.0f) 
49 {
50         bExploded = true;
51 OnRep_Exploded();
52         FVector BoostIntensity = FVector::UpVector *ExplosionImpulse;
53         MeshComp->AddImpulse(BoostIntensity, NAME_None, true);
54 
55 UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ExplosionEffect, GetActorLocation());
56         MeshComp->SetMaterial(0, ExplodedMaterial);
57         RadialForceComp->FireImpulse();
58 }
59 }
60 
61 voidASExplosiveBarrel::OnRep_Exploded()
62 {
63 UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ExplosionEffect, GetActorLocation());
64     MeshComp->SetMaterial(0, ExplodedMaterial);
65 }
66 
67 void ASExplosiveBarrel::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
68 {
69 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
70 
71 DOREPLIFETIME(ASExplosiveBarrel,bExploded);
72 }
SExplosiveBarrel.cpp
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #pragma once
4 
5 #include "CoreMinimal.h"
6 #include "Components/ActorComponent.h"
7 #include "SHealthComponent.generated.h"
8 
9 //OnHealthChanged event
10 DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, USHealthComponent*, HealthComp, float, Health, float, HealthDelta, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);
11 UCLASS( ClassGroup=(COOP), meta=(BlueprintSpawnableComponent))
12 class COOPGAME_API USHealthComponent : publicUActorComponent
13 {
14 GENERATED_BODY()
15 
16 public:    
17     //Sets default values for this component's properties
18 USHealthComponent();
19 
20 protected:
21     //Called when the game starts
22     virtual void BeginPlay() override;
23 
24     UPROPERTY(Replicated,BlueprintReadOnly,Category = "HealthComponent")
25     floatHealth;
26 
27     UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = "HealthComponent")
28     floatDefaultHealth;
29 
30 UFUNCTION()
31     void HandleTakeAnyDamage(AActor* DamagedActor ,float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor*DamageCauser);
32 
33 
34 public:    
35 
36     UPROPERTY(BlueprintAssignable,Category = "Events")
37 FOnHealthChangedSignature    OnHealthChanged;
38     
39 };
SHealthComponent.h
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #include "SHealthComponent.h"
4 #include"Net/UnrealNetwork.h"
5 
6 
7 //Sets default values for this component's properties
8 USHealthComponent::USHealthComponent()
9 {
10     DefaultHealth = 100;
11 
12     SetIsReplicated(true);
13 }
14 
15 
16 //Called when the game starts
17 voidUSHealthComponent::BeginPlay()
18 {
19 Super::BeginPlay();
20 
21     //...
22     //Only hook if we are server
23     if (GetOwnerRole() ==ROLE_Authority) 
24 {
25 
26         AActor* MyOwner =GetOwner();
27 
28         if(MyOwner)
29 {
30             MyOwner->OnTakeAnyDamage.AddDynamic(this, &USHealthComponent::HandleTakeAnyDamage);
31 }
32 }
33 
34 
35     Health =DefaultHealth;
36 }
37 
38 void USHealthComponent::HandleTakeAnyDamage(AActor * DamagedActor, float Damage, const UDamageType * DamageType, AController * InstigatedBy, AActor *DamageCauser)
39 {
40     if (Damage <= 0.0f) 
41 {
42         return;
43 }
44 
45     //update helth clamped
46     Health = FMath::Clamp(Health - Damage, 0.0f, DefaultHealth);
47 
48     UE_LOG(LogTemp, Warning, TEXT("Health Changed: %s"),*FString::SanitizeFloat(Health));
49 
50     OnHealthChanged.Broadcast(this, Health, Damage, DamageType, InstigatedBy, DamageCauser);
51 }
52 void USHealthComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
53 {
54 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
55 
56 DOREPLIFETIME(USHealthComponent, Health);
57 }
SHealthComponent.cpp
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #pragma once
4 
5 #include "CoreMinimal.h"
6 #include "GameFramework/Actor.h"
7 #include "SWeapon.generated.h"
8 
9 classUDamageType;
10 classUParticleSystem;
11 
12 //
13 USTRUCT()
14 structFHitScanTrace
15 {
16 GENERATED_BODY()
17 
18 public:
19 UPROPERTY()
20     TEnumAsByte<EPhysicalSurface>SurfaceType;
21 UPROPERTY()
22 FVector_NetQuantize TraceTo;
23 };
24 
25 UCLASS()
26 class COOPGAME_API ASWeapon : publicAActor
27 {
28 GENERATED_BODY()
29     
30 public:    
31     //Sets default values for this actor's properties
32 ASWeapon();
33 
34 protected:
35     //Called when the game starts or when spawned
36     virtual void BeginPlay() override;
37 
38     UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Components")
39     USkeletalMeshComponent*MeshComp;
40 
41 
42     voidPlayFireEffects(FVector TraceEnd);
43 
44     voidPlayImpatEffects(EPhysicalSurface SurfaceType, FVector ImpactPoint);
45 
46     UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
47     TSubclassOf<UDamageType>DamageType;
48 
49     UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
50 FName MuzzleSocketName;
51     UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
52 FName TracerTargetName;
53 
54     UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
55     UParticleSystem*MuzzleEffect;
56 
57     UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
58     UParticleSystem*DefaultImpactEffect;
59 
60     UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
61     UParticleSystem*FleshImpactEffect;
62 
63     UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
64     UParticleSystem*TraceEffect;
65 
66     UPROPERTY(EditDefaultsOnly, Category = "Weapon")
67     TSubclassOf<UCameraShake>FireCameraShake;
68 
69     UPROPERTY(EditDefaultsOnly, Category = "Weapon")
70     floatBaseDamage;
71 
72 UFUNCTION(Server, Reliable, WithValidation)
73     voidServerFire();
74 
75 FTimerHandle TimerHandle_TimeBetweenShots;
76 
77     floatLastFireTime;
78 
79     /*RPM- Bullets per minute fired by weapon*/
80     UPROPERTY(EditDefaultsOnly, Category = "Weapon")
81     floatRateOfFire;
82 
83     floatTimeBetweenShots;
84 
85     UPROPERTY(ReplicatedUsing =OnRep_HitScanTrace)
86 FHitScanTrace HitScanTrace;
87 
88 UFUNCTION()
89     voidOnRep_HitScanTrace();
90 public:    
91     //Called every frame
92     virtual void Tick(float DeltaTime) override;
93 
94     UFUNCTION(BlueprintCallable, Category = "Weapon")
95     virtual voidFire();
96 
97 
98     voidStartFire();
99 
100     voidStopFire();
101 
102     
103 };
SWeapon.h
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #include "Public/SWeapon.h"
4 #include"Components/SkeletalMeshComponent.h"
5 #include"DrawDebugHelpers.h"
6 #include"Kismet/GameplayStatics.h"
7 #include"Particles/ParticleSystem.h"
8 #include"PhysicalMaterials/PhysicalMaterial.h"
9 #include"Particles/ParticleSystemComponent.h"
10 #include"CoopGame.h"
11 #include"TimerManager.h"
12 #include"Net/UnrealNetwork.h"
13 
14 
15 static int32 DebugWeaponDrawing = 0;
16 FAutoConsoleVariableRef CVARDebugWeaponDrawing(
17     TEXT("COOP.DebugWeapons"),
18 DebugWeaponDrawing, 
19     TEXT("Draw Debug Lines for Weapons"), 
20 ECVF_Cheat);
21 //Sets default values
22 ASWeapon::ASWeapon()
23 {
24      //Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
25     PrimaryActorTick.bCanEverTick = true;
26 
27     MeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshComp"));
28     RootComponent =MeshComp;
29 
30     MuzzleSocketName = "MuzzleSocket";    
31     TracerTargetName = "Target";
32 
33     BaseDamage = 20.0f;
34 
35     RateOfFire = 600;
36 
37     SetReplicates(true);
38 
39     NetUpdateFrequency = 66.0f;
40     MinNetUpdateFrequency = 33.0f;
41 }
42 
43 //Called when the game starts or when spawned
44 voidASWeapon::BeginPlay()
45 {
46 Super::BeginPlay();
47     
48     TimeBetweenShots = 60 /RateOfFire;
49 }
50 
51 voidASWeapon::Fire()
52 {
53     //Trace the World ,form pawn eyes to cross hair location
54 
55     if (Role <ROLE_Authority) 
56 {
57 ServerFire();
58 }
59 
60     AActor* MyOwner =GetOwner();
61     if(MyOwner) 
62 {
63 FVector EyeLocation;
64 FRotator EyeRotation;
65         MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation);
66 
67         FVector ShotDirection =EyeRotation.Vector();
68         FVector TraceEnd = EyeLocation + (ShotDirection * 10000);
69 
70 FCollisionQueryParams QueryParams;
71 QueryParams.AddIgnoredActor(MyOwner);
72         QueryParams.AddIgnoredActor(this);
73         QueryParams.bTraceComplex = true;
74         QueryParams.bReturnPhysicalMaterial = true;
75 
76         //Particle"Target"parameter
77         FVector TracerEndPoint =TraceEnd;
78 
79         EPhysicalSurface SurfaceType =SurfaceType_Default;
80 
81 FHitResult Hit;
82         if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON,QueryParams))
83 {
84             AActor* HitActor =Hit.GetActor();
85 
86             EPhysicalSurface SurfaceType =UPhysicalMaterial::DetermineSurfaceType(Hit.PhysMaterial.Get());
87 
88             float ActualDamage =BaseDamage;
89             if (SurfaceType ==SURFACE_FLESHVULNERABLE) 
90 {  
91                 //UE_LOG(LogTemp, Warning, TEXT(".........................."));
92                  ActualDamage *= 4.0f;
93 }
94 
95             UGameplayStatics::ApplyPointDamage(HitActor, ActualDamage, ShotDirection, Hit, MyOwner->GetInstigatorController(), this, DamageType);
96 
97 PlayImpatEffects(SurfaceType, Hit.ImpactPoint);
98 
99             TracerEndPoint =Hit.ImpactPoint;
100 
101             HitScanTrace.SurfaceType =SurfaceType;
102 }
103         if (DebugWeaponDrawing > 0)
104 {
105             DrawDebugLine(GetWorld(), EyeLocation, TraceEnd, FColor::White, false, 1.0f, 0, 1.0f);
106 }
107 PlayFireEffects(TracerEndPoint);
108 
109         if (Role ==ROLE_Authority) 
110 {
111             HitScanTrace.TraceTo =TracerEndPoint;
112 
113 }
114     
115         LastFireTime = GetWorld()->TimeSeconds;
116 }
117 }
118 
119 voidASWeapon::StartFire()
120 {
121     float FirstDelay =FMath::Max(LastFireTime + TimeBetweenShots - GetWorld()->TimeSeconds,0.0f);
122 
123     GetWorldTimerManager().SetTimer(TimerHandle_TimeBetweenShots,this,&ASWeapon::Fire, TimeBetweenShots, true, FirstDelay);
124 
125 }
126 
127 voidASWeapon::StopFire()
128 {
129 GetWorldTimerManager().ClearTimer(TimerHandle_TimeBetweenShots);
130 }
131 
132 voidASWeapon::PlayFireEffects(FVector TraceEnd)
133 {
134     if(MuzzleEffect)
135 {
136 UGameplayStatics::SpawnEmitterAttached(MuzzleEffect, MeshComp, MuzzleSocketName);
137 }
138 
139     if(TraceEffect)
140 {
141         FVector MuzzleLocation = MeshComp->GetSocketLocation(MuzzleSocketName);
142 
143         UParticleSystemComponent* TracerComp =UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), TraceEffect, MuzzleLocation);
144 
145         if(TracerComp)
146 {
147             TracerComp->SetVectorParameter("Target", TraceEnd);
148 }
149 }
150 
151     APawn* MyOwner = Cast<APawn>(GetOwner());
152 
153     if(MyOwner) 
154 {
155         APlayerController* PC = Cast<APlayerController>(MyOwner->GetController());
156         if(PC) 
157 {
158             PC->ClientPlayCameraShake(FireCameraShake);
159 }
160 
161 }
162 }
163 
164 voidASWeapon::PlayImpatEffects(EPhysicalSurface SurfaceType,FVector ImpactPoint)
165 {
166     UParticleSystem* SelectedEffect =nullptr;
167     switch(SurfaceType)
168 {
169     caseSURFACE_FLESHDEFAULT:
170     caseSURFACE_FLESHVULNERABLE:
171         SelectedEffect =FleshImpactEffect;
172         break;
173     default:
174         SelectedEffect =DefaultImpactEffect;
175         break;
176 }
177     if(SelectedEffect)
178 {
179         FVector MuzzleLocation = MeshComp->GetSocketLocation(MuzzleSocketName);
180         FVector ShotDirection = ImpactPoint -MuzzleLocation;
181 ShotDirection.Normalize();
182 UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, ImpactPoint, ShotDirection.Rotation());
183 
184 }
185 
186 }
187 
188 voidASWeapon::ServerFire_Implementation()
189 {
190 Fire();
191 }
192 
193 boolASWeapon::ServerFire_Validate()
194 {
195     return true;
196 }
197 
198 voidASWeapon::OnRep_HitScanTrace()
199 {
200     //play cosmetic FX
201 PlayFireEffects(HitScanTrace.TraceTo);
202 PlayImpatEffects(HitScanTrace.SurfaceType, HitScanTrace.TraceTo);
203 }
204 
205 //Called every frame
206 void ASWeapon::Tick(floatDeltaTime)
207 {
208 Super::Tick(DeltaTime);
209 
210 }
211 
212 void ASWeapon::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
213 {
214 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
215 
216 DOREPLIFETIME_CONDITION(ASWeapon, HitScanTrace,COND_SkipOwner);
217 }
SWeapon.cpp
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #pragma once
4 
5 #include "CoreMinimal.h"
6 
7 #define SURFACE_FLESHDEFAULT        SurfaceType1
8 #define SURFACE_FLESHVULNERABLE        SurfaceType2
9 
10 #define COLLISION_WEAPON            ECC_GameTraceChannel1
CoopGame.h
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #include "CoopGame.h"
4 #include "Modules/ModuleManager.h"
5 
6 IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, CoopGame, "CoopGame" );
CoopGame.cpp
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #pragma once
4 
5 #include "CoreMinimal.h"
6 #include "SWeapon.h"
7 #include "SProjectileWeapon.generated.h"
8 
9 /**
10 * 
11  */
12 UCLASS()
13 class COOPGAME_API ASProjectileWeapon : publicASWeapon
14 {
15 GENERATED_BODY()
16     
17     
18 protected:
19 
20     virtual void Fire() override;
21     UPROPERTY(EditDefaultsOnly,Category = "ProjectileWeapon")
22     TSubclassOf<AActor>ProjectileClass;
23 };
SProjectileWeapon.h
1 //Fill out your copyright notice in the Description page of Project Settings.
2 
3 #include "Public/SProjectileWeapon.h"
4 
5 voidASProjectileWeapon::Fire() 
6 {
7     AActor* MyOwner =GetOwner();
8     if (MyOwner &&ProjectileClass)
9 {
10 FVector EyeLocation;
11 FRotator EyeRotation;
12         MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation);
13 
14         FVector MuzzleLocation = MeshComp->GetSocketLocation(MuzzleSocketName);
15 
16 FActorSpawnParameters SpawnParams;
17         SpawnParams.SpawnCollisionHandlingOverride =ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
18 
19         GetWorld()->SpawnActor<AActor>(ProjectileClass,MuzzleLocation,EyeRotation, SpawnParams);
20 }
21 }
SProjectileWeapon.cpp

免责声明:文章转载自《UE4 多人网络对战游戏笔记》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇QML动态创建自定义组件LXD 2.0 系列(七):LXD 中的 Docker下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

移动通信网络中的 GTP 协议

在EPSUP中使用GTP的优点之一是GTP具有固有的可识别隧道机制和GTP可以为UE提供的移动性。注意:GTPv2-U协议不存在。GTP-C协议GTP-C是GTP的控制平面,使用UDP端口2123。在EPS中,GTPv2-C协议负责创建、维护和删除S1、S5/S8和其他接口上的GTP-U隧道。它是一种基于IP的隧道协议,允许在GTP UProtocolEnt...

汇编指令MOV

格式:MOVDST,SRC例如:MOVEAX,#050aH;将十六进制050a传送到通用寄存器eax中MOVDI,BXMOVES,AXMOVAX,DSMOVAL,23HMOV[2000H],02HMOV[2061H],BX...

前端导航站点(PC端)

本篇LIST1.项目预览地址:项目预览地址2.项目完成效果:3.HTML布局拆分1.tip提示部分2.title标题部分3.搜索栏部分找的是codepen上现成的搜索框样式,包含搜索框展开收缩的特效。...

使用Docker构建redis集群

将六个独立的Redis节点关联到主机上的Redis集群中。Redis部落。rb是Redis官方提供的一个ruby脚本,用于构建Redis集群并修改Redis conf将其移动到上部路径/usr/docker_root/redis_Cluster/。受保护模式norequipassa1s2W3l4%Greunbind无法连接到凹坑以构建Redis基本映像。9....

PLSQL 美化规则文件详解

开始---①createtablestudent;结束;--② 美化效果是:开始——① CREATETABLESTUDENT;结束;--②...

一些替代Xshell的软件推荐

TransmitTransmit是一个30美元价格的共享软件,它覆盖了几乎所有的常用功能,包括远程文件编辑和文件夹同步,尽管其有30美元的价格,很多Windows用户也希望Transmit能出一个Win版的。FireFTPFireFTP是一个Firefox扩展,能直接集成一个强大的FTP客户端到我们最喜爱的浏览器Firefox上。CyberduckCyber...