무기 기본 클래스 확장

무기 기본 클래스의 구현은 이전에 소개되었으며 이제 이 무기 기본 클래스를 기반으로 파생 클래스인 발사체 무기 및 광선 무기를 구현하도록 확장되었습니다.

발사체 무기

.h 파일:

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

#pragma once

#include "CoreMinimal.h"
#include "Weapon.h"
#include "ProjectileWeapon.generated.h"

/**
 * 
 */
UCLASS()
class TPS_API AProjectileWeapon : public AWeapon
{
    
    
	GENERATED_BODY()

public:
	virtual void Fire(const FVector& HitTarget) override;

private:
	UPROPERTY(EditAnywhere)
	TSubclassOf<class AProjectile> ProjectileClass;
};

.cpp 파일:

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


#include "ProjectileWeapon.h"

#include "Projectile.h"
#include "Engine/SkeletalMeshSocket.h"

void AProjectileWeapon::Fire(const FVector& HitTarget)
{
    
    
	Super::Fire(HitTarget);

	if(!HasAuthority()) return;
	
	APawn* InstigatorPawn = Cast<APawn>(GetOwner());
	const USkeletalMeshSocket* MuzzleFlashSocket = GetWeaponMesh()->GetSocketByName(FName("MuzzleFlash"));
	
	if(MuzzleFlashSocket)
	{
    
    
		//获取枪口插槽的Transform,也就是子弹射出的点
		FTransform SocketTransform = MuzzleFlashSocket->GetSocketTransform(GetWeaponMesh());
		//枪口指向射线检测的目标
		FVector ToTarget = HitTarget - SocketTransform.GetLocation();
		FRotator TargetRotation = ToTarget.Rotation();
		if(ProjectileClass && InstigatorPawn)
		{
    
    
			FActorSpawnParameters SpawnParams;
			SpawnParams.Owner = GetOwner();
			SpawnParams.Instigator = InstigatorPawn;
			UWorld* World = GetWorld();
			if(World)
			{
    
    
				World->SpawnActor<AProjectile>(
					ProjectileClass,
					SocketTransform.GetLocation(),
					TargetRotation,
					SpawnParams
				);
			}
		}
	}
}

발사체 무기에 필요한 변경 사항은 많지 않으며 대부분의 함수는 무기 기본 클래스의 메서드를 직접 사용할 수 있습니다. 무기 기본 클래스에서 Fire 함수는 무기 발사 애니메이션, 포탄 방출 및 총알 계산을 구현하므로 발사체 무기는 인스턴스화된 총알을 추가하고 이를 기반으로 함수를 발사하기만 하면 됩니다.

.h 파일에서 재정의된 Fire 함수를 선언하고 총알 클래스 멤버를 선언합니다. Fire 함수는 .cpp 파일에서 재작성하는데, 이는 Weapon Base 클래스의 Fire 함수의 함수가 필요하므로 Super::Fire(HitTarget) 를 사용하여 상위 클래스 함수를 호출하는 것입니다. 그런 다음 무기 객체의 소유자와 총구 슬롯을 가져와서 변수로 저장하고 광선 감지 대상을 가리키는 총구 슬롯과 총구의 변환을 가져와 총알의 위치와 회전을 결정합니다. 생성된 다음 SpawnActor 메서드 Create bullets를 사용합니다. Bullet 관련 기능은 Bullet 클래스에 의해 구현됩니다.

광선 무기

.h 파일:

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

#pragma once

#include "CoreMinimal.h"
#include "Weapon.h"
#include "HitScanWeapon.generated.h"

/**
 * 
 */
UCLASS()
class TPS_API AHitScanWeapon : public AWeapon
{
    
    
	GENERATED_BODY()

public:
	virtual void Fire(const FVector& HitTarget) override;

protected:
	FVector TraceEndWithScatter(const FVector& TraceStart, const FVector& HitTarget);
	void WeaponTraceHit(const FVector& TraceStart, const FVector& HitTarget, FHitResult& OutHit);

	UPROPERTY(EditAnywhere)
	class UParticleSystem* ImpactParticles;

	UPROPERTY(EditAnywhere)
	USoundCue* HitSound;

	UPROPERTY(EditAnywhere)
	float Damage = 20.f;
	
private:
	UPROPERTY(EditAnywhere)
	UParticleSystem* BeamParticles;
	
	UPROPERTY(EditAnywhere, Category = "Weapon Scatter")
	float DistanceToSphere = 800.f;

	UPROPERTY(EditAnywhere, Category = "Weapon Scatter")
	float SphereRadius = 75.f;

	UPROPERTY(EditAnywhere, Category = "Weapon Scatter")
	bool bUseScatter = false;
};

.cpp 파일:

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


#include "HitScanWeapon.h"

#include "DrawDebugHelpers.h"
#include "Engine/SkeletalMeshSocket.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "Particles/ParticleSystemComponent.h"
#include "PhysicalMaterials/PhysicalMaterial.h"
#include "Sound/SoundCue.h"
#include "TPS/TPS.h"
#include "TPS/BlasterComponents/CombatComponent.h"
#include "TPS/Character/BlasterCharacter.h"
#include "TPS/Enemy/Enemy.h"

void AHitScanWeapon::Fire(const FVector& HitTarget)
{
    
    
	Super::Fire(HitTarget);

	APawn* OwnerPawn = Cast<APawn>(GetOwner());
	if(OwnerPawn == nullptr) return;
	AController* InstigatorController = OwnerPawn->GetController();

	const USkeletalMeshSocket* MuzzleFlashSocket = GetWeaponMesh()->GetSocketByName("MuzzleFlash");
	if(MuzzleFlashSocket && InstigatorController)
	{
    
    
		FTransform SocketTransform = MuzzleFlashSocket->GetSocketTransform(GetWeaponMesh());
		FVector Start = SocketTransform.GetLocation();

		FHitResult FireHit;
		WeaponTraceHit(Start, HitTarget, FireHit);
		
		if(FireHit.GetActor() && HasAuthority() && InstigatorController && !Cast<ABlasterCharacter>(FireHit.GetActor()))
		{
    
    
			const float FinalDamage = FireHit.BoneName.ToString() == FString("head") ? Damage * 1.4 : Damage;
			
			UGameplayStatics::ApplyDamage(
				FireHit.GetActor(),
				FinalDamage,
				InstigatorController,
				this,
				UDamageType::StaticClass()
			);
		}
		if(ImpactParticles)
		{
    
    
			UGameplayStatics::SpawnEmitterAtLocation(
				GetWorld(),
				ImpactParticles,
				FireHit.ImpactPoint,
				FireHit.ImpactNormal.Rotation()
			);
		}
		if(HitSound)
		{
    
    
			UGameplayStatics::PlaySoundAtLocation(
				this,
				HitSound,
				FireHit.ImpactPoint
			);
		}
	}
}

void AHitScanWeapon::WeaponTraceHit(const FVector& TraceStart, const FVector& HitTarget, FHitResult& OutHit)
{
    
    
	UWorld* World = GetWorld();
	if (World)
	{
    
    
		FVector End = bUseScatter ? TraceEndWithScatter(TraceStart, HitTarget) : TraceStart + (HitTarget - TraceStart) * 1.25f;

		World->LineTraceSingleByChannel(
			OutHit,
			TraceStart,
			End,
			ECollisionChannel::ECC_Visibility
		);
		FVector BeamEnd = End;
		if (OutHit.bBlockingHit)
		{
    
    
			BeamEnd = OutHit.ImpactPoint;
		}
		if (BeamParticles)
		{
    
    
			UParticleSystemComponent* Beam = UGameplayStatics::SpawnEmitterAtLocation(
				World,
				BeamParticles,
				TraceStart,
				FRotator::ZeroRotator,
				true
			);
			if (Beam)
			{
    
    
				Beam->SetVectorParameter(FName("Target"), BeamEnd);
			}
		}
	}
}


FVector AHitScanWeapon::TraceEndWithScatter(const FVector& TraceStart, const FVector& HitTarget)
{
    
    
	FVector ToTargetNormalized = (HitTarget - TraceStart).GetSafeNormal();
	FVector SphereCenter = TraceStart + ToTargetNormalized * DistanceToSphere;
	FVector RandVec = UKismetMathLibrary::RandomUnitVector() * FMath::FRandRange(0.f, SphereRadius);
	FVector EndLoc = SphereCenter + RandVec;
	FVector ToEndLoc = EndLoc - TraceStart;

	return FVector(TraceStart + ToEndLoc * TRACE_LENGTH / ToEndLoc.Size());
}

광선 무기는 많이 달라진 것 같은데, 주로 물리적 탄환이 없기 때문에 탄환 클래스가 필요 없고 적중과 관련된 기능 함수와 변수가 무기 클래스 자체에 배치되어 있기 때문입니다. .cpp 파일에는 세 가지 방법이 구현되어 있으며, 이에 대해 차례로 소개합니다.

TraceEndWithScatter: 시작 위치 벡터와 목표 지점 벡터를 전달하고 FMath::FRandRange를 사용하여 임의 오프셋을 생성하고 끝 위치에 추가하고 원형 범위 내에서 무작위로 떨어지는 총알 궤적의 효과를 실현합니다.

WeaponTraceHit: 시작 위치 벡터와 목표 지점 벡터, 히트 포인트 참조(OutHit)를 전달하고, 먼저 무기 bUseScatter가 참인지 판단하고, 참이면 총알 오프셋에 적합한 무기라는 뜻입니다. TraceEndWithScatter를 사용하여 오프셋 광선 끝점을 계산합니다. 그렇지 않으면 HitTarget 확장을 광선의 끝점으로 직접 사용한 다음 LineTraceSingleByChannel 메서드를 사용하여 광선이 충돌하는 첫 번째 가시 객체를 감지하고 이를 OutHit에 할당합니다. 히트 포인트를 획득하면 후행 효과가 생성됩니다.

발사: 발사체 무기와 마찬가지로 광선 무기도 발사 애니메이션, 포탄 방출 및 총알 계산과 같은 기능이 필요하므로 Super::Fire(HitTarget)를 호출합니다. 다음 구현은 발사체 무기와 유사하여 무기 홀더와 총구 슬롯을 얻지만 총알을 인스턴스화하는 대신 WeaponTraceHit 메서드를 호출하여 히트 포인트를 얻고 히트 포인트 정보는 FireHit 변수에 저장됩니다. 오브젝트를 때리는 것은 FireHit.GetActor() 메소드를 통해 얻을 수 있으며, 캐릭터 클래스가 아닌 다른 타입으로 변환할 수 있다면 다음 일련의 히트 메소드를 적용할 수 있습니다. 따라서 변환할 수 있는 타격 개체가 역할 유형인 경우 무시됩니다.) 타격 조건이 충족되면 타격 부분이 머리인지 판단하고 직접 ApplyDamage 메서드를 사용하여 데미지를 적용한 다음 입자 효과와 타격음 효과를 생성합니다.

Supongo que te gusta

Origin blog.csdn.net/weixin_47260762/article/details/127707188
Recomendado
Clasificación