문제: 

Tick 함수가 너무 길어짐

 

보통 

  • 함수는 한 가지 일만 해야 한다
  • 짧을수록 좋다 (보통 20줄 이내)
  • 함수 이름이 곧 문서다

 

Tick을 단계별로 분해

 

지금 Tick에서 일어나는 일을 큰 흐름으로 정리

1. 도로 위 진행도 갱신
2. 곡률 측정 (현재, 전방)
3. 조향 오차 3가지 계산
4. 오차들을 핸들 입력으로 변환
5. 목표 속도 갱신
6. 속도를 페달 입력으로 변환

 

 

리팩토링 후 Tick (AI 도움)

void TickComponent(float DeltaTime, ...)
{
    Super::TickComponent(...);

    if (!OwnerPawn.IsValid() || !TargetRoad.IsValid()) return;

    const FVector VehicleLoc = OwnerPawn->GetActorLocation();
    const float VehicleSpeed = OwnerPawn->GetVelocity().Size();
    const float VehicleYaw = OwnerPawn->GetActorRotation().Yaw;

    // 1. 진행도 갱신 + 끝 도달 체크
    if (UpdateProgressDistance(VehicleLoc, VehicleSpeed))
    {
        HandlePathCompleted();
        return;
    }

    // 2. 곡률 측정
    float CurvHere, CurvAhead;
    SampleCurvatures(CurvHere, CurvAhead);

    // 3-4. 조향 명령 계산 → 적용
    const FSteeringErrors Errors = ComputeSteeringErrors(VehicleLoc, VehicleYaw, VehicleSpeed, CurvHere);
    const float Steer = BlendSteeringInput(Errors, CurvHere);
    ApplySteeringCommand(Steer);

    // 5-6. 속도 명령 계산 → 적용
    const float TargetSpeed = UpdateTargetSpeed(CurvHere, CurvAhead, DeltaTime);
    ApplySpeedCommand(TargetSpeed, VehicleSpeed);
}

 

각 함수의 책임

// 한 가지 일만 하는 함수들
bool UpdateProgressDistance(...)            // 진행도 갱신만
void SampleCurvatures(float& A, float& B)   // 곡률 측정만
FSteeringErrors ComputeSteeringErrors(...)  // 오차 계산만
float BlendSteeringInput(...)               // 오차 → 핸들 변환만
float UpdateTargetSpeed(...)                // 목표 속도 결정만
void ApplySpeedCommand(...)                 // 속도 명령 적용만

 

 

데이터 구조체 도입

 

구조체로 묶기

struct FSteeringErrors
{
    float PositionError = 0.f;
    float HeadingError = 0.f;
    float CrossTrackError = 0.f;
};

 

함수가 깔끔해진다

FSteeringErrors ComputeSteeringErrors(
    const FVector& VehicleLocation,
    float VehicleYaw,
    float VehicleSpeed,
    float CurvHere
) const;

 

호출하는 쪽도

const FSteeringErrors Errors = ComputeSteeringErrors(...);
const float Steer = BlendSteeringInput(Errors, CurvHere);

 

데이터가 함께 다닐 거면 구조체로 묶자

인자 4개를 따로 넘기는 것보다 의미가 명확


코드 곳곳에 있는 알 수 없는 숫자들 정리

 

UPROPERTY로 추출

UPROPERTY(EditAnywhere, BlueprintReadWrite,
    Category = "Team24|Autopilot|Steering",
    meta=(AllowPrivateAccess="true"))
float SharpCurveSensitivity = 3.f;

UPROPERTY(EditAnywhere, BlueprintReadWrite,
    Category = "Team24|Autopilot|Steering",
    meta=(ClampMin="0.1", ClampMax="1.0", AllowPrivateAccess="true"))
float SharpCurveLookAheadScale = 0.5f;

UPROPERTY(EditAnywhere, BlueprintReadWrite,
    Category = "Team24|Autopilot|Steering",
    meta=(ClampMin="0", ClampMax="1", AllowPrivateAccess="true"))
float HeadingWeight = 0.7f;

UPROPERTY(EditAnywhere, BlueprintReadWrite,
    Category = "Team24|Autopilot|Steering",
    meta=(ClampMin="0", ClampMax="1", AllowPrivateAccess="true"))
float HeadingWeightOnSharpCurve = 0.3f;

UPROPERTY(EditAnywhere, BlueprintReadWrite,
    Category = "Team24|Autopilot|Speed",
    meta=(AllowPrivateAccess="true"))
float CoastDeadzone = 0.05f;

 

코드 사용부

const float CurvNorm = FMath::Clamp(CurvHere * SharpCurveSensitivity, 0.f, 1.f);
const float CurvScale = FMath::Lerp(1.f, SharpCurveLookAheadScale, CurvNorm);
const float HdgW = FMath::Lerp(HeadingWeight, HeadingWeightOnSharpCurve,

 

 

UPROPERTY 옵션 정리

매번 헷갈리는 옵션들

EditAnywhere 에디터 어디서든 수정 가능
BlueprintReadWrite 블루프린트에서도 읽고 쓸 수 있음
Category 디테일 패널 분류 (계층은 | 로)
meta=(ClampMin="0") 최솟값 제한
meta=(AllowPrivateAccess="true") private 멤버라도 블루프린트 접근 허용

효과

  • 차가 너무 둔감하다 → HeadingWeight 0.7 → 0.6 으로 변경
  • 급커브에서 잘린다 → SharpCurveLookAheadScale 0.5 → 0.4로 변경

디지털 트윈 확장 준비

RoadActor에 메타데이터 추가

지금까지는 도로가 그냥 경로였지만 디지털 트윈으로 가려면 도로에 더 많은 정보가 필요함

class ARoadActor : public AActor
{
    /* 도로 이름 (디버그용) */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Team24|Road")
    FString RoadName = TEXT("Unnamed Road");

    /* 제한 속도 (cm/s, 0이면 무제한) */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Team24|Road",
        meta=(ClampMin="0"))
    float SpeedLimit = 0.f;

    /* 자율주행에 사용할지 여부 */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Team24|Road")
    bool bUseForAutopilot = true;
};

 

 

이런 정보들이 도로에 직접 붙어있으면 자율주행 컴포넌트가

  • 여기는 위험 구역이니 미리 감속
  • 어린이보호구역이니 30km/h
  • 신호등이 있으니 정지 준비

같은 방어 운전 로직을 추가하기 쉬워짐

+ Recent posts