Started radial menu setup
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
// RadialMenuController.h
|
||||
// Local-only radial weapon selector for the Naked Desire project.
|
||||
// No replication, no RPCs: this is single-player UI logic.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "RadialMenuController.generated.h"
|
||||
|
||||
class URadialMenuWidget;
|
||||
|
||||
/**
|
||||
* One entry in the radial menu. Swap this out for your real item type later
|
||||
* (e.g. a soft pointer to a UPrimaryDataAsset) — the controller only ever
|
||||
* reads DisplayName + Icon to build slices, so the rest of the menu is agnostic.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRadialMenuEntry
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
|
||||
FText DisplayName;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
|
||||
TObjectPtr<UTexture2D> Icon = nullptr;
|
||||
|
||||
// Optional payload tag so the owning code knows what to equip on confirm.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
|
||||
FName ItemId = NAME_None;
|
||||
|
||||
// Set false to draw the slice greyed-out (e.g. weapon not yet unlocked).
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
|
||||
bool bEnabled = true;
|
||||
};
|
||||
|
||||
// Fires when the player confirms a slice. Index is into the Entries array; -1 = cancelled.
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRadialSelectionConfirmed, int32, SelectedIndex);
|
||||
|
||||
UCLASS(ClassGroup = (UI), meta = (BlueprintSpawnableComponent))
|
||||
class URadialMenuController : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
URadialMenuController();
|
||||
|
||||
// --- Public API ---------------------------------------------------------
|
||||
|
||||
// Call on "hold" pressed. Opens the menu, dilates time, shows the cursor.
|
||||
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
|
||||
void OpenMenu();
|
||||
|
||||
// Call on "hold" released. Confirms the hovered slice and closes.
|
||||
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
|
||||
void CloseAndConfirm();
|
||||
|
||||
// Close without selecting anything (e.g. pressed a cancel key).
|
||||
UFUNCTION(BlueprintCallable, Category = "Radial Menu")
|
||||
void CloseAndCancel();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Radial Menu")
|
||||
bool IsOpen() const { return bIsOpen; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Radial Menu")
|
||||
int32 GetHoveredIndex() const { return HoveredIndex; }
|
||||
|
||||
// The data the menu draws. Populate from wherever you like (data table,
|
||||
// inventory component, hardcoded list) before calling OpenMenu().
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu")
|
||||
TArray<FRadialMenuEntry> Entries;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "Radial Menu")
|
||||
FOnRadialSelectionConfirmed OnSelectionConfirmed;
|
||||
|
||||
// --- Tunables -----------------------------------------------------------
|
||||
|
||||
// How long after opening (real seconds) confirms are ignored, so the tap
|
||||
// that opens the wheel can't immediately select. ~0.15s is imperceptible
|
||||
// but covers the same-frame / next-frame case. Set 0 to disable.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu|Tuning",
|
||||
meta = (ClampMin = "0.0"))
|
||||
float OpenInputGuardSeconds = 0.15f;
|
||||
|
||||
// Time scale while the menu is open. GTA sits around 0.2; 0.0 = full pause.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu|Tuning",
|
||||
meta = (ClampMin = "0.0", ClampMax = "1.0"))
|
||||
float OpenTimeDilation = 0.2f;
|
||||
|
||||
// Dead zone (gamepad) / radius in px (mouse) below which we keep the last
|
||||
// hovered slice instead of snapping to a new one. Stops jitter near center.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu|Tuning")
|
||||
float SelectionDeadZone = 0.25f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu|Tuning")
|
||||
TSubclassOf<URadialMenuWidget> WidgetClass;
|
||||
|
||||
protected:
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType,
|
||||
FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
private:
|
||||
// Converts a screen-space or stick direction into a slice index.
|
||||
// Angle is measured clockwise from straight up (12 o'clock), matching GTA.
|
||||
int32 AngleToSegment(float AngleDegrees) const;
|
||||
|
||||
// Reads current input (mouse delta or right stick) and updates HoveredIndex.
|
||||
void UpdateHoverFromInput();
|
||||
|
||||
void SetTimeDilation(float Scale);
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<URadialMenuWidget> ActiveWidget = nullptr;
|
||||
|
||||
bool bIsOpen = false;
|
||||
int32 HoveredIndex = -1;
|
||||
|
||||
// Real-time timestamp when the menu opened. CloseAndConfirm ignores confirms
|
||||
// that arrive within OpenInputGuardSeconds, so the tap that opens the wheel
|
||||
// can't also register as a selection on the same/next frame.
|
||||
double OpenRealTimeSeconds = 0.0;
|
||||
|
||||
// Cached so we can restore exactly what the game had before we opened.
|
||||
float CachedTimeDilation = 1.0f;
|
||||
};
|
||||
Reference in New Issue
Block a user