#pragma once #include "CoreMinimal.h" #include "Components/Widget.h" #include "WorldMapWidget.generated.h" class SWorldMap; class UWorldMapDefinition; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWorldMapClickedDynamic, FVector2D, WorldCm); /** * The world map, as a widget a Blueprint can drop into a screen. * * It is a UWidget wrapping SWorldMap rather than a UUserWidget, because the map has no parts to compose: it is * one thing that draws itself. The frame around it - the layer buttons, the close button, the title - is what * WBP_WorldMap is for, and that is a UUserWidget containing one of these. Which is also the C++/Blueprint line * the conventions ask for: C++ owns what the map is, the Blueprint owns what it looks like around the edges. */ UCLASS(meta = (DisplayName = "World Map")) class SALTY_API UWorldMapWidget : public UWidget { GENERATED_BODY() public: /** * Which map to draw. Leave it unset and the widget asks the level's UWorldMapSubsystem, which is the * normal case: a screen should not have to know which world it was opened in. Set it to show a particular * map regardless - a world other than the one being played, or a designer preview. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "World Map") TObjectPtr Definition; /** NAME_None opens on the definition's default layer. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "World Map") FName Layer; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "World Map|Show") bool bShowGrid = true; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "World Map|Show") bool bShowScaleBar = true; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "World Map|Show") bool bShowMarkers = true; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "World Map|Show") bool bShowLocalPlayer = true; /** False makes it a picture: no pan, no zoom, no click. What a minimap wants. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "World Map|Input") bool bAllowInput = true; /** Keep the view on the player. Panning by hand turns it off; this is the starting state. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "World Map|Input") bool bFollowLocalPlayer = false; /** A place on the ground was clicked, in world centimetres. Not raised by a drag that happened to end. */ UPROPERTY(BlueprintAssignable, Category = "World Map") FOnWorldMapClickedDynamic OnMapClicked; UFUNCTION(BlueprintCallable, Category = "World Map") void SetLayer(FName InLayer); UFUNCTION(BlueprintCallable, Category = "World Map") void NextLayer(); UFUNCTION(BlueprintPure, Category = "World Map") FName GetLayer() const; UFUNCTION(BlueprintPure, Category = "World Map") TArray GetLayerIds() const; /** Centre the map on a world location. Z is ignored. */ UFUNCTION(BlueprintCallable, Category = "World Map") void FocusOnWorldLocation(FVector WorldLocation); UFUNCTION(BlueprintCallable, Category = "World Map") void ZoomToFit(); UFUNCTION(BlueprintCallable, Category = "World Map") void SetFollowLocalPlayer(bool bValue); /** * Centre on the local player and follow them again. False when there is no local body to follow. What a * "recentre" button on a screen calls; the map itself does it on a left double-click. */ UFUNCTION(BlueprintCallable, Category = "World Map") bool FocusOnLocalPlayer(); /** Ground metres to one screen pixel, for a readout or a zoom slider. */ UFUNCTION(BlueprintPure, Category = "World Map") float GetMetresPerPixel() const; UFUNCTION(BlueprintCallable, Category = "World Map") void SetMetresPerPixel(float InMetresPerPixel); /** What the map is actually showing, resolved: the override if there is one, otherwise the level's. */ UFUNCTION(BlueprintPure, Category = "World Map") UWorldMapDefinition* GetResolvedDefinition() const; // UWidget virtual void SynchronizeProperties() override; virtual void ReleaseSlateResources(bool bReleaseChildren) override; #if WITH_EDITOR virtual const FText GetPaletteCategory() override; #endif protected: virtual TSharedRef RebuildWidget() override; private: void HandleClicked(FVector2D WorldCm); TSharedPtr MapWidget; };