How to draw HUD in editor?
I’m trying to draw some 2D lines in 2D screen space.
I setup my HUD class and my slate widget, and when in PIE mode,
it worked well, but now I want my HUD display in editor, I searched Google
with key word “UE4 SHOW HUD IN EDITOR” but got nothing.
What should I do to enable mu HUD in editor?
Thanks!
Update: after about one week studying source code of UE4, I finally managed
draw HUD in editor. yey!
It’s simple yet ugly.
FLevelEditorModule& LevelEditor = FModuleManager::GetModuleChecked<FLevelEditorModule>( TEXT("LevelEditor") );
TWeakPtr<SLevelEditor> editor = LevelEditor.GetLevelEditorInstance();
TSharedPtr<SLevelEditor> PinnedEditor( editor.Pin() );
if( PinnedEditor.IsValid() )
{
TSharedPtr<SLevelViewport> slevelviewport = PinnedEditor->GetActiveViewport();
FChildren* childrenSlot = slevelviewport->GetChildren();
if(childrenSlot )
{
const TSharedRef<SWidget>& Child = childrenSlot->GetChildAt(0)->GetChildren()->GetChildAt(0);
TSharedRef<SOverlay> ViewportWidget = StaticCastSharedRef<SOverlay>(Child);
ViewportWidget->AddSlot()
SNew(SOverlay)
+SOverlay::Slot()
.VAlign(VAlign_Top)
.HAlign(HAlign_Center)
SNew(STextBlock)
.ShadowColorAndOpacity(FLinearColor::Black)
.ColorAndOpacity(FLinearColor::Red)
.ShadowOffset(FIntPoint(-1, 1))
.Font(FSlateFontInfo("Veranda", 16))
.Text(LOCTEXT("HelloSlate", "Hello, Hooked Level Editor Slate :)))) "))
]
];
}
}
Another Update: Since my question is drawing 2D lines, so I’ll just continue here to show how to draw 2D lines.
First of all, create your own SCompoundWidget, in my case, it’s SMyCompoundWidget.
Then override OnPaint method:
//.h:
virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override;
//.cpp:
int32 SMyCompoundWidget::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}
Take a look at DrawElement.h, there are plenty of functions that you can use for doodling
I use FSlateDrawElement::MakeLines for drawing lines.
To draw a rectangle:
int32 size = 80;
const FVector2D P0( 0, 0 );
const FVector2D P1( 0,size);
const FVector2D P2( size,size);
const FVector2D P3( size,0);
// We want to draw this:
//(0,0)----->
// |
// | P0---------P1
// V | |
// | |
// | |
// | |
// P3---------P2
// Inner Box
{
TArray<FVector2D> InnerBox;
InnerBox.Add( P0 );
InnerBox.Add( P1 );
InnerBox.Add( P2 );
InnerBox.Add( P3 );
InnerBox.Add( P0 );
FSlateDrawElement::MakeLines(
OutDrawElements,
LayerId,
AllottedGeometry.ToPaintGeometry(),
InnerBox,
MyClippingRect
);
}
Finally, my SCompoundWidget::OnPaint looked like this:
int32 SMyCompoundWidget::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const
{
int32 size = 80;
const FVector2D P0( 0, 0 );
const FVector2D P1( 0,size);
const FVector2D P2( size,size);
const FVector2D P3( size,0);
// We want to draw this:
//(0,0)----->
// |
// | P0---------P1
// V | |
// | |
// | |
// | |
// P3---------P2
// Inner Box
{
TArray<FVector2D> InnerBox;
InnerBox.Add( P0 );
InnerBox.Add( P1 );
InnerBox.Add( P2 );
InnerBox.Add( P3 );
InnerBox.Add( P0 );
FSlateDrawElement::MakeLines(
OutDrawElements,
LayerId,
AllottedGeometry.ToPaintGeometry(),
InnerBox,
MyClippingRect
);
}
return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}
Now we’re done with SMyCompoundWidget.
Finally:
//change
ViewportWidget->AddSlot()
SNew(SOverlay)
+SOverlay::Slot()
.VAlign(VAlign_Top)
.HAlign(HAlign_Center)
SNew(STextBlock)
.ShadowColorAndOpacity(FLinearColor::Black)
.ColorAndOpacity(FLinearColor::Red)
.ShadowOffset(FIntPoint(-1, 1))
.Font(FSlateFontInfo("Veranda", 16))
.Text(LOCTEXT("HelloSlate", "Hello, Hooked Level Editor Slate :)))) "))
]
];
//to
ViewportWidget->AddSlot()[SNew(SMyCompoundWidget)];
Can you see that tiny little cute white rectangle on top left corner?
This little baby costs me almost one week. But, you know what, live & learn, and thank you Epic, for bringing such wonderful engine to us!
Thank you again!
Update:
Code
TWeakPtr<SLevelEditor> editor = LevelEditor.GetLevelEditorInstance();
TSharedPtr<SLevelEditor> PinnedEditor( editor.Pin() );
if( PinnedEditor.IsValid() )
{
TSharedPtr<SLevelViewport> slevelviewport = PinnedEditor->GetActiveViewport();
...
Sometimes won’t work on Windows, but perfectly on OS X.
When I say “sometimes”, which means I tried compile code without changing anything, sometimes it compiles, sometimes fails, but most of the time, it fails. This is really odd.
I don’t know why, it just keep failing linking even if I added “LevelEditor” dependency to Build.cs file, so if above code didn’t work, then try below:
TSharedPtr<SLevelViewport> slevelviewport = StaticCastSharedPtr<SLevelViewport>(LevelEditor.GetFirstActiveViewport());
This works.