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{} //在服务器上,自己处理开火
源码贴:
// 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 多人网络对战游戏笔记的更多相关文章
- JAVASCRIPT开发HTML5游戏--斗地主(网络对战PART4)
继之前用游戏引擎(青瓷引擎)做了斗地主单机版游戏之后,这里分享下使用socket.io来实现网络对战,代码可已放到github上,在此谈谈自己整个的开发思路吧. 客户端代码 服务端代码 (点击图片进入 ...
- Android手游《》斗地主完整的源代码(支持单机和网络对战)
Android手游<斗地主>完整的源代码(支持单机和网络对战)下载.一个很不错的源代码. 斗地主掌游是一个独特的国内社会斗地主棋牌游戏,之后玩家可以下载网上斗地主和全世界.掌游斗地主特点: ...
- ADO.Net(五)——实战:对战游戏
对战游戏 要求: 自建数据表(例如:数据表包含:代号,姓名,性别,血量,攻击力,防御力,命中,闪避,等级等字段) 需要通过程序向数据表添加人员 添加的时候,根据用户输入的名字,自动计算生成相应的血量. ...
- C#小游戏(文字对战游戏)
第一代,不是很完善,会在后续增加更多的功能 主: using System; using System.Collections.Generic; using System.Linq; using Sy ...
- 【经典】C++&RPG对战游戏
博文背景: 还记大二上学期的时候看的这个C++&RPG游戏(博主大一下学期自学的php,涵盖oop内容),一个外校的同学他们大一学的C++,大二初期C++实训要求做一个程序填空,就是这个 RP ...
- c#部分---网吧充值系统;简易的闹钟;出租车计费;简单计算器;对战游戏;等额本金法计算贷款还款利息等;随机生成10个不重复的50以内的整数;推箱子;
网吧充值系统namespace ConsoleApplication1 { class Program { struct huiyuan { public string name; public st ...
- ADO.NET 扩展属性、配置文件 和 对战游戏
扩展属性 有外键关系时将信息处理成用户可看懂的 利用扩展属性 如:Info表中的民族列显示的是民族代号处理成Nation表中的民族名称 需要在Info类里面扩展一个显示nation名称的属性 例:先前 ...
- C# 推箱子游戏&对战游戏
推箱子游戏提纲,只有向右向上的操作,向左向下同理,后期需完善. namespace 推箱子 { class Program { static void Main(string[] args) { // ...
- 基于Udp的五子棋对战游戏
引言 本文主要讲述在局域网内,使用c#基于Udp协议编写一个对战的五子棋游戏.主要从Udp的使用.游戏的绘制.对战的逻辑这三个部分来讲解. 开发环境:vs2013,.Net4.0,在文章的末尾提供源代 ...
随机推荐
- Spark配置参数详解
以下是整理的Spark中的一些配置参数,官方文档请参考Spark Configuration. Spark提供三个位置用来配置系统: Spark属性:控制大部分的应用程序参数,可以用SparkConf ...
- Linux基础入门-文件系统操作与磁盘管理
一.简单文件系统操作: df (-h) 查看磁盘容量: rootfs作为系统启动时内核载入内存之后,在挂载真正的磁盘之前的一个临时文件系统: /dev/sda2 对应主机硬盘的分区,后面的a表示第几块 ...
- 机器学习实战ch04 关于python版本所支持的文本格式问题
函数定义中: def spamTest(): docList=[]; classList = []; fullText =[] for i in range(1,26):# print('cycle ...
- python yield返回多个值
yield可以返回多个值到setup函数中去,但是需要用括号括起来,然后下面具体的函数接受到传值就不需要每次都实例化了. 举例如下: @pytest.fixture()def setup(driver ...
- TensorFlow-GPU+cuda8+cudnn6+anaconda安装遇到的版本错误
第一遍装的时候是cuda10+cudnn5.1这个诡异的组合,失败 卸载cuda就是把所有的NVIDIA有关的应用都删掉,c盘文件也都删掉,不用留. 第二遍是cuda8+cudnn5.1.版本还是对不 ...
- note 8 字符串
字符串String 一个字符的序列 使用成对的单引号或双引号括起来 或者三引号""" 和 ''' 表示块注释 字符串运算 长度 len()函数 first_name = ...
- 傻瓜学编程之block_3
block 捕获自动变量的瞬间值: 注释在代码中:请参考傻瓜学编程之block_3 import "People.h" @interface People() { int your ...
- Pandas学习笔记(三)
(1)系列对象( Series)基本功能 编号 属性或方法 描述 1 axes 返回行轴标签列表. 2 dtype 返回对象的数据类型(dtype). 3 empty 如果系列为空,则返回True. ...
- 检查 TCP 80 端口是否正常工作
检查 TCP 80 端口是否正常工作 2017-09-13 22:12:50 目录 Windows Server 2012 Windows Server 2008 CentOS 7.3 Ubuntu ...
- mongodb mac
==> mongodb To have launchd start mongodb now and restart at login: brew services start mongodb O ...