09.24 - TIL

김혁·2025년 9월 24일

TIL

목록 보기
25/84

오늘의 코드카타

상담원 인원

  • 그리디를 활용한 인원 분배
  • 우선순위 큐를 활용한 시간 계산
  • LV3 - 16%
    -> 문제 풀이

오늘의 공부

문 액터 만들기

1. 인터렉션 컴포넌트 만들기

  • IMC_InteractionIA_Interact를 선언해서 입력을 연결
  • 라인트레이스를 통해 검사한 후에 인터페이스를 통해 Interact() 실행
// EGInteractionComponent.cpp

void UEGInteractionComponent::SetupInput()
{
	if (ACharacter* Character = Cast<ACharacter>(GetOwner()))
	{
		if (APlayerController* PC = Cast<APlayerController>(Character->GetController()))
		{
			if (ULocalPlayer* LocalPlayer = PC->GetLocalPlayer())
			{
				if (UEnhancedInputLocalPlayerSubsystem* Subsystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
				{
					if (IMC_Interaction)
					{
						Subsystem->AddMappingContext(IMC_Interaction, 0);
					}
				}
			}

			if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(PC->InputComponent))
			{
				if (IA_Interact)
				{
					EIC->BindAction(IA_Interact, ETriggerEvent::Started, this, &UEGInteractionComponent::HandleInteract);
				}
			}
		}
	}
}

void UEGInteractionComponent::PerformInteraction()
{
	AActor* Owner = GetOwner();
	if (!Owner) return;

	FVector StartLoc = Owner->GetActorLocation();
	FVector ForwardVec = Owner->GetActorForwardVector();
	FVector EndLoc = StartLoc + ForwardVec * TraceDistance;

	FHitResult Hit;
	FCollisionQueryParams Params;
	Params.AddIgnoredActor(Owner);

	if (GetWorld()->LineTraceSingleByChannel(Hit, StartLoc, EndLoc, ECC_Visibility, Params))
	{
		if (AActor* HitActor = Hit.GetActor())
		{
			if (HitActor->GetClass()->ImplementsInterface(UEGInteractInterface::StaticClass()))
			{
				IEGInteractInterface::Execute_Interact(HitActor);
			}
		}
	}
    
    DrawDebugLine(GetWorld(), StartLoc, EndLoc, FColor::Green, false, 3.f, 0, 2.f);
}

2. 인터랙트 인터페이스 생성

class EG_API IEGInteractInterface
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Interact")
	void Interact();
};

3. 문 액터 생성

  • 인터랙트 인터페이스 기반으로 문 열고 닫히는 액터 생성
  • 타임라인 활용해서 액터 로테이션 설정
    -> 타임라인은 왠만하면 블루프린트를 활용하자..
// EGDoor.h
UPROPERTY()
UTimelineComponent* DoorTimeline;

UPROPERTY(EditAnywhere)
UCurveFloat* DoorCurve;

// EGDoor.cpp
void AEGDoor::BeginPlay()
{
	Super::BeginPlay();
    
	if (DoorCurve)
	{
		FOnTimelineFloat InterpFunction;
		InterpFunction.BindUFunction(this, FName("HandleDoor"));
		
		DoorTimeline->AddInterpFloat(DoorCurve, InterpFunction);
		DoorTimeline->SetLooping(false);
	}
}

void AEGDoor::Interact_Implementation()
{
	if (DoorTimeline->IsPlaying())
	{
		DoorTimeline->Reverse();
	}
	else
	{
		if (bIsOpen)
		{
			DoorTimeline->ReverseFromEnd();
		}
		else
		{
			DoorTimeline->PlayFromStart();
		}
	}
	
	bIsOpen = !bIsOpen;
}

오늘의 CS

컨텍스트 스위칭

  • 컨텍스트
    • CPU가 처리하는 프로세스나 스레드의 현재 실행 상태
    • 어디까지 실행했는지, 어떤 자원을 쓰고 있는지를 저장한 정보
  • 개념
    • 운영체제가 CPU를 여러 프로세스/스레드를 번갈아 사용할 수 있도록 하는 기술
    • 멀티 프로세스 환경에서 CPU가 처리 중인 프로세스의 정보를 바꾸는 것
    • 레지스터에 로드하는 동안 CPU가 일을 못하기 때문에 오버헤드가 발생
  • 실행 과정
    1. CPU가 P1을 처리하던 중 OS에 의해 인터럽트 발생
    2. CPU 스케줄러는 레지스터에 있는 실행 중이던 프로세스의 상태를 PCB(Process Control Block)에 저장
    3. P2의 PCB에 있는 정보를 가져와 레지스터에 로드하고 CPU는 P2를 처리함
    4. P2 처리가 끝나면 다시 P1을 레지스터에 로드하고 프로세스를 계속 실행
  • PCB(Process Control Block)
    • OS가 프로세스를 관리하는 데 필요한 모든 정보를 담고 있는 자료구조
    • 각각의 프로세스는 고유한 PCB를 가지며, 프로세스가 생성될 때 함께 만들어지고 종료되면 사라짐
    • 레지스터 값, 프로그램 카운터, 스택 포인터 등을 저장
  • 오버헤드
    • 레지스터 값 저장 / 복원 -> CPU 시간 소모(일 못함)
    • 캐시 메모리 : 다른 프로세스의 데이터로 덮이면 이전 프로세스의 데이터가 캐시에서 사라짐
      -> 다음에 접근할 때 RAM에서 다시 로드 필요 (캐시 미스 발생)
    • TLB : 프로세스 전환 시 다른 페이지 테이블을 쓰면 TLB 매핑이 무효화되어 다시 페이지 테이블을 읽어와야 함
  • 프로세스 컨텍스트 스위치 vs 스레드 컨텍스트 스위치
    • 프로세스 컨텍스트 스위치
      • 가상 메모리 주소 공간까지 바꿔야 함 -> 페이지 테이블 교체 필요, TLB 대량 무효화 필요
    • 스레드 컨텍스트 스위치
      • 같은 가상 메모리 주소 공간 공유 -> 페이지 테이블 교체 불필요, TLB 변환 필요 없음
        -> 스레드 전환은 동일한 가상주소 공간을 공유하므로 메모리 변환 캐시와 주소공간 관련 오버헤드를 피할 수 있어서 훨씬 비용이 싸다.
profile
게임 개발자를 향해..

0개의 댓글