TIL_080 : 대각선 맵, Crouch, 스택오버플로우

김펭귄·2025년 12월 12일

Today What I Learned (TIL)

목록 보기
80/111

오늘 학습 키워드

  • 대각선 맵

  • 스택오버플로우 해결

1. 대각선 맵

  • 좀보이드는 맵이 대각선으로 기울어진 형태로 되어 있다. 건물, 차, 방의 구조 등 모두 대각선 형태

  • 하지만, 맵에서 액터를 배치할 때 항상 대각선으로 돌려서 배치하기엔 너무 효율성이 떨어질 것 같아 다른 방법이 없을까 고민해보았다

  • 그래서 맵을 대각선으로 돌리는 대신에 카메라를 45도 회전시키면 동일한 효과를 나타낼 수 있을 것 같아 레벨에 액터는 똑바르게 배치하고, 카메라만 회전시켜 해결하였다

1.1. 스프링암

// PlayerCharacter.cpp

SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
SpringArm->SetupAttachment(RootComponent);
SpringArm->SetUsingAbsoluteRotation(true);
SpringArm->TargetArmLength = 1800.f;
SpringArm->SetRelativeRotation(FRotator(-50.f, 45.f, 0.f));
SpringArm->bDoCollisionTest = false;
  • 탑다운 방식이므로 스프링암을 위로 회전시키고, 대각방향으로 회전시켜주었다

  • 탑다운 방식의 게임에선 카메라가 벽에 부딪힌다고 스프링암의 길이가 줄어들거나 하면 안 되므로, bDoCollisionTestfalse로 설정하여, 카메라가 고정된 느낌을 주도록 하였다

1.2. 이동

// PlayerCharacter.cpp
void AMyCharacter::MoveAction(const FInputActionValue& Value)
{
	const FVector2D InMovementVector = Value.Get<FVector2D>();

	AddMovementInput(Camera->GetForwardVector(), InMovementVector.X);
	AddMovementInput(Camera->GetRightVector(), InMovementVector.Y);
}
  • 카메라가 회전되었기에 월드가 회전된 것처럼 보이지만, 캐릭터의 이동은 카메라가 바라보는 기준으로 상하좌우로 움직여야 함

  • 따라서, 월드나 컨트롤러를 기준으로 하는 것이 아닌 카메라를 기준으로 삼아 이동

1.3. 결과영상

2. Crouch

  • ACharacter가 기본적으로 가지고 있는 Crouch함수를 사용하려고 함

  • bIsCrouched 변수를 통해, 현재 캐릭터가 앉아있는지, 아닌지를 확인

  • GetCharacterMovement()->NavAgentProps.bCanCrouch 값을 참으로 해줘야 실제로 앉기가 작동함

  • 원하는 속도로 움직이게 하고 싶어 MaxWalkSpeedCrouched에 직접 값 입력

  • Crouch함수가 호출되면 캡슐 사이즈도 작아지면서 스프링암도 밑으로 당겨지게 된다. 그래서 SpringArm->bEnableCameraLag을 참으로 하여 카메라가 부드럽게 이동하게 함

  • 이러면 위치, 회전만 부드럽게 되는거고 타겟암의 길이변화에 대해선 해당되지 않음

void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	EnhancedInput->BindAction(PlayerController->CrouchAction, 
    						  ETriggerEvent::Started, 
                              this, 
                              &AMyCharacter::StartCrouch);
}

void AMyCharacter::StartCrouch(const FInputActionValue& Value)
{
	if (GetCharacterMovement())
	{
		if (bIsCrouched)
		{
			GetCharacterMovement()->MaxWalkSpeedCrouched = BaseWalkSpeed;
			UnCrouch(true);
		}
		else
		{
			if (CanCrouch())
			{
				GetCharacterMovement()->MaxWalkSpeedCrouched = 
                	BaseWalkSpeed * CrouchSpeedMultiplier;
				Crouch(true);
			}
		}
	}
}

3. 스택오버플로우 해결

  • 지역변수를 너무 많이 할당받거나, 재귀함수를 계속 호출하여 스택의 용량이 부족할 때 발생

  • 해결법으로는 아래와 같음

  1. 크기가 너무 큰 지역변수는 new를 이용해 힙에 할당받음

  2. 재귀함수의 최대 깊이 한도를 조절하여 설계함 (memoization으로도 가능)

  3. 재귀함수를 사용하지 않고 반복문을 이용해 stack메모리를 계속 할당받지 않도록 함

  4. 애초에 컴파일 전에 스택메모리 크기 제한을 풀어 좀 많이 늘려버린다

3.1. reserve / commit

  • reserve

    • 스레드가 사용할 스택 주소 범위를 미리 예약해 두는 것으로, 가상 주소 공간만 확보한 상태
    • 실제 RAM이나 페이지 파일을 거의 쓰지 않기 때문에 물리 메모리 사용량은 늘지 않음
  • commit

    • reserve로 확보해 둔 주소 중 실제로 사용 가능한 스택 부분에 대해 물리 메모리(또는 페이지 파일)를 할당해 둔 크기
    • 처음 시작할 때 실제 메모리에 올라가게 되는 스택의 초기 크기

MSDN 참고자료

profile
반갑습니다

0개의 댓글