09.16 - TIL

김혁·2025년 9월 16일

TIL

목록 보기
19/84

오늘의 코드카타

억억단을 외우자

  • 배수를 통한 약수 찾기
  • DP를 통해 최대값 원소 찾기
  • LV3 - 23%
    -> 문제 풀이

오늘의 공부

GAS 공부

Ability API

  1. UAbilityTask_ApplyRootMotionConstantForce
    • Ability : Applies force to Character's movement
    • 대쉬할 때 사용 (캐릭터한테 지정한만큼 힘과 시간 적용)
  2. UAbilityTask_WaitDelay
    • Ability : Wait for Duration
    • 끝나는 타이밍을 명확히 할 때 사용 (지정한 시간만큼 기다린 후에 EndAbility 발동)
void UDashAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,
	const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData){
 
 	...
 
	const FVector Direction = Character->GetActorForwardVector().GetSafeNormal();
	const float Strength = (DashDuration > 0.f) ? (DashDistance / DashDuration) : DashDistance;

	UAbilityTask_ApplyRootMotionConstantForce* RMTask = UAbilityTask_ApplyRootMotionConstantForce::ApplyRootMotionConstantForce(
		this, NAME_None, Direction, Strength,
		DashDuration, false, nullptr,
		ERootMotionFinishVelocityMode::MaintainLastRootMotionVelocity,
		FVector::ZeroVector, !bIgnoreGravity, true);

	if (RMTask)
	{
		RMTask->ReadyForActivation();
	}
    
	if (UAbilityTask_WaitDelay* Delay = UAbilityTask_WaitDelay::WaitDelay(this, DashDuration))
	{
		Delay->OnFinish.AddDynamic(this, &ThisClass::OnDashFinished);
		Delay->ReadyForActivation();
	}    
}

Effect API

  1. Cost Effect
    • 필요한 자원을 Attribute Set에서 검사해서 차감시킴 (차감 불가능한 경우 Effect 불가능)
UHealCostEffect::UHealCostEffect()
{
	DurationPolicy = EGameplayEffectDurationType::Instant;

	FGameplayModifierInfo ManaMod;
	ManaMod.Attribute = UMyAttributeSet::GetManaAttribute();
	ManaMod.ModifierOp = EGameplayModOp::Additive;
	ManaMod.ModifierMagnitude = FGameplayEffectModifierMagnitude(FScalableFloat(-40.f));
	
	Modifiers.Add(ManaMod);
}
  1. Cooldown Effect
    • Tag를 이용해서 Effect의 쿨타임 계산 (Tag를 가지고 있을 시에 Effect 불가능)
    • UTargetTagsGameplayEffectComponent
      • Effect : GameplayEffect의 Target에게 Tag를 부여하는 컴포넌트
UE_DEFINE_GAMEPLAY_TAG(TAG_Cooldown_Heal, "Cooldown.Heal");

UHealCooldownEffect::UHealCooldownEffect()
{
	DurationPolicy = EGameplayEffectDurationType::HasDuration;
	DurationMagnitude = FGameplayEffectModifierMagnitude(FScalableFloat(5.f));
    
	UTargetTagsGameplayEffectComponent* TargetTags = CreateDefaultSubobject<UTargetTagsGameplayEffectComponent>(TEXT("TargetTagsComp"));
	FInheritedTagContainer TagChanges = TargetTags->GetConfiguredTargetTagChanges();
	TagChanges.Added.AddTag(TAG_Cooldown_Heal);
	TargetTags->SetAndApplyTargetTagChanges(TagChanges);
}
  1. Heal Effect (예시)
    • Attribute Set에서 체력 값을 증가
UHealEffect::UHealEffect()
{
    DurationPolicy = EGameplayEffectDurationType::Instant;

    FGameplayModifierInfo HealthMod;
    HealthMod.Attribute         = UMyAttributeSet::GetHealthAttribute();
    HealthMod.ModifierOp        = EGameplayModOp::Additive; 
    HealthMod.ModifierMagnitude = FGameplayEffectModifierMagnitude(FScalableFloat(80.f));
    Modifiers.Add(HealthMod);
}
  1. Ability에 Cost & Cooldown Effect 설정
UHealAbility::UHealAbility()
{
    // 인스턴싱 설정
    InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;

    // Cost와 Cooldown Effect 연결 - GameplayAbility 내부에 이미 선언
    CostGameplayEffectClass = UHealCostEffect::StaticClass();
    CooldownGameplayEffectClass = UHealCooldownEffect::StaticClass();

    // 실제 힐링 Effect 설정 - UHealAbility.h 파일에서 선언
    HealEffectClass = UHealEffect::StaticClass();
}
  1. Effect 중첩 설정
UStrengthBuffEffect::UStrengthBuffEffect()
{
	...
    
	StackingType = EGameplayEffectStackingType::AggregateByTarget;
	StackLimitCount = 5;
	StackDurationRefreshPolicy = EGameplayEffectStackingDurationPolicy::RefreshOnSuccessfulApplication;
	StackPeriodResetPolicy = EGameplayEffectStackingPeriodPolicy::ResetOnSuccessfulApplication;
}
  1. Effect 적용
void UBuffAbility::ActivateAbility(...)
{
	...

    if (BuffEffectClass && ActorInfo->AbilitySystemComponent.IsValid())
    {
        FGameplayEffectContextHandle ContextHandle =
            ActorInfo->AbilitySystemComponent->MakeEffectContext();
        ContextHandle.AddSourceObject(this);

        FGameplayEffectSpecHandle SpecHandle =
            ActorInfo->AbilitySystemComponent->MakeOutgoingSpec(
                BuffEffectClass, 1, ContextHandle);

        if (SpecHandle.IsValid())
        {
            FActiveGameplayEffectHandle ActiveHandle =
                ActorInfo->AbilitySystemComponent->ApplyGameplayEffectSpecToSelf(
                    *SpecHandle.Data.Get());

            if (ActiveHandle.WasSuccessfullyApplied())
            {
                UE_LOG(LogTemp, Log, TEXT("Strength Buff applied!"));
            }
        }
    }
}

오늘의 CS

스택 오버플로우

  • 정의
    • 스택에 할당된 공간을 초과하여 데이터를 저장하려 할 때 발생하는 오류
  • 원인
    1. 무한 재귀 호출 : 함수가 자기 자신을 끝없이 호출하는 무한 재귀에 빠질 때 발생
    2. 지나치게 큰 지역 변수 : 함수 내에서 매우 큰 배열 같은 지역 변수를 선언하면, 스택 공간을 너무 많이 차지하여 오버플로우 발생 가능
  • 해결법
    1. 함수 종료 조건을 명확하게 함
    2. 재귀 대신 반복문을 사용
    3. 과도한 스택 사이즈보다는 동적 메모리 할당을 사용
    4. 컴파일러 옵션을 통한 스택 사이즈 조절


댕글링 포인터 (Dangling Pointer)

  • 유효하지 않은(이미 해제되었거나 존재하지 않는) 메모리를 가리키는 포인터
  • 보통 어떤 리소스를 가리키는 포인터를 2개 만들었을 때, 이미 다른 포인터가 해당 리소스를 해제한지 모르고 포인터를 참조했을 때 발생
  • 스코프를 벗어난 지역 변수 참조, 잘못된 포인터 연산

포인터 vs 레퍼런스의 성능 차이

  • 단순히 언어 차원에서의 성능보다는, CPU 메모리 계층 구조메모리 접근 패턴에서 차이가 나게 됨
  • 레퍼런스
    • 이미 존재하는 객체의 별칭으로, 가리키는 대상이 확정적 정보이기 때문에 주소가 이미 확정적이라서, 컴파일러는 보통 레지스터로 최적화해서 접근
  • 포인터
    • 런타임에 가리키는 대상이 달라질 수 있기 때문에 최적화를 제한적으로 적용하게 되고, 불필요한 메모리 접근이 발생할 수 있음
    • 포인터가 랜덤한 위치를 가리킨다면, CPU 캐시에 데이터가 없을 확률이 커져서 캐시 미스 발생


캐시 히트와 메모리 접근 패턴

  • CPU 캐시는 공간 지역성과 시간 지역성을 이용
    • 공간 지역성 : 가까운 메모리는 같이 쓰일 확률이 높음
    • 시간 지역성 : 최근에 쓴 메모리는 또 쓸 확률이 높음
  • 캐시 히트 : CPU가 어떤 데이터를 읽으려 할 때, 이미 캐시에 그 데이터가 존재하는 경우
  • 캐시 미스 : CPU가 요청한 데이터가 캐시에 없어서 RAM에서 가져와야 하는 경우
  • 캐시 친화적인 구조
    • 연속된 컨테이너(배열) 사용
    • AoS (Array of Structures) 보다는 SoA(Structure of Arrays) 사용

AoS vs SoA

  • AoS (Array of Structures)
    • 메모리 구조 : [x,y,z,vx,vy,vz][x,y,z,vx,vy,vz][x,y,z,vx,vy,vz]...
    • 장점 : 직관적, 객체지향적
    • 단점 : x만 필요해도 (x,y,z,vx,vy,vz)를 한꺼번에 캐시로 가져옴
struct Particle {
    float x, y, z;   
    float vx, vy, vz;
};

std::vector<Particle> particles;
  • SoA (Structure of Arrays)
    • 메모리 구조 : [x0,x1,x2...][y0,y1,y2...]...
    • 장점 : x 좌표만 연산할 때, 캐시에 x 값들만 맞게 올라옴 -> 캐시 히트율 증가
    • 단점 : 구조가 복잡해지고 관리가 힘듦
struct Particles {
    std::vector<float> x, y, z;
    std::vector<float> vx, vy, vz;
};
profile
게임 개발자를 향해..

0개의 댓글