
어제에 이어서 미사일 아이템 작업을 진행하였다.
// V12HomingMissile.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "V12HomingMissile.generated.h"
class USphereComponent;
class UProjectileMovementComponent;
UCLASS()
class V12_THE_GAME_API AV12HomingMissile : public AActor
{
GENERATED_BODY()
public:
AV12HomingMissile();
void SetHomingTarget(AActor* NewTarget);
virtual void Tick(float DeltaTime) override;
void CheckArrival();
protected:
virtual void BeginPlay() override;
UFUNCTION()
void OnMissileHit
(
UPrimitiveComponent* HitComp,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
FVector NormalImpulse,
const FHitResult& Hit
);
// Explode + NockBack
void Explode();
UPROPERTY(VisibleAnywhere)
USphereComponent* Collision;
UPROPERTY(VisibleAnywhere)
UProjectileMovementComponent* ProjectileMovement;
UPROPERTY(EditDefaultsOnly, Category = "Explosion")
bool bVelocityChange = true;
UPROPERTY(EditDefaultsOnly, Category = "Effects")
TSubclassOf<AActor> ExplosionEffectClass;
UPROPERTY()
AActor* HomingTarget;
// 목표물 도착 반경
UPROPERTY(EditDefaultsOnly, Category = "Missile|Flight")
float ArrivalRadius = 200.f;
// 비행 고도
UPROPERTY(EditDefaultsOnly, Category = "Missile|Flight")
float DesiredAltitude = 300.f;
// 고도 보정 속도
UPROPERTY(EditDefaultsOnly, Category = "Missile|Flight")
float AltitudeInterpSpeed = 5.f;
// 지형 체크 거리
UPROPERTY(EditDefaultsOnly, Category = "Missile|Flight")
float GroundTraceDistance = 2000.f;
bool bExploded = false;
};
// V12HomingMissile.cpp
#include "Items/V12HomingMissile.h"
#include "Components/SphereComponent.h"
#include "Components/StaticMeshComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "ChaosVehicleMovementComponent.h"
#include "V12_the_gameSportsCar.h"
AV12HomingMissile::AV12HomingMissile()
{
PrimaryActorTick.bCanEverTick = true;
// Collision
Collision = CreateDefaultSubobject<USphereComponent>(TEXT("Collision"));
Collision->InitSphereRadius(80.f);
Collision->SetNotifyRigidBodyCollision(true);
Collision->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
Collision->SetCollisionObjectType(ECC_GameTraceChannel1); // Missile Collision Channel
Collision->SetCollisionResponseToAllChannels(ECR_Ignore);
Collision->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Block);
Collision->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Block);
Collision->SetCollisionResponseToChannel(ECC_Pawn, ECR_Block);
Collision->SetCollisionResponseToChannel(ECC_Vehicle, ECR_Block);
RootComponent = Collision;
// ProjectileMovement
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovement"));
ProjectileMovement->InitialSpeed = 4000.f;
ProjectileMovement->MaxSpeed = 4000.f;
ProjectileMovement->bRotationFollowsVelocity = true;
ProjectileMovement->bIsHomingProjectile = true;
ProjectileMovement->HomingAccelerationMagnitude = 15000.f;
// Hit Event
Collision->OnComponentHit.AddDynamic(this, &AV12HomingMissile::OnMissileHit);
}
void AV12HomingMissile::BeginPlay()
{
Super::BeginPlay();
// OwnerActor Collision Ignore
if (AActor* OwnerActor = GetOwner())
{
Collision->IgnoreActorWhenMoving(OwnerActor, true);
}
}
// 코드 재확인 필요
void AV12HomingMissile::SetHomingTarget(AActor* NewTarget)
{
HomingTarget = NewTarget;
if (!ProjectileMovement || !NewTarget)
{
return;
}
// 1순위: 충돌 있는 PrimitiveComponent 찾기
TArray<UPrimitiveComponent*> Components;
NewTarget->GetComponents<UPrimitiveComponent>(Components);
for (UPrimitiveComponent* Comp : Components)
{
if (Comp->IsCollisionEnabled())
{
ProjectileMovement->HomingTargetComponent = Comp;
return;
}
}
ProjectileMovement->HomingTargetComponent = NewTarget->GetRootComponent();
}
void AV12HomingMissile::OnMissileHit(
UPrimitiveComponent* HitComp,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
FVector NormalImpulse,
const FHitResult& Hit)
{
if (bExploded)
{
return;
}
// 자기 자신, 오너 무시
if (!OtherActor || OtherActor == this || OtherActor == GetOwner())
{
return;
}
UE_LOG(LogTemp, Warning, TEXT("Target Hit!"));
Explode();
}
void AV12HomingMissile::Explode()
{
if (bExploded)
{
return;
}
bExploded = true;
UE_LOG(LogTemp, Warning, TEXT("Explode called: %s"), *GetName());
// 이동 정지
ProjectileMovement->StopMovementImmediately();
ProjectileMovement->Deactivate();
ProjectileMovement->SetUpdatedComponent(nullptr);
SetActorEnableCollision(false);
// 타겟 연결 완전 해제
if (ProjectileMovement)
{
ProjectileMovement->HomingTargetComponent = nullptr;
}
UWorld* World = GetWorld();
if (!World) return;
// 폭발 이펙트
if (ExplosionEffectClass)
{
FActorSpawnParameters Params;
Params.SpawnCollisionHandlingOverride =
ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
GetWorld()->SpawnActor<AActor>(
ExplosionEffectClass,
GetActorLocation(),
FRotator::ZeroRotator,
Params
);
}
// 넉백 처리(차량 폰 클래스에서 함수를 만들고 호출하는 것으로 변경 예정)
if (HomingTarget)
{
APawn* Pawn = Cast<APawn>(HomingTarget);
if (!Pawn) return;
AV12_the_gameSportsCar* Vehicle =
Cast<AV12_the_gameSportsCar>(HomingTarget);
if (Vehicle)
{
Vehicle->LaunchAndSpin(GetActorLocation());
}
}
SetLifeSpan(0.1f);
}
void AV12HomingMissile::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// DebugSphere
DrawDebugSphere(
GetWorld(),
GetActorLocation(),
50.f,
12,
FColor::Red,
false,
0.1f
);
if (bExploded) return;
UWorld* World = GetWorld();
if (!World) return;
FVector Start = GetActorLocation();
FVector End = Start - FVector(0.f, 0.f, GroundTraceDistance);
FHitResult Hit;
FCollisionQueryParams Params;
Params.AddIgnoredActor(this);
if (World->LineTraceSingleByChannel(
Hit,
Start,
End,
ECC_Visibility,
Params))
{
float TargetZ = Hit.Location.Z + DesiredAltitude;
FVector CurrentLocation = GetActorLocation();
float NewZ = FMath::FInterpTo(
CurrentLocation.Z,
TargetZ,
DeltaTime,
AltitudeInterpSpeed
);
SetActorLocation(
FVector(CurrentLocation.X, CurrentLocation.Y, NewZ),
false
);
}
CheckArrival();
}
// 목표물 도착 판정 함수
void AV12HomingMissile::CheckArrival()
{
if (bExploded || !IsValid(HomingTarget)) return;
float Distance =
FVector::Dist(GetActorLocation(), HomingTarget->GetActorLocation());
if (Distance <= ArrivalRadius)
{
UE_LOG(LogTemp, Warning, TEXT("Arrival Explode"));
Explode();
}
}
목표물 도착 후 차량에서의 반응에 대한 함수 호출 되지 않아 미사일이 차량 주변을 뱅글 뱅글 도는 현상이 발생하였다. 지금은 조치를 하여 미사일이 한번에 목표물에 도달하고 있다.