代码分享(_杰森大师)

Character.h

.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "GameCharacter.generated.h"
class ASWeapon;
class HSHealthComponent;
UCLASS()
class NOSTOPP_API AGameCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AGameCharacter();
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = Camera)
		class	UCameraComponent*CameraComp;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = CameraBoom)
		class USpringArmComponent*Cameraboom;
	UPROPERTY(EditDefaultsOnly, Category = "Player")
		TSubclassOf<ASWeapon> StarterWeaponClass;
	UPROPERTY(VisibleDefaultsOnly, Category = "Player")
		FName WeaponAttachSocketName;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

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 override;
protected:
	void MoveForward(float value);
	void MoveRight(float value);
	void BeginCrouch();
	void EndCrouch();
	void StartFire();
	void EndFire();
	void StopRun();
	void Run();
	void BeginZoom();
	void EndZoom();
	bool bWantToBoom;
	USHealthComponent*HealthComp;
	UPROPERTY(Replicated)
	 ASWeapon* CurrentWeapon;
	UPROPERTY(EditDefaultsOnly, Category = "Player")
		float ZoomFov;

	UPROPERTY(EditDefaultsOnly, Category = "Player", meta = (ClampMin = 0.0, ClampMax = 100))//meta是指把flaot限制在0.1到100之间
		float ZoomInterpSpeed;
	float DefaultFov;

	
	UPROPERTY(Replicated,BlueprintReadOnly,Category="Player")
	bool bDied;
	UFUNCTION()
	void OnHealthChanged(USHealthComponent* OwningHealthComponent, float Health, float HealthDelta, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
	
};




Character.cpp

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

#include "GameCharacter.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/PawnMovementComponent.h"
#include "Public/SWeapon.h"
#include "Components/CapsuleComponent.h"
#include "NoStopP.h"
#include "Components/SHealthComponent.h"
#include "Net/UnrealNetwork.h"
#include "GameFramework/CharacterMovementComponent.h"



// Sets default values
AGameCharacter::AGameCharacter()
{
	// 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;
	Cameraboom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	Cameraboom->bUsePawnControlRotation = true;
	Cameraboom->SetupAttachment(RootComponent);

	GetMovementComponent()->GetNavAgentPropertiesRef().bCanCrouch = true;

	GetCapsuleComponent()->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Ignore);

	HealthComp = CreateDefaultSubobject<USHealthComponent>(TEXT("HealthComp"));
	CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
	CameraComp->SetupAttachment(Cameraboom);
	ZoomFov = 65.0f;
	ZoomInterpSpeed = 20;
	WeaponAttachSocketName = "WeaponSocket";
	
}


// Called when the game starts or when spawned
void AGameCharacter::BeginPlay()
{
	Super::BeginPlay();
	DefaultFov = CameraComp->FieldOfView;
	HealthComp->OnHealthChanged.AddDynamic(this, &AGameCharacter::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);
		}
	}
	//生成默认的武器
}

// Called every frame
void AGameCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	float TargetFov = bWantToBoom ? ZoomFov : DefaultFov;
	float NewFov = FMath::FInterpTo(CameraComp->FieldOfView, TargetFov, DeltaTime, ZoomInterpSpeed);
	CameraComp->SetFieldOfView(NewFov);
}



FVector AGameCharacter::GetPawnViewLocation() const
{
	if (CameraComp)
	{
		return CameraComp->GetComponentLocation();
	}
	return Super::GetPawnViewLocation();
}



void AGameCharacter::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(1.0f);
}

}


void AGameCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(AGameCharacter,CurrentWeapon);
	DOREPLIFETIME(AGameCharacter, bDied);
}


// Called to bind functionality to input
void AGameCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	PlayerInputComponent->BindAction("jump", IE_Pressed, this, &AGameCharacter::Jump);
	PlayerInputComponent->BindAction("Crouch", IE_Pressed, this, &AGameCharacter::BeginCrouch);
	PlayerInputComponent->BindAction("Crouch", IE_Released, this, &AGameCharacter::EndCrouch);
	PlayerInputComponent->BindAction("Zoom", IE_Pressed, this, &AGameCharacter::BeginZoom);
	PlayerInputComponent->BindAction("Zoom", IE_Released, this, &AGameCharacter::EndZoom);
	PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AGameCharacter::StartFire);
	PlayerInputComponent->BindAction("Fire", IE_Released, this, &AGameCharacter::EndFire);
	PlayerInputComponent->BindAction("Run", IE_Pressed, this, &AGameCharacter::Run);
	PlayerInputComponent->BindAction("Run", IE_Released, this, &AGameCharacter::StopRun);
	PlayerInputComponent->BindAxis("MoveForward", this, &AGameCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AGameCharacter::MoveRight);
	PlayerInputComponent->BindAxis("CameraX", this, &AGameCharacter::AddControllerPitchInput);
	PlayerInputComponent->BindAxis("CameraY", this, &AGameCharacter::AddControllerYawInput);

}
void AGameCharacter::MoveForward(float value)
{
	AddMovementInput(GetActorForwardVector()*value);
}

void AGameCharacter::MoveRight(float value)
{
	AddMovementInput(GetActorRightVector()*value);
}
void AGameCharacter::BeginCrouch()
{
	Crouch();
}
void AGameCharacter::EndCrouch()
{
	UnCrouch();
}
void AGameCharacter::BeginZoom()
{
	bWantToBoom = true;
}
void AGameCharacter::EndZoom()
{
	bWantToBoom = false;
}

void AGameCharacter::StartFire()
{
	if (CurrentWeapon)
	{
		CurrentWeapon->StartFire();
	}
}

void AGameCharacter::EndFire()
{
	if (CurrentWeapon)
	{
		CurrentWeapon->EndFire();
	}
}


void AGameCharacter::StopRun()
{
	GetCharacterMovement()->MaxWalkSpeed = 300.f;
}

void AGameCharacter::Run()
{
	GetCharacterMovement()->MaxWalkSpeed =1200.f;

}

SWeapon.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SWeapon.generated.h"


USTRUCT()
struct FHitScanTrace
{
	GENERATED_BODY()
public:
	UPROPERTY()
		TEnumAsByte<EPhysicalSurface> SurfaceType;
	UPROPERTY()
		FVector_NetQuantize TraceTo;

};
UCLASS()
class NOSTOPP_API ASWeapon : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	ASWeapon();
   UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "weapon")
		class USkeletalMeshComponent*MeshComponent;
public:
	void StartFire();
	void EndFire();

protected:

	virtual void BeginPlay() override;
	void Fire();
	void PlayFireEffect(FVector TraceEnd);
	void PlayImpactEffects(EPhysicalSurface SurfaceType, FVector ImpactPoint);


	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "DAMAGE")
		class TSubclassOf<UDamageType> DamageType;
	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "weapon")
		FName MuzzleSocketName;
	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "weapon")
		FName TraceTargetName;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "weapon")
		class UParticleSystem*MuzzleEffect;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "weapon")
		class UParticleSystem*DefaultImpactEffect;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "weapon")
		class UParticleSystem*FleshImpactEffect;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "weapon")
		class UParticleSystem*TraceEffect;
	UPROPERTY(EditDefaultsOnly, Category = "weapon")
		TSubclassOf<UCameraShake> FireCamShake;
	UPROPERTY(EditDefaultsOnly, Category = "weapon")
		float BaseDamage;
	UFUNCTION(Server, Reliable, WithValidation)
		void ServerFire();

	UPROPERTY(ReplicatedUsing = OnRep_HitScanTrace)
		FHitScanTrace HitScanTrace;
	UFUNCTION()
		void OnRep_HitScanTrace();

	float LastFireTime;
	//Second Fire Damo
	UPROPERTY(EditDefaultsOnly, Category = "weapon")
		float RateOfFire;
	//Derived From RateOfRate
	float TimerBetweenShots;

	FTimerHandle TimerHandle_TimeBetweenShot;
};

SWeapon.cpp


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

#include "SWeapon.h"
#include "Components/SkeletalMeshComponent.h"
#include "DrawDebugHelpers.h"
#include "Kismet/GameplayStatics.h"
#include "Particles/ParticleSystem.h"
#include "Particles/ParticleSystemComponent.h"
#include "NoStopP.h"
#include "PhysicalMaterials/PhysicalMaterial.h"
#include "TimerManager.h"
#include "Net/UnrealNetwork.h"

static int32 DebugWeaponDrawing = 0;
FAutoConsoleVariable CVARDebugWeaponDrawing(TEXT("COOP.DebugWeapons"), DebugWeaponDrawing, TEXT("Draw Debug Lines for Weapons"),
	ECVF_Cheat);
// Sets default values
ASWeapon::ASWeapon()
{

	MeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshComp"));
	RootComponent = MeshComponent;

	MuzzleSocketName = "MuzzleSocket";
	TraceTargetName = "Target";

	BaseDamage = 20.0f;

	RateOfFire = 600;
	SetReplicates(true);
	NetUpdateFrequency = 66.0f;
	MinNetUpdateFrequency = 33.0f;
}


void ASWeapon::BeginPlay()
{
	Super::BeginPlay();

	TimerBetweenShots = 60 / RateOfFire;

}

void ASWeapon::StartFire()
{
	float FirstDelay = FMath::Max(LastFireTime + TimerBetweenShots - GetWorld()->TimeSeconds, 0.0f);
	GetWorldTimerManager().SetTimer(TimerHandle_TimeBetweenShot, this, &ASWeapon::Fire, TimerBetweenShots, true, 0.0f);
	Fire();
}

void ASWeapon::EndFire()
{
	GetWorldTimerManager().ClearTimer(TimerHandle_TimeBetweenShot);
}



void ASWeapon::Fire()
{
	if (Role < ROLE_Authority)
	{
		ServerFire();
		
	}

	AActor*MyOwner = GetOwner();//蓝图spawn函数里面有个owner持有者用主角self就可以使用
	if (MyOwner)
	{
		FVector EyeLocation;//发射位置
		FRotator EyeRotation;//发射角度	
		MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotation);//(这函数是获取actor双眼视角)获取发射位置和角度

		FVector ShotDiretion = EyeRotation.Vector();
		FVector traceEnd = EyeLocation + (ShotDiretion * 10000);//最多发射到的位置

		FCollisionQueryParams QueryParams;//碰撞通道
		QueryParams.AddIgnoredActor(MyOwner);
		QueryParams.AddIgnoredActor(this);
		QueryParams.bTraceComplex = true;
		QueryParams.bReturnPhysicalMaterial = true;
		//粒子“目的”参数
		FVector TraceEndPoint = traceEnd;
		EPhysicalSurface SurfaceType = SurfaceType_Default;
		FHitResult Hit;//碰撞hit返回结果
		if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, traceEnd, COLLISION_WEAPON, QueryParams))
		{
			//阻挡hit。点击伤害
			AActor*HitActor = Hit.GetActor();

			EPhysicalSurface SurfaceType = UPhysicalMaterial::DetermineSurfaceType(Hit.PhysMaterial.Get());

			float ActualDamage = BaseDamage;
			if (SurfaceType == SURFACE_FLESHVULNERABLE)
			{
				ActualDamage *= 4.0f;
			}
			UGameplayStatics::ApplyPointDamage(HitActor, ActualDamage, ShotDiretion, Hit, MyOwner->GetInstigatorController(), this, DamageType);
			PlayImpactEffects(SurfaceType, Hit.ImpactPoint);


			TraceEndPoint = Hit.ImpactPoint;

		}
		if (DebugWeaponDrawing > 0)
		{
			DrawDebugLine(GetWorld(), EyeLocation, traceEnd, FColor::White, false, 1.0f, 0, 1.0f);
		}
		/*	DrawDebugLine(GetWorld(), EyeLocation, traceEnd, FColor::White, false, 1.0f, 0, 1.0f);*/

		PlayFireEffect(TraceEndPoint);
		if (Role == ROLE_Authority)
		{
			HitScanTrace.TraceTo = TraceEndPoint;

		}

		LastFireTime = GetWorld()->TimeSeconds;
	}

}

void ASWeapon::PlayFireEffect(FVector TraceEnd)
{
	if (MuzzleEffect)
	{
		UGameplayStatics::SpawnEmitterAttached(MuzzleEffect, MeshComponent, MuzzleSocketName);
	}

	if (TraceEffect)
	{
		FVector MuzzleLocation = MeshComponent->GetSocketLocation(MuzzleSocketName);

		UParticleSystemComponent*TraceComp = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), TraceEffect, MuzzleLocation);
		if (TraceComp)
		{
			TraceComp->SetVectorParameter(TraceTargetName, TraceEnd);
		}
	}
	APawn*MyOwner = Cast<APawn>(GetOwner());
	if (MyOwner)
	{

		APlayerController*PC = Cast<APlayerController>(MyOwner->GetController());
		if (PC)
		{
			PC->ClientPlayCameraShake(FireCamShake);
		}
	}
}
//多人播放冲击FX粒子
void ASWeapon::PlayImpactEffects(EPhysicalSurface SurfaceType, FVector ImpactPoint)
{

	UParticleSystem*SelectedEffect = nullptr;
	switch (SurfaceType)
	{
	case SURFACE_FLESHDEFAULT:
	case SURFACE_FLESHVULNERABLE:
		break;
		SelectedEffect = FleshImpactEffect;
	default:
		SelectedEffect = DefaultImpactEffect;
		break;
	}

	if (SelectedEffect)

	{
		FVector MuzzleLocation = MeshComponent->GetSocketLocation(MuzzleSocketName);
		FVector ShotDirection = ImpactPoint - MuzzleLocation;
		ShotDirection.Normalize();

		UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, ImpactPoint, ShotDirection.Rotation());
	}
}

void ASWeapon::OnRep_HitScanTrace()
{//播发外部特效FX
	PlayFireEffect(HitScanTrace.TraceTo);
	PlayImpactEffects(HitScanTrace.SurfaceType, HitScanTrace.TraceTo);

}
//实现多人射击
void ASWeapon::ServerFire_Implementation()
{
	Fire();
}

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


void ASWeapon::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME_CONDITION(ASWeapon, HitScanTrace, COND_SkipOwner);
}

SHealthComponent.h


#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "SHealthComponent.generated.h"

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 NOSTOPP_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,EditAnywhere, BlueprintReadOnly, Category = "HealthComponent")
		float Health;
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "HealthComponent")
		float DefaultHealth;

	UFUNCTION()
	void HandleTakeAnyDamage( AActor* DamagedActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

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

HealthComponent.cpp


#include "SHealthComponent.h"
#include "Net/UnrealNetwork.h"


// Sets default values for this component's properties
USHealthComponent::USHealthComponent()
{
	
	DefaultHealth = 100;
	// ...
	SetIsReplicated(true);

}


// Called when the game starts
void USHealthComponent::BeginPlay()
{
	Super::BeginPlay();
	//仅当我们为服务器时

	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 class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
{
	if (Damage <= 0.0f)
	{
		return;
	}
	Health = FMath::Clamp(Health - Damage, 0.0f, DefaultHealth);
	UE_LOG(LogTemp, Log, TEXT("Health Changed:%s"), *FString::SanitizeFloat(Health));
	OnHealthChanged.Broadcast(this, Health, Damage, DamageType, InstigatedBy, DamageCauser);
}
// Called every frame
void USHealthComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...
}


void USHealthComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(USHealthComponent, Health);
}

其中有些宏去项目头文件去创建

#pragma once

#include "CoreMinimal.h"

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

效果图,
在这里插入图片描述

发布了20 篇原创文章 · 获赞 1 · 访问量 2706

猜你喜欢

转载自blog.csdn.net/weixin_42295465/article/details/88659259