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{}          //在服务器上,自己处理开火

源码贴:

 // Fill out your copyright notice in the Description page of Project Settings.

 #pragma once

 #include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include"Public/SWeapon.h"
#include "SCharacter.generated.h" class UCameraComponent;
class USpringArmComponent;
class ASWeapon;
class USHealthComponent; UCLASS()
class COOPGAME_API ASCharacter : public ACharacter
{
GENERATED_BODY() public:
// Sets default values for this character's properties
ASCharacter(); protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override; void MoveForward(float value); void MoveRight(float value); void BeginCrouch(); void EndCrouch();
UFUNCTION(BlueprintImplementableEvent)
void JumpFromAction(); UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Components")
UCameraComponent* CameraComp; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
USpringArmComponent* SpringArmComp; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
USHealthComponent* HealthComp; bool bWantsToZoom; UPROPERTY(EditDefaultsOnly, Category = "Player")
float ZoomedFOV; UPROPERTY(EditDefaultsOnly, Category = "Player",meta = (ClampMin = 0.1,ClampMax = ))
float ZoomInterpSpeed; /*default FOV set during begin play*/
float DefaultFOV; void BeginZoom(); void EndZoom(); UPROPERTY(Replicated)
ASWeapon* CurrentWeapon; UPROPERTY(EditDefaultsOnly,Category = "Player")
TSubclassOf<ASWeapon> StarterWeaponClass; UPROPERTY(VisibleDefaultsOnly,Category = "Player")
FName WeaponAttachSocketName;
void StartFire(); void StopFire(); UFUNCTION()
void OnHealthChanged(USHealthComponent* OwingHealthComp, float Health, float HealthDelta, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser); UPROPERTY(Replicated,BlueprintReadOnly,Category = "Player")
bool bDied ;
public:
// Called every frame
virtual void Tick(float DeltaTime) override; // Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; virtual FVector GetPawnViewLocation() const; };

SCharacter.h

 // Fill out your copyright notice in the Description page of Project Settings.

 #include "Public/SCharacter.h"
#include"Camera/CameraComponent.h"
#include"GameFramework/SpringArmComponent.h"
#include"Components/CapsuleComponent.h"
#include"CoopGame/CoopGame.h"
#include"SHealthComponent.h"
#include"GameFramework/PawnMovementComponent.h"
#include"Net/UnrealNetwork.h" // Sets default values
ASCharacter::ASCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true; SpringArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComp"));
SpringArmComp->bUsePawnControlRotation = true;
SpringArmComp->SetupAttachment(RootComponent); GetMovementComponent()->GetNavAgentPropertiesRef().bCanCrouch = true; GetCapsuleComponent()->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Ignore); HealthComp = CreateDefaultSubobject<USHealthComponent>(TEXT("HealthComp")); CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
CameraComp->bUsePawnControlRotation = true;
CameraComp->SetupAttachment(SpringArmComp); ZoomedFOV = 65.0f;
ZoomInterpSpeed = 20.0f; WeaponAttachSocketName = "WeaponSocket";
} // Called when the game starts or when spawned
void ASCharacter::BeginPlay()
{
Super::BeginPlay(); DefaultFOV = CameraComp->FieldOfView; HealthComp->OnHealthChanged.AddDynamic(this, &ASCharacter::OnHealthChanged); if (Role == ROLE_Authority)
{ FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; CurrentWeapon = GetWorld()->SpawnActor<ASWeapon>(StarterWeaponClass, FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);
if (CurrentWeapon)
{
CurrentWeapon->SetOwner(this);
CurrentWeapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale,WeaponAttachSocketName);
} }
} void ASCharacter::MoveForward(float value)
{
AddMovementInput(GetActorForwardVector()*value);
} void ASCharacter::MoveRight(float value)
{
AddMovementInput(GetActorRightVector()*value);
} void ASCharacter::BeginCrouch()
{
Crouch();
} void ASCharacter::EndCrouch()
{
UnCrouch();
} void ASCharacter::BeginZoom()
{
bWantsToZoom = true;
} void ASCharacter::EndZoom()
{
bWantsToZoom = false;
} void ASCharacter::StartFire()
{
if (CurrentWeapon)
{
CurrentWeapon->StartFire();
}
} void ASCharacter::StopFire()
{
if (CurrentWeapon)
{
CurrentWeapon->StopFire();
}
} void ASCharacter::OnHealthChanged(USHealthComponent* HealthComp, float Health, float HealthDelta,
const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
{
if (Health <= 0.0f && !bDied)
{
bDied = true;
GetMovementComponent()->StopMovementImmediately();
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision); DetachFromControllerPendingDestroy(); SetLifeSpan(10.0f);
}
} // Called every frame
void ASCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime); float TargetFOV = bWantsToZoom ? ZoomedFOV : DefaultFOV; float NewFOV = FMath::FInterpTo(CameraComp->FieldOfView, TargetFOV, DeltaTime, ZoomInterpSpeed);
CameraComp->SetFieldOfView(NewFOV); } // Called to bind functionality to input
void ASCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent); PlayerInputComponent->BindAxis("MoveForward", this, &ASCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ASCharacter::MoveRight); PlayerInputComponent->BindAxis("LookUp", this, &ASCharacter::AddControllerPitchInput);
PlayerInputComponent->BindAxis("Turn", this, &ASCharacter::AddControllerYawInput); PlayerInputComponent->BindAction("Crouch", IE_Pressed,this, &ASCharacter::BeginCrouch);
PlayerInputComponent->BindAction("Crouch", IE_Released,this, &ASCharacter::EndCrouch); PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ASCharacter::JumpFromAction); PlayerInputComponent->BindAction("Zoom", IE_Pressed, this, &ASCharacter::BeginZoom);
PlayerInputComponent->BindAction("Zoom", IE_Released, this, &ASCharacter::EndZoom); PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ASCharacter::StartFire);
PlayerInputComponent->BindAction("Fire", IE_Released, this, &ASCharacter::StopFire);
} FVector ASCharacter::GetPawnViewLocation() const
{
if (CameraComp)
{
return CameraComp->GetComponentLocation();
} return FVector();
}
void ASCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(ASCharacter, CurrentWeapon);
DOREPLIFETIME(ASCharacter, bDied);
}

SCharacter.cpp

 // Fill out your copyright notice in the Description page of Project Settings.

 #pragma once

 #include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SExplosiveBarrel.generated.h" class USHealthComponent;
class URadialForceComponent;
class UParticleSystem;
UCLASS()
class COOPGAME_API ASExplosiveBarrel : public AActor
{
GENERATED_BODY() public:
// Sets default values for this actor's properties
ASExplosiveBarrel(); protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override; UPROPERTY(VisibleAnywhere,Category = "Components")
USHealthComponent* HealthComp; UPROPERTY(VisibleAnywhere, Category = "Components")
UStaticMeshComponent* MeshComp; UPROPERTY(VisibleAnywhere, Category = "Components")
URadialForceComponent* RadialForceComp; UFUNCTION()
void OnHealthChanged(USHealthComponent* OwningHealthComp, float Health, float HealthDelta,
const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser); UPROPERTY(ReplicatedUsing = OnRep_Exploded)
bool bExploded; UFUNCTION()
void OnRep_Exploded(); UPROPERTY(EditDefaultsOnly, Category = "FX")
float ExplosionImpulse;
UPROPERTY(EditDefaultsOnly, Category = "FX")
UParticleSystem* ExplosionEffect;
UPROPERTY(EditDefaultsOnly, Category = "FX")
UMaterialInterface* ExplodedMaterial; public: };

SExplosiveBarrel.h

 // Fill out your copyright notice in the Description page of Project Settings.

 #include "SExplosiveBarrel.h"
#include"SHealthComponent.h"
#include"Kismet/GameplayStatics.h"
#include"PhysicsEngine/RadialForceComponent.h"
#include"Components/StaticMeshComponent.h"
#include"Net/UnrealNetwork.h" // Sets default values
ASExplosiveBarrel::ASExplosiveBarrel()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
HealthComp = CreateDefaultSubobject<USHealthComponent>(TEXT("HealthComp"));
HealthComp->OnHealthChanged.AddDynamic(this, &ASExplosiveBarrel::OnHealthChanged); MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
RootComponent = MeshComp; 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
RadialForceComp->bIgnoreOwningActor = true;//ignore self ExplosionImpulse = ; SetReplicates(true);
SetReplicateMovement(true); } // Called when the game starts or when spawned
void ASExplosiveBarrel::BeginPlay()
{
Super::BeginPlay(); } 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(, ExplodedMaterial);
RadialForceComp->FireImpulse();
}
} void ASExplosiveBarrel::OnRep_Exploded()
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ExplosionEffect, GetActorLocation());
MeshComp->SetMaterial(, ExplodedMaterial);
} void ASExplosiveBarrel::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(ASExplosiveBarrel,bExploded);
}

SExplosiveBarrel.cpp

 // Fill out your copyright notice in the Description page of Project Settings.

 #pragma once

 #include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "SHealthComponent.generated.h" //OnHealthChanged event
DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, USHealthComponent*, HealthComp, float, Health, float, HealthDelta, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);
UCLASS( ClassGroup=(COOP), meta=(BlueprintSpawnableComponent))
class COOPGAME_API USHealthComponent : public UActorComponent
{
GENERATED_BODY() public:
// Sets default values for this component's properties
USHealthComponent(); protected:
// Called when the game starts
virtual void BeginPlay() override; UPROPERTY(Replicated,BlueprintReadOnly,Category = "HealthComponent")
float Health; UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = "HealthComponent")
float DefaultHealth; UFUNCTION()
void HandleTakeAnyDamage(AActor* DamagedActor ,float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser); public: UPROPERTY(BlueprintAssignable,Category = "Events")
FOnHealthChangedSignature OnHealthChanged; };

SHealthComponent.h

 // Fill out your copyright notice in the Description page of Project Settings.

 #include "SHealthComponent.h"
#include"Net/UnrealNetwork.h" // Sets default values for this component's properties
USHealthComponent::USHealthComponent()
{
DefaultHealth = ; SetIsReplicated(true);
} // Called when the game starts
void USHealthComponent::BeginPlay()
{
Super::BeginPlay(); // ...
// Only hook if we are server
if (GetOwnerRole() == ROLE_Authority)
{ AActor* MyOwner = GetOwner(); if (MyOwner)
{
MyOwner->OnTakeAnyDamage.AddDynamic(this, &USHealthComponent::HandleTakeAnyDamage);
}
} Health = DefaultHealth;
} 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);
}
void USHealthComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(USHealthComponent, Health);
}

SHealthComponent.cpp

 // Fill out your copyright notice in the Description page of Project Settings.

 #pragma once

 #include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SWeapon.generated.h" class UDamageType;
class UParticleSystem; //
USTRUCT()
struct FHitScanTrace
{
GENERATED_BODY() public:
UPROPERTY()
TEnumAsByte<EPhysicalSurface> SurfaceType;
UPROPERTY()
FVector_NetQuantize TraceTo;
}; UCLASS()
class COOPGAME_API ASWeapon : public AActor
{
GENERATED_BODY() public:
// Sets default values for this actor's properties
ASWeapon(); protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override; UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Components")
USkeletalMeshComponent* MeshComp; void PlayFireEffects(FVector TraceEnd); void PlayImpatEffects(EPhysicalSurface SurfaceType, FVector ImpactPoint); UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
TSubclassOf<UDamageType> DamageType; UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
FName MuzzleSocketName;
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
FName TracerTargetName; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
UParticleSystem* MuzzleEffect; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
UParticleSystem*DefaultImpactEffect; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
UParticleSystem*FleshImpactEffect; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
UParticleSystem*TraceEffect; UPROPERTY(EditDefaultsOnly, Category = "Weapon")
TSubclassOf<UCameraShake> FireCameraShake; UPROPERTY(EditDefaultsOnly, Category = "Weapon")
float BaseDamage; UFUNCTION(Server, Reliable, WithValidation)
void ServerFire(); FTimerHandle TimerHandle_TimeBetweenShots; float LastFireTime; /*RPM- Bullets per minute fired by weapon*/
UPROPERTY(EditDefaultsOnly, Category = "Weapon")
float RateOfFire; float TimeBetweenShots; UPROPERTY(ReplicatedUsing = OnRep_HitScanTrace)
FHitScanTrace HitScanTrace; UFUNCTION()
void OnRep_HitScanTrace();
public:
// Called every frame
virtual void Tick(float DeltaTime) override; UFUNCTION(BlueprintCallable, Category = "Weapon")
virtual void Fire(); void StartFire(); void StopFire(); };

SWeapon.h

 // Fill out your copyright notice in the Description page of Project Settings.

 #include "Public/SWeapon.h"
#include"Components/SkeletalMeshComponent.h"
#include"DrawDebugHelpers.h"
#include"Kismet/GameplayStatics.h"
#include"Particles/ParticleSystem.h"
#include"PhysicalMaterials/PhysicalMaterial.h"
#include"Particles/ParticleSystemComponent.h"
#include"CoopGame.h"
#include"TimerManager.h"
#include"Net/UnrealNetwork.h" static int32 DebugWeaponDrawing = ;
FAutoConsoleVariableRef CVARDebugWeaponDrawing(
TEXT("COOP.DebugWeapons"),
DebugWeaponDrawing,
TEXT("Draw Debug Lines for Weapons"),
ECVF_Cheat);
// Sets default values
ASWeapon::ASWeapon()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true; MeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshComp"));
RootComponent = MeshComp; MuzzleSocketName = "MuzzleSocket";
TracerTargetName = "Target"; BaseDamage = 20.0f; RateOfFire = ; SetReplicates(true); NetUpdateFrequency = 66.0f;
MinNetUpdateFrequency = 33.0f;
} // Called when the game starts or when spawned
void ASWeapon::BeginPlay()
{
Super::BeginPlay(); TimeBetweenShots = / RateOfFire;
} void ASWeapon::Fire()
{
//Trace the World ,form pawn eyes to cross hair location if (Role < ROLE_Authority)
{
ServerFire();
} AActor* MyOwner = GetOwner();
if (MyOwner)
{
FVector EyeLocation;
FRotator EyeRotation;
MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation); FVector ShotDirection = EyeRotation.Vector();
FVector TraceEnd = EyeLocation + (ShotDirection * ); FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(MyOwner);
QueryParams.AddIgnoredActor(this);
QueryParams.bTraceComplex = true;
QueryParams.bReturnPhysicalMaterial = true; //Particle"Target"parameter
FVector TracerEndPoint = TraceEnd; EPhysicalSurface SurfaceType = SurfaceType_Default; FHitResult Hit;
if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON,QueryParams))
{
AActor* HitActor = Hit.GetActor(); EPhysicalSurface SurfaceType = UPhysicalMaterial::DetermineSurfaceType(Hit.PhysMaterial.Get()); float ActualDamage = BaseDamage;
if (SurfaceType == SURFACE_FLESHVULNERABLE)
{
//UE_LOG(LogTemp, Warning, TEXT(".........................."));
ActualDamage *= 4.0f;
} UGameplayStatics::ApplyPointDamage(HitActor, ActualDamage, ShotDirection, Hit, MyOwner->GetInstigatorController(), this, DamageType); PlayImpatEffects(SurfaceType, Hit.ImpactPoint); TracerEndPoint = Hit.ImpactPoint; HitScanTrace.SurfaceType = SurfaceType;
}
if (DebugWeaponDrawing > )
{
DrawDebugLine(GetWorld(), EyeLocation, TraceEnd, FColor::White, false, 1.0f, , 1.0f);
}
PlayFireEffects(TracerEndPoint); if (Role == ROLE_Authority)
{
HitScanTrace.TraceTo = TracerEndPoint; } LastFireTime = GetWorld()->TimeSeconds;
}
} void ASWeapon::StartFire()
{
float FirstDelay =FMath::Max(LastFireTime + TimeBetweenShots - GetWorld()->TimeSeconds,0.0f); GetWorldTimerManager().SetTimer(TimerHandle_TimeBetweenShots,this,&ASWeapon::Fire, TimeBetweenShots, true, FirstDelay); } void ASWeapon::StopFire()
{
GetWorldTimerManager().ClearTimer(TimerHandle_TimeBetweenShots);
} void ASWeapon::PlayFireEffects(FVector TraceEnd)
{
if (MuzzleEffect)
{
UGameplayStatics::SpawnEmitterAttached(MuzzleEffect, MeshComp, MuzzleSocketName);
} if (TraceEffect)
{
FVector MuzzleLocation = MeshComp->GetSocketLocation(MuzzleSocketName); UParticleSystemComponent* TracerComp = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), TraceEffect, MuzzleLocation); if (TracerComp)
{
TracerComp->SetVectorParameter("Target", TraceEnd);
}
} APawn* MyOwner = Cast<APawn>(GetOwner()); if (MyOwner)
{
APlayerController* PC = Cast<APlayerController>(MyOwner->GetController());
if (PC)
{
PC->ClientPlayCameraShake(FireCameraShake);
} }
} void ASWeapon::PlayImpatEffects(EPhysicalSurface SurfaceType,FVector ImpactPoint)
{
UParticleSystem* SelectedEffect = nullptr;
switch (SurfaceType)
{
case SURFACE_FLESHDEFAULT:
case SURFACE_FLESHVULNERABLE:
SelectedEffect = FleshImpactEffect;
break;
default:
SelectedEffect = DefaultImpactEffect;
break;
}
if (SelectedEffect)
{
FVector MuzzleLocation = MeshComp->GetSocketLocation(MuzzleSocketName);
FVector ShotDirection = ImpactPoint - MuzzleLocation;
ShotDirection.Normalize();
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, ImpactPoint, ShotDirection.Rotation()); } } void ASWeapon::ServerFire_Implementation()
{
Fire();
} bool ASWeapon::ServerFire_Validate()
{
return true;
} void ASWeapon::OnRep_HitScanTrace()
{
//play cosmetic FX
PlayFireEffects(HitScanTrace.TraceTo);
PlayImpatEffects(HitScanTrace.SurfaceType, HitScanTrace.TraceTo);
} // Called every frame
void ASWeapon::Tick(float DeltaTime)
{
Super::Tick(DeltaTime); } void ASWeapon::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME_CONDITION(ASWeapon, HitScanTrace,COND_SkipOwner);
}

SWeapon.cpp

 // Fill out your copyright notice in the Description page of Project Settings.

 #pragma once

 #include "CoreMinimal.h"

 #define SURFACE_FLESHDEFAULT        SurfaceType1
#define SURFACE_FLESHVULNERABLE SurfaceType2 #define COLLISION_WEAPON ECC_GameTraceChannel1

CoopGame.h

 // Fill out your copyright notice in the Description page of Project Settings.

 #include "CoopGame.h"
#include "Modules/ModuleManager.h" IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, CoopGame, "CoopGame" );

CoopGame.cpp

 // Fill out your copyright notice in the Description page of Project Settings.

 #pragma once

 #include "CoreMinimal.h"
#include "SWeapon.h"
#include "SProjectileWeapon.generated.h" /**
*
*/
UCLASS()
class COOPGAME_API ASProjectileWeapon : public ASWeapon
{
GENERATED_BODY() protected: virtual void Fire() override;
UPROPERTY(EditDefaultsOnly,Category = "ProjectileWeapon")
TSubclassOf<AActor> ProjectileClass;
};

SProjectileWeapon.h

 // Fill out your copyright notice in the Description page of Project Settings.

 #include "Public/SProjectileWeapon.h"

 void ASProjectileWeapon::Fire()
{
AActor* MyOwner = GetOwner();
if (MyOwner && ProjectileClass)
{
FVector EyeLocation;
FRotator EyeRotation;
MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation); FVector MuzzleLocation = MeshComp->GetSocketLocation(MuzzleSocketName); FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; GetWorld()->SpawnActor<AActor>(ProjectileClass,MuzzleLocation,EyeRotation, SpawnParams);
}
}

SProjectileWeapon.cpp

UE4 多人网络对战游戏笔记的更多相关文章

  1. JAVASCRIPT开发HTML5游戏--斗地主(网络对战PART4)

    继之前用游戏引擎(青瓷引擎)做了斗地主单机版游戏之后,这里分享下使用socket.io来实现网络对战,代码可已放到github上,在此谈谈自己整个的开发思路吧. 客户端代码 服务端代码 (点击图片进入 ...

  2. Android手游《》斗地主完整的源代码(支持单机和网络对战)

    Android手游<斗地主>完整的源代码(支持单机和网络对战)下载.一个很不错的源代码. 斗地主掌游是一个独特的国内社会斗地主棋牌游戏,之后玩家可以下载网上斗地主和全世界.掌游斗地主特点: ...

  3. ADO.Net(五)——实战:对战游戏

    对战游戏 要求: 自建数据表(例如:数据表包含:代号,姓名,性别,血量,攻击力,防御力,命中,闪避,等级等字段) 需要通过程序向数据表添加人员 添加的时候,根据用户输入的名字,自动计算生成相应的血量. ...

  4. C#小游戏(文字对战游戏)

    第一代,不是很完善,会在后续增加更多的功能 主: using System; using System.Collections.Generic; using System.Linq; using Sy ...

  5. 【经典】C++&RPG对战游戏

    博文背景: 还记大二上学期的时候看的这个C++&RPG游戏(博主大一下学期自学的php,涵盖oop内容),一个外校的同学他们大一学的C++,大二初期C++实训要求做一个程序填空,就是这个 RP ...

  6. c#部分---网吧充值系统;简易的闹钟;出租车计费;简单计算器;对战游戏;等额本金法计算贷款还款利息等;随机生成10个不重复的50以内的整数;推箱子;

    网吧充值系统namespace ConsoleApplication1 { class Program { struct huiyuan { public string name; public st ...

  7. ADO.NET 扩展属性、配置文件 和 对战游戏

    扩展属性 有外键关系时将信息处理成用户可看懂的 利用扩展属性 如:Info表中的民族列显示的是民族代号处理成Nation表中的民族名称 需要在Info类里面扩展一个显示nation名称的属性 例:先前 ...

  8. C# 推箱子游戏&对战游戏

    推箱子游戏提纲,只有向右向上的操作,向左向下同理,后期需完善. namespace 推箱子 { class Program { static void Main(string[] args) { // ...

  9. 基于Udp的五子棋对战游戏

    引言 本文主要讲述在局域网内,使用c#基于Udp协议编写一个对战的五子棋游戏.主要从Udp的使用.游戏的绘制.对战的逻辑这三个部分来讲解. 开发环境:vs2013,.Net4.0,在文章的末尾提供源代 ...

随机推荐

  1. day061 cookie和session

    一. cookie 1.cookie 的原理 工作原理是:浏览器访问服务端,带着一个空的cookie,然后由服务器产生内容, 浏览器收到相应后保存在本地:当浏览器再次访问时,浏览器会自动带上Cooki ...

  2. java 运算符的优先级比较

    口诀:淡云一笔安洛三福 单目>算数运算符>移位>比较>按位>逻辑>三目>赋值 单目运算符:+,-,++,-- 算数运算符:+,-,*,/,% 移位运算符:&l ...

  3. Javascript校验密码复杂度的正则表达式

    1.密码中必须包含大小字母.数字.特称字符,至少8个字符,最多30个字符. var regex = new RegExp('(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.* ...

  4. VSCode扩展包离线安装

    下载离线包 下载地址:https://marketplace.visualstudio.com/vscode 安装离线包

  5. 树莓派中学TensorFlow

    树莓派中默认的虚拟环境为python 2.x,需要用下面的-p参数修改为python3环境.电信wifi和公司网络直接用pip3 install TensorFlow都不好使,用联通手机热点可以安装. ...

  6. C# 6.0:Null – Conditional 操作符

    在引入nameof操作符的同时,C# 6.0 还引入了Null-Conditional操作符.它使开发者可以检查object引用链中的null值.这个null-conditional 操作符写作&qu ...

  7. Scrapy实战篇(七)之爬取爱基金网站基金业绩数据

    本篇我们以scrapy+selelum的方式来爬取爱基金网站(http://fund.10jqka.com.cn/datacenter/jz/)的基金业绩数据. 思路:我们以http://fund.1 ...

  8. mybatis关于ORM的使用以及设计(三)[参数对象转换为SQL语言]

    上节分析了Mapper对象的创建. 在ORM的定义中可以理解为Object->SQLMapper抽象层(这一层并不负责具体的SQL执行.这一层可以理解为SQL代理层) 本节分析以下内容: ①Sq ...

  9. 02-cookie简单使用

    @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletExcep ...

  10. 刘志梅201771010115.《面向对象程序设计(java)》第十五周学习总结

    实验十五  GUI编程练习与应用程序部署 实验时间 2018-12-6 1.实验目的与要求 (1)一个JAR文件既可以包含类文件,也可以包含诸如图像和声音这些其他类型的文件. 创建一个新的JAR文件应 ...