팀프로젝트 - 자율주행 위험 구간 분석 시뮬레이터
역할 : 에이전트 로직 담당
클래스 구조
[월드]
│
├── ARoadActor (도로 경로 정의)
│ └── USplineComponent (스플라인 데이터)
│
└── APawn (차량)
└── USplineFollowerComponent (자율주행 로직)
└── 매 프레임 ARoadActor를 찾아 따라감
| ARoadActor | 도로의 형태와 속성 정의 |
| USplineFollowerComponent | 도로를 따라가는 운전 판단 |
| APawn | 실제로 움직이는 차량 객체 |
이렇게 분리하면 한 차량이 여러 도로를 갈아타거나, 여러 차량이 같은 도로를 공유하는 시나리오를 쉽게 구현할 수 있다
폴더 구조
Source/Team24Unreal/
├── Actor/
│ ├── RoadActor.h
│ └── RoadActor.cpp
└── Component/
├── SplineFollowerComponent.h
└── SplineFollowerComponent.cpp
팀 협업을 고려해 클래스 종류별로 폴더를 분리했다
- 곡선을 정의하는 컴포넌트
- 점을 여러 개 찍으면 자동으로 곡선이 됨
- 도로나 강 같은 거 만들 때 씀
스플라인 = 점들을 이어서 만든 곡선
사람이 운전할 때:
1. 도로를 본다 (눈)
2. 어디로 가야 할지 안다 (판단)
3. 핸들을 돌린다 (조향)
4. 페달을 밟는다 (가속/감속)
5. 커브가 보이면 미리 속도 줄인다
6. 도로 가운데에서 벗어나면 핸들로 보정한다
- 도로를 본다 → 어떻게든 도로 데이터를 가져와야 함
- 어디로 가야 할지 안다 → "앞쪽 어딘가 한 점"을 정해야 함
- 핸들을 돌린다 → 차의 방향을 바꿔야 함
- 페달을 밟는다 → 차의 속도를 바꿔야 함
1. 도로 — 월드에 놓여있고, 모양 정보를 가짐
2. 자동차 — 움직이는 물체
3. 자동 운전 두뇌 — 도로 보고 자동차 조작
→ 클래스 3개로 나누자.
근데 자동 운전 두뇌를 클래스로 따로 만들지, 아니면 자동차 안에 넣을지 고민됨.
- Actor: 월드에 직접 놓이는 것 (예: 자동차, 도로)
- Component: Actor에 붙여서 기능을 추가하는 것 (예: 메시, 충돌체, 카메라)
자동 운전 로직을 Component로 만들면:
- 자동차에 붙여서 자율주행 기능 추가
- 다른 차에도 똑같이 붙일 수 있음
- 자동차 클래스가 너무 커지지 않음
ARoadActor ← 도로 (Actor)
APawn (기본 사용) ← 자동차 (Pawn = 조종 가능한 Actor)
USplineFollowerComponent ← 자율주행 두뇌 (Component)
클래스 이름 앞 글자 A는 Actor, U는 UObject(Component 포함)라는 언리얼 컨벤션
RoadActor
Unreal Forums: SplineMeshComponent vs SplineComponent
- USplineComponent = 곡선 경로 정의 (보이지 않음)
- USplineMeshComponent = 두 점 사이에 메시를 휘어서 표시
내가 필요한 건 경로 데이터 → USplineComponent
AActor를 직접 상속받자
- ASplineActor는 그냥 AActor + USplineComponent를 묶어놓은 것
- 내가 직접 묶으면 더 자유로움 (나중에 위험 영역, 신호등 정보 같은 거 추가하기 쉬움)
- 디지털 트윈 프로젝트라 도로에 메타데이터가 많이 붙을 예정
→ 부모 클래스: AActor, 안에 USplineComponent를 직접 추가.
도로 위에 차 놓기
- GetLocationAtTime — 시간 기반? 안 쓸 듯
- GetLocationAtSplinePoint — 점 인덱스 기반
- GetLocationAtDistanceAlongSpline ← 거리로 위치를 얻는다
- FindLocationClosestToWorldLocation ← 가장 가까운 위치 찾기
- GetSplineLength — 전체 길이
차를 도로 시작점에 텔레포트
void BeginPlay()
{
ARoadActor* Road = ...;
USplineComponent* Spline = Road->GetSplineComponent();
FVector StartPos = Spline->GetLocationAtDistanceAlongSpline(0.f, ESplineCoordinateSpace::World);
OwnerPawn->SetActorLocation(StartPos);
}
"월드에서 Actor 어떻게 찾지?" 검색
→ Unreal 공식 문서: TActorIterator
for (TActorIterator<ARoadActor> It(GetWorld()); It; ++It)
{
ARoadActor* Road = *It;
// 이걸로 사용
}
SplineFollowerComponent를 만들기 시작
부모는 UActorComponent.
// SplineFollowerComponent.h (첫 버전)
UCLASS(meta=(BlueprintSpawnableComponent))
class TEAM24UNREAL_API USplineFollowerComponent : public UActorComponent
{
GENERATED_BODY()
public:
USplineFollowerComponent();
protected:
virtual void BeginPlay() override;
virtual void TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override;
private:
UPROPERTY()
TWeakObjectPtr<ARoadActor> TargetRoad;
UPROPERTY()
TWeakObjectPtr<APawn> OwnerPawn;
};
TWeakObjectPtr?
- 그냥 ARoadActor* (raw pointer): 객체가 삭제되면 댕글링 포인터 → 크래시
- TWeakObjectPtr<ARoadActor>: 객체가 삭제되면 자동으로 nullptr 처리
BeginPlay 첫 구현
void USplineFollowerComponent::BeginPlay()
{
Super::BeginPlay();
// 이 컴포넌트가 붙어있는 액터를 가져옴
OwnerPawn = Cast<APawn>(GetOwner());
// 월드에서 첫 번째 RoadActor 찾기
for (TActorIterator<ARoadActor> It(GetWorld()); It; ++It)
{
TargetRoad = *It;
break;
}
}
Cast<>는 다이나믹 캐스트 같은 것. 실패하면 nullptr.
위치 확인 및 이동시키기 (GetActorLocation / SetActorLocation)
// 1. 내 현재 위치 가져오기 (FVector는 X, Y, Z 좌표 상자)
FVector MyLocation = GetActorLocation();
// 2. 새로운 위치로 순간이동 시키기 (예: 하늘 위로 500만큼 띄우기)
FVector NewLocation = MyLocation + FVector(0.f, 0.f, 500.f);
SetActorLocation(NewLocation);
형변환, Cast
OwnerPawn = Cast<APawn>(GetOwner());
-> GetOwner()가 Pawn이면 이 코드에서 그거 이름을 OwnerPawn이라고 부르겠다.
아니면 nullptr이 반환됨
'프로젝트 > 자율주행 위험구간 분석 시뮬레이터' 카테고리의 다른 글
| 파라미터 (0) | 2026.05.08 |
|---|---|
| 코드 정리와 확장 준비 (0) | 2026.05.08 |
| 커브에서 안 미끄러지는 속도 제어 (0) | 2026.05.08 |
| 조향 알고리즘 (0) | 2026.05.08 |
| 매 프레임 도로 따라가기 (0) | 2026.05.07 |
