Skip to content
This repository was archived by the owner on Oct 26, 2025. It is now read-only.

Commit 04e9ed8

Browse files
committed
add CustomSoundTray class
requires a little bit of setup in a global script to use, but it shouldn't be too difficult when scs releases you can check it's global.hxs and sound_tray.hxs for examples on how to use this class
1 parent 85e6e60 commit 04e9ed8

4 files changed

Lines changed: 122 additions & 10 deletions

File tree

source/funkin/scripting/FunkinScript.hx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ class FunkinScript {
203203
setClass(funkin.ui.UIUtil);
204204
set("UIWindow", funkin.ui.Window);
205205

206+
set("SoundTray", funkin.ui.SoundTray);
207+
set("CustomSoundTray", funkin.ui.CustomSoundTray);
208+
206209
setClass(funkin.utilities.UndoList);
207210
setClass(funkin.utilities.TouchUtil);
208211
setClass(funkin.utilities.SwipeUtil);
@@ -233,6 +236,9 @@ class FunkinScript {
233236

234237
set("game", PlayState.instance);
235238
set("closeScript", close);
239+
240+
if(unsafe)
241+
set("__script__", this);
236242
}
237243

238244
public function execute():Void {}

source/funkin/scripting/FunkinScriptGroup.hx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ class FunkinScriptGroup {
2020
members = [];
2121
}
2222

23-
public function importScript(path:String):Void {
23+
public function importScript(path:String):FunkinScript {
2424
final scriptPath:String = Paths.script(path);
2525
final contentMetadata = Paths.contentMetadata.get(Paths.getContentPackFromPath(scriptPath));
2626
final script:FunkinScript = FunkinScript.fromFile(scriptPath, contentMetadata?.allowUnsafeScripts ?? false);
2727
add(script);
2828
script.execute();
29+
return script;
2930
}
3031

3132
public function execute():Void {
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package funkin.ui;
2+
3+
import flixel.system.ui.FlxSoundTray;
4+
import flixel.system.FlxAssets.FlxSoundAsset;
5+
6+
import flixel.util.FlxSignal.FlxTypedSignal;
7+
8+
#if SCRIPTING_ALLOWED
9+
import funkin.scripting.FunkinScript;
10+
#end
11+
12+
class CustomSoundTray extends FlxSoundTray {
13+
public var volumeMaxSound:String;
14+
15+
public var onCreate:FlxTypedSignal<Void->Void> = new FlxTypedSignal<Void->Void>();
16+
public var onUpdate:FlxTypedSignal<Float->Void> = new FlxTypedSignal<Float->Void>();
17+
public var onShowAnim:FlxTypedSignal<Float->Bool->Void> = new FlxTypedSignal<Float->Bool->Void>();
18+
public var onDestroy:FlxTypedSignal<Void->Void> = new FlxTypedSignal<Void->Void>();
19+
20+
public function new() {
21+
super();
22+
}
23+
24+
public function create():Void {
25+
removeChildren();
26+
volumeMaxSound = volumeUpSound;
27+
28+
FlxG.sound.applySoundCurve = SoundTray.applySoundCurve;
29+
FlxG.sound.reverseSoundCurve = SoundTray.reverseSoundCurve;
30+
31+
onCreate.dispatch();
32+
}
33+
34+
override function update(MS:Float):Void {
35+
final elapsed:Float = Math.min(MS / 1000, FlxG.maxElapsed);
36+
onUpdate.dispatch(elapsed);
37+
}
38+
39+
#if SCRIPTING_ALLOWED
40+
public function attachToScript(script:FunkinScript):Void {
41+
script.setParent(this);
42+
onCreate.add(() -> script.call("onCreate"));
43+
onUpdate.add((elapsed:Float) -> script.call("onUpdate", [elapsed]));
44+
onShowAnim.add((volume:Float, up:Bool) -> script.call("onShowAnim", [volume, up]));
45+
onDestroy.add(() -> script.call("onDestroy"));
46+
}
47+
#end
48+
49+
public function saveVolume():Void {
50+
#if FLX_SAVE
51+
// Save sound preferences
52+
if(FlxG.save.isBound) {
53+
FlxG.save.data.mute = FlxG.sound.muted;
54+
FlxG.save.data.volume = FlxG.sound.volume;
55+
FlxG.save.flush();
56+
}
57+
#end
58+
}
59+
60+
/**
61+
* Makes the little volume tray slide out.
62+
*
63+
* @param up Whether the volume is increasing.
64+
*/
65+
override function showAnim(volume:Float, ?sound:FlxSoundAsset, duration = 1.0, label = "VOLUME"):Void {
66+
onShowAnim.dispatch(volume, _up);
67+
}
68+
69+
override function showIncrement():Void {
70+
final volume = FlxG.sound.muted ? 0 : FlxG.sound.volume;
71+
_up = true;
72+
showAnim(volume, silent ? null : ((volume >= 1) ? volumeMaxSound : volumeUpSound));
73+
}
74+
75+
override function showDecrement():Void {
76+
final volume = FlxG.sound.muted ? 0 : FlxG.sound.volume;
77+
_up = false;
78+
showAnim(volume, silent ? null : volumeDownSound);
79+
}
80+
81+
override function screenCenter():Void {
82+
x = (0.5 * (FlxG.stage.stageWidth - width) - FlxG.game.x);
83+
}
84+
85+
public function destroy():Void {
86+
FlxG.sound.applySoundCurve = SoundTray.applySoundCurve;
87+
FlxG.sound.reverseSoundCurve = SoundTray.reverseSoundCurve;
88+
FlxG.sound.amountChange = 0.1;
89+
onDestroy.dispatch();
90+
}
91+
92+
private var _up:Bool = false;
93+
}

source/funkin/ui/SoundTray.hx

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package funkin.ui;
22

33
import openfl.display.Bitmap;
4+
import openfl.display.BitmapData;
45
import openfl.display.Sprite;
56

67
import flixel.system.ui.FlxSoundTray;
@@ -9,6 +10,8 @@ import flixel.system.FlxAssets.FlxSoundAsset;
910
class SoundTray extends FlxSoundTray {
1011
public static final GRAPHIC_SCALE:Float = 0.3;
1112

13+
public var barBitmapDatas:Map<Int, BitmapData> = [];
14+
1215
public var trayContainer:Sprite;
1316
public var barDisplay:Bitmap;
1417

@@ -53,7 +56,7 @@ class SoundTray extends FlxSoundTray {
5356

5457
_bars = [];
5558
for(i in 1...11)
56-
FlxG.assets.getBitmapData(Paths.image("ui/images/volume/bars_" + i));
59+
barBitmapDatas.set(i * 10, FlxG.assets.getBitmapData(Paths.image("ui/images/volume/bars_" + i)));
5760

5861
y = -88;
5962
visible = false;
@@ -65,18 +68,31 @@ class SoundTray extends FlxSoundTray {
6568

6669
FlxG.sound.applySoundCurve = applySoundCurve;
6770
FlxG.sound.reverseSoundCurve = reverseSoundCurve;
71+
FlxG.sound.amountChange = 0.1;
6872
}
6973

70-
public function applySoundCurve(x:Float):Float {
74+
public static function applySoundCurve(x:Float):Float {
7175
x = Math.max(0, Math.min(1, x));
7276
return Math.exp(Math.log(0.001) * (1 - x));
7377
}
7478

75-
public function reverseSoundCurve(x:Float):Float {
79+
public static function reverseSoundCurve(x:Float):Float {
7680
x = Math.max(0, Math.min(1, x));
7781
return 1 - (Math.log(Math.max(x, 0.001)) / Math.log(0.001));
7882
}
7983

84+
public function destroy():Void {
85+
for(bmp in barBitmapDatas) {
86+
@:privateAccess {
87+
if(bmp.__texture != null)
88+
bmp.__texture.dispose();
89+
}
90+
bmp.disposeImage();
91+
bmp.dispose();
92+
}
93+
barBitmapDatas = null;
94+
}
95+
8096
override function update(MS:Float):Void {
8197
MS = Math.min(MS, FlxG.maxElapsed * 1000);
8298

@@ -148,12 +164,8 @@ class SoundTray extends FlxSoundTray {
148164
FlxG.sound.play(sound);
149165

150166
if(globalVolume != 0) {
151-
final imgPath:String = Paths.image("ui/images/volume/bars_" + globalVolume);
152-
if(FlxG.assets.exists(imgPath)) {
153-
barDisplay.visible = true;
154-
barDisplay.bitmapData = FlxG.assets.getBitmapData(imgPath);
155-
} else
156-
barDisplay.visible = false;
167+
barDisplay.bitmapData = barBitmapDatas.get(globalVolume);
168+
barDisplay.visible = true;
157169
} else
158170
barDisplay.visible = false;
159171

0 commit comments

Comments
 (0)