• UE4 多人网络对战游戏笔记


    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 class UCameraComponent;
    11 class USpringArmComponent;
    12 class ASWeapon;
    13 class USHealthComponent;
    14 
    15 UCLASS()
    16 class COOPGAME_API ASCharacter : public ACharacter
    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(float value);
    29 
    30     void MoveRight(float value);
    31 
    32     void BeginCrouch();
    33 
    34     void EndCrouch();
    35     UFUNCTION(BlueprintImplementableEvent)
    36     void JumpFromAction();
    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     bool bWantsToZoom;
    48 
    49 
    50     UPROPERTY(EditDefaultsOnly, Category = "Player")
    51     float ZoomedFOV;
    52 
    53     UPROPERTY(EditDefaultsOnly, Category = "Player",meta = (ClampMin = 0.1,ClampMax = 100))
    54     float ZoomInterpSpeed;
    55 
    56     /*default FOV set during begin play*/
    57     float DefaultFOV;
    58 
    59     void BeginZoom();
    60 
    61     void EndZoom();
    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     void StartFire();
    72 
    73     void StopFire();
    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     bool bDied ;
    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 void ASCharacter::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(float value)
     65 {
     66     AddMovementInput(GetActorForwardVector()*value);
     67 }
     68 
     69 void ASCharacter::MoveRight(float value)
     70 {
     71     AddMovementInput(GetActorRightVector()*value);
     72 }
     73 
     74 void ASCharacter::BeginCrouch()
     75 {
     76     Crouch();
     77 }
     78 
     79 void ASCharacter::EndCrouch()
     80 {
     81     UnCrouch();
     82 }
     83 
     84 
     85 void ASCharacter::BeginZoom()
     86 {
     87     bWantsToZoom = true;
     88 }
     89 
     90 void ASCharacter::EndZoom()
     91 {
     92     bWantsToZoom = false;
     93 }
     94 
     95 void ASCharacter::StartFire()
     96 {
     97     if (CurrentWeapon) 
     98     {
     99         CurrentWeapon->StartFire();
    100     }
    101 }
    102 
    103 void ASCharacter::StopFire()
    104 {
    105     if (CurrentWeapon) 
    106     {
    107         CurrentWeapon->StopFire();
    108     }
    109 }
    110 
    111 void ASCharacter::OnHealthChanged(USHealthComponent* HealthComp, float Health, float HealthDelta, 
    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(float DeltaTime)
    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     return FVector();
    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 class USHealthComponent;
    10 class URadialForceComponent;
    11 class UParticleSystem;
    12 UCLASS()
    13 class COOPGAME_API ASExplosiveBarrel : public AActor
    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, float HealthDelta, 
    36             const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
    37 
    38     UPROPERTY(ReplicatedUsing = OnRep_Exploded)
    39         bool bExploded;
    40 
    41     UFUNCTION()
    42         void OnRep_Exploded();
    43 
    44     UPROPERTY(EditDefaultsOnly, Category = "FX")
    45         float ExplosionImpulse;
    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 void ASExplosiveBarrel::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 void ASExplosiveBarrel::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 : public UActorComponent
    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     float Health;
    26 
    27     UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = "HealthComponent")
    28     float DefaultHealth;
    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 void USHealthComponent::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 class UDamageType;
     10 class UParticleSystem;
     11 
     12 //
     13 USTRUCT()
     14 struct FHitScanTrace
     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 : public AActor
     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     void PlayFireEffects(FVector TraceEnd);
     43 
     44     void PlayImpatEffects(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     float BaseDamage;
     71 
     72     UFUNCTION(Server, Reliable, WithValidation)
     73     void ServerFire();
     74 
     75     FTimerHandle TimerHandle_TimeBetweenShots;
     76 
     77     float LastFireTime;
     78 
     79     /*RPM- Bullets per minute fired by weapon*/
     80     UPROPERTY(EditDefaultsOnly, Category = "Weapon")
     81     float RateOfFire;
     82 
     83     float TimeBetweenShots;
     84 
     85     UPROPERTY(ReplicatedUsing = OnRep_HitScanTrace)
     86     FHitScanTrace HitScanTrace;
     87 
     88     UFUNCTION()
     89     void OnRep_HitScanTrace();
     90 public:    
     91     // Called every frame
     92     virtual void Tick(float DeltaTime) override;
     93 
     94     UFUNCTION(BlueprintCallable, Category = "Weapon")
     95     virtual void Fire();
     96 
     97 
     98     void StartFire();
     99 
    100     void StopFire();
    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 void ASWeapon::BeginPlay()
     45 {
     46     Super::BeginPlay();
     47     
     48     TimeBetweenShots = 60 / RateOfFire;
     49 }
     50 
     51 void ASWeapon::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 void ASWeapon::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 void ASWeapon::StopFire()
    128 {
    129     GetWorldTimerManager().ClearTimer(TimerHandle_TimeBetweenShots);
    130 }
    131 
    132 void ASWeapon::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 void ASWeapon::PlayImpatEffects(EPhysicalSurface SurfaceType,FVector ImpactPoint)
    165 {
    166     UParticleSystem* SelectedEffect = nullptr;
    167     switch (SurfaceType)
    168     {
    169     case  SURFACE_FLESHDEFAULT:
    170     case  SURFACE_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 void ASWeapon::ServerFire_Implementation()
    189 {
    190     Fire();
    191 }
    192 
    193 bool ASWeapon::ServerFire_Validate()
    194 {
    195     return true;
    196 }
    197 
    198 void ASWeapon::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(float DeltaTime)
    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 : public ASWeapon
    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 void ASProjectileWeapon::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
  • 相关阅读:
    ArcMap操作随记(10)
    python的matplotlib.pyplot绘制甘特图
    C# 使用Newtonsoft.Json读写Json文件
    MVVM-后台代码绑定事件命令
    abp vue did you register the component correctly
    .net orm写入oracle数据库的clob字段提示:"ORA-01461:仅可以插入LONG列的LONG值赋值"
    WindowsServer2012 IIS8 500.19错误 ExtensionlessUrlHandler-Integrated-4.0
    Wpf TextBox 如何简单粗暴的实现水印效果?
    面向对象23种设计模式系列(三)- 行为型设计模式
    值类型取值范围、与运算(&)、或运算(|)、非运算(~)、异或运算(^)、位运算和位枚举
  • 原文地址:https://www.cnblogs.com/yukiArea/p/10255882.html
Copyright © 2020-2023  润新知