PART 3 · 강의 2/3

커스텀 Slate 위젯

SLeafWidget으로 직접 렌더링하는 위젯을 만들고, UWidget으로 래핑하여 UMG 에디터에서 사용하는 방법을 학습합니다.

01

SLeafWidget 이해

자식 없이 직접 그리는 말단 위젯

SLeafWidget은 자식 위젯 없이 직접 렌더링을 담당하는 위젯입니다. OnPaint()를 오버라이드하여 도형, 선, 텍스트 등을 직접 그립니다. 커스텀 게이지, 미니맵, 레이더 등에 활용됩니다.

C++ - SLeafWidget 커스텀 원형 게이지
class SCircularGauge : public SLeafWidget { public: SLATE_BEGIN_ARGS(SCircularGauge) : _Percent(1.0f) , _Thickness(4.0f) , _Color(FLinearColor::Cyan) {} SLATE_ATTRIBUTE(float, Percent) SLATE_ATTRIBUTE(float, Thickness) SLATE_ATTRIBUTE(FLinearColor, Color) SLATE_END_ARGS() void Construct(const FArguments& InArgs) { Percent = InArgs._Percent; Thickness = InArgs._Thickness; Color = InArgs._Color; } // 위젯의 희망 크기 반환 virtual FVector2D ComputeDesiredSize(float) const override { return FVector2D(64.f, 64.f); } // 직접 렌더링 virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; private: TAttribute<float> Percent; TAttribute<float> Thickness; TAttribute<FLinearColor> Color; };

SCompoundWidget

  • - 기존 Slate 위젯을 조합
  • - ChildSlot에 자식 배치
  • - OnPaint 오버라이드 불필요
  • - 대부분의 커스텀 UI에 적합

SLeafWidget

  • - 자식 위젯 없음
  • - OnPaint에서 직접 그림
  • - FSlateDrawElement 사용
  • - 커스텀 렌더링이 필요한 경우
02

OnPaint 구현

FSlateDrawElement로 직접 렌더링하기

C++ - OnPaint 구현 예제
int32 SCircularGauge::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { const FVector2D LocalSize = AllottedGeometry.GetLocalSize(); const FVector2D Center = LocalSize * 0.5f; const float Radius = FMath::Min(Center.X, Center.Y) - Thickness.Get(); // 호(arc)를 이루는 점들 생성 const int32 NumSegments = 32; const float AngleStep = 2.f * PI * Percent.Get() / NumSegments; TArray<FVector2D> Points; for (int32 i = 0; i <= NumSegments; ++i) { float Angle = -PI / 2.f + i * AngleStep; // 12시 시작 Points.Add(FVector2D( Center.X + Radius * FMath::Cos(Angle), Center.Y + Radius * FMath::Sin(Angle) )); } // 배경 원 그리기 FSlateDrawElement::MakeLines( OutDrawElements, LayerId, AllottedGeometry.ToPaintGeometry(), /* 전체 원 점 배열 */ BackgroundPoints, ESlateDrawEffect::None, FLinearColor(0.2f, 0.2f, 0.2f), true, // bAntialias Thickness.Get() ); // 전경 호 그리기 (퍼센트에 따라) FSlateDrawElement::MakeLines( OutDrawElements, LayerId + 1, AllottedGeometry.ToPaintGeometry(), Points, ESlateDrawEffect::None, Color.Get(), true, Thickness.Get() ); return LayerId + 1; }
FSlateDrawElement 주요 메서드

MakeBox() - 사각형/이미지 렌더링, MakeLines() - 선/경로 렌더링, MakeText() - 텍스트 렌더링, MakeSpline() - 스플라인 곡선 렌더링. 각 메서드는 LayerId를 반환하여 그리기 순서를 제어합니다.

03

UWidget 래핑

Slate 위젯을 UMG에서 사용 가능하게 만들기

커스텀 Slate 위젯을 블루프린트와 UMG 디자이너에서 사용하려면 UWidget 서브클래스로 래핑해야 합니다.

C++ - UWidget 래핑 완전한 예제
// .h 파일 UCLASS() class UCircularGaugeWidget : public UWidget { GENERATED_BODY() public: // UMG 에디터/블루프린트에 노출되는 프로퍼티 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gauge") float Percent = 1.0f; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gauge") float Thickness = 4.0f; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gauge") FLinearColor GaugeColor = FLinearColor::Cyan; // 블루프린트에서 호출 가능한 함수 UFUNCTION(BlueprintCallable, Category = "Gauge") void SetPercent(float NewPercent); protected: // Slate 위젯 생성 virtual TSharedRef<SWidget> RebuildWidget() override; // Slate 리소스 해제 virtual void ReleaseSlateResources(bool bReleaseChildren) override; // UPROPERTY를 SWidget에 동기화 virtual void SynchronizeProperties() override; private: TSharedPtr<SCircularGauge> MySlateGauge; }; // .cpp 파일 TSharedRef<SWidget> UCircularGaugeWidget::RebuildWidget() { MySlateGauge = SNew(SCircularGauge) .Percent(Percent) .Thickness(Thickness) .Color(GaugeColor); return MySlateGauge.ToSharedRef(); } void UCircularGaugeWidget::ReleaseSlateResources(bool bReleaseChildren) { Super::ReleaseSlateResources(bReleaseChildren); MySlateGauge.Reset(); } void UCircularGaugeWidget::SynchronizeProperties() { Super::SynchronizeProperties(); // 에디터에서 프로퍼티 변경 시 Slate 위젯에 반영 // TAttribute 재설정으로 동기화 } void UCircularGaugeWidget::SetPercent(float NewPercent) { Percent = FMath::Clamp(NewPercent, 0.f, 1.f); // Slate 위젯에 직접 전달 }
에디터 미리보기

SynchronizeProperties()는 에디터의 Widget Designer에서 프로퍼티를 변경할 때도 호출됩니다. 이를 통해 디자이너에서 실시간 미리보기가 가능합니다. 에디터 전용 미리보기가 필요하면 NativePreConstruct()도 활용하세요.

04

이벤트 처리와 상호작용

마우스/키보드 이벤트 처리 오버라이드

C++ - 마우스 이벤트 처리
class SInteractiveWidget : public SLeafWidget { public: // 마우스 클릭 처리 virtual FReply OnMouseButtonDown( const FGeometry& Geometry, const FPointerEvent& MouseEvent) override { if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) { bIsPressed = true; return FReply::Handled().CaptureMouse(SharedThis(this)); } return FReply::Unhandled(); } virtual FReply OnMouseButtonUp( const FGeometry& Geometry, const FPointerEvent& MouseEvent) override { bIsPressed = false; return FReply::Handled().ReleaseMouseCapture(); } // 마우스 호버 처리 virtual void OnMouseEnter( const FGeometry& Geometry, const FPointerEvent& MouseEvent) override { bIsHovered = true; } virtual void OnMouseLeave( const FPointerEvent& MouseEvent) override { bIsHovered = false; } // 드래그 처리 virtual FReply OnMouseMove( const FGeometry& Geometry, const FPointerEvent& MouseEvent) override { if (bIsPressed) { // 드래그 로직 FVector2D LocalPos = Geometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition()); } return FReply::Handled(); } };
SUMMARY

핵심 요약

  • SLeafWidget은 자식 없이 OnPaint()에서 직접 렌더링하는 말단 위젯이며, SCompoundWidget은 기존 위젯을 조합하는 복합 위젯입니다
  • FSlateDrawElement::MakeBox/MakeLines/MakeText 등으로 OnPaint() 내에서 커스텀 렌더링을 수행합니다
  • Slate 위젯을 UMG에서 사용하려면 UWidget 서브클래스로 래핑하고 RebuildWidget(), ReleaseSlateResources(), SynchronizeProperties()를 구현합니다
  • 마우스 이벤트는 OnMouseButtonDown, OnMouseEnter 등을 오버라이드하고 FReply로 처리 결과를 반환합니다
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: SLeafWidget으로 원형 게이지 구현

SLeafWidget을 상속하여 OnPaint()에서 FSlateDrawElement::MakeLines()로 원형 게이지를 직접 그리는 위젯을 만드세요. Percent, Color, Thickness 속성을 SLATE_ATTRIBUTE로 노출합니다.

실습 2: UWidget 래핑 및 에디터 노출

만든 SLeafWidget을 UWidget으로 래핑하는 클래스를 작성하세요. RebuildWidget()에서 Slate 위젯을 생성하고, SynchronizeProperties()로 UPROPERTY 변경을 동기화하여 Widget Blueprint에서 사용 가능하게 합니다.

심화 과제

SLeafWidget 기반으로 실시간 미니맵 위젯을 구현하세요. OnPaint()에서 배경 텍스처, 플레이어 위치 마커, 적 마커, 시야 범위(부채꼴)를 직접 렌더링하고, UWidget으로 래핑하여 HUD에 배치합니다.