24.11.27 Weapon 수정 사항입니다.
기존의 무기는 보스캐릭터만을 위한 cpp 파일이라서 직접적으로 자식 클래스로 활용하기에는 무리가 있었습니다.
( 메시를 새로 덮으려고 할 때 오류가 발생합니다. )
그래서 기본이될 무기 클래스를 다시 만들고 자식 클래스로 보스 무기와 잡몹 무기를 새로 만들었습니다.
그와 동시에 기존에 데미지 전달 방식이 아닌 스피어 트레이스로 변경해보았습니다.
기존 방식으로는 피격지점을 찾을 수 없어 동적인 이펙트 출력이 불가능 하기 때문에 변경하게 되었습니다.
EDR_Enemy_Weapon.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "EDR_Enemy_Weapon.generated.h"
UCLASS()
class EDR_API AEDR_Enemy_Weapon : public AActor
{
GENERATED_BODY()
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//Get
UFUNCTION(BlueprintPure, category = "Weapon")
float GetDamage() { return Damage; }
//Set
UFUNCTION(BlueprintCallable, category = "Weapon")
void SetDamage(float NewDamage);
// Sets default values for this actor's properties
AEDR_Enemy_Weapon();
//데미지 주기----------------------------------
UFUNCTION()
void OverlapActor(class UPrimitiveComponent* HitComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
void AddIgnoreActor(AActor* IgnoreActor);
void StopAttack();
void StartAttack();
void TraceAttack();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
//스태틱 메시
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, category = "Weapon")
TObjectPtr<UStaticMeshComponent> WeaponMesh;
//데미지 콜리전
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, category = "Weapon")
TObjectPtr<class UBoxComponent> AttackCollision;
//트레이스 시작포인트
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, category = "Weapon")
TObjectPtr<class USceneComponent> AttackPointStart;
//트레이스 끝 포인트
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, category = "Weapon")
TObjectPtr<class USceneComponent> AttackPointEnd;
//데미지
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, category = "Weapon")
float Damage;
TArray<TObjectPtr<AActor>> IgnoreActors;
bool bAttacking;
public:
AActor* WeaponOwner;
AActor* Player;
};
EDR_Enemy_Weapon.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "EDR_Enemy_Weapon.h"
#include "Engine/DamageEvents.h"
#include "Components/BoxComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Components/SceneComponent.h"
// Sets default values
AEDR_Enemy_Weapon::AEDR_Enemy_Weapon()
{
PrimaryActorTick.bCanEverTick = true;
// 무기 메시
//Weapon = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WEAPON"));
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
WeaponMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WEAPONMESH"));
WeaponMesh->SetupAttachment(RootComponent);
//// 기본 칼
// static ConstructorHelpers::FObjectFinder<UStaticMesh> SK_WEAPON(TEXT("/Game/BLACKSUN_BOSSBUNDLE1/Static_Meshes/Weapons/SM_Vanter_Sword.SM_Vanter_Sword"));
// if (SK_WEAPON.Succeeded())
// {
// WeaponMesh->SetStaticMesh(SK_WEAPON.Object);
// }
// WeaponMesh->SetCollisionProfileName(TEXT("NoCollision"));
//TracePoint
AttackPointStart = CreateDefaultSubobject<USceneComponent>(TEXT("ATTACKPOINTSTART"));
AttackPointEnd = CreateDefaultSubobject<USceneComponent>(TEXT("ATTACKPOINTEND"));
AttackPointStart->SetupAttachment(WeaponMesh);
AttackPointEnd->SetupAttachment(WeaponMesh);
//AttackPointStart->SetRelativeLocation(FVector(0.f, 0.f, 10.f));
//AttackPointEnd->SetRelativeLocation(FVector(0.f, 0.f, 120.f));
//데미지 초기화
Damage = 20.f;
}
void AEDR_Enemy_Weapon::BeginPlay()
{
Super::BeginPlay();
Player = Cast<AActor>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
// 소유자 설정 (GetOwner는 무기를 소유한 액터를 반환)
WeaponOwner = GetOwner();
if (WeaponOwner)
{
IgnoreActors.Add(WeaponOwner);
}
}
// Called every frame
void AEDR_Enemy_Weapon::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (bAttacking)
{
TraceAttack();
}
}
void AEDR_Enemy_Weapon::SetDamage(float NewDamage)
{
Damage = NewDamage;
}
void AEDR_Enemy_Weapon::OverlapActor(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
}
void AEDR_Enemy_Weapon::AddIgnoreActor(AActor* IgnoreActor)
{
IgnoreActors.Add(IgnoreActor);
}
void AEDR_Enemy_Weapon::StopAttack()
{
bAttacking = false;
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, TEXT("BBABBABBA"));
IgnoreActors.Empty();
}
void AEDR_Enemy_Weapon::StartAttack()
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, TEXT("AttackStart"));
bAttacking = true;
WeaponOwner = GetOwner();
if (WeaponOwner && !IgnoreActors.Contains(WeaponOwner))
{
IgnoreActors.Add(WeaponOwner);
}
}
void AEDR_Enemy_Weapon::TraceAttack()
{
bool Trace;
FHitResult OutHit;
TArray<AActor*> ignores;
// 스피어 트레이스 설정
FVector StartLocation = AttackPointStart->GetComponentLocation(); // 칼날 시작 지점 (손잡이)
FVector EndLocation = AttackPointEnd->GetComponentLocation(); // 칼날 끝 지점
FVector SphereCenter = (StartLocation + EndLocation) / 2.0f; // 스피어 중심: 칼날의 중간
float SphereRadius = FVector::Distance(StartLocation, EndLocation)/2.0f; // 스피어 반지름: 칼날 길이의 절반
// 스피어 트레이스 실행
Trace = UKismetSystemLibrary::SphereTraceSingle(
GetWorld(),
SphereCenter, // 스피어 중심
SphereCenter, // 시작과 끝을 동일하게 설정
SphereRadius, // 스피어 반지름
UEngineTypes::ConvertToTraceType(ECC_PhysicsBody), // 충돌 채널
false, // 복잡한 트레이스 사용 여부
IgnoreActors, // 무시할 액터 목록
EDrawDebugTrace::ForDuration, // 디버그 시각화 설정
OutHit, // 충돌 결과
true, // 자신 무시 여부
FLinearColor::Red, // 트레이스 색상
FLinearColor::Green, // 히트 색상
3.f // 디버그 표시 시간
);
//bool Trace;
//FHitResult OutHit;
//TArray<AActor*> ignores;
//
//FVector StartLocation = AttackPointStart->GetComponentLocation();
//FVector EndLocation = AttackPointEnd->GetComponentLocation();
//
// Trace = UKismetSystemLibrary::LineTraceSingle
// (
// GetWorld(),
// StartLocation,
// EndLocation,
// UEngineTypes::ConvertToTraceType(ECC_PhysicsBody),
// false,
// ignores,
// EDrawDebugTrace::ForDuration,
// OutHit,
// true,
// FLinearColor::Red,
// FLinearColor::Green,
// 3.f
//
// );
//
if (IgnoreActors.Contains(OutHit.GetActor())) return;
if (OutHit.GetActor() == Player)
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, TEXT("Hit!!!!!!!!!!"));
if (OutHit.bBlockingHit)
{
// 타격이 들어온 방향 (무기에서 OtherActor 쪽으로)
FVector HitDirection = OutHit.GetActor()->GetActorLocation() - GetActorLocation();
UGameplayStatics::ApplyPointDamage(
OutHit.GetActor(), // 피해를 받을 액터
Damage, // 적용할 데미지 값
HitDirection, // 타격이 들어온 방향
OutHit, // 충돌 정보를 담은 FHitResult
GetInstigatorController(), // 무기를 휘두른 캐릭터의 컨트롤러
this, // 데미지를 입힌 무기
UDamageType::StaticClass() // 기본 데미지 타입 사용
);
IgnoreActors.Add(OutHit.GetActor());
}
}
}
처음에 라인트레이스로 판정하게 하였는데 보스 무기는 크기가 크다보니까 너무 잘 빗나가게 되어 스피어 트레이스로 변경하였습니다.
캐릭터에서 Attack 실행시 무기의 bAttacking를 true로 재정의 하고 무기의 tick함수에서 트레이스를 시작합니다.
공격 애니메이션 종료시에는 캐릭터에서 bAttacking을 false로 하여 공격 판정을 종료 시킵니다.
자식 클래스
하위 클래스들에서는 메시를 입혀주고, 트레이스 시작 종료 지점을 입력해 줍니다.
EDR_Enemy_BWeapon.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EDR_Enemy_Weapon.h"
#include "EDR_Enemy_BWeapon.generated.h"
/**
*
*/
UCLASS()
class EDR_API AEDR_Enemy_BWeapon : public AEDR_Enemy_Weapon
{
GENERATED_BODY()
public:
AEDR_Enemy_BWeapon();
};
EDR_Enemy_BWeapon.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "EDR_Enemy_BWeapon.h"
AEDR_Enemy_BWeapon::AEDR_Enemy_BWeapon()
{
// 기본 칼
static ConstructorHelpers::FObjectFinder<UStaticMesh> SK_WEAPON(TEXT("/Game/BLACKSUN_BOSSBUNDLE1/Static_Meshes/Weapons/SM_Vanter_Sword.SM_Vanter_Sword"));
if (SK_WEAPON.Succeeded())
{
WeaponMesh->SetStaticMesh(SK_WEAPON.Object);
}
WeaponMesh->SetCollisionProfileName(TEXT("NoCollision"));
// 무기 크기 키우기
SetActorScale3D(FVector(2.0f, 2.0f, 2.0f));
//TracePoint
//AttackPointStart = CreateDefaultSubobject<USceneComponent>(TEXT("ATTACKPOINTSTART"));
//AttackPointEnd = CreateDefaultSubobject<USceneComponent>(TEXT("ATTACKPOINTEND"));
//AttackPointStart->SetupAttachment(WeaponMesh);
//AttackPointEnd->SetupAttachment(WeaponMesh);
AttackPointStart->SetRelativeLocation(FVector(0.f, 0.f, 25.f));
AttackPointEnd->SetRelativeLocation(FVector(0.f, 0.f, -65.0f));
//SphereRadius = 40.0f; // 원하는 스피어의 반지름
Damage = 1.0f;
}
EDR_Enemy_SWeapon.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EDR_Enemy_Weapon.h"
#include "EDR_Enemy_SWeapon.generated.h"
/**
*
*/
UCLASS()
class EDR_API AEDR_Enemy_SWeapon : public AEDR_Enemy_Weapon
{
GENERATED_BODY()
public:
AEDR_Enemy_SWeapon();
};
EDR_Enemy_SWeapon.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "EDR_Enemy_SWeapon.h"
AEDR_Enemy_SWeapon::AEDR_Enemy_SWeapon()
{
// 메시 입히기
static ConstructorHelpers::FObjectFinder<UStaticMesh> SK_WEAPON(TEXT("/Game/GKnight/Meshes/Weapon/SM_WP_GothicKnight_Sword.SM_WP_GothicKnight_Sword"));
if (SK_WEAPON.Succeeded())
{
WeaponMesh->SetStaticMesh(SK_WEAPON.Object);
}
WeaponMesh->SetCollisionProfileName(TEXT("NoCollision"));
//SphereRadius = 20.0f; // 원하는 스피어의 반지름
////TracePoint
//AttackPointStart = CreateDefaultSubobject<USceneComponent>(TEXT("ATTACKPOINTSTART"));
//AttackPointEnd = CreateDefaultSubobject<USceneComponent>(TEXT("ATTACKPOINTEND"));
//AttackPointStart->SetupAttachment(WeaponMesh);
//AttackPointEnd->SetupAttachment(WeaponMesh);
//AttackPointStart->SetRelativeLocation(FVector(0.f, 0.f, 10.f));
//AttackPointEnd->SetRelativeLocation(FVector(0.f, 0.f, 120.f));
AttackPointStart->SetRelativeLocation(FVector(0.f, 0.f, 15.f));
AttackPointEnd->SetRelativeLocation(FVector(0.f, 0.f, 140.0f));
}
실행 화면
'Unreal Engine 5 > EDR_Project' 카테고리의 다른 글
EDR_Project / AnimInstance (3) 공격 판정 끝 (0) | 2024.12.02 |
---|---|
EDR_Project / Character (11) 공격, 판정 수정 (3) | 2024.12.02 |
EDR_Project / EDR_Boss_Knight (3) 피격시 이펙트, 사운드 (0) | 2024.11.26 |
EDR_Project / CanAttack (3) (0) | 2024.11.25 |
EDR_Project / TurnToTarget (1) (1) | 2024.11.25 |