1. 사전캠프 적응과 미니 프로젝트 합류

    • 사전캠프 적응을 위해 담임 매니저님과 1:1 OT 진행 후 팀 배정 배정 받은 팀에서 팀 노션, 하루 일정 그리고 캠프 전반에 대한 흐름을 들으며 적응
    • [미니프로젝트] 선배기수 Unreal 엔진 게임 분석 선정 게임 전달 및 어떤 식으로 진행할 것인지 논의
  2. 선배 기수 Unreal 엔진 게임 분석 선정 (Dominion Protocol)

    • 팀원들과 모여 플레이하며 각자 인상깊거나 불편했던 상호작용 분석
      1. Z키를 이용해 적 락온: 소울라이크 특유의 1:1 전투에서 한 타겟을 대상으로 락온을해 공격과 회피를 도와 주는 시스템
        • 너무 가까워지거나 적이 원거리 공격을 깔아두고 이동기를 사용해 화면 밖으로 이동하는 경우 시선이 그쪽으로 포커스 되어 원거리 공격이 안보이는 문제가 있어 화면에서 적이 사라지면 강제로 락온을 해제한다면 좋을 것
      2. 패링 기능: 타이밍을 맞춰 패링 사용시 하이리스크 하이리턴의 보상을 주는 기능
        • 원거리 공격의 경우 반사로 적에 대미지를 줄 수 있지만 근거리 공격 패링은 단순 스턴효과만 생겨 기본공격의 경직효과와 크게 차이없는 결과가 나와 스턴상태 특수 공격을 추가 하면 좋을 것
      3. 원거리 스킬: 원거리 공격을 하는 마법 스킬 사용
        • 따로 마나스텟이 없이 스테미나에 통합 되어 사용되기 때문에 게임을 플레이하는데 난이도를 너무 낮추는 효과를 가져옴 마나와 마나포션을 추가해 밸런스 조정을 하는 것이 좋을 것
      4. 아이템 수집: 아이템 오브젝트에 F키 상호작용으로 수집
        • 특정 아이템은 습득 시 표기가 되지만 어떤 특정 아이템은 표기가 안돼 인벤토리에 들어가 따로 확인을 해야함 습득시 잘보이게 어떤 아이템을 습득 했는지 표기하는 것이 좋을 것
  3. 학습하며 겪었던 문제점 & 에러

    • 선배 기수의 게임을 다운로드하여 프로젝트 실행을 했으나 버전 오류로 인해 실행이 안됨
      • 기존에 깔려있던 5.6.1버전이 아닌 5.5.4버전으로 재설치 후 실행 예정
      • 우선 게임 분석을 위해 선배 기수의 게임 노션 페이지와 빌드 실행파일로 게임을 플레이한 뒤 미니프로젝트 진행을 하여 완료 하였음
      • 미니프로젝트의 요구사항은 프로젝트 실행 후 구성을 분석하는 것이 아닌 단순 게임 플레이를 한 뒤 게임의 상호작용 들에대한 분석이였기 때문에 프로젝트 실행은 뒤로 미루었음
      • 다음에도 비슷한 상황을 대비하여 다른 프로젝트를 열어볼때 최초 환경설정을 위하여 개발 환경(언리얼 버전, 비주얼 스튜디오 버전 등)을 우선적으로 확인한 다음 같은 환경을 준비하여 진행
  4. 새롭게 알게 된 점

    • 팀과제를 위해 노션, slack, zep 등의 협업 툴을 사용해본 것은 첨음이였기 때문에 노션의 워크스페이스 동시작업 같은 협업 작업에 대한 장점과 주의사항 등을 알게 되었음
  5. 내일 학습 내용

    • 오늘의 팀 활동내용을 바탕으로 5분 정도의 발표자료 작성(시각 자료 활용)
    • 발표자 선정 및 발표

프로젝트 세팅에서 Object Channel 추가로인한 오류 발생

  • 기존에 아무것도 생성하지않은 상태에서 Item Object Channel 추가로 인해 비헤비어트리 서비스 노드에 문제가 발생하여 Enemy가 Player를 타겟으로 서치하는 BTService_SearchTarget 클래스가 제대로 작동하지않음

  • 위와같이Object Channel을 추가하게 되면 DefaultEngine.ini파일에 아래와 같은 코드가 추가되어 ECC_GameTraceChannel1 에 Item이 할당되게 된다.
DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=False,bStaticObject=False,Name="Item")
  • 위와 같이 ECC_GameTraceChannel1 에 Item할당되게 되면 기존의 BTService_SearchTarget에서 Player를 찾기위해 OverlapMultiByChannel을 사용할때 기본 설정으로 사용했던 ECC_GameTraceChannel1가 새로 추가한 Item 오브젝트의 설정을 따라가게되고 기본 반응이 무시로 덮어쓰이게됨.
  • 따라서 이를 해결하기 위해서는 새로운 Object Channel을 설정하고 그 채널을 사용하거나 아무것도 할당되지 않은 ECC_GameTraceChannel2 채널을 사용하도록 수정할 필요가있어 ECC_GameTraceChannel2 채널을 사용하도록 수정하였음
//수정 전
void UBTService_SearchTarget::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
    Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);

    auto Pawn = OwnerComp.GetAIOwner()->GetPawn();
    if (Pawn != nullptr)
    {
        FVector Center = Pawn->GetActorLocation();
        float SearchDistance = 500.f;
        TArray<FOverlapResult> OverlapResults;
        FCollisionQueryParams QueryParams(NAME_Name, false, Pawn);

        bool Result = GetWorld()->OverlapMultiByChannel
        (
            OverlapResults,
            Center,
            FQuat::Identity,
            ECollisionChannel::ECC_GameTraceChannel1, // Item Object Channel이 할당되어 수정이 필요해진 부분
            FCollisionShape::MakeSphere(SearchDistance),
            QueryParams
        );

        if (Result)
        {
            for (auto& OverlapResult : OverlapResults)
            {
                auto Player = Cast<AMyPlayer>(OverlapResult.GetActor());
                if (Player)
                {
                    DrawDebugSphere(GetWorld(), Center, SearchDistance, 10, FColor::Green, false, 0.5f);
                    OwnerComp.GetBlackboardComponent()->SetValueAsObject(FName("Target"), Player);
                    return;
                }

            }

        }


        OwnerComp.GetBlackboardComponent()->SetValueAsObject(FName("Target"), nullptr);
        DrawDebugSphere(GetWorld(), Center, SearchDistance, 10, FColor::Red, false, 0.5f);

    }


}

//수정 후
void UBTService_SearchTarget::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
    Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);

    auto Pawn = OwnerComp.GetAIOwner()->GetPawn();
    if (Pawn != nullptr)
    {
        FVector Center = Pawn->GetActorLocation();
        float SearchDistance = 500.f;
        TArray<FOverlapResult> OverlapResults;
        FCollisionQueryParams QueryParams(NAME_Name, false, Pawn);

        bool Result = GetWorld()->OverlapMultiByChanne2 // 수정 된 부분
        (
            OverlapResults,
            Center,
            FQuat::Identity,
            ECollisionChannel::ECC_GameTraceChannel1,
            FCollisionShape::MakeSphere(SearchDistance),
            QueryParams
        );

        if (Result)
        {
            for (auto& OverlapResult : OverlapResults)
            {
                auto Player = Cast<AMyPlayer>(OverlapResult.GetActor());
                if (Player)
                {
                    DrawDebugSphere(GetWorld(), Center, SearchDistance, 10, FColor::Green, false, 0.5f);
                    OwnerComp.GetBlackboardComponent()->SetValueAsObject(FName("Target"), Player);
                    return;
                }

            }

        }


        OwnerComp.GetBlackboardComponent()->SetValueAsObject(FName("Target"), nullptr);
        DrawDebugSphere(GetWorld(), Center, SearchDistance, 10, FColor::Red, false, 0.5f);

    }


}

' > 공부' 카테고리의 다른 글

Claude 사용기  (3) 2025.08.22
AI와 기술 부채  (3) 2025.08.10

DoDefaultAttack() 함수에서 실제 공격 판정 Sphere와 DrawDebugCapsule에서 그리는 Capsule의 형태가 일치 X

  • 실제 공격판정인 SweepSingleByChannel에서는 FQuat::Identity를 사용해 스피어가 Z축 기준으로 수직으로 서있는 형태이고  DrawDebugCapsule에서는 FQuat Rotation = FRotationMatrix::MakeFromZ(Vec).ToQuat() 변수를 선언한뒤 Rotaion을 적용하여 캐릭터의 정면 방향으로 그리게 되는 것을 FQuat Rot = FRotationMatrix::MakeFromZ(EndPos - StartPos).ToQuat(); 를 공통으로 사용하여 일치하게 수정
void ACOECharacter::DoDefaultAttack()
{
	FHitResult HitResult;
	FCollisionQueryParams Params;
	Params.AddIgnoredActor(this);
	Params.bTraceComplex = false;
	Params.bReturnPhysicalMaterial = false;

	float AttackRange = 250.f;
	float AttackRadius = 50.f;
	FVector StartPos = GetActorLocation();
	FVector EndPos = GetActorLocation() + GetActorForwardVector() * AttackRange;
	FQuat Rot = FRotationMatrix::MakeFromZ(EndPos - StartPos).ToQuat(); // 수정을 위해 추가된 부분
	bool Result = GetWorld()->SweepSingleByChannel
	(
		HitResult,														
		StartPos,									
		EndPos,										
		Rot,							//FQuat::Identity에서 미리 선언한 Rot으로 수정
		ECC_GameTraceChannel3,						
		FCollisionShape::MakeSphere(AttackRadius),	
		Params										
	);


	
	FVector Center = (StartPos + EndPos) * 0.5f;
	float HalfHeight = AttackRange * 0.5f;
    //FQuat Rotation = FRotationMatrix::MakeFromZ(Vec).ToQuat(); -> 같은 FQuat Rot을 사용하기 위해 삭제
	FColor DrawColor;

	DrawColor = Result ? FColor::Green : FColor::Red;
	//실제 공격에 사용한 FQuat값을 사용하기위해 기존의 Rotation 대신 Rot을 사용
	DrawDebugCapsule(GetWorld(), Center, HalfHeight, AttackRadius, Rot, DrawColor, false, 2.f);

	if (Result && HitResult.GetActor())
	{
		UE_LOG(LogTemp, Log, TEXT("Hit : %s"), *HitResult.GetActor()->GetName());
		
		UGameplayStatics::ApplyDamage(HitResult.GetActor(), 10.f, GetInstigatorController(), this, nullptr);
		
		if (AExplorationEnemy* Enemy = Cast<AExplorationEnemy>(HitResult.GetActor()))
		{	
			
			if (Enemy->PossibleBattleLevels.Num() > 0)
			{
				
				FName SelectedBattleMap = Enemy->PossibleBattleLevels[FMath::RandRange(0, Enemy->PossibleBattleLevels.Num() - 1)];
			
				if (UCOEGameInstance* GI = Cast<UCOEGameInstance>(UGameplayStatics::GetGameInstance(this)))
				{
					GI->bPlayerInitiative = true; 
					GI->bPlayerWasDetected = false;
					GI->ReturnLocation = GetActorLocation();
					GI->ReturnMapName = FName("Lvl_ThirdPerson"); 
					GI->EnemyToRemove = HitResult.GetActor();
				}

				
				UGameplayStatics::OpenLevel(this, SelectedBattleMap);
			}
			else
			{
				UE_LOG(LogTemp, Warning, TEXT("Enemy has no PossibleBattleLevels!"));
			}
		}
	}
	UE_LOG(LogTemp, Warning, TEXT("DefaultAttack() called in TurnBattleLevel!"));
}

 

 

DetectPlayerComponent.cpp 구현 중 생성자에 스피어 반경, CollisionProfile 설정, Bind overlap Event 등을 구현하였더니 컴파일이 안되는 오류 발생

  • 생성자에서 구현 X BeginPlay에서 구현하여 CollsionProfile 시스템이 완전히 초기화 된 이후 안전하게 적용
// 초기 작성 코드
UDetectPlayerComponent::UDetectPlayerComponent()
{
    // 충돌 반경설정
    SetSphereRadius(100.f);
    SetCollisionProfileName(TEXT("OverlapAllDynamic"));

    // Bind overlap events
    OnComponentBeginOverlap.AddDynamic(this, &UDetectPlayerComponent::HandleBeginOverlap);
    OnComponentEndOverlap.AddDynamic(this, &UDetectPlayerComponent::HandleEndOverlap);
}

void UDetectPlayerComponent::BeginPlay()
{
    Super::BeginPlay();
}

// 수정 코드
UDetectPlayerComponent::UDetectPlayerComponent()
{
   
}

void UDetectPlayerComponent::BeginPlay()
{
    Super::BeginPlay();
    // 충돌 반경설정
    SetSphereRadius(100.f);
    SetCollisionProfileName(TEXT("OverlapAllDynamic"));

    // Bind overlap events
    OnComponentBeginOverlap.AddDynamic(this, &UDetectPlayerComponent::HandleBeginOverlap);
    OnComponentEndOverlap.AddDynamic(this, &UDetectPlayerComponent::HandleEndOverlap);
}

 

' > 포트폴리오' 카테고리의 다른 글

포트폴리오 log #6  (0) 2025.08.05
포트폴리오 log #4  (4) 2025.07.17
포트폴리오 log #3  (0) 2025.07.16
포트폴리오 log #2  (0) 2025.07.15
포트폴리오 log #1  (0) 2025.07.11

캐릭터 Stats 구조체 구현

  • 처음에는 가장 베이스가 될 COECharacter클래스에 CharacterStats에 관련된 변수를 선언하려 하였으나 구초체로 구현하는 것이 더 적합할 것이라는 판단에 구현하던중 여러 Character 및 Enemy 클래스에서 활용하기에는 구조체 클래스를 하나 만드는 것이 적합하다는 판단에 FCharacterStats 클래스를 만들기로 결정 앞의 F는 언리얼 명명체계임

FCharacterStats 클래스 생성을위해 빈 C++클래스 생성

  • 생성된 FCharacterStats.h에서 #include "CoreMinimal.h" #include "FCharacterStats.generated.h" 두개 만 남기고 다 삭제한다음 아래코드로 작성 #include "클래스명.generated.h" 가 가장 마지막에 선언되지않으면 빌드에 문제가 생김 
    → 몰라서 다른 문제인지 찾아보다가 GPT에서 알려줘서 고침
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "FCharacterStats.generated.h"

/**
 * 
 */
USTRUCT(BlueprintType)
struct FCharacterStats
{
	GENERATED_BODY()

public:
	
	/** HPMAX */
	UPROPERTY(BlueprintReadOnly, Category = "Status")
	float MAXHP;

	/** HP */
	UPROPERTY(BlueprintReadOnly, Category = "Status")
	float CurrentHP;

	/** Vitality */
	UPROPERTY(BlueprintReadOnly, Category = "Status")
	float Vitality;

	/** AttackPower */
	UPROPERTY(BlueprintReadOnly, Category = "Status")
	float AttackPower;

	/** Defense */
	UPROPERTY(BlueprintReadOnly, Category = "Status")
	float Defense;

	/** Agility */
	UPROPERTY(BlueprintReadOnly, Category = "Status")
	float Agility;

	/** Luck */
	UPROPERTY(BlueprintReadOnly, Category = "Status")
	float Luck;
};

//COECharacter 클래스에서 사용하기 위해 COECharacter.h에 #include "FCharacterStats.h" 추가
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Logging/LogMacros.h"
#include "FCharacterStats.h"
#include "COECharacter.generated.h" //각 클래스의 generate.h가 가장 마지막에 선언 되어야함

 

' > 포트폴리오' 카테고리의 다른 글

포트폴리오 log #6  (0) 2025.08.05
포트폴리오 log #5  (2) 2025.07.31
포트폴리오 log #3  (0) 2025.07.16
포트폴리오 log #2  (0) 2025.07.15
포트폴리오 log #1  (0) 2025.07.11

SetAinming상태 전환중 불안정한 카메라 전환 해결

  • 아래와 같이 단순 CameraBoom의 좌표변경으로는 전환이 매끄럽지않은 문제가 발생하여 구글링과 GPT를 비교해본 결과
void ACOECharacter::SetAiming(bool bNewAiming)
{

	if (bIsAiming)
		{
			// 조준 카메라로 전환
			// 속도 감소 등
			UE_LOG(LogTemp, Log, TEXT("IsAiming"));
			CameraBoom->SocketOffset = FVector(300.f, 80.f, 50.f);
		
		}
		else
		{
			// 기본 상태 복귀
			UE_LOG(LogTemp, Log, TEXT("IsNotAiming"));
			CameraBoom->SocketOffset = FVector(200.f, 80.f, 50.f);
		}
}
  • 아래와 같은 공통된 방법이 있어 코드를 수정하였으나 조준상태에서 벗어나지 못하는 문제가 발생
void ACOECharacter::SetAiming(bool bNewAiming)
{
	bIsAiming = bNewAiming;
	GetWorldTimerManager().ClearTimer(AimingInterpTimerHandle); // 이전 타이머 정리

	StartSocketOffset = CameraBoom->SocketOffset;
	TargetSocketOffset = bIsAiming
		? FVector(300.f, 80.f, 50.f)
		: FVector(200.f, 80.f, 50.f);


	InterpAlpha = 0.f;
	bInterpToAiming = bIsAiming;

	GetWorldTimerManager().SetTimer
	(
		AimingInterpTimerHandle,
		this,
		&ACOECharacter::UpdateAimingInterp,
		0.01f, // 10ms 간격
		true   // 반복 실행
	);
}

void ACOECharacter::UpdateAimingInterp()
{
	InterpAlpha +=  0.05f; // 0~1로 점점 증가 (속도 조절 가능)

	FVector NewOffset = FMath::Lerp(StartSocketOffset, TargetSocketOffset, InterpAlpha);
	CameraBoom->SocketOffset = NewOffset;

	if (InterpAlpha >= 1.0f)
	{
		CameraBoom->SocketOffset = TargetSocketOffset;
		GetWorldTimerManager().ClearTimer(AimingInterpTimerHandle);
	}
}
  • 아래의 사진에 표시한 한계치들을 짧게 하여 우클릭을 누르자마자 길게누르기 판정을 줘 해결함

' > 포트폴리오' 카테고리의 다른 글

포트폴리오 log #6  (0) 2025.08.05
포트폴리오 log #5  (2) 2025.07.31
포트폴리오 log #4  (4) 2025.07.17
포트폴리오 log #2  (0) 2025.07.15
포트폴리오 log #1  (0) 2025.07.11

언리얼 C++ 근접 공격 Input 중복 문제 해결

  • 공격 Mongtage 작업 완료 후 공격 모션중 충돌 판정이 필요한 부분에 Collision 작업과 공격당한 상대에게 Damage 판정을 구현 중 이전의 코드 상태면 AnimMontage는 공격 모션이 다 끝나야 다시 시작할 수 있지만 Controller 입력과 Character 의 함수는 계속 호출 됨으로써 COECharacter에 구현할 Collision과 Damage판정에 오류가 생길 가능성을 예방하기 위해 bIsAttacking 값을 만들어 false일때만 공격하게 만들 필요성이 생김
  • 처음에는 COECharacter에서 bool bIsAttacking = false인 변수를 public으로 만들고 COEPlayerController에서 인풋이 들어오면 true로 바꾼다음 AnimMontage가 끝날때 OnAttackMontageEnded 함수를 통해 bIsAttacking = fasle로 만들어주려 했으나 계속 true값이 나오는 문제가 생겨 AnimNotify를 이용하는 방법을 찾아 아래와 같이 적용함

//COEPlayerController

// COEChar nullptr 검사와 COEChar->GetCharacter()->IsFalling()으로 공중에있는지 이미 공격 중인지 체크
if (!IsValid(COEChar) || COEChar->GetCharacterMovement()->IsFalling())
{
	UE_LOG(LogTemp, Log, TEXT("COEChar == nullptr && bIsFalling == true"));
	return;
}
// 공격중이라면 입력 X
if (COEChar->bIsAttacking)
{
	UE_LOG(LogTemp, Log, TEXT("bIsAttacking == true"));
	return;
}
// 문제없을 시 COECharacter의 DefaultAttack() 실행
COEChar->DefaultAttack();
COEChar->bIsAttacking = true;

//COEAnimInstance
	
//공격이 끝나면 bIsAttacking = false
UFUNCTION(BlueprintCallable, Category = "Animation")
void AnimNotify_End();
//공격모션 중 타격 타이밍에 Collision 생성
UFUNCTION(BlueprintCallable, Category = "Animation")
void AnimNotify_DoDefaultAttack();
	
void UCOEAnimInstance::AnimNotify_End()
{
	Character->bIsAttacking = false;
	UE_LOG(LogTemp, Log, TEXT("bIsAttacking == false"));
}

void UCOEAnimInstance::AnimNotify_DoDefaultAttack()
{
	Character->DoDefaultAttck();
	UE_LOG(LogTemp, Log, TEXT("DoDefaultAttack"));
}

→ 위와 같은 수정으로 AttackMontage가 끝나야만 공격 Input을 받을 수 있게 변경

' > 포트폴리오' 카테고리의 다른 글

포트폴리오 log #6  (0) 2025.08.05
포트폴리오 log #5  (2) 2025.07.31
포트폴리오 log #4  (4) 2025.07.17
포트폴리오 log #3  (0) 2025.07.16
포트폴리오 log #1  (0) 2025.07.11

언리얼 C++  Character 변수명 오류 및 Cast<자료형>(GetCharacter())오류 해결과 Build 시간 단축

  • 언리얼 포트폴리오 작성 중 샘플C++파일을 수정하면서 모든 Input은 PlayerController쪽 클래스에 몰아넣고 Character클래스 쪽에는 카메라 및 AnimInstance 캐스트 정도만 생성자에 몰아 넣어둔 상태로 개발하였고 매번 빌드때마다 오래걸리는 이슈가 발생하였으나 원인을 찾지못한 상태로 진행
  • PlayerController쪽에 키보드 F클릭시 기본공격(근접)을 받아오고 거기서 Character의 DefaultAttakc() 을 호출해서 Character클래스의 DefaultAttack()을 실행 그 뒤 AnimInstance의 DefaultAttackAnim()으로 AttackAnimMontage를 실행 시켜주는 방식으로 구성
  • 그 상태에서 ACOECharacter* Character 같은 변수선언을 COEPlayerController클래스에서 사용 시 오류가 발생하는것을 발견 이전에도 COEPlayerController에서 GetPawn()과 GetCharacter()를 받을때 Character, Pawn등을 변수명으로 사용하면 문제가 되었기에 혹시나 하는 마음으로 Character는 COEChar 으로 아래와 같이 수정하고 매번 Cast해주던 것을 BeginPlay()에서 한번만 Cast해줬더니 빌드가 오래걸리는 문제와 수정전의 불필요해보이고 지저분했던 코드 문제 해결
if (ACOECharacter* Character = Cast<ACOECharacter>(GetCharacter()))
//처음엔 위 코드로 작성하여 사용할때는 Character변수명에 오류 발생

ACharacter* ControllerCharacter = this->GetCharacter(); //수정전
    if (ControllerCharacter != nullptr) 
//처럼 매번 ControllerCharacter에 this->GetCharacter()를 할당해서 사용하던 코드를  아래처럼 BeginPlay()에서 한번만 Cast해주고
void ACOEPlayerController::BeginPlay()
{
	Super::BeginPlay();

	COEChar = Cast<ACOECharacter>(GetCharacter());
}
	if (IsValid(COEChar)) //수정후
//위 코드로 수정하였더니 코드도 간결해 지고 빌드도 빨라짐
  • 추가로 오늘 작업목표중 근접공격 구현에서 아래와 같이 코드를 작성했을때 AnimInstance가 null이 되는 문제가 생겨 찾아보니 생성자에서 AnimInstance를 캐스트하면 매시가 생성전이라 제대로 작동하지 않을 수 있다고 하여 아래와 같이 BeginPlay() 에서 캐스트 해주도록 수정
void ACOECharacter::BeginPlay()
{
    Super::BeginPlay();
    //AnimInstance 캐스트
    AnimInstance = Cast<UCOEAnimInstance>(GetMesh()->GetAnimInstance());
}

void ACOECharacter::DefaultAttack()
{
    //AnimInstance가 nullptr이 아니라면 DefaultAttackAnim 실행
    if (IsValid(AnimInstance))
    {
        AnimInstance->DefaultAttackAnim();
    }
    else
    {
        UE_LOG(LogTemp, Log, TEXT("Null"));
    }
    UE_LOG(LogTemp, Log, TEXT("DefaultAttack"));
}

' > 포트폴리오' 카테고리의 다른 글

포트폴리오 log #6  (0) 2025.08.05
포트폴리오 log #5  (2) 2025.07.31
포트폴리오 log #4  (4) 2025.07.17
포트폴리오 log #3  (0) 2025.07.16
포트폴리오 log #2  (0) 2025.07.15

+ Recent posts