Reexport map textures and fixes for map marker, also fix for seed bed actor
This commit is contained in:
@@ -187,7 +187,7 @@ REM carries, which for this map are 16384 in eight tiles; a piece is baked at th
|
|||||||
REM pixels over a quarter of the width is what a piece is.
|
REM pixels over a quarter of the width is what a piece is.
|
||||||
SET MAP=/Game/Maps/Persistent_GameWorld
|
SET MAP=/Game/Maps/Persistent_GameWorld
|
||||||
SET BUILDER=-run=WorldPartitionBuilderCommandlet -Builder=/Script/ProjectEleriEditor.WorldMapBuilder -AllowCommandletRendering -SCCProvider=None -unattended -Verbose
|
SET BUILDER=-run=WorldPartitionBuilderCommandlet -Builder=/Script/ProjectEleriEditor.WorldMapBuilder -AllowCommandletRendering -SCCProvider=None -unattended -Verbose
|
||||||
SET PIECE_SIZE=8192
|
SET PIECE_SIZE=4096
|
||||||
SET PIECE_TILES=4
|
SET PIECE_TILES=4
|
||||||
SET PIECE_GRID=8
|
SET PIECE_GRID=8
|
||||||
SET PIECE_ROOT=%PROJECT_ROOT%Intermediate\WorldMap
|
SET PIECE_ROOT=%PROJECT_ROOT%Intermediate\WorldMap
|
||||||
|
|||||||
@@ -109,6 +109,8 @@ bSkipMovies=False
|
|||||||
+MapsToCook=(FilePath="/Game/Maps/W_Island_1")
|
+MapsToCook=(FilePath="/Game/Maps/W_Island_1")
|
||||||
+DirectoriesToAlwaysCook=(Path="/Game/GameData")
|
+DirectoriesToAlwaysCook=(Path="/Game/GameData")
|
||||||
+DirectoriesToAlwaysCook=(Path="/NNEDenoiser")
|
+DirectoriesToAlwaysCook=(Path="/NNEDenoiser")
|
||||||
|
+DirectoriesToAlwaysCook=(Path="/Game/Textures/Map")
|
||||||
|
+DirectoriesToAlwaysCook=(Path="/Game/Maps/Generated")
|
||||||
bRetainStagedDirectory=False
|
bRetainStagedDirectory=False
|
||||||
CustomStageCopyHandler=
|
CustomStageCopyHandler=
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/UI/WBP_MapWidget.uasset
LFS
BIN
Content/UI/WBP_MapWidget.uasset
LFS
Binary file not shown.
@@ -604,7 +604,10 @@ FSeedBedSeedSlot& ASeedBedActor::CreateSlot(FIntVector2 SlotCoordinate, bool bRe
|
|||||||
DestroySlotComponents(Slot);
|
DestroySlotComponents(Slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
Slot.SeedBedDecal = CreateSlotDecalComponent(this, GetRootComponent(), GetSlotComponentName(SlotCoordinate, TEXT("Slot")));
|
if (!IsValid(Slot.SeedBedDecal))
|
||||||
|
{
|
||||||
|
Slot.SeedBedDecal = CreateSlotDecalComponent(this, GetRootComponent(), GetSlotComponentName(SlotCoordinate, TEXT("Slot")));
|
||||||
|
}
|
||||||
if (SeedBedDecalMaterial.IsValid())
|
if (SeedBedDecalMaterial.IsValid())
|
||||||
{
|
{
|
||||||
Slot.SeedBedDynamicMat = UKismetMaterialLibrary::CreateDynamicMaterialInstance(this, SeedBedDecalMaterial.Get(), NAME_None, EMIDCreationFlags::Transient);
|
Slot.SeedBedDynamicMat = UKismetMaterialLibrary::CreateDynamicMaterialInstance(this, SeedBedDecalMaterial.Get(), NAME_None, EMIDCreationFlags::Transient);
|
||||||
|
|||||||
@@ -121,8 +121,15 @@ UMapWidget::UMapWidget()
|
|||||||
bCenterOnPlayerByDefault = true;
|
bCenterOnPlayerByDefault = true;
|
||||||
MarkerSize = 32.f;
|
MarkerSize = 32.f;
|
||||||
|
|
||||||
|
// The marker comes down as the map is pulled back, but by less than the map does: readable when the whole
|
||||||
|
// map is in view, without crowding a map that is zoomed in on a corner of itself.
|
||||||
|
MarkerZoomScale = -0.5f;
|
||||||
|
|
||||||
MarkerFacingOffset = 0.f;
|
MarkerFacingOffset = 0.f;
|
||||||
|
|
||||||
|
// PlayerMarkerTexture is deliberately left empty: what the marker is a picture of is the design's to say,
|
||||||
|
// and a map with nothing set there draws no marker rather than failing to open.
|
||||||
|
|
||||||
MapBackgroundColor = FLinearColor(0.03f, 0.04f, 0.05f, 0.9f);
|
MapBackgroundColor = FLinearColor(0.03f, 0.04f, 0.05f, 0.9f);
|
||||||
|
|
||||||
Zoom = 1.f;
|
Zoom = 1.f;
|
||||||
@@ -132,13 +139,14 @@ UMapWidget::UMapWidget()
|
|||||||
|
|
||||||
bMapReady = false;
|
bMapReady = false;
|
||||||
bPiecesRequested = false;
|
bPiecesRequested = false;
|
||||||
|
bMarkerRequested = false;
|
||||||
bMarkerPlaced = false;
|
bMarkerPlaced = false;
|
||||||
|
|
||||||
// Nothing has been turned yet, and there is no map yet to say how the map lies in the world.
|
// Nothing has been turned yet, and there is no map yet to say how the map lies in the world.
|
||||||
MarkerAngle = 0.f;
|
MarkerAngle = 0.f;
|
||||||
bMarkerAngleApplied = false;
|
bMarkerAngleApplied = false;
|
||||||
|
|
||||||
// Nothing has been said yet about the design having no marker in it.
|
// Nothing has been said yet about this map having no marker art assigned.
|
||||||
bMissingMarkerReported = false;
|
bMissingMarkerReported = false;
|
||||||
MapUVPerWorldX = FVector2D::ZeroVector;
|
MapUVPerWorldX = FVector2D::ZeroVector;
|
||||||
MapUVPerWorldY = FVector2D::ZeroVector;
|
MapUVPerWorldY = FVector2D::ZeroVector;
|
||||||
@@ -172,9 +180,9 @@ TSharedRef<SWidget> UMapWidget::RebuildWidget()
|
|||||||
void UMapWidget::EnsureWidgetTree()
|
void UMapWidget::EnsureWidgetTree()
|
||||||
{
|
{
|
||||||
// Called from RebuildWidget and again from everything that wants the map on screen, so the work is only
|
// Called from RebuildWidget and again from everything that wants the map on screen, so the work is only
|
||||||
// done when there is something to do: a standing tree is the whole test. The marker is not part of it,
|
// done when there is something to do: a standing tree is the whole test, and the marker built below is as
|
||||||
// because the design's marker is not the map's to make.
|
// much a part of that tree as the pieces are.
|
||||||
if (MapRoot && MapViewport && MapLayer && PieceGrid && Interaction)
|
if (MapRoot && MapViewport && MapLayer && PieceGrid && PlayerMarker && Interaction)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -267,9 +275,25 @@ void UMapWidget::EnsureWidgetTree()
|
|||||||
NewPieceImages.Add(PieceImage);
|
NewPieceImages.Add(PieceImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The player's marker is not built here: it is the widget named PlayerMarker in the design, and it is taken
|
// The player's marker is made here rather than taken from the blueprint: the map is what knows where the
|
||||||
// onto this layer by EnsureMarkerOnMap once the layer is standing. A marker built in code could only ever
|
// player is, and the map is what has to size it, place it and turn it. It is one image at one place, so an
|
||||||
// be the one thing this file knew how to draw.
|
// image is the whole of it, and the one thing the design says about it is which art it draws, which
|
||||||
|
// PlayerMarkerTexture names. It goes on the map's own layer, because that is the thing that moves and zooms
|
||||||
|
// with the map it marks, and above the pieces, which is what its z order says. It starts hidden and stays
|
||||||
|
// that way until there is both a place to put it and something to draw there. It is the one widget built
|
||||||
|
// here that carries a name, because it is the one that gets looked for when the player's place is the thing
|
||||||
|
// that is wrong, and the name is its own so that nothing the design left in the blueprint answers to it.
|
||||||
|
UImage* NewMarker = WidgetTree->ConstructWidget<UImage>(UImage::StaticClass(), TEXT("MapPlayerMarker"));
|
||||||
|
NewMarker->SetVisibility(ESlateVisibility::Hidden);
|
||||||
|
|
||||||
|
if (UCanvasPanelSlot* NewMarkerSlot = NewLayer->AddChildToCanvas(NewMarker))
|
||||||
|
{
|
||||||
|
NewMarkerSlot->SetAnchors(FAnchors(0.f, 0.f, 0.f, 0.f));
|
||||||
|
// Alignment centres the widget on the slot's position, so a place on the map is one pair of numbers.
|
||||||
|
NewMarkerSlot->SetAlignment(FVector2D(0.5f, 0.5f));
|
||||||
|
NewMarkerSlot->SetAutoSize(false);
|
||||||
|
NewMarkerSlot->SetZOrder(2);
|
||||||
|
}
|
||||||
|
|
||||||
// Everything the map listens for arrives through this last widget: it lies over the whole view, so a drag
|
// Everything the map listens for arrives through this last widget: it lies over the whole view, so a drag
|
||||||
// on the map is a drag on the map and never a click on the level behind it. Nothing is drawn for it.
|
// on the map is a drag on the map and never a click on the level behind it. Nothing is drawn for it.
|
||||||
@@ -311,6 +335,7 @@ void UMapWidget::EnsureWidgetTree()
|
|||||||
MapBackground = NewBackground;
|
MapBackground = NewBackground;
|
||||||
PieceGrid = NewPieceGrid;
|
PieceGrid = NewPieceGrid;
|
||||||
PieceImages = MoveTemp(NewPieceImages);
|
PieceImages = MoveTemp(NewPieceImages);
|
||||||
|
PlayerMarker = NewMarker;
|
||||||
Interaction = NewInteraction;
|
Interaction = NewInteraction;
|
||||||
|
|
||||||
// The tree is standing but has not been laid out, so the transform is left to the next tick, which is the
|
// The tree is standing but has not been laid out, so the transform is left to the next tick, which is the
|
||||||
@@ -341,6 +366,7 @@ void UMapWidget::EnsureMapReady()
|
|||||||
}
|
}
|
||||||
|
|
||||||
RequestPieceLoads();
|
RequestPieceLoads();
|
||||||
|
RequestMarkerLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UMapWidget::ResolveMapLayout()
|
bool UMapWidget::ResolveMapLayout()
|
||||||
@@ -462,16 +488,6 @@ void UMapWidget::ResolveMapAxes()
|
|||||||
MapUVPerWorldX = (CaptureActor->WorldToBakedMapUV(Centre + FVector(Step, 0.0, 0.0)) - CentreUV) / Step;
|
MapUVPerWorldX = (CaptureActor->WorldToBakedMapUV(Centre + FVector(Step, 0.0, 0.0)) - CentreUV) / Step;
|
||||||
MapUVPerWorldY = (CaptureActor->WorldToBakedMapUV(Centre + FVector(0.0, Step, 0.0)) - CentreUV) / Step;
|
MapUVPerWorldY = (CaptureActor->WorldToBakedMapUV(Centre + FVector(0.0, Step, 0.0)) - CentreUV) / Step;
|
||||||
|
|
||||||
// A mapping that moves the map nowhere in one of the two directions has nothing to say about which way the
|
|
||||||
// map lies, and a marker turned by it would be turned by noise.
|
|
||||||
// if (MapUVPerWorldX.IsNearlyZero() || MapUVPerWorldY.IsNearlyZero())
|
|
||||||
// {
|
|
||||||
// MapUVPerWorldX = FVector2D::ZeroVector;
|
|
||||||
// MapUVPerWorldY = FVector2D::ZeroVector;
|
|
||||||
//
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
bMapAxesResolved = true;
|
bMapAxesResolved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,6 +761,74 @@ void UMapWidget::ApplyPieceBrush(UImage* PieceImage, UTexture2D* PieceTexture) c
|
|||||||
PieceImage->SetBrush(Brush);
|
PieceImage->SetBrush(Brush);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UMapWidget::RequestMarkerLoad()
|
||||||
|
{
|
||||||
|
if (bMarkerRequested)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bMarkerRequested = true;
|
||||||
|
|
||||||
|
const FSoftObjectPath MarkerPath = PlayerMarkerTexture.ToSoftObjectPath();
|
||||||
|
if (!MarkerPath.IsValid())
|
||||||
|
{
|
||||||
|
// Said once rather than every frame: a map with no marker art is a map somebody has not filled in, and
|
||||||
|
// it is still a map.
|
||||||
|
if (!bMissingMarkerReported)
|
||||||
|
{
|
||||||
|
bMissingMarkerReported = true;
|
||||||
|
|
||||||
|
UE_LOG(LogEleriMapWidget, Warning,
|
||||||
|
TEXT("This map has no marker art assigned, so the player's place is not drawn. Point Player Marker Texture at a texture to draw one."));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asked for on its own rather than with the pieces, because it is one texture and there is nothing for it
|
||||||
|
// to wait for: it can arrive while the bake is still being resolved and be waiting on the layer.
|
||||||
|
MarkerStreamHandle = UAssetManager::GetStreamableManager().RequestAsyncLoad(
|
||||||
|
MarkerPath,
|
||||||
|
FStreamableDelegate::CreateUObject(this, &UMapWidget::ApplyLoadedMarker),
|
||||||
|
FStreamableManager::AsyncLoadHighPriority);
|
||||||
|
|
||||||
|
UE_LOG(LogEleriMapWidget, Verbose, TEXT("Asked for the marker art %s."), *MarkerPath.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void UMapWidget::ApplyLoadedMarker()
|
||||||
|
{
|
||||||
|
// Resolved from the path rather than taken from the load's own list of what it brought in, so that art
|
||||||
|
// something else has already loaded counts as arrived just as much as one this request fetched.
|
||||||
|
UTexture2D* MarkerTexture = Cast<UTexture2D>(PlayerMarkerTexture.ToSoftObjectPath().ResolveObject());
|
||||||
|
|
||||||
|
if (!MarkerTexture || !PlayerMarker)
|
||||||
|
{
|
||||||
|
UE_LOG(LogEleriMapWidget, Warning,
|
||||||
|
TEXT("The marker art %s did not arrive, so the player's place is not drawn."), *PlayerMarkerTexture.ToString());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The brush is replaced whole rather than adjusted, so that the way the marker is drawn is decided in one
|
||||||
|
// place. Its image size is the art's own, which is also the shape GetMarkerSlotSize reads back out of it,
|
||||||
|
// so the marker is drawn at the shape it was drawn in rather than squeezed into a square.
|
||||||
|
const FIntPoint ImportedSize = MarkerTexture->GetImportedSize();
|
||||||
|
|
||||||
|
FSlateBrush Brush;
|
||||||
|
Brush.SetResourceObject(MarkerTexture);
|
||||||
|
Brush.DrawAs = ESlateBrushDrawType::Image;
|
||||||
|
Brush.SetImageSize(FVector2D(ImportedSize.X, ImportedSize.Y));
|
||||||
|
|
||||||
|
PlayerMarker->SetBrush(Brush);
|
||||||
|
|
||||||
|
// The art can arrive after the marker has already been placed, so it is placed and sized again now that it
|
||||||
|
// has a shape, rather than left square until the next tick happens to notice.
|
||||||
|
UpdateMarkerView();
|
||||||
|
|
||||||
|
UE_LOG(LogEleriMapWidget, Verbose, TEXT("The marker art %s is up."), *PlayerMarkerTexture.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
void UMapWidget::ReportMapLayout()
|
void UMapWidget::ReportMapLayout()
|
||||||
{
|
{
|
||||||
const int32 Grid = FMath::Max(1, GridSize);
|
const int32 Grid = FMath::Max(1, GridSize);
|
||||||
@@ -905,16 +989,22 @@ bool UMapWidget::GetPlayerMapUV(FVector2D& OutUV) const
|
|||||||
FVector2D UMapWidget::GetMarkerSlotSize() const
|
FVector2D UMapWidget::GetMarkerSlotSize() const
|
||||||
{
|
{
|
||||||
// The one thing about the marker's size the map decides: the longer side of it, in the map's own units.
|
// The one thing about the marker's size the map decides: the longer side of it, in the map's own units.
|
||||||
const float Size = FMath::Max(2.f, MarkerSize);
|
// MarkerSize is that size at the map's closest zoom, and MarkerZoomScale is how much of the map being pulled
|
||||||
|
// back from there the marker's size follows: see the property for what its ends mean. The two ends of the
|
||||||
|
// zoom range are read in the order they are set in, as they are everywhere else here.
|
||||||
|
const float ClosestZoom = FMath::Max(FMath::Max(MinZoom, MaxZoom), KINDA_SMALL_NUMBER);
|
||||||
|
const float ZoomShare = FMath::Clamp(Zoom / ClosestZoom, KINDA_SMALL_NUMBER, 1.f);
|
||||||
|
|
||||||
|
const float Size = FMath::Max(2.f, MarkerSize * FMath::Pow(ZoomShare, MarkerZoomScale));
|
||||||
|
|
||||||
FVector2D MarkerShape = FVector2D::ZeroVector;
|
FVector2D MarkerShape = FVector2D::ZeroVector;
|
||||||
|
|
||||||
// An icon says what shape it is through the art it draws: the size the art was imported at is the shape it
|
// The marker says what shape it is through the art it draws: the size the art was imported at is the shape
|
||||||
// was drawn with, and the size of what is resident is the second choice for a texture with nothing imported
|
// it was drawn with, and the size of what is resident is the second choice for a texture with nothing
|
||||||
// to give.
|
// imported to give. Before the art has arrived the brush holds no texture at all, so there is no shape.
|
||||||
if (const UImage* MarkerIcon = Cast<UImage>(PlayerMarker))
|
if (PlayerMarker)
|
||||||
{
|
{
|
||||||
if (const UTexture2D* IconTexture = Cast<UTexture2D>(MarkerIcon->GetBrush().GetResourceObject()))
|
if (const UTexture2D* IconTexture = Cast<UTexture2D>(PlayerMarker->GetBrush().GetResourceObject()))
|
||||||
{
|
{
|
||||||
const FIntPoint ImportedSize = IconTexture->GetImportedSize();
|
const FIntPoint ImportedSize = IconTexture->GetImportedSize();
|
||||||
|
|
||||||
@@ -926,23 +1016,23 @@ FVector2D UMapWidget::GetMarkerSlotSize() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anything else -- a box, a panel, or an icon with no art pointed at yet -- says what shape it is by the
|
// With no art yet -- or none assigned at all -- the image says what shape it is by the size it asks to be
|
||||||
// size it asks to be drawn at, which is what the art of an image and the contents of a panel are measured
|
// drawn at, which is nothing at all for an empty brush; nothing has a size until it has been laid out, so
|
||||||
// into. Nothing has a size until it has been laid out, so this is asked again whenever the size is written
|
// this is asked again whenever the size is written rather than once.
|
||||||
// rather than once.
|
|
||||||
if (MarkerShape.X <= 0.0 || MarkerShape.Y <= 0.0)
|
if (MarkerShape.X <= 0.0 || MarkerShape.Y <= 0.0)
|
||||||
{
|
{
|
||||||
MarkerShape = PlayerMarker ? PlayerMarker->GetDesiredSize() : FVector2D::ZeroVector;
|
MarkerShape = PlayerMarker ? PlayerMarker->GetDesiredSize() : FVector2D::ZeroVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A marker with nothing to say what shape it is is drawn square: a plain box of a marker is a marker.
|
// A marker with no shape of its own -- no art assigned, or none arrived yet -- is drawn square rather than
|
||||||
|
// not at all: the map still has a size to place it at, and the art may yet turn up.
|
||||||
if (MarkerShape.X <= 0.0 || MarkerShape.Y <= 0.0)
|
if (MarkerShape.X <= 0.0 || MarkerShape.Y <= 0.0)
|
||||||
{
|
{
|
||||||
return FVector2D(Size, Size);
|
return FVector2D(Size, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The design's own shape, drawn at the size the map asks for: one setting is the size of the marker whether
|
// The art's own shape, drawn at the size the map asks for: one setting is the size of the marker whatever
|
||||||
// the marker is an icon, a box or a panel of several, and none of them is squeezed out of shape by it.
|
// shape that art is, and none of it is squeezed out of shape by it.
|
||||||
return MarkerShape * (static_cast<double>(Size) / FMath::Max(MarkerShape.X, MarkerShape.Y));
|
return MarkerShape * (static_cast<double>(Size) / FMath::Max(MarkerShape.X, MarkerShape.Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -967,6 +1057,8 @@ bool UMapWidget::ResolveMarkerAngle(float& OutAngle) const
|
|||||||
|
|
||||||
void UMapWidget::UpdateMarkerView()
|
void UMapWidget::UpdateMarkerView()
|
||||||
{
|
{
|
||||||
|
// There is nothing to place until the tree is standing, and building the tree is what makes the marker, so
|
||||||
|
// this is the test for "not built yet" rather than for a design that has no marker in it.
|
||||||
if (!PlayerMarker)
|
if (!PlayerMarker)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -993,14 +1085,18 @@ void UMapWidget::UpdateMarkerView()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Whether the marker is drawn is the map's to say, because the map is what knows whether there is a place
|
// Whether the marker is drawn is the map's to say, because the map is what knows whether there is a place
|
||||||
// to put it; what the design says is what it looks like when there is one. Only the marker itself is taken
|
// to put it. Only the marker itself is taken out of the way of the pointer, so a press on the map is never
|
||||||
// out of the way of the pointer, so a marker made of several widgets keeps whatever they do themselves.
|
// a press on the marker.
|
||||||
PlayerMarker->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
PlayerMarker->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||||
|
|
||||||
if (UCanvasPanelSlot* MarkerSlot = Cast<UCanvasPanelSlot>(PlayerMarker->Slot))
|
if (UCanvasPanelSlot* MarkerSlot = Cast<UCanvasPanelSlot>(PlayerMarker->Slot))
|
||||||
{
|
{
|
||||||
// Alignment centres the widget on the slot's position, so a place on the map is one pair of numbers.
|
// Alignment centres the widget on the slot's position, so a place on the map is one pair of numbers.
|
||||||
MarkerSlot->SetPosition(MarkerMapUV * static_cast<double>(GetMapDesignSize()));
|
MarkerSlot->SetPosition(MarkerMapUV * static_cast<double>(GetMapDesignSize()));
|
||||||
|
|
||||||
|
// The size is written here rather than once at build, because it is the art arriving that gives the
|
||||||
|
// marker a shape, and the art can arrive after the marker has already been placed.
|
||||||
|
MarkerSlot->SetSize(GetMarkerSlotSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
// The turn is the one thing about the marker that changes without its place on the map changing, and it is
|
// The turn is the one thing about the marker that changes without its place on the map changing, and it is
|
||||||
@@ -1033,6 +1129,10 @@ void UMapWidget::SetZoom(float NewZoom)
|
|||||||
Zoom = Clamped;
|
Zoom = Clamped;
|
||||||
|
|
||||||
ApplyViewTransform();
|
ApplyViewTransform();
|
||||||
|
|
||||||
|
// The marker's size is the map's to say, and the map has just changed how large it is drawn at, so the
|
||||||
|
// marker is sized here rather than at the next tick: a tick later is a frame of it at the old size.
|
||||||
|
UpdateMarkerView();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UMapWidget::ZoomBy(float Amount)
|
void UMapWidget::ZoomBy(float Amount)
|
||||||
@@ -1225,16 +1325,23 @@ void UMapWidget::NativeConstruct()
|
|||||||
|
|
||||||
void UMapWidget::NativeDestruct()
|
void UMapWidget::NativeDestruct()
|
||||||
{
|
{
|
||||||
// The pieces are wanted by this widget and by nothing else, so letting go of the request lets go of whatever
|
// The pieces and the marker art are wanted by this widget and by nothing else, so letting go of the requests
|
||||||
// of them nothing else is holding on to. Asking again on the next show is cheap: what is still in memory
|
// lets go of whatever of them nothing else is holding on to. Asking again on the next show is cheap: what is
|
||||||
// arrives at once.
|
// still in memory arrives at once.
|
||||||
if (PieceStreamHandle.IsValid())
|
if (PieceStreamHandle.IsValid())
|
||||||
{
|
{
|
||||||
PieceStreamHandle->ReleaseHandle();
|
PieceStreamHandle->ReleaseHandle();
|
||||||
PieceStreamHandle.Reset();
|
PieceStreamHandle.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MarkerStreamHandle.IsValid())
|
||||||
|
{
|
||||||
|
MarkerStreamHandle->ReleaseHandle();
|
||||||
|
MarkerStreamHandle.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
bPiecesRequested = false;
|
bPiecesRequested = false;
|
||||||
|
bMarkerRequested = false;
|
||||||
PanPointerIndex = INDEX_NONE;
|
PanPointerIndex = INDEX_NONE;
|
||||||
bPanning = false;
|
bPanning = false;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "UI/EleriBaseWidget.h"
|
#include "UI/EleriBaseWidget.h"
|
||||||
|
#include "UObject/SoftObjectPtr.h"
|
||||||
#include "MapWidget.generated.h"
|
#include "MapWidget.generated.h"
|
||||||
|
|
||||||
class AOrthoMapCaptureActor;
|
class AOrthoMapCaptureActor;
|
||||||
@@ -118,9 +119,9 @@ struct FEleriMapPieceCell
|
|||||||
* The map itself is built in code, in RebuildWidget, because a user widget's slate widget is made from the root
|
* The map itself is built in code, in RebuildWidget, because a user widget's slate widget is made from the root
|
||||||
* of its widget tree and there is no tree at all until the widget has been initialized. A blueprint subclass of
|
* of its widget tree and there is no tree at all until the widget has been initialized. A blueprint subclass of
|
||||||
* this therefore needs to hold nothing: it may be empty, or its root may be a panel, which is where this
|
* this therefore needs to hold nothing: it may be empty, or its root may be a panel, which is where this
|
||||||
* widget's own tree is added. The one part of the map that is not built here is the player's marker, which is
|
* widget's own tree is added. The player's marker is built here too, because the map is what knows where the
|
||||||
* the widget named PlayerMarker in that blueprint: what a marker looks like is the design's business, and only
|
* player is and is what has to place, size and turn it; what the marker is a picture of is the one thing left
|
||||||
* where it sits on the map is the map's.
|
* to the design, and PlayerMarkerTexture is what says it.
|
||||||
*
|
*
|
||||||
* The pieces are 16384 pixel virtual textures, so loading all 64 of them eagerly would be a stall and a
|
* The pieces are 16384 pixel virtual textures, so loading all 64 of them eagerly would be a stall and a
|
||||||
* virtual texture pool full of a map nobody is looking at. They are asked for lazily, the first time the
|
* virtual texture pool full of a map nobody is looking at. They are asked for lazily, the first time the
|
||||||
@@ -216,22 +217,32 @@ public:
|
|||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Map|Marker")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Map|Marker")
|
||||||
bool bCenterOnPlayerByDefault;
|
bool bCenterOnPlayerByDefault;
|
||||||
|
|
||||||
/** The player's place on the map: the widget of this name in the blueprint this map is drawn in, found by
|
/** The art the player's marker is drawn with. The marker itself is made here rather than found in the
|
||||||
* name rather than made here. Nothing in this file draws it, so what the marker looks like -- its brush,
|
* blueprint this map is drawn in: the map is what places it, sizes it and turns it, so the one thing left
|
||||||
* its colours, its corner radii -- belongs to the design. The map takes it onto its own layer, which is
|
* for the design to say is what it is a picture of. Soft, so the art is not loaded until a map is actually
|
||||||
* what a marker has to be on to move and zoom with the map it marks, and then sizes it, places it and
|
* looked at, and optional, because a map with no art is a map with no marker rather than a map that will
|
||||||
* turns it. Any kind of widget will do, from an image to a panel holding several. Optional, because a
|
* not open. */
|
||||||
* design with no marker in it is a map that says so once rather than a map that will not open. */
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Map|Marker")
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "Eleri|Map|Marker", meta = (BindWidgetOptional))
|
TSoftObjectPtr<UTexture2D> PlayerMarkerTexture;
|
||||||
TObjectPtr<UWidget> PlayerMarker;
|
|
||||||
|
|
||||||
/** How long the marker's longer side is drawn, in the map's own design units, which is the one thing about
|
/** How long the marker's longer side is drawn, in the map's own design units, at the map's closest zoom: see
|
||||||
* the marker's look the map has to know, because the map is what places it and is measured in these units.
|
* MarkerZoomScale for what it is drawn at further back than that. What shape it is comes from the art
|
||||||
* What shape it is comes from the design: an icon's shape is the shape of its art, and anything else is
|
* PlayerMarkerTexture names, which is the shape that art was imported at, so a wide or a tall marker is not
|
||||||
* drawn at the shape it asks to be, so a wide or a tall marker is not squeezed into a square. */
|
* squeezed into a square. */
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Map|Marker", meta = (ClampMin = "2"))
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Map|Marker", meta = (ClampMin = "2"))
|
||||||
float MarkerSize;
|
float MarkerSize;
|
||||||
|
|
||||||
|
/** How much of the map being pulled back the marker's size follows, as the power the zoom relative to
|
||||||
|
* MaxZoom is raised to: the marker is drawn at MarkerSize when the map is at its closest, whatever this
|
||||||
|
* says, and this is what it does below that. At nought the marker is that size in the map's own units at
|
||||||
|
* every zoom, so it comes down in the view exactly as fast as the map does. At one it comes down in step
|
||||||
|
* with the zoom as well, which is twice as fast as the map does on screen, and soon leaves a marker too
|
||||||
|
* small to read. Below nought the marker grows in map units as the map is pulled back instead, so it comes
|
||||||
|
* down in the view more slowly than the map does: at -1 it holds one size on screen however far out the
|
||||||
|
* map goes, which stays readable but stops describing the world. */
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Map|Marker", meta = (ClampMin = "-1", ClampMax = "1"))
|
||||||
|
float MarkerZoomScale;
|
||||||
|
|
||||||
/** Degrees added to the turn the marker is given, for art that does not point up: an arrow drawn pointing
|
/** Degrees added to the turn the marker is given, for art that does not point up: an arrow drawn pointing
|
||||||
* right wants -90 here, and one drawn pointing down wants 180. */
|
* right wants -90 here, and one drawn pointing down wants 180. */
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Map|Marker")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Map|Marker")
|
||||||
@@ -381,6 +392,12 @@ protected:
|
|||||||
/** Puts every arrived piece on its image, and reports the ones that did not arrive. */
|
/** Puts every arrived piece on its image, and reports the ones that did not arrive. */
|
||||||
void ApplyLoadedPieces();
|
void ApplyLoadedPieces();
|
||||||
|
|
||||||
|
/** Asks for PlayerMarkerTexture, once. */
|
||||||
|
void RequestMarkerLoad();
|
||||||
|
|
||||||
|
/** Puts the arrived marker texture on the marker, and reports it once if it did not arrive. */
|
||||||
|
void ApplyLoadedMarker();
|
||||||
|
|
||||||
/** The brush one piece image is drawn with: the piece's own texture, and the mirroring the bake needs,
|
/** The brush one piece image is drawn with: the piece's own texture, and the mirroring the bake needs,
|
||||||
* which is the one thing about a piece that cannot be asked for and has to be told. */
|
* which is the one thing about a piece that cannot be asked for and has to be told. */
|
||||||
void ApplyPieceBrush(UImage* PieceImage, UTexture2D* PieceTexture) const;
|
void ApplyPieceBrush(UImage* PieceImage, UTexture2D* PieceTexture) const;
|
||||||
@@ -412,9 +429,9 @@ protected:
|
|||||||
* actor to put their position through. */
|
* actor to put their position through. */
|
||||||
bool GetPlayerMapUV(FVector2D& OutUV) const;
|
bool GetPlayerMapUV(FVector2D& OutUV) const;
|
||||||
|
|
||||||
/** The size the marker is drawn at: the shape the design gave it, with its longer side at MarkerSize, so
|
/** The size the marker is drawn at: the shape of the art PlayerMarkerTexture names, with its longer side at
|
||||||
* that a wide or a tall marker is not squeezed into a square. A marker with nothing to say what shape it
|
* MarkerSize, so that a wide or a tall marker is not squeezed into a square. Before the art has arrived,
|
||||||
* is -- a box with nothing in it, or a panel with nothing in that -- is drawn square. */
|
* or with no art assigned at all, the marker has no shape to give and is drawn square. */
|
||||||
FVector2D GetMarkerSlotSize() const;
|
FVector2D GetMarkerSlotSize() const;
|
||||||
|
|
||||||
/** The angle the marker is turned to on screen, in degrees clockwise, or false when there is nothing to
|
/** The angle the marker is turned to on screen, in degrees clockwise, or false when there is nothing to
|
||||||
@@ -465,6 +482,11 @@ protected:
|
|||||||
UPROPERTY(Transient)
|
UPROPERTY(Transient)
|
||||||
TArray<TObjectPtr<UImage>> PieceImages;
|
TArray<TObjectPtr<UImage>> PieceImages;
|
||||||
|
|
||||||
|
/** The player's place on the map, made here and put on MapLayer above the pieces. An image, because the
|
||||||
|
* marker is one texture at one place; everything about how it looks comes from PlayerMarkerTexture. */
|
||||||
|
UPROPERTY(Transient)
|
||||||
|
TObjectPtr<UImage> PlayerMarker;
|
||||||
|
|
||||||
/** Takes every pointer event the map needs, so that a drag is never also a click on the level behind
|
/** Takes every pointer event the map needs, so that a drag is never also a click on the level behind
|
||||||
* the map. */
|
* the map. */
|
||||||
UPROPERTY(Transient)
|
UPROPERTY(Transient)
|
||||||
@@ -491,6 +513,12 @@ protected:
|
|||||||
/** What does the loading, held so that the pieces stay wanted until they have arrived. */
|
/** What does the loading, held so that the pieces stay wanted until they have arrived. */
|
||||||
TSharedPtr<FStreamableHandle> PieceStreamHandle;
|
TSharedPtr<FStreamableHandle> PieceStreamHandle;
|
||||||
|
|
||||||
|
/** Whether PlayerMarkerTexture has been asked for, so that asking happens once rather than once per show. */
|
||||||
|
bool bMarkerRequested;
|
||||||
|
|
||||||
|
/** What does the loading, held so that the marker stays wanted until it has arrived. */
|
||||||
|
TSharedPtr<FStreamableHandle> MarkerStreamHandle;
|
||||||
|
|
||||||
/** How much the map is zoomed, and the content point held at the centre of the view. */
|
/** How much the map is zoomed, and the content point held at the centre of the view. */
|
||||||
FVector2D FocusPoint;
|
FVector2D FocusPoint;
|
||||||
|
|
||||||
@@ -507,7 +535,7 @@ protected:
|
|||||||
|
|
||||||
bool bMarkerAngleApplied;
|
bool bMarkerAngleApplied;
|
||||||
|
|
||||||
/** Whether the map has already said that the design has no marker in it, so that a map drawn without one
|
/** Whether the map has already said that no marker art is assigned, so that a map drawn without a marker
|
||||||
* says so once rather than on every update. */
|
* says so once rather than on every update. */
|
||||||
bool bMissingMarkerReported;
|
bool bMissingMarkerReported;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user