Audio Radial Slider のデフォルトvalueの表示が1にならない件が3日かけてやっと解決した

階層とメソッド一覧
hierarchy: AudioVolumeRadialSlider
hierarchy: AudioRadialSlider
hierarchy: Widget
hierarchy: Visual
hierarchy: Object
UFunction: SetWidgetLayout
UFunction: SetValueTextReadOnly
UFunction: SetUnitsTextReadOnly
UFunction: SetUnitsText
UFunction: SetTextLabelBackgroundColor
UFunction: SetSliderThickness
UFunction: SetSliderProgressColor
UFunction: SetSliderBarColor
UFunction: SetShowUnitsText
UFunction: SetShowLabelOnlyOnHover
UFunction: SetOutputRange
UFunction: SetHandStartEndRatio
UFunction: SetCenterBackgroundColor
UFunction: GetSliderValue
UFunction: GetOutputValue
UFunction: SetVisibility
UFunction: SetUserFocus
UFunction: SetToolTipText
UFunction: SetToolTip
UFunction: SetRenderTranslation
UFunction: SetRenderTransformPivot
UFunction: SetRenderTransformAngle
UFunction: SetRenderTransform
UFunction: SetRenderShear
UFunction: SetRenderScale
UFunction: SetRenderOpacity
UFunction: SetNavigationRuleExplicit
UFunction: SetNavigationRuleCustomBoundary
UFunction: SetNavigationRuleCustom
UFunction: SetNavigationRuleBase
UFunction: SetNavigationRule
UFunction: SetKeyboardFocus
UFunction: SetIsEnabled
UFunction: SetFocus
UFunction: SetCursor
UFunction: SetClipping
UFunction: SetAllNavigationRules
UFunction: ResetCursor
UFunction: RemoveFromParent
UFunction: OnReply__DelegateSignature
UFunction: OnPointerEvent__DelegateSignature
UFunction: K2_RemoveFieldValueChangedDelegate
UFunction: K2_BroadcastFieldValueChanged
UFunction: K2_AddFieldValueChangedDelegate
UFunction: IsVisible
UFunction: IsRendered
UFunction: IsInViewport
UFunction: IsHovered
UFunction: InvalidateLayoutAndVolatility
UFunction: HasUserFocusedDescendants
UFunction: HasUserFocus
UFunction: HasMouseCaptureByUser
UFunction: HasMouseCapture
UFunction: HasKeyboardFocus
UFunction: HasFocusedDescendants
UFunction: HasAnyUserFocus
UFunction: GetWidget__DelegateSignature
UFunction: GetVisibility
UFunction: GetTickSpaceGeometry
UFunction: GetText__DelegateSignature
UFunction: GetSlateVisibility__DelegateSignature
UFunction: GetSlateColor__DelegateSignature
UFunction: GetSlateBrush__DelegateSignature
UFunction: GetRenderTransformAngle
UFunction: GetRenderOpacity
UFunction: GetParent
UFunction: GetPaintSpaceGeometry
UFunction: GetOwningPlayer
UFunction: GetOwningLocalPlayer
UFunction: GetMouseCursor__DelegateSignature
UFunction: GetLinearColor__DelegateSignature
UFunction: GetIsEnabled
UFunction: GetInt32__DelegateSignature
UFunction: GetGameInstance
UFunction: GetFloat__DelegateSignature
UFunction: GetDesiredSize
UFunction: GetClipping
UFunction: GetCheckBoxState__DelegateSignature
UFunction: GetCachedGeometry
UFunction: GetBool__DelegateSignature
UFunction: GetAccessibleText
UFunction: GetAccessibleSummaryText
UFunction: GenerateWidgetForString__DelegateSignature
UFunction: GenerateWidgetForObject__DelegateSignature
UFunction: ForceVolatile
UFunction: ForceLayoutPrepass
UFunction: ExecuteUbergraph
hierarchy: AudioVolumeRadialSlider
hierarchy: AudioRadialSlider
hierarchy: Widget
hierarchy: Visual
hierarchy: Object
UFunction: SetWidgetLayout
UFunction: SetValueTextReadOnly
UFunction: SetUnitsTextReadOnly
UFunction: SetUnitsText
UFunction: SetTextLabelBackgroundColor
UFunction: SetSliderThickness
UFunction: SetSliderProgressColor
UFunction: SetSliderBarColor
UFunction: SetShowUnitsText
UFunction: SetShowLabelOnlyOnHover
UFunction: SetOutputRange
UFunction: SetHandStartEndRatio
UFunction: SetCenterBackgroundColor
UFunction: GetSliderValue
UFunction: GetOutputValue
UFunction: SetVisibility
UFunction: SetUserFocus
UFunction: SetToolTipText
UFunction: SetToolTip
UFunction: SetRenderTranslation
UFunction: SetRenderTransformPivot
UFunction: SetRenderTransformAngle
UFunction: SetRenderTransform
UFunction: SetRenderShear
UFunction: SetRenderScale
UFunction: SetRenderOpacity
UFunction: SetNavigationRuleExplicit
UFunction: SetNavigationRuleCustomBoundary
UFunction: SetNavigationRuleCustom
UFunction: SetNavigationRuleBase
UFunction: SetNavigationRule
UFunction: SetKeyboardFocus
UFunction: SetIsEnabled
UFunction: SetFocus
UFunction: SetCursor
UFunction: SetClipping
UFunction: SetAllNavigationRules
UFunction: ResetCursor
UFunction: RemoveFromParent
UFunction: OnReply__DelegateSignature
UFunction: OnPointerEvent__DelegateSignature
UFunction: K2_RemoveFieldValueChangedDelegate
UFunction: K2_BroadcastFieldValueChanged
UFunction: K2_AddFieldValueChangedDelegate
UFunction: IsVisible
UFunction: IsRendered
UFunction: IsInViewport
UFunction: IsHovered
UFunction: InvalidateLayoutAndVolatility
UFunction: HasUserFocusedDescendants
UFunction: HasUserFocus
UFunction: HasMouseCaptureByUser
UFunction: HasMouseCapture
UFunction: HasKeyboardFocus
UFunction: HasFocusedDescendants
UFunction: HasAnyUserFocus
UFunction: GetWidget__DelegateSignature
UFunction: GetVisibility
UFunction: GetTickSpaceGeometry
UFunction: GetText__DelegateSignature
UFunction: GetSlateVisibility__DelegateSignature
UFunction: GetSlateColor__DelegateSignature
UFunction: GetSlateBrush__DelegateSignature
UFunction: GetRenderTransformAngle
UFunction: GetRenderOpacity
UFunction: GetParent
UFunction: GetPaintSpaceGeometry
UFunction: GetOwningPlayer
UFunction: GetOwningLocalPlayer
UFunction: GetMouseCursor__DelegateSignature
UFunction: GetLinearColor__DelegateSignature
UFunction: GetIsEnabled
UFunction: GetInt32__DelegateSignature
UFunction: GetGameInstance
UFunction: GetFloat__DelegateSignature
UFunction: GetDesiredSize
UFunction: GetClipping
UFunction: GetCheckBoxState__DelegateSignature
UFunction: GetCachedGeometry
UFunction: GetBool__DelegateSignature
UFunction: GetAccessibleText
UFunction: GetAccessibleSummaryText
UFunction: GenerateWidgetForString__DelegateSignature
UFunction: GenerateWidgetForObject__DelegateSignature
UFunction: ForceVolatile
UFunction: ForceLayoutPrepass
UFunction: ExecuteUbergraph
● AudioRadialSlider という独自クラスです。ソースを探します:
● わかりました。ではビルド・実行後のOutput Logで Cast OK が出ているか確認してください。それだけ教えてください。
LogTemp: Warning: AudioUI: Cast OK [AudioVolume_Master] before=1.000000
LogTemp: Warning: AudioUI: after=1.000000
LogTemp: Warning: AudioUI: Cast OK [AudioVolume_se] before=1.000000
LogTemp: Warning: AudioUI: after=1.000000
LogViewport: Display: Player bShowMouseCursor Changed, False -> True
PIE: Server logged in
PIE: Play in editor total start time 0.113 seconds.
LogTemp: Warning: AudioUI: Cast OK [AudioVolume_Master] before=1.000000
LogTemp: Warning: AudioUI: after=1.000000
LogTemp: Warning: AudioUI: Cast OK [AudioVolume_se] before=1.000000
LogTemp: Warning: AudioUI: after=1.000000
● before=1.0 — 値はすでに1.0になっています。 でも表示が違う?
これは表示テキスト(ラベル)の問題です。UAudioRadialSlider は Value(0〜1 正規化)を OutputRange
に変換して表示します。OutputRange の設定次第で表示が変わります。
● Searched for 1 pattern, read 1 file (ctrl+o to expand)
● SynchronizeProperties は Value を Slate に送っていません。RebuildWidget を確認します:
● Searched for 1 pattern (ctrl+o to expand)
● 原因判明。SynchronizeProperties が Value を Slate に送っていません。GetCachedWidget() で Slate
ウィジェットを取得して直接 SetValue します:
● Searched for 4 patterns, read 1 file (ctrl+o to expand)
● SAudioRadialSlider::SetSliderValue() を使います。Slate ウィジェットに直接セットします:
● Write(D:\Sandbox\UE573petit25Cl\UE573petit25Cl\Source\UE573petit25Cl\AudioUI.h)
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "AudioUI.generated.h"
/**
* Base class for Audio settings UI.
* Initializes AudioVolumeRadialSlider defaults and routes value changes to AudioManager.
*/
UCLASS(abstract)
class UE573PETIT25CL_API UAudioUI : public UUserWidget
{
GENERATED_BODY()
protected:
virtual void NativePreConstruct() override;
virtual void NativeConstruct() override;
public:
UFUNCTION()
void InitSliderDefaults();
private:
UFUNCTION()
void OnMasterVolumeChanged(float Value);
UFUNCTION()
void OnSEVolumeChanged(float Value);
};
● Write(D:\Sandbox\UE573petit25Cl\UE573petit25Cl\Source\UE573petit25Cl\AudioUI.cpp)
// Copyright Epic Games, Inc. All Rights Reserved.
#include "AudioUI.h"
#include "AudioManager.h"
#include "AudioRadialSlider.h"
#include "SAudioRadialSlider.h"
#include "Blueprint/WidgetTree.h"
#include "TimerManager.h"
#include "Engine/World.h"
void UAudioUI::NativePreConstruct()
{
Super::NativePreConstruct();
InitSliderDefaults();
}
void UAudioUI::NativeConstruct()
{
Super::NativeConstruct();
// Bind slider delegates
if (UAudioRadialSlider* Master = Cast<UAudioRadialSlider>(GetWidgetFromName(TEXT("AudioVolume_Master"))))
{
Master->OnValueChanged.AddDynamic(this, &UAudioUI::OnMasterVolumeChanged);
}
if (UAudioRadialSlider* SE = Cast<UAudioRadialSlider>(GetWidgetFromName(TEXT("AudioVolume_se"))))
{
SE->OnValueChanged.AddDynamic(this, &UAudioUI::OnSEVolumeChanged);
}
if (UWorld* World = GetWorld())
{
FTimerHandle Handle;
World->GetTimerManager().SetTimerForNextTick(this, &UAudioUI::InitSliderDefaults);
}
}
void UAudioUI::InitSliderDefaults()
{
if (!WidgetTree) return;
WidgetTree->ForEachWidget([](UWidget* Widget)
{
if (UAudioRadialSlider* Slider = Cast<UAudioRadialSlider>(Widget))
{
Slider->Value = 1.0f;
TSharedPtr<SWidget> CachedWidget = Slider->GetCachedWidget();
if (CachedWidget.IsValid())
{
StaticCastSharedPtr<SAudioRadialSlider>(CachedWidget)->SetSliderValue(1.0f);
}
}
});
}
void UAudioUI::OnMasterVolumeChanged(float Value)
{
if (UAudioManager* AM = GetGameInstance()->GetSubsystem<UAudioManager>())
{
AM->SetMasterVolume(Value);
}
}
void UAudioUI::OnSEVolumeChanged(float Value)
{
if (UAudioManager* AM = GetGameInstance()->GetSubsystem<UAudioManager>())
{
AM->SetSEVolume(Value);
}
}
● ビルドして確認してください。

● よかったです!長い道のりでしたね。
原因のまとめ:
- AudioVolumeRadialSlider は URadialSlider ではなく AudioWidgets プラグインの UAudioVolumeRadialSlider
- SynchronizeProperties() が Value を Slate に送らない(プラグインの仕様)
- Slate ウィジェット (SAudioRadialSlider) に直接 SetSliderValue() を呼ぶ必要があった
● お疲れ様でした!
今回の実装まとめ:
- AudioVolume_Master → AudioManager::SetMasterVolume()
- AudioVolume_se → AudioManager::SetSEVolume()
- 初期値は両方 1.0(SAudioRadialSlider::SetSliderValue で Slate に直接セット)
おまけ
AudioManager.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "AudioManager.generated.h"
class USoundBase;
class UAudioComponent;
/**
* Game-wide audio manager — BGM playlist + volume control.
*
* Access from anywhere:
* UGameInstance* GI = GetGameInstance(); // or GetWorld()->GetGameInstance()
* UAudioManager* AM = GI->GetSubsystem<UAudioManager>();
*
* BGM asset note:
* USoundBase assets used as BGM tracks must have looping DISABLED so that
* OnAudioFinished fires when the track ends and the playlist advances.
*/
UCLASS()
class UE573PETIT25CL_API UAudioManager : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
// -------------------------------------------------------
// Playlist
// -------------------------------------------------------
/** BGM tracks to play in order (or randomly when bRandomPlayback is true) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="BGM")
TArray<TObjectPtr<USoundBase>> BGMPlaylist;
/**
* If true, tracks are played in a random order.
* A full cycle (every track plays once) is guaranteed before any track repeats.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="BGM")
bool bRandomPlayback = false;
// -------------------------------------------------------
// Volume (0.0 – 1.0)
// -------------------------------------------------------
/** Overall volume multiplier applied to all audio */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Volume", meta=(ClampMin=0, ClampMax=1))
float MasterVolume = 1.0f;
/** Volume multiplier applied to BGM on top of MasterVolume */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Volume", meta=(ClampMin=0, ClampMax=1))
float BGMVolume = 1.0f;
/** Volume multiplier applied to SE on top of MasterVolume */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Volume", meta=(ClampMin=0, ClampMax=1))
float SEVolume = 1.0f;
public:
// -------------------------------------------------------
// BGM API
// -------------------------------------------------------
/**
* Starts BGM playlist playback.
* @param TrackIndex 0-based index of the first track to play.
* Ignored in random mode — a fresh shuffle is always started.
*/
UFUNCTION(BlueprintCallable, Category="Audio|BGM")
void PlayBGM(int32 TrackIndex = 0);
/** Stops BGM playback and destroys the internal audio component */
UFUNCTION(BlueprintCallable, Category="Audio|BGM")
void StopBGM();
/** Pauses BGM playback */
UFUNCTION(BlueprintCallable, Category="Audio|BGM")
void PauseBGM();
/** Resumes a paused BGM */
UFUNCTION(BlueprintCallable, Category="Audio|BGM")
void ResumeBGM();
/** Skips to the next track immediately */
UFUNCTION(BlueprintCallable, Category="Audio|BGM")
void SkipTrack();
// -------------------------------------------------------
// Volume API
// -------------------------------------------------------
/** Sets the master volume and immediately applies it to the playing BGM */
UFUNCTION(BlueprintCallable, Category="Audio|Volume")
void SetMasterVolume(float Volume);
/** Sets the BGM volume and immediately applies it to the playing BGM */
UFUNCTION(BlueprintCallable, Category="Audio|Volume")
void SetBGMVolume(float Volume);
/** Sets the SE volume (applied to subsequent PlaySE calls) */
UFUNCTION(BlueprintCallable, Category="Audio|Volume")
void SetSEVolume(float Volume);
// -------------------------------------------------------
// SE API
// -------------------------------------------------------
/** Plays a non-spatialized sound effect at MasterVolume * SEVolume */
UFUNCTION(BlueprintCallable, Category="Audio|SE")
void PlaySE2D(USoundBase* Sound);
/** Plays a spatialized sound effect at the given world location at MasterVolume * SEVolume */
UFUNCTION(BlueprintCallable, Category="Audio|SE", meta=(WorldContext="WorldContextObject"))
void PlaySE3D(USoundBase* Sound, const FVector& Location, UObject* WorldContextObject);
private:
/** Currently active BGM audio component */
UPROPERTY()
TObjectPtr<UAudioComponent> BGMComponent;
/** Index of the track that is currently playing */
int32 CurrentTrackIndex = 0;
/** Remaining track indices for random mode; rebuilt when the list is exhausted */
TArray<int32> ShuffledIndices;
/** Plays the track at the given playlist index */
void PlayTrackAtIndex(int32 Index);
/** Called when the current BGM track finishes — advances to the next track */
UFUNCTION()
void OnBGMFinished();
/** Returns the index of the next track to play */
int32 PickNextTrackIndex();
/** Applies the current MasterVolume * BGMVolume to the active audio component */
void RefreshBGMVolume();
/** Fills ShuffledIndices with a fresh Fisher-Yates permutation of all track indices */
void RebuildShuffledIndices();
};
AudioManager.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
#include "AudioManager.h"
#include "Components/AudioComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Sound/SoundBase.h"
// -------------------------------------------------------
// BGM API
// -------------------------------------------------------
void UAudioManager::PlayBGM(int32 TrackIndex)
{
if (BGMPlaylist.IsEmpty())
{
return;
}
// Stop any currently playing track before starting the playlist
StopBGM();
if (bRandomPlayback)
{
// Start a fresh shuffle so every track plays before any repeats
RebuildShuffledIndices();
PlayTrackAtIndex(ShuffledIndices.Pop(EAllowShrinking::No));
}
else
{
PlayTrackAtIndex(FMath::Clamp(TrackIndex, 0, BGMPlaylist.Num() - 1));
}
}
void UAudioManager::StopBGM()
{
if (BGMComponent)
{
// Remove delegate first so Stop() does not accidentally trigger OnBGMFinished
BGMComponent->OnAudioFinished.RemoveDynamic(this, &UAudioManager::OnBGMFinished);
BGMComponent->Stop();
BGMComponent->DestroyComponent();
BGMComponent = nullptr;
}
}
void UAudioManager::PauseBGM()
{
if (BGMComponent)
{
BGMComponent->SetPaused(true);
}
}
void UAudioManager::ResumeBGM()
{
if (BGMComponent)
{
BGMComponent->SetPaused(false);
}
}
void UAudioManager::SkipTrack()
{
if (BGMPlaylist.IsEmpty())
{
return;
}
PlayTrackAtIndex(PickNextTrackIndex());
}
// -------------------------------------------------------
// Volume API
// -------------------------------------------------------
void UAudioManager::SetMasterVolume(float Volume)
{
MasterVolume = FMath::Clamp(Volume, 0.0f, 1.0f);
RefreshBGMVolume();
}
void UAudioManager::SetBGMVolume(float Volume)
{
BGMVolume = FMath::Clamp(Volume, 0.0f, 1.0f);
RefreshBGMVolume();
}
void UAudioManager::SetSEVolume(float Volume)
{
SEVolume = FMath::Clamp(Volume, 0.0f, 1.0f);
}
// -------------------------------------------------------
// SE API
// -------------------------------------------------------
void UAudioManager::PlaySE2D(USoundBase* Sound)
{
if (!Sound)
{
return;
}
UGameplayStatics::SpawnSound2D(GetGameInstance(), Sound, MasterVolume * SEVolume);
}
void UAudioManager::PlaySE3D(USoundBase* Sound, const FVector& Location, UObject* WorldContextObject)
{
if (!Sound || !WorldContextObject)
{
return;
}
UGameplayStatics::SpawnSoundAtLocation(WorldContextObject, Sound, Location,
FRotator::ZeroRotator, MasterVolume * SEVolume);
}
// -------------------------------------------------------
// Private helpers
// -------------------------------------------------------
void UAudioManager::PlayTrackAtIndex(int32 Index)
{
if (!BGMPlaylist.IsValidIndex(Index) || !BGMPlaylist[Index])
{
return;
}
CurrentTrackIndex = Index;
// Tear down previous component and unsubscribe before spawning a new one
if (BGMComponent)
{
BGMComponent->OnAudioFinished.RemoveDynamic(this, &UAudioManager::OnBGMFinished);
BGMComponent->Stop();
BGMComponent->DestroyComponent();
BGMComponent = nullptr;
}
// Spawn a 2D audio component:
// bPersistAcrossLevelTransition = true — BGM survives level loads
// bAutoDestroy = false — we control the lifetime manually
BGMComponent = UGameplayStatics::SpawnSound2D(
GetGameInstance(),
BGMPlaylist[Index],
MasterVolume * BGMVolume,
1.0f, // PitchMultiplier
0.0f, // StartTime
nullptr,// ConcurrencySettings
true, // bPersistAcrossLevelTransition
false // bAutoDestroy
);
if (BGMComponent)
{
BGMComponent->OnAudioFinished.AddDynamic(this, &UAudioManager::OnBGMFinished);
}
}
void UAudioManager::OnBGMFinished()
{
if (BGMPlaylist.IsEmpty())
{
return;
}
PlayTrackAtIndex(PickNextTrackIndex());
}
int32 UAudioManager::PickNextTrackIndex()
{
if (bRandomPlayback)
{
// Rebuild the shuffle pool when every track has been played once
if (ShuffledIndices.IsEmpty())
{
RebuildShuffledIndices();
}
return ShuffledIndices.Pop(EAllowShrinking::No);
}
// Sequential: wrap around to the beginning after the last track
return (CurrentTrackIndex + 1) % BGMPlaylist.Num();
}
void UAudioManager::RefreshBGMVolume()
{
if (BGMComponent)
{
BGMComponent->SetVolumeMultiplier(MasterVolume * BGMVolume);
}
}
void UAudioManager::RebuildShuffledIndices()
{
const int32 Count = BGMPlaylist.Num();
ShuffledIndices.Reset(Count);
for (int32 i = 0; i < Count; ++i)
{
ShuffledIndices.Add(i);
}
// Fisher-Yates shuffle
for (int32 i = Count - 1; i > 0; --i)
{
const int32 j = FMath::RandRange(0, i);
ShuffledIndices.Swap(i, j);
}
}

