08-06~08-07 MidBoss SkillAttack2, 3추가, 쉴드 버그 수정, 쉴드 C++화
MidBoss SkillAttack2 (물폭풍)






CannonArrow
BeginPlay -> Set Life Span 을 설정하여 시간이 되면 삭제
Cannon
TimeLine -> 시간동안 반복을 위해 사용
Arrow에서 Trace를 쏴서 Vector값과 블록인지 아닌지를 체크
벽이면 벽까지 Transform길이를 늘리고 아닌경우는 Distance값 만큼 크기를 늘림
Tick
지속형 데미지를 주기위해 사용
BeginOverlap, EndOverlap
Player가 닿았는지를 체크

Water본인
특정 Action이 실행되면 WaterCannon을 Point부분에 Spawn한다.

Cannon 역시 전 Shield처럼 Enemy가 죽으면 삭제한다.
MidBoss SkillAttack3 (물보라) - 차후 수정예정
Pooling 기술 사용 - 차후 C++로 변경예정



PoolManager역할




Projectile을 Pool 갯수만큼 생성한다.

Count만큼 Projectile을 반복하고 Count에 따라 방향값을 구해 시계방향으로 Projectile이 생성된다.
Pool이 가지고있는 Spawn From Pool을 불러온다.
참조영상
Shield

Player를 밀어주는 부분을 추가하였다.
C++
Shiled.cpp
#include "Enemy/FShield.h"
#include "GameFramework/Character.h"
#include "GameFramework/PlayerController.h"
#include "Kismet/KismetSystemLibrary.h"
#include "FGameFunctionLibrary.h"
#include "Player/FAttributeComponent.h"
#include "Buff/FBuffComponent.h"
// Sets default values
AFShield::AFShield()
{
PrimaryActorTick.bCanEverTick = true;
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ShiledMesh"));
AttributeComp = CreateDefaultSubobject<UFAttributeComponent>(TEXT("AttributeComp"));
BuffComp = CreateDefaultSubobject<UFBuffComponent>(TEXT("BuffComp"));
}
void AFShield::BeginPlay()
{
Super::BeginPlay();
PlayerIn();
SetLifeSpan(LifeTime);
AttributeComp->OnHealthChanged.AddDynamic(this, &AFShield::OnHealthChanged);
//데미지형 쉴드인지 아닌지 판별
if(bDamageShield)
{
FTimerHandle Timer;
GetWorldTimerManager().SetTimer(Timer, this, &AFShield::OnDamage, 8.5f, false);
}
}
void AFShield::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AFShield::OnHealthChanged(AActor* InstigatorActor, UFAttributeComponent* OwningComp, float Delta, float NewHealth)
{
if (!AttributeComp->IsAlive())
{
Destroy();
}
}
//데미지를 줄 경우
void AFShield::OnDamage()
{
if (AttributeComp->IsAlive())
{
FVector Start = GetActorLocation();
FVector ForwardVector = GetActorForwardVector();
FVector End = Start + ForwardVector;
TArray<AActor*> ActorsToIgnore;
ActorsToIgnore.Add(this);
TArray<FHitResult> OutHits;
float Radius = 400.0f;
TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_Pawn));
bool bTraceComplex = false;
//Radius 거리만큼 SphereTrace를 생성하여 hit된 특정 object에 데미지를 부여
auto isHit = UKismetSystemLibrary::SphereTraceMultiForObjects(GetWorld(),Start, End, Radius, ObjectTypes, bTraceComplex, ActorsToIgnore, EDrawDebugTrace::None, OutHits, true);
if (isHit)
{
for(auto&Hit:OutHits)
{
AActor* HitActor = Hit.GetActor();
if (HitActor)
{
UActorComponent* TargetComponent = HitActor->GetComponentByClass(UFAttributeComponent::StaticClass());
if (IsValid(TargetComponent))
{
TArray<TSubclassOf<UFBuff>> buffArray;
UFGameFunctionLibrary::ApplyDamage(GetInstigator(), HitActor, AttributeComp->CharacterStatusInfo.MagicalPower, buffArray);
}
}
}
}
}
}
//Player가 들어왔는지 아닌지를 판별 후 밀어냄
void AFShield::PlayerIn()
{
APlayerController* Player = GetWorld()->GetFirstPlayerController();
ACharacter* PlayerCharacter = Cast<ACharacter>(Player->GetCharacter());
FVector PlayerLocation = PlayerCharacter->GetActorLocation();
FVector ShiledLocation = GetActorLocation();
FVector Distance = (PlayerLocation - ShiledLocation).GetSafeNormal();
if ((PlayerLocation - ShiledLocation).Size() < 300)
{
PlayerCharacter->LaunchCharacter(((PlayerLocation - ShiledLocation).GetSafeNormal()) * 300, true, true);
}
}