mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-23 08:07:54 -05:00
Merge branch 'rewrite/master' into feature/freeplay-album-art
This commit is contained in:
commit
f7acee94cd
23 changed files with 691 additions and 89 deletions
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -85,7 +85,7 @@
|
||||||
},
|
},
|
||||||
"projectManager.git.baseFolders": ["./"],
|
"projectManager.git.baseFolders": ["./"],
|
||||||
|
|
||||||
"haxecheckstyle.sourceFolders": ["src", "Source"],
|
"haxecheckstyle.sourceFolders": ["src", "source"],
|
||||||
"haxecheckstyle.externalSourceRoots": [],
|
"haxecheckstyle.externalSourceRoots": [],
|
||||||
"haxecheckstyle.configurationFile": "checkstyle.json",
|
"haxecheckstyle.configurationFile": "checkstyle.json",
|
||||||
"haxecheckstyle.codeSimilarityBufferSize": 100,
|
"haxecheckstyle.codeSimilarityBufferSize": 100,
|
||||||
|
|
2
hmm.json
2
hmm.json
|
@ -146,7 +146,7 @@
|
||||||
"name": "polymod",
|
"name": "polymod",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "be712450e5d3ba446008884921bb56873b299a64",
|
"ref": "5547763a22858a1f10939e082de421d587c862bf",
|
||||||
"url": "https://github.com/larsiusprime/polymod"
|
"url": "https://github.com/larsiusprime/polymod"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -100,8 +100,15 @@ class Main extends Sprite
|
||||||
|
|
||||||
// George recommends binding the save before FlxGame is created.
|
// George recommends binding the save before FlxGame is created.
|
||||||
Save.load();
|
Save.load();
|
||||||
|
var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen);
|
||||||
|
|
||||||
addChild(new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen));
|
// FlxG.game._customSoundTray wants just the class, it calls new from
|
||||||
|
// create() in there, which gets called when it's added to stage
|
||||||
|
// which is why it needs to be added before addChild(game) here
|
||||||
|
@:privateAccess
|
||||||
|
game._customSoundTray = funkin.ui.options.FunkinSoundTray;
|
||||||
|
|
||||||
|
addChild(game);
|
||||||
|
|
||||||
#if hxcpp_debug_server
|
#if hxcpp_debug_server
|
||||||
trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.');
|
trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.');
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
package funkin.audio;
|
package funkin.audio;
|
||||||
|
|
||||||
#if flash11
|
|
||||||
import flash.media.Sound;
|
|
||||||
import flash.utils.ByteArray;
|
|
||||||
#end
|
|
||||||
import flixel.sound.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
import flixel.util.FlxSignal.FlxTypedSignal;
|
||||||
import flixel.system.FlxAssets.FlxSoundAsset;
|
import flixel.system.FlxAssets.FlxSoundAsset;
|
||||||
import funkin.util.tools.ICloneable;
|
import funkin.util.tools.ICloneable;
|
||||||
import funkin.data.song.SongData.SongMusicData;
|
import funkin.data.song.SongData.SongMusicData;
|
||||||
|
@ -27,6 +24,25 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
{
|
{
|
||||||
static final MAX_VOLUME:Float = 1.0;
|
static final MAX_VOLUME:Float = 1.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An FlxSignal which is dispatched when the volume changes.
|
||||||
|
*/
|
||||||
|
public static var onVolumeChanged(get, never):FlxTypedSignal<Float->Void>;
|
||||||
|
|
||||||
|
static var _onVolumeChanged:Null<FlxTypedSignal<Float->Void>> = null;
|
||||||
|
|
||||||
|
static function get_onVolumeChanged():FlxTypedSignal<Float->Void>
|
||||||
|
{
|
||||||
|
if (_onVolumeChanged == null)
|
||||||
|
{
|
||||||
|
_onVolumeChanged = new FlxTypedSignal<Float->Void>();
|
||||||
|
FlxG.sound.volumeHandler = function(volume:Float) {
|
||||||
|
_onVolumeChanged.dispatch(volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _onVolumeChanged;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using `FunkinSound.load` will override a dead instance from here rather than creating a new one, if possible!
|
* Using `FunkinSound.load` will override a dead instance from here rather than creating a new one, if possible!
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -706,7 +706,7 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
||||||
this = new SongEventDataRaw(time, eventKind, value);
|
this = new SongEventDataRaw(time, eventKind, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function valueAsStruct(?defaultKey:String = "key"):Dynamic
|
public function valueAsStruct(?defaultKey:String = "key"):Dynamic
|
||||||
{
|
{
|
||||||
if (this.value == null) return {};
|
if (this.value == null) return {};
|
||||||
if (Std.isOfType(this.value, Array))
|
if (Std.isOfType(this.value, Array))
|
||||||
|
|
|
@ -4,6 +4,9 @@ import flixel.FlxSprite;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.graphics.FlxGraphic;
|
import flixel.graphics.FlxGraphic;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
|
import openfl.display3D.textures.TextureBase;
|
||||||
|
import funkin.graphics.framebuffer.FixedBitmapData;
|
||||||
|
import openfl.display.BitmapData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An FlxSprite with additional functionality.
|
* An FlxSprite with additional functionality.
|
||||||
|
@ -42,7 +45,7 @@ class FunkinSprite extends FlxSprite
|
||||||
*/
|
*/
|
||||||
public static function create(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite
|
public static function create(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite
|
||||||
{
|
{
|
||||||
var sprite = new FunkinSprite(x, y);
|
var sprite:FunkinSprite = new FunkinSprite(x, y);
|
||||||
sprite.loadTexture(key);
|
sprite.loadTexture(key);
|
||||||
return sprite;
|
return sprite;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +59,7 @@ class FunkinSprite extends FlxSprite
|
||||||
*/
|
*/
|
||||||
public static function createSparrow(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite
|
public static function createSparrow(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite
|
||||||
{
|
{
|
||||||
var sprite = new FunkinSprite(x, y);
|
var sprite:FunkinSprite = new FunkinSprite(x, y);
|
||||||
sprite.loadSparrow(key);
|
sprite.loadSparrow(key);
|
||||||
return sprite;
|
return sprite;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +73,7 @@ class FunkinSprite extends FlxSprite
|
||||||
*/
|
*/
|
||||||
public static function createPacker(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite
|
public static function createPacker(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite
|
||||||
{
|
{
|
||||||
var sprite = new FunkinSprite(x, y);
|
var sprite:FunkinSprite = new FunkinSprite(x, y);
|
||||||
sprite.loadPacker(key);
|
sprite.loadPacker(key);
|
||||||
return sprite;
|
return sprite;
|
||||||
}
|
}
|
||||||
|
@ -90,6 +93,30 @@ class FunkinSprite extends FlxSprite
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply an OpenFL `BitmapData` to this sprite.
|
||||||
|
* @param input The OpenFL `BitmapData` to apply
|
||||||
|
* @return This sprite, for chaining
|
||||||
|
*/
|
||||||
|
public function loadBitmapData(input:BitmapData):FunkinSprite
|
||||||
|
{
|
||||||
|
loadGraphic(input);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply an OpenFL `TextureBase` to this sprite.
|
||||||
|
* @param input The OpenFL `TextureBase` to apply
|
||||||
|
* @return This sprite, for chaining
|
||||||
|
*/
|
||||||
|
public function loadTextureBase(input:TextureBase):FunkinSprite
|
||||||
|
{
|
||||||
|
var inputBitmap:FixedBitmapData = FixedBitmapData.fromTexture(input);
|
||||||
|
|
||||||
|
return loadBitmapData(inputBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an animated texture (Sparrow atlas spritesheet) as the sprite's texture.
|
* Load an animated texture (Sparrow atlas spritesheet) as the sprite's texture.
|
||||||
* @param key The key of the texture to load.
|
* @param key The key of the texture to load.
|
||||||
|
@ -120,11 +147,20 @@ class FunkinSprite extends FlxSprite
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the texture with the given key is cached.
|
||||||
|
* @param key The key of the texture to check.
|
||||||
|
* @return Whether the texture is cached.
|
||||||
|
*/
|
||||||
public static function isTextureCached(key:String):Bool
|
public static function isTextureCached(key:String):Bool
|
||||||
{
|
{
|
||||||
return FlxG.bitmap.get(key) != null;
|
return FlxG.bitmap.get(key) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the texture with the given key is cached.
|
||||||
|
* @param key The key of the texture to cache.
|
||||||
|
*/
|
||||||
public static function cacheTexture(key:String):Void
|
public static function cacheTexture(key:String):Void
|
||||||
{
|
{
|
||||||
// We don't want to cache the same texture twice.
|
// We don't want to cache the same texture twice.
|
||||||
|
@ -140,7 +176,7 @@ class FunkinSprite extends FlxSprite
|
||||||
}
|
}
|
||||||
|
|
||||||
// Else, texture is currently uncached.
|
// Else, texture is currently uncached.
|
||||||
var graphic = flixel.graphics.FlxGraphic.fromAssetKey(key, false, null, true);
|
var graphic:FlxGraphic = FlxGraphic.fromAssetKey(key, false, null, true);
|
||||||
if (graphic == null)
|
if (graphic == null)
|
||||||
{
|
{
|
||||||
FlxG.log.warn('Failed to cache graphic: $key');
|
FlxG.log.warn('Failed to cache graphic: $key');
|
||||||
|
|
|
@ -32,11 +32,11 @@ class FixedBitmapData extends BitmapData
|
||||||
public static function fromTexture(texture:TextureBase):FixedBitmapData
|
public static function fromTexture(texture:TextureBase):FixedBitmapData
|
||||||
{
|
{
|
||||||
if (texture == null) return null;
|
if (texture == null) return null;
|
||||||
final bitmapData = new FixedBitmapData(texture.__width, texture.__height, true, 0);
|
final bitmapData:FixedBitmapData = new FixedBitmapData(texture.__width, texture.__height, true, 0);
|
||||||
bitmapData.readable = false;
|
// bitmapData.readable = false;
|
||||||
bitmapData.__texture = texture;
|
bitmapData.__texture = texture;
|
||||||
bitmapData.__textureContext = texture.__textureContext;
|
bitmapData.__textureContext = texture.__textureContext;
|
||||||
bitmapData.image = null;
|
// bitmapData.image = null;
|
||||||
return bitmapData;
|
return bitmapData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,58 @@
|
||||||
package funkin.graphics.video;
|
package funkin.graphics.video;
|
||||||
|
|
||||||
import flixel.FlxBasic;
|
import flixel.util.FlxColor;
|
||||||
import flixel.FlxSprite;
|
import flixel.util.FlxSignal.FlxTypedSignal;
|
||||||
|
import funkin.audio.FunkinSound;
|
||||||
|
import openfl.display3D.textures.TextureBase;
|
||||||
import openfl.events.NetStatusEvent;
|
import openfl.events.NetStatusEvent;
|
||||||
|
import openfl.media.SoundTransform;
|
||||||
import openfl.media.Video;
|
import openfl.media.Video;
|
||||||
import openfl.net.NetConnection;
|
import openfl.net.NetConnection;
|
||||||
import openfl.net.NetStream;
|
import openfl.net.NetStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plays a video via a NetStream. Only works on HTML5.
|
* Plays a video via a NetStream. Only works on HTML5.
|
||||||
* This does NOT replace hxCodec, nor does hxCodec replace this. hxCodec only works on desktop and does not work on HTML5!
|
* This does NOT replace hxCodec, nor does hxCodec replace this.
|
||||||
|
* hxCodec only works on desktop and does not work on HTML5!
|
||||||
*/
|
*/
|
||||||
class FlxVideo extends FlxBasic
|
class FlxVideo extends FunkinSprite
|
||||||
{
|
{
|
||||||
var video:Video;
|
var video:Video;
|
||||||
var netStream:NetStream;
|
var netStream:NetStream;
|
||||||
|
var videoPath:String;
|
||||||
public var finishCallback:Void->Void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Doesn't actually interact with Flixel shit, only just a pleasant to use class
|
* A callback to execute when the video finishes.
|
||||||
*/
|
*/
|
||||||
|
public var finishCallback:Void->Void;
|
||||||
|
|
||||||
public function new(videoPath:String)
|
public function new(videoPath:String)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.videoPath = videoPath;
|
||||||
|
|
||||||
|
makeGraphic(2, 2, FlxColor.TRANSPARENT);
|
||||||
|
|
||||||
video = new Video();
|
video = new Video();
|
||||||
video.x = 0;
|
video.x = 0;
|
||||||
video.y = 0;
|
video.y = 0;
|
||||||
|
video.alpha = 0;
|
||||||
|
|
||||||
FlxG.addChildBelowMouse(video);
|
FlxG.game.addChild(video);
|
||||||
|
|
||||||
var netConnection = new NetConnection();
|
var netConnection:NetConnection = new NetConnection();
|
||||||
netConnection.connect(null);
|
netConnection.connect(null);
|
||||||
|
|
||||||
netStream = new NetStream(netConnection);
|
netStream = new NetStream(netConnection);
|
||||||
netStream.client = {onMetaData: client_onMetaData};
|
netStream.client = {onMetaData: onClientMetaData};
|
||||||
netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnection_onNetStatus);
|
netConnection.addEventListener(NetStatusEvent.NET_STATUS, onNetConnectionNetStatus);
|
||||||
netStream.play(videoPath);
|
netStream.play(videoPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the FlxVideo to pause playback.
|
||||||
|
*/
|
||||||
public function pauseVideo():Void
|
public function pauseVideo():Void
|
||||||
{
|
{
|
||||||
if (netStream != null)
|
if (netStream != null)
|
||||||
|
@ -48,6 +61,9 @@ class FlxVideo extends FlxBasic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the FlxVideo to resume if it is paused.
|
||||||
|
*/
|
||||||
public function resumeVideo():Void
|
public function resumeVideo():Void
|
||||||
{
|
{
|
||||||
// Resume playing the video.
|
// Resume playing the video.
|
||||||
|
@ -57,6 +73,29 @@ class FlxVideo extends FlxBasic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var videoAvailable:Bool = false;
|
||||||
|
var frameTimer:Float;
|
||||||
|
|
||||||
|
static final FRAME_RATE:Float = 60;
|
||||||
|
|
||||||
|
public override function update(elapsed:Float):Void
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
|
||||||
|
if (frameTimer >= (1 / FRAME_RATE))
|
||||||
|
{
|
||||||
|
frameTimer = 0;
|
||||||
|
// TODO: We just draw the video buffer to the sprite 60 times a second.
|
||||||
|
// Can we copy the video buffer instead somehow?
|
||||||
|
pixels.draw(video);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoAvailable) frameTimer += elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the FlxVideo to seek to the beginning.
|
||||||
|
*/
|
||||||
public function restartVideo():Void
|
public function restartVideo():Void
|
||||||
{
|
{
|
||||||
// Seek to the beginning of the video.
|
// Seek to the beginning of the video.
|
||||||
|
@ -66,6 +105,9 @@ class FlxVideo extends FlxBasic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the FlxVideo to end.
|
||||||
|
*/
|
||||||
public function finishVideo():Void
|
public function finishVideo():Void
|
||||||
{
|
{
|
||||||
netStream.dispose();
|
netStream.dispose();
|
||||||
|
@ -74,15 +116,48 @@ class FlxVideo extends FlxBasic
|
||||||
if (finishCallback != null) finishCallback();
|
if (finishCallback != null) finishCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function client_onMetaData(metaData:Dynamic)
|
public override function destroy():Void
|
||||||
|
{
|
||||||
|
if (netStream != null)
|
||||||
|
{
|
||||||
|
netStream.dispose();
|
||||||
|
|
||||||
|
if (FlxG.game.contains(video)) FlxG.game.removeChild(video);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback executed when the video stream loads.
|
||||||
|
* @param metaData The metadata of the video
|
||||||
|
*/
|
||||||
|
public function onClientMetaData(metaData:Dynamic):Void
|
||||||
{
|
{
|
||||||
video.attachNetStream(netStream);
|
video.attachNetStream(netStream);
|
||||||
|
|
||||||
video.width = FlxG.width;
|
onVideoReady();
|
||||||
video.height = FlxG.height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function netConnection_onNetStatus(event:NetStatusEvent):Void
|
function onVideoReady():Void
|
||||||
|
{
|
||||||
|
video.width = FlxG.width;
|
||||||
|
video.height = FlxG.height;
|
||||||
|
|
||||||
|
videoAvailable = true;
|
||||||
|
|
||||||
|
FunkinSound.onVolumeChanged.add(onVolumeChanged);
|
||||||
|
onVolumeChanged(FlxG.sound.muted ? 0 : FlxG.sound.volume);
|
||||||
|
|
||||||
|
makeGraphic(Std.int(video.width), Std.int(video.height), FlxColor.TRANSPARENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onVolumeChanged(volume:Float):Void
|
||||||
|
{
|
||||||
|
netStream.soundTransform = new SoundTransform(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onNetConnectionNetStatus(event:NetStatusEvent):Void
|
||||||
{
|
{
|
||||||
if (event.info.code == 'NetStream.Play.Complete') finishVideo();
|
if (event.info.code == 'NetStream.Play.Complete') finishVideo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,8 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
// Set up the visuals
|
// Set up the visuals
|
||||||
//
|
//
|
||||||
|
|
||||||
|
var playState = PlayState.instance;
|
||||||
|
|
||||||
// Add a black background to the screen.
|
// Add a black background to the screen.
|
||||||
var bg = new FunkinSprite().makeSolidColor(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
|
var bg = new FunkinSprite().makeSolidColor(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
|
||||||
// We make this transparent so that we can see the stage underneath during debugging,
|
// We make this transparent so that we can see the stage underneath during debugging,
|
||||||
|
@ -130,13 +132,16 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
|
|
||||||
// Pluck Boyfriend from the PlayState and place him (in the same position) in the GameOverSubState.
|
// Pluck Boyfriend from the PlayState and place him (in the same position) in the GameOverSubState.
|
||||||
// We can then play the character's `firstDeath` animation.
|
// We can then play the character's `firstDeath` animation.
|
||||||
boyfriend = PlayState.instance.currentStage.getBoyfriend(true);
|
boyfriend = playState.currentStage.getBoyfriend(true);
|
||||||
boyfriend.isDead = true;
|
boyfriend.isDead = true;
|
||||||
add(boyfriend);
|
add(boyfriend);
|
||||||
boyfriend.resetCharacter();
|
boyfriend.resetCharacter();
|
||||||
|
|
||||||
|
// Cancel camera tweening if it's currently active.
|
||||||
|
playState.cancelAllCameraTweens();
|
||||||
|
|
||||||
// Assign a camera follow point to the boyfriend's position.
|
// Assign a camera follow point to the boyfriend's position.
|
||||||
cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1);
|
cameraFollowPoint = new FlxObject(playState.cameraFollowPoint.x, playState.cameraFollowPoint.y, 1, 1);
|
||||||
cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x;
|
cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x;
|
||||||
cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y;
|
cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y;
|
||||||
var offsets:Array<Float> = boyfriend.getDeathCameraOffsets();
|
var offsets:Array<Float> = boyfriend.getDeathCameraOffsets();
|
||||||
|
|
|
@ -237,6 +237,17 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
public var cameraFollowPoint:FlxObject;
|
public var cameraFollowPoint:FlxObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An FlxTween that tweens the camera to the follow point.
|
||||||
|
* Only used when tweening the camera manually, rather than tweening via follow.
|
||||||
|
*/
|
||||||
|
public var cameraFollowTween:FlxTween;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An FlxTween that zooms the camera to the desired amount.
|
||||||
|
*/
|
||||||
|
public var cameraZoomTween:FlxTween;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The camera follow point from the last stage.
|
* The camera follow point from the last stage.
|
||||||
* Used to persist the position of the `cameraFollowPosition` between levels.
|
* Used to persist the position of the `cameraFollowPosition` between levels.
|
||||||
|
@ -244,14 +255,23 @@ class PlayState extends MusicBeatSubState
|
||||||
public var previousCameraFollowPoint:FlxPoint = null;
|
public var previousCameraFollowPoint:FlxPoint = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current camera zoom level.
|
* The current camera zoom level without any modifiers applied.
|
||||||
*
|
*/
|
||||||
* The camera zoom is increased every beat, and lerped back to this value every frame, creating a smooth 'zoom-in' effect.
|
public var currentCameraZoom:Float = FlxCamera.defaultZoom * 1.05;
|
||||||
* Defaults to 1.05 but may be larger or smaller depending on the current stage,
|
|
||||||
* and may be changed by the `ZoomCamera` song event.
|
/**
|
||||||
|
* currentCameraZoom is increased every beat, and lerped back to this value every frame, creating a smooth 'zoom-in' effect.
|
||||||
|
* Defaults to 1.05, but may be larger or smaller depending on the current stage.
|
||||||
|
* Tweened via the `ZoomCamera` song event in direct mode.
|
||||||
*/
|
*/
|
||||||
public var defaultCameraZoom:Float = FlxCamera.defaultZoom * 1.05;
|
public var defaultCameraZoom:Float = FlxCamera.defaultZoom * 1.05;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Camera zoom applied on top of currentCameraZoom.
|
||||||
|
* Tweened via the `ZoomCamera` song event in additive mode.
|
||||||
|
*/
|
||||||
|
public var additiveCameraZoom:Float = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current HUD camera zoom level.
|
* The current HUD camera zoom level.
|
||||||
*
|
*
|
||||||
|
@ -397,10 +417,15 @@ class PlayState extends MusicBeatSubState
|
||||||
var startingSong:Bool = false;
|
var startingSong:Bool = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* False if `FlxG.sound.music`
|
* Track if we currently have the music paused for a Pause substate, so we can unpause it when we return.
|
||||||
*/
|
*/
|
||||||
var musicPausedBySubState:Bool = false;
|
var musicPausedBySubState:Bool = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track any camera tweens we've paused for a Pause substate, so we can unpause them when we return.
|
||||||
|
*/
|
||||||
|
var cameraTweensPausedBySubState:List<FlxTween> = new List<FlxTween>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* False until `create()` has completed.
|
* False until `create()` has completed.
|
||||||
*/
|
*/
|
||||||
|
@ -943,7 +968,9 @@ class PlayState extends MusicBeatSubState
|
||||||
// Lerp the camera zoom towards the target level.
|
// Lerp the camera zoom towards the target level.
|
||||||
if (subState == null)
|
if (subState == null)
|
||||||
{
|
{
|
||||||
FlxG.camera.zoom = FlxMath.lerp(defaultCameraZoom, FlxG.camera.zoom, 0.95);
|
currentCameraZoom = FlxMath.lerp(defaultCameraZoom, currentCameraZoom, 0.95);
|
||||||
|
FlxG.camera.zoom = currentCameraZoom + additiveCameraZoom;
|
||||||
|
|
||||||
camHUD.zoom = FlxMath.lerp(defaultHUDCameraZoom, camHUD.zoom, 0.95);
|
camHUD.zoom = FlxMath.lerp(defaultHUDCameraZoom, camHUD.zoom, 0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1121,14 +1148,30 @@ class PlayState extends MusicBeatSubState
|
||||||
// Pause the music.
|
// Pause the music.
|
||||||
if (FlxG.sound.music != null)
|
if (FlxG.sound.music != null)
|
||||||
{
|
{
|
||||||
musicPausedBySubState = FlxG.sound.music.playing;
|
if (FlxG.sound.music.playing)
|
||||||
if (musicPausedBySubState)
|
|
||||||
{
|
{
|
||||||
FlxG.sound.music.pause();
|
FlxG.sound.music.pause();
|
||||||
|
musicPausedBySubState = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pause vocals.
|
||||||
|
// Not tracking that we've done this via a bool because vocal re-syncing involves pausing the vocals anyway.
|
||||||
if (vocals != null) vocals.pause();
|
if (vocals != null) vocals.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pause camera tweening, and keep track of which tweens we pause.
|
||||||
|
if (cameraFollowTween != null && cameraFollowTween.active)
|
||||||
|
{
|
||||||
|
cameraFollowTween.active = false;
|
||||||
|
cameraTweensPausedBySubState.add(cameraFollowTween);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cameraZoomTween != null && cameraZoomTween.active)
|
||||||
|
{
|
||||||
|
cameraZoomTween.active = false;
|
||||||
|
cameraTweensPausedBySubState.add(cameraZoomTween);
|
||||||
|
}
|
||||||
|
|
||||||
// Pause the countdown.
|
// Pause the countdown.
|
||||||
Countdown.pauseCountdown();
|
Countdown.pauseCountdown();
|
||||||
}
|
}
|
||||||
|
@ -1150,17 +1193,26 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
if (event.eventCanceled) return;
|
if (event.eventCanceled) return;
|
||||||
|
|
||||||
// Resume
|
// Resume music if we paused it.
|
||||||
if (musicPausedBySubState)
|
if (musicPausedBySubState)
|
||||||
{
|
{
|
||||||
FlxG.sound.music.play();
|
FlxG.sound.music.play();
|
||||||
|
musicPausedBySubState = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resume camera tweens if we paused any.
|
||||||
|
for (camTween in cameraTweensPausedBySubState)
|
||||||
|
{
|
||||||
|
camTween.active = true;
|
||||||
|
}
|
||||||
|
cameraTweensPausedBySubState.clear();
|
||||||
|
|
||||||
if (currentConversation != null)
|
if (currentConversation != null)
|
||||||
{
|
{
|
||||||
currentConversation.resumeMusic();
|
currentConversation.resumeMusic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-sync vocals.
|
||||||
if (FlxG.sound.music != null && !startingSong && !isInCutscene) resyncVocals();
|
if (FlxG.sound.music != null && !startingSong && !isInCutscene) resyncVocals();
|
||||||
|
|
||||||
// Resume the countdown.
|
// Resume the countdown.
|
||||||
|
@ -1308,7 +1360,7 @@ class PlayState extends MusicBeatSubState
|
||||||
if (FlxG.camera.zoom < (1.35 * defaultCameraZoom) && cameraZoomRate > 0 && Conductor.instance.currentBeat % cameraZoomRate == 0)
|
if (FlxG.camera.zoom < (1.35 * defaultCameraZoom) && cameraZoomRate > 0 && Conductor.instance.currentBeat % cameraZoomRate == 0)
|
||||||
{
|
{
|
||||||
// Zoom camera in (1.5%)
|
// Zoom camera in (1.5%)
|
||||||
FlxG.camera.zoom += cameraZoomIntensity * defaultCameraZoom;
|
currentCameraZoom += cameraZoomIntensity * defaultCameraZoom;
|
||||||
// Hud zooms double (3%)
|
// Hud zooms double (3%)
|
||||||
camHUD.zoom += hudCameraZoomIntensity * defaultHUDCameraZoom;
|
camHUD.zoom += hudCameraZoomIntensity * defaultHUDCameraZoom;
|
||||||
}
|
}
|
||||||
|
@ -1500,6 +1552,11 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
// Apply camera zoom level from stage data.
|
// Apply camera zoom level from stage data.
|
||||||
defaultCameraZoom = currentStage.camZoom;
|
defaultCameraZoom = currentStage.camZoom;
|
||||||
|
currentCameraZoom = defaultCameraZoom;
|
||||||
|
FlxG.camera.zoom = currentCameraZoom;
|
||||||
|
|
||||||
|
// Reset additive zoom.
|
||||||
|
additiveCameraZoom = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2847,6 +2904,9 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
function performCleanup():Void
|
function performCleanup():Void
|
||||||
{
|
{
|
||||||
|
// If the camera is being tweened, stop it.
|
||||||
|
cancelAllCameraTweens();
|
||||||
|
|
||||||
if (currentConversation != null)
|
if (currentConversation != null)
|
||||||
{
|
{
|
||||||
remove(currentConversation);
|
remove(currentConversation);
|
||||||
|
@ -2905,6 +2965,9 @@ class PlayState extends MusicBeatSubState
|
||||||
// Stop camera zooming on beat.
|
// Stop camera zooming on beat.
|
||||||
cameraZoomRate = 0;
|
cameraZoomRate = 0;
|
||||||
|
|
||||||
|
// Cancel camera tweening if it's active.
|
||||||
|
cancelAllCameraTweens();
|
||||||
|
|
||||||
// If the opponent is GF, zoom in on the opponent.
|
// If the opponent is GF, zoom in on the opponent.
|
||||||
// Else, if there is no GF, zoom in on BF.
|
// Else, if there is no GF, zoom in on BF.
|
||||||
// Else, zoom in on GF.
|
// Else, zoom in on GF.
|
||||||
|
@ -2991,15 +3054,119 @@ class PlayState extends MusicBeatSubState
|
||||||
/**
|
/**
|
||||||
* Resets the camera's zoom level and focus point.
|
* Resets the camera's zoom level and focus point.
|
||||||
*/
|
*/
|
||||||
public function resetCamera():Void
|
public function resetCamera(?resetZoom:Bool = true, ?cancelTweens:Bool = true):Void
|
||||||
{
|
{
|
||||||
|
// Cancel camera tweens if any are active.
|
||||||
|
if (cancelTweens)
|
||||||
|
{
|
||||||
|
cancelAllCameraTweens();
|
||||||
|
}
|
||||||
|
|
||||||
FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.04);
|
FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.04);
|
||||||
FlxG.camera.targetOffset.set();
|
FlxG.camera.targetOffset.set();
|
||||||
FlxG.camera.zoom = defaultCameraZoom;
|
|
||||||
|
if (resetZoom)
|
||||||
|
{
|
||||||
|
resetCameraZoom();
|
||||||
|
}
|
||||||
|
|
||||||
// Snap the camera to the follow point immediately.
|
// Snap the camera to the follow point immediately.
|
||||||
FlxG.camera.focusOn(cameraFollowPoint.getPosition());
|
FlxG.camera.focusOn(cameraFollowPoint.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables camera following and tweens the camera to the follow point manually.
|
||||||
|
*/
|
||||||
|
public function tweenCameraToFollowPoint(?duration:Float, ?ease:Null<Float->Float>):Void
|
||||||
|
{
|
||||||
|
// Cancel the current tween if it's active.
|
||||||
|
cancelCameraFollowTween();
|
||||||
|
|
||||||
|
if (duration == 0)
|
||||||
|
{
|
||||||
|
// Instant movement. Just reset the camera to force it to the follow point.
|
||||||
|
resetCamera(false, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Disable camera following for the duration of the tween.
|
||||||
|
FlxG.camera.target = null;
|
||||||
|
|
||||||
|
// Follow tween! Caching it so we can cancel/pause it later if needed.
|
||||||
|
var followPos:FlxPoint = cameraFollowPoint.getPosition() - FlxPoint.weak(FlxG.camera.width * 0.5, FlxG.camera.height * 0.5);
|
||||||
|
cameraFollowTween = FlxTween.tween(FlxG.camera.scroll, {x: followPos.x, y: followPos.y}, duration,
|
||||||
|
{
|
||||||
|
ease: ease,
|
||||||
|
onComplete: function(_) {
|
||||||
|
resetCamera(false, false); // Re-enable camera following when the tween is complete.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancelCameraFollowTween()
|
||||||
|
{
|
||||||
|
if (cameraFollowTween != null)
|
||||||
|
{
|
||||||
|
cameraFollowTween.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tweens the camera zoom to the desired amount.
|
||||||
|
*/
|
||||||
|
public function tweenCameraZoom(?zoom:Float, ?duration:Float, ?directMode:Bool, ?ease:Null<Float->Float>):Void
|
||||||
|
{
|
||||||
|
// Cancel the current tween if it's active.
|
||||||
|
cancelCameraZoomTween();
|
||||||
|
|
||||||
|
var targetZoom = zoom * FlxCamera.defaultZoom;
|
||||||
|
|
||||||
|
if (directMode) // Direct mode: Tween defaultCameraZoom for basic "smooth" zooms.
|
||||||
|
{
|
||||||
|
if (duration == 0)
|
||||||
|
{
|
||||||
|
// Instant zoom. No tween needed.
|
||||||
|
defaultCameraZoom = targetZoom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Zoom tween! Caching it so we can cancel/pause it later if needed.
|
||||||
|
cameraZoomTween = FlxTween.tween(this, {defaultCameraZoom: targetZoom}, duration, {ease: ease});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Additive mode: Tween additiveCameraZoom for ease-based zooms.
|
||||||
|
{
|
||||||
|
if (duration == 0)
|
||||||
|
{
|
||||||
|
// Instant zoom. No tween needed.
|
||||||
|
additiveCameraZoom = targetZoom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Zoom tween! Caching it so we can cancel/pause it later if needed.
|
||||||
|
cameraZoomTween = FlxTween.tween(this, {additiveCameraZoom: targetZoom}, duration, {ease: ease});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancelCameraZoomTween()
|
||||||
|
{
|
||||||
|
if (cameraZoomTween != null)
|
||||||
|
{
|
||||||
|
cameraZoomTween.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel all active camera tweens simultaneously.
|
||||||
|
*/
|
||||||
|
public function cancelAllCameraTweens()
|
||||||
|
{
|
||||||
|
cancelCameraFollowTween();
|
||||||
|
cancelCameraZoomTween();
|
||||||
|
}
|
||||||
|
|
||||||
#if (debug || FORCE_DEBUG_VERSION)
|
#if (debug || FORCE_DEBUG_VERSION)
|
||||||
/**
|
/**
|
||||||
* Jumps forward or backward a number of sections in the song.
|
* Jumps forward or backward a number of sections in the song.
|
||||||
|
|
|
@ -193,6 +193,11 @@ class BaseCharacter extends Bopper
|
||||||
return _data.death?.cameraOffsets ?? [0.0, 0.0];
|
return _data.death?.cameraOffsets ?? [0.0, 0.0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBaseScale():Float
|
||||||
|
{
|
||||||
|
return _data.scale;
|
||||||
|
}
|
||||||
|
|
||||||
public function getDeathCameraZoom():Float
|
public function getDeathCameraZoom():Float
|
||||||
{
|
{
|
||||||
return _data.death?.cameraZoom ?? 1.0;
|
return _data.death?.cameraZoom ?? 1.0;
|
||||||
|
@ -260,8 +265,8 @@ class BaseCharacter extends Bopper
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the sprite scale to the appropriate value.
|
* Set the character's sprite scale to the appropriate value.
|
||||||
* @param scale
|
* @param scale The desired scale.
|
||||||
*/
|
*/
|
||||||
public function setScale(scale:Null<Float>):Void
|
public function setScale(scale:Null<Float>):Void
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package funkin.play.event;
|
package funkin.play.event;
|
||||||
|
|
||||||
|
import flixel.tweens.FlxEase;
|
||||||
// Data from the chart
|
// Data from the chart
|
||||||
import funkin.data.song.SongData;
|
import funkin.data.song.SongData;
|
||||||
import funkin.data.song.SongData.SongEventData;
|
import funkin.data.song.SongData.SongEventData;
|
||||||
|
@ -69,6 +70,13 @@ class FocusCameraSongEvent extends SongEvent
|
||||||
|
|
||||||
if (char == null) char = cast data.value;
|
if (char == null) char = cast data.value;
|
||||||
|
|
||||||
|
var useTween:Null<Bool> = data.getBool('useTween');
|
||||||
|
if (useTween == null) useTween = false;
|
||||||
|
var duration:Null<Float> = data.getFloat('duration');
|
||||||
|
if (duration == null) duration = 4.0;
|
||||||
|
var ease:Null<String> = data.getString('ease');
|
||||||
|
if (ease == null) ease = 'linear';
|
||||||
|
|
||||||
switch (char)
|
switch (char)
|
||||||
{
|
{
|
||||||
case -1: // Position
|
case -1: // Position
|
||||||
|
@ -117,6 +125,26 @@ class FocusCameraSongEvent extends SongEvent
|
||||||
default:
|
default:
|
||||||
trace('Unknown camera focus: ' + data);
|
trace('Unknown camera focus: ' + data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (useTween)
|
||||||
|
{
|
||||||
|
switch (ease)
|
||||||
|
{
|
||||||
|
case 'INSTANT':
|
||||||
|
PlayState.instance.tweenCameraToFollowPoint(0);
|
||||||
|
default:
|
||||||
|
var durSeconds = Conductor.instance.stepLengthMs * duration / 1000;
|
||||||
|
|
||||||
|
var easeFunction:Null<Float->Float> = Reflect.field(FlxEase, ease);
|
||||||
|
if (easeFunction == null)
|
||||||
|
{
|
||||||
|
trace('Invalid ease function: $ease');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayState.instance.tweenCameraToFollowPoint(durSeconds, easeFunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function getTitle():String
|
public override function getTitle():String
|
||||||
|
@ -158,6 +186,51 @@ class FocusCameraSongEvent extends SongEvent
|
||||||
step: 10.0,
|
step: 10.0,
|
||||||
type: SongEventFieldType.FLOAT,
|
type: SongEventFieldType.FLOAT,
|
||||||
units: "px"
|
units: "px"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'useTween',
|
||||||
|
title: 'Use Tween',
|
||||||
|
type: SongEventFieldType.BOOL,
|
||||||
|
defaultValue: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'duration',
|
||||||
|
title: 'Duration',
|
||||||
|
defaultValue: 4.0,
|
||||||
|
step: 0.5,
|
||||||
|
type: SongEventFieldType.FLOAT,
|
||||||
|
units: 'steps'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ease',
|
||||||
|
title: 'Easing Type',
|
||||||
|
defaultValue: 'linear',
|
||||||
|
type: SongEventFieldType.ENUM,
|
||||||
|
keys: [
|
||||||
|
'Linear' => 'linear',
|
||||||
|
'Instant' => 'INSTANT',
|
||||||
|
'Quad In' => 'quadIn',
|
||||||
|
'Quad Out' => 'quadOut',
|
||||||
|
'Quad In/Out' => 'quadInOut',
|
||||||
|
'Cube In' => 'cubeIn',
|
||||||
|
'Cube Out' => 'cubeOut',
|
||||||
|
'Cube In/Out' => 'cubeInOut',
|
||||||
|
'Quart In' => 'quartIn',
|
||||||
|
'Quart Out' => 'quartOut',
|
||||||
|
'Quart In/Out' => 'quartInOut',
|
||||||
|
'Quint In' => 'quintIn',
|
||||||
|
'Quint Out' => 'quintOut',
|
||||||
|
'Quint In/Out' => 'quintInOut',
|
||||||
|
'Smooth Step In' => 'smoothStepIn',
|
||||||
|
'Smooth Step Out' => 'smoothStepOut',
|
||||||
|
'Smooth Step In/Out' => 'smoothStepInOut',
|
||||||
|
'Sine In' => 'sineIn',
|
||||||
|
'Sine Out' => 'sineOut',
|
||||||
|
'Sine In/Out' => 'sineInOut',
|
||||||
|
'Elastic In' => 'elasticIn',
|
||||||
|
'Elastic Out' => 'elasticOut',
|
||||||
|
'Elastic In/Out' => 'elasticInOut',
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,19 +62,26 @@ class ZoomCameraSongEvent extends SongEvent
|
||||||
|
|
||||||
var zoom:Null<Float> = data.getFloat('zoom');
|
var zoom:Null<Float> = data.getFloat('zoom');
|
||||||
if (zoom == null) zoom = 1.0;
|
if (zoom == null) zoom = 1.0;
|
||||||
|
|
||||||
var duration:Null<Float> = data.getFloat('duration');
|
var duration:Null<Float> = data.getFloat('duration');
|
||||||
if (duration == null) duration = 4.0;
|
if (duration == null) duration = 4.0;
|
||||||
|
|
||||||
|
var mode:Null<String> = data.getString('mode');
|
||||||
|
if (mode == null) mode = 'additive';
|
||||||
|
|
||||||
var ease:Null<String> = data.getString('ease');
|
var ease:Null<String> = data.getString('ease');
|
||||||
if (ease == null) ease = 'linear';
|
if (ease == null) ease = 'linear';
|
||||||
|
|
||||||
|
var directMode:Bool = mode == 'direct';
|
||||||
|
|
||||||
// If it's a string, check the value.
|
// If it's a string, check the value.
|
||||||
switch (ease)
|
switch (ease)
|
||||||
{
|
{
|
||||||
case 'INSTANT':
|
case 'INSTANT':
|
||||||
// Set the zoom. Use defaultCameraZoom to prevent breaking camera bops.
|
PlayState.instance.tweenCameraZoom(zoom, 0, directMode);
|
||||||
PlayState.instance.defaultCameraZoom = zoom * FlxCamera.defaultZoom;
|
|
||||||
default:
|
default:
|
||||||
|
var durSeconds = Conductor.instance.stepLengthMs * duration / 1000;
|
||||||
|
|
||||||
var easeFunction:Null<Float->Float> = Reflect.field(FlxEase, ease);
|
var easeFunction:Null<Float->Float> = Reflect.field(FlxEase, ease);
|
||||||
if (easeFunction == null)
|
if (easeFunction == null)
|
||||||
{
|
{
|
||||||
|
@ -82,8 +89,7 @@ class ZoomCameraSongEvent extends SongEvent
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FlxTween.tween(PlayState.instance, {defaultCameraZoom: zoom * FlxCamera.defaultZoom}, (Conductor.instance.stepLengthMs * duration / 1000),
|
PlayState.instance.tweenCameraZoom(zoom, durSeconds, directMode, easeFunction);
|
||||||
{ease: easeFunction});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,8 +102,9 @@ class ZoomCameraSongEvent extends SongEvent
|
||||||
* ```
|
* ```
|
||||||
* {
|
* {
|
||||||
* 'zoom': FLOAT, // Target zoom level.
|
* 'zoom': FLOAT, // Target zoom level.
|
||||||
* 'duration': FLOAT, // Optional duration in steps
|
* 'duration': FLOAT, // Optional duration in steps.
|
||||||
* 'ease': ENUM, // Optional easing function
|
* 'mode': ENUM, // Whether to set additive zoom or direct zoom.
|
||||||
|
* 'ease': ENUM, // Optional easing function.
|
||||||
* }
|
* }
|
||||||
* @return SongEventSchema
|
* @return SongEventSchema
|
||||||
*/
|
*/
|
||||||
|
@ -120,6 +127,13 @@ class ZoomCameraSongEvent extends SongEvent
|
||||||
type: SongEventFieldType.FLOAT,
|
type: SongEventFieldType.FLOAT,
|
||||||
units: 'steps'
|
units: 'steps'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'mode',
|
||||||
|
title: 'Mode',
|
||||||
|
defaultValue: 'additive',
|
||||||
|
type: SongEventFieldType.ENUM,
|
||||||
|
keys: ['Additive' => 'additive', 'Direct' => 'direct']
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'ease',
|
name: 'ease',
|
||||||
title: 'Easing Type',
|
title: 'Easing Type',
|
||||||
|
|
|
@ -387,11 +387,14 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List all the difficulties in this song.
|
* List all the difficulties in this song.
|
||||||
|
*
|
||||||
* @param variationId Optionally filter by a single variation.
|
* @param variationId Optionally filter by a single variation.
|
||||||
* @param variationIds Optionally filter by multiple variations.
|
* @param variationIds Optionally filter by multiple variations.
|
||||||
|
* @param showHidden Include charts which are not accessible to the player.
|
||||||
|
*
|
||||||
* @return The list of difficulties.
|
* @return The list of difficulties.
|
||||||
*/
|
*/
|
||||||
public function listDifficulties(?variationId:String, ?variationIds:Array<String>):Array<String>
|
public function listDifficulties(?variationId:String, ?variationIds:Array<String>, showHidden:Bool = false):Array<String>
|
||||||
{
|
{
|
||||||
if (variationIds == null) variationIds = [];
|
if (variationIds == null) variationIds = [];
|
||||||
if (variationId != null) variationIds.push(variationId);
|
if (variationId != null) variationIds.push(variationId);
|
||||||
|
@ -407,6 +410,15 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
||||||
return difficulty.difficulty;
|
return difficulty.difficulty;
|
||||||
}).nonNull().unique();
|
}).nonNull().unique();
|
||||||
|
|
||||||
|
diffFiltered = diffFiltered.filter(function(diffId:String):Bool {
|
||||||
|
if (showHidden) return true;
|
||||||
|
for (targetVariation in variationIds)
|
||||||
|
{
|
||||||
|
if (isDifficultyVisible(diffId, targetVariation)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
diffFiltered.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_DIFFICULTY_LIST));
|
diffFiltered.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_DIFFICULTY_LIST));
|
||||||
|
|
||||||
return diffFiltered;
|
return diffFiltered;
|
||||||
|
@ -425,6 +437,13 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isDifficultyVisible(diffId:String, variationId:String):Bool
|
||||||
|
{
|
||||||
|
var variation = _metadata.get(variationId);
|
||||||
|
if (variation == null) return false;
|
||||||
|
return variation.playData.difficulties.contains(diffId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purge the cached chart data for each difficulty of this song.
|
* Purge the cached chart data for each difficulty of this song.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -109,10 +109,11 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
{
|
{
|
||||||
getBoyfriend().resetCharacter(true);
|
getBoyfriend().resetCharacter(true);
|
||||||
// Reapply the camera offsets.
|
// Reapply the camera offsets.
|
||||||
var charData = _data.characters.bf;
|
var stageCharData:StageDataCharacter = _data.characters.bf;
|
||||||
getBoyfriend().scale.set(charData.scale, charData.scale);
|
var finalScale:Float = getBoyfriend().getBaseScale() * stageCharData.scale;
|
||||||
getBoyfriend().cameraFocusPoint.x += charData.cameraOffsets[0];
|
getBoyfriend().setScale(finalScale);
|
||||||
getBoyfriend().cameraFocusPoint.y += charData.cameraOffsets[1];
|
getBoyfriend().cameraFocusPoint.x += stageCharData.cameraOffsets[0];
|
||||||
|
getBoyfriend().cameraFocusPoint.y += stageCharData.cameraOffsets[1];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -122,19 +123,21 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
{
|
{
|
||||||
getGirlfriend().resetCharacter(true);
|
getGirlfriend().resetCharacter(true);
|
||||||
// Reapply the camera offsets.
|
// Reapply the camera offsets.
|
||||||
var charData = _data.characters.gf;
|
var stageCharData:StageDataCharacter = _data.characters.gf;
|
||||||
getGirlfriend().scale.set(charData.scale, charData.scale);
|
var finalScale:Float = getBoyfriend().getBaseScale() * stageCharData.scale;
|
||||||
getGirlfriend().cameraFocusPoint.x += charData.cameraOffsets[0];
|
getGirlfriend().setScale(finalScale);
|
||||||
getGirlfriend().cameraFocusPoint.y += charData.cameraOffsets[1];
|
getGirlfriend().cameraFocusPoint.x += stageCharData.cameraOffsets[0];
|
||||||
|
getGirlfriend().cameraFocusPoint.y += stageCharData.cameraOffsets[1];
|
||||||
}
|
}
|
||||||
if (getDad() != null)
|
if (getDad() != null)
|
||||||
{
|
{
|
||||||
getDad().resetCharacter(true);
|
getDad().resetCharacter(true);
|
||||||
// Reapply the camera offsets.
|
// Reapply the camera offsets.
|
||||||
var charData = _data.characters.dad;
|
var stageCharData:StageDataCharacter = _data.characters.dad;
|
||||||
getDad().scale.set(charData.scale, charData.scale);
|
var finalScale:Float = getBoyfriend().getBaseScale() * stageCharData.scale;
|
||||||
getDad().cameraFocusPoint.x += charData.cameraOffsets[0];
|
getDad().setScale(finalScale);
|
||||||
getDad().cameraFocusPoint.y += charData.cameraOffsets[1];
|
getDad().cameraFocusPoint.x += stageCharData.cameraOffsets[0];
|
||||||
|
getDad().cameraFocusPoint.y += stageCharData.cameraOffsets[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset positions of named props.
|
// Reset positions of named props.
|
||||||
|
@ -393,23 +396,23 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
#end
|
#end
|
||||||
|
|
||||||
// Apply position and z-index.
|
// Apply position and z-index.
|
||||||
var charData:StageDataCharacter = null;
|
var stageCharData:StageDataCharacter = null;
|
||||||
switch (charType)
|
switch (charType)
|
||||||
{
|
{
|
||||||
case BF:
|
case BF:
|
||||||
this.characters.set('bf', character);
|
this.characters.set('bf', character);
|
||||||
charData = _data.characters.bf;
|
stageCharData = _data.characters.bf;
|
||||||
character.flipX = !character.getDataFlipX();
|
character.flipX = !character.getDataFlipX();
|
||||||
character.name = 'bf';
|
character.name = 'bf';
|
||||||
character.initHealthIcon(false);
|
character.initHealthIcon(false);
|
||||||
case GF:
|
case GF:
|
||||||
this.characters.set('gf', character);
|
this.characters.set('gf', character);
|
||||||
charData = _data.characters.gf;
|
stageCharData = _data.characters.gf;
|
||||||
character.flipX = character.getDataFlipX();
|
character.flipX = character.getDataFlipX();
|
||||||
character.name = 'gf';
|
character.name = 'gf';
|
||||||
case DAD:
|
case DAD:
|
||||||
this.characters.set('dad', character);
|
this.characters.set('dad', character);
|
||||||
charData = _data.characters.dad;
|
stageCharData = _data.characters.dad;
|
||||||
character.flipX = character.getDataFlipX();
|
character.flipX = character.getDataFlipX();
|
||||||
character.name = 'dad';
|
character.name = 'dad';
|
||||||
character.initHealthIcon(true);
|
character.initHealthIcon(true);
|
||||||
|
@ -421,15 +424,15 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
// This ensures positioning is based on the idle animation.
|
// This ensures positioning is based on the idle animation.
|
||||||
character.resetCharacter(true);
|
character.resetCharacter(true);
|
||||||
|
|
||||||
if (charData != null)
|
if (stageCharData != null)
|
||||||
{
|
{
|
||||||
character.zIndex = charData.zIndex;
|
character.zIndex = stageCharData.zIndex;
|
||||||
|
|
||||||
// Start with the per-stage character position.
|
// Start with the per-stage character position.
|
||||||
// Subtracting the origin ensures characters are positioned relative to their feet.
|
// Subtracting the origin ensures characters are positioned relative to their feet.
|
||||||
// Subtracting the global offset allows positioning on a per-character basis.
|
// Subtracting the global offset allows positioning on a per-character basis.
|
||||||
character.x = charData.position[0] - character.characterOrigin.x + character.globalOffsets[0];
|
character.x = stageCharData.position[0] - character.characterOrigin.x + character.globalOffsets[0];
|
||||||
character.y = charData.position[1] - character.characterOrigin.y + character.globalOffsets[1];
|
character.y = stageCharData.position[1] - character.characterOrigin.y + character.globalOffsets[1];
|
||||||
|
|
||||||
@:privateAccess(funkin.play.stage.Bopper)
|
@:privateAccess(funkin.play.stage.Bopper)
|
||||||
{
|
{
|
||||||
|
@ -438,16 +441,17 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
character.originalPosition.y = character.y + character.animOffsets[1];
|
character.originalPosition.y = character.y + character.animOffsets[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
character.scale.set(charData.scale, charData.scale);
|
var finalScale = character.getBaseScale() * stageCharData.scale;
|
||||||
character.cameraFocusPoint.x += charData.cameraOffsets[0];
|
character.setScale(finalScale); // Don't use scale.set for characters!
|
||||||
character.cameraFocusPoint.y += charData.cameraOffsets[1];
|
character.cameraFocusPoint.x += stageCharData.cameraOffsets[0];
|
||||||
|
character.cameraFocusPoint.y += stageCharData.cameraOffsets[1];
|
||||||
|
|
||||||
#if debug
|
#if debug
|
||||||
// Draw the debug icon at the character's feet.
|
// Draw the debug icon at the character's feet.
|
||||||
if (charType == BF || charType == DAD)
|
if (charType == BF || charType == DAD)
|
||||||
{
|
{
|
||||||
debugIcon.x = charData.position[0];
|
debugIcon.x = stageCharData.position[0];
|
||||||
debugIcon.y = charData.position[1];
|
debugIcon.y = stageCharData.position[1];
|
||||||
debugIcon2.x = character.x;
|
debugIcon2.x = character.x;
|
||||||
debugIcon2.y = character.y;
|
debugIcon2.y = character.y;
|
||||||
}
|
}
|
||||||
|
|
|
@ -878,6 +878,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
*/
|
*/
|
||||||
var noteDisplayDirty:Bool = true;
|
var noteDisplayDirty:Bool = true;
|
||||||
|
|
||||||
|
var noteTooltipsDirty:Bool = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the selected charactesr have been modified and the health icons need to be updated.
|
* Whether the selected charactesr have been modified and the health icons need to be updated.
|
||||||
*/
|
*/
|
||||||
|
@ -1541,6 +1543,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
// Make sure view is updated when the variation changes.
|
// Make sure view is updated when the variation changes.
|
||||||
noteDisplayDirty = true;
|
noteDisplayDirty = true;
|
||||||
notePreviewDirty = true;
|
notePreviewDirty = true;
|
||||||
|
noteTooltipsDirty = true;
|
||||||
notePreviewViewportBoundsDirty = true;
|
notePreviewViewportBoundsDirty = true;
|
||||||
|
|
||||||
switchToCurrentInstrumental();
|
switchToCurrentInstrumental();
|
||||||
|
@ -1562,6 +1565,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
// Make sure view is updated when the difficulty changes.
|
// Make sure view is updated when the difficulty changes.
|
||||||
noteDisplayDirty = true;
|
noteDisplayDirty = true;
|
||||||
notePreviewDirty = true;
|
notePreviewDirty = true;
|
||||||
|
noteTooltipsDirty = true;
|
||||||
notePreviewViewportBoundsDirty = true;
|
notePreviewViewportBoundsDirty = true;
|
||||||
|
|
||||||
// Make sure the difficulty we selected is in the list of difficulties.
|
// Make sure the difficulty we selected is in the list of difficulties.
|
||||||
|
@ -3663,8 +3667,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
selectionSquare.width = eventSprite.width;
|
selectionSquare.width = eventSprite.width;
|
||||||
selectionSquare.height = eventSprite.height;
|
selectionSquare.height = eventSprite.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Additional cleanup on notes.
|
||||||
|
if (noteTooltipsDirty) eventSprite.updateTooltipText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noteTooltipsDirty = false;
|
||||||
|
|
||||||
// Sort the notes DESCENDING. This keeps the sustain behind the associated note.
|
// Sort the notes DESCENDING. This keeps the sustain behind the associated note.
|
||||||
renderedNotes.sort(FlxSort.byY, FlxSort.DESCENDING); // TODO: .group.insertionSort()
|
renderedNotes.sort(FlxSort.byY, FlxSort.DESCENDING); // TODO: .group.insertionSort()
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,12 @@ class SetItemSelectionCommand implements ChartEditorCommand
|
||||||
}
|
}
|
||||||
var eventData = eventSelected.valueAsStruct(defaultKey);
|
var eventData = eventSelected.valueAsStruct(defaultKey);
|
||||||
|
|
||||||
state.eventDataToPlace = eventData;
|
var eventDataClone = Reflect.copy(eventData);
|
||||||
|
|
||||||
|
if (eventDataClone != null)
|
||||||
|
{
|
||||||
|
state.eventDataToPlace = eventDataClone;
|
||||||
|
}
|
||||||
|
|
||||||
state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT);
|
state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_EVENT_DATA_LAYOUT);
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,8 +164,7 @@ class ChartEditorEventSprite extends FlxSprite
|
||||||
this.eventData = value;
|
this.eventData = value;
|
||||||
// Update the position to match the note data.
|
// Update the position to match the note data.
|
||||||
updateEventPosition();
|
updateEventPosition();
|
||||||
// Update the tooltip text.
|
updateTooltipText();
|
||||||
this.tooltip.tipData = {text: this.eventData.buildTooltip()};
|
|
||||||
return this.eventData;
|
return this.eventData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,6 +187,13 @@ class ChartEditorEventSprite extends FlxSprite
|
||||||
this.updateTooltipPosition();
|
this.updateTooltipPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateTooltipText():Void
|
||||||
|
{
|
||||||
|
if (this.eventData == null) return;
|
||||||
|
if (this.isGhost) return;
|
||||||
|
this.tooltip.tipData = {text: this.eventData.buildTooltip()};
|
||||||
|
}
|
||||||
|
|
||||||
public function updateTooltipPosition():Void
|
public function updateTooltipPosition():Void
|
||||||
{
|
{
|
||||||
// No tooltip for ghost sprites.
|
// No tooltip for ghost sprites.
|
||||||
|
|
|
@ -237,6 +237,11 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
{
|
{
|
||||||
value = event.target.value.value;
|
value = event.target.value.value;
|
||||||
}
|
}
|
||||||
|
else if (field.type == BOOL)
|
||||||
|
{
|
||||||
|
var chk:CheckBox = cast event.target;
|
||||||
|
value = cast(chk.selected, Null<Bool>); // Need to cast to nullable bool or the compiler will get mad.
|
||||||
|
}
|
||||||
|
|
||||||
trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${value}');
|
trace('ChartEditorToolboxHandler.buildEventDataFormFromSchema() - ${event.target.id} = ${value}');
|
||||||
|
|
||||||
|
@ -253,14 +258,15 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
// Edit the event data of any existing events.
|
// Edit the event data of any existing events.
|
||||||
if (!_initializing && chartEditorState.currentEventSelection.length > 0)
|
if (!_initializing && chartEditorState.currentEventSelection.length > 0)
|
||||||
{
|
{
|
||||||
for (event in chartEditorState.currentEventSelection)
|
for (songEvent in chartEditorState.currentEventSelection)
|
||||||
{
|
{
|
||||||
event.eventKind = chartEditorState.eventKindToPlace;
|
songEvent.eventKind = chartEditorState.eventKindToPlace;
|
||||||
event.value = chartEditorState.eventDataToPlace;
|
songEvent.value = Reflect.copy(chartEditorState.eventDataToPlace);
|
||||||
}
|
}
|
||||||
chartEditorState.saveDataDirty = true;
|
chartEditorState.saveDataDirty = true;
|
||||||
chartEditorState.noteDisplayDirty = true;
|
chartEditorState.noteDisplayDirty = true;
|
||||||
chartEditorState.notePreviewDirty = true;
|
chartEditorState.notePreviewDirty = true;
|
||||||
|
chartEditorState.noteTooltipsDirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,11 @@ class StageOffsetSubState extends HaxeUISubState
|
||||||
{
|
{
|
||||||
super.create();
|
super.create();
|
||||||
|
|
||||||
|
var playState = PlayState.instance;
|
||||||
|
|
||||||
FlxG.mouse.visible = true;
|
FlxG.mouse.visible = true;
|
||||||
PlayState.instance.pauseMusic();
|
playState.pauseMusic();
|
||||||
|
playState.cancelAllCameraTweens();
|
||||||
FlxG.camera.target = null;
|
FlxG.camera.target = null;
|
||||||
|
|
||||||
setupUIListeners();
|
setupUIListeners();
|
||||||
|
@ -63,8 +66,8 @@ class StageOffsetSubState extends HaxeUISubState
|
||||||
|
|
||||||
// add(uiStuff);
|
// add(uiStuff);
|
||||||
|
|
||||||
PlayState.instance.persistentUpdate = true;
|
playState.persistentUpdate = true;
|
||||||
component.cameras = [PlayState.instance.camHUD];
|
component.cameras = [playState.camHUD];
|
||||||
// uiStuff.cameras = [PlayState.instance.camHUD];
|
// uiStuff.cameras = [PlayState.instance.camHUD];
|
||||||
// btn.cameras = [PlayState.instance.camHUD];
|
// btn.cameras = [PlayState.instance.camHUD];
|
||||||
|
|
||||||
|
@ -72,7 +75,7 @@ class StageOffsetSubState extends HaxeUISubState
|
||||||
|
|
||||||
var layerList:ListView = findComponent("prop-layers");
|
var layerList:ListView = findComponent("prop-layers");
|
||||||
|
|
||||||
for (thing in PlayState.instance.currentStage)
|
for (thing in playState.currentStage)
|
||||||
{
|
{
|
||||||
var prop:StageProp = cast thing;
|
var prop:StageProp = cast thing;
|
||||||
if (prop != null && prop.name != null)
|
if (prop != null && prop.name != null)
|
||||||
|
|
147
source/funkin/ui/options/FunkinSoundTray.hx
Normal file
147
source/funkin/ui/options/FunkinSoundTray.hx
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
package funkin.ui.options;
|
||||||
|
|
||||||
|
import flixel.system.ui.FlxSoundTray;
|
||||||
|
import flixel.tweens.FlxTween;
|
||||||
|
import flixel.system.FlxAssets;
|
||||||
|
import flixel.tweens.FlxEase;
|
||||||
|
import openfl.display.Bitmap;
|
||||||
|
import openfl.display.BitmapData;
|
||||||
|
import openfl.utils.Assets;
|
||||||
|
import funkin.util.MathUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends the default flixel soundtray, but with some art
|
||||||
|
* and lil polish!
|
||||||
|
*
|
||||||
|
* Gets added to the game in Main.hx, right after FlxGame is new'd
|
||||||
|
* since it's a Sprite rather than Flixel related object
|
||||||
|
*/
|
||||||
|
class FunkinSoundTray extends FlxSoundTray
|
||||||
|
{
|
||||||
|
var graphicScale:Float = 0.30;
|
||||||
|
var lerpYPos:Float = 0;
|
||||||
|
|
||||||
|
var volumeMaxSound:String;
|
||||||
|
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
// calls super, then removes all children to add our own
|
||||||
|
// graphics
|
||||||
|
super();
|
||||||
|
removeChildren();
|
||||||
|
|
||||||
|
var bg:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/volumebox")));
|
||||||
|
bg.scaleX = graphicScale;
|
||||||
|
bg.scaleY = graphicScale;
|
||||||
|
addChild(bg);
|
||||||
|
|
||||||
|
y = -height;
|
||||||
|
visible = false;
|
||||||
|
|
||||||
|
// makes an alpha'd version of all the bars (bar_10.png)
|
||||||
|
var backingBar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_10")));
|
||||||
|
backingBar.x = 10;
|
||||||
|
backingBar.y = 5;
|
||||||
|
backingBar.scaleX = graphicScale;
|
||||||
|
backingBar.scaleY = graphicScale;
|
||||||
|
addChild(backingBar);
|
||||||
|
backingBar.alpha = 0.4;
|
||||||
|
|
||||||
|
// clear the bars array entirely, it was initialized
|
||||||
|
// in the super class
|
||||||
|
_bars = [];
|
||||||
|
|
||||||
|
// 1...11 due to how block named the assets,
|
||||||
|
// we are trying to get assets bars_1-10
|
||||||
|
for (i in 1...11)
|
||||||
|
{
|
||||||
|
var bar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_" + i)));
|
||||||
|
bar.x = 10;
|
||||||
|
bar.y = 5;
|
||||||
|
bar.scaleX = graphicScale;
|
||||||
|
bar.scaleY = graphicScale;
|
||||||
|
addChild(bar);
|
||||||
|
_bars.push(bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
y = -height;
|
||||||
|
screenCenter();
|
||||||
|
|
||||||
|
volumeUpSound = Paths.sound("soundtray/Volup");
|
||||||
|
volumeDownSound = Paths.sound("soundtray/Voldown");
|
||||||
|
volumeMaxSound = Paths.sound("soundtray/VolMAX");
|
||||||
|
|
||||||
|
trace("Custom tray added!");
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function update(MS:Float):Void
|
||||||
|
{
|
||||||
|
y = MathUtil.coolLerp(y, lerpYPos, 0.1);
|
||||||
|
|
||||||
|
// Animate sound tray thing
|
||||||
|
if (_timer > 0)
|
||||||
|
{
|
||||||
|
_timer -= (MS / 1000);
|
||||||
|
}
|
||||||
|
else if (y > -height)
|
||||||
|
{
|
||||||
|
lerpYPos = -height - 10;
|
||||||
|
|
||||||
|
if (y <= -height)
|
||||||
|
{
|
||||||
|
visible = false;
|
||||||
|
active = false;
|
||||||
|
|
||||||
|
#if FLX_SAVE
|
||||||
|
// Save sound preferences
|
||||||
|
if (FlxG.save.isBound)
|
||||||
|
{
|
||||||
|
FlxG.save.data.mute = FlxG.sound.muted;
|
||||||
|
FlxG.save.data.volume = FlxG.sound.volume;
|
||||||
|
FlxG.save.flush();
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the little volume tray slide out.
|
||||||
|
*
|
||||||
|
* @param up Whether the volume is increasing.
|
||||||
|
*/
|
||||||
|
override public function show(up:Bool = false):Void
|
||||||
|
{
|
||||||
|
_timer = 1;
|
||||||
|
lerpYPos = 10;
|
||||||
|
visible = true;
|
||||||
|
active = true;
|
||||||
|
var globalVolume:Int = Math.round(FlxG.sound.volume * 10);
|
||||||
|
|
||||||
|
if (FlxG.sound.muted)
|
||||||
|
{
|
||||||
|
globalVolume = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!silent)
|
||||||
|
{
|
||||||
|
var sound = up ? volumeUpSound : volumeDownSound;
|
||||||
|
|
||||||
|
if (globalVolume == 10) sound = volumeMaxSound;
|
||||||
|
|
||||||
|
if (sound != null) FlxG.sound.load(sound).play();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0..._bars.length)
|
||||||
|
{
|
||||||
|
if (i < globalVolume)
|
||||||
|
{
|
||||||
|
_bars[i].visible = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_bars[i].visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -223,6 +223,7 @@ class TitleState extends MusicBeatState
|
||||||
var shouldFadeIn = (FlxG.sound.music == null);
|
var shouldFadeIn = (FlxG.sound.music == null);
|
||||||
// Load music. Includes logic to handle BPM changes.
|
// Load music. Includes logic to handle BPM changes.
|
||||||
FunkinSound.playMusic('freakyMenu', false, true);
|
FunkinSound.playMusic('freakyMenu', false, true);
|
||||||
|
FlxG.sound.music.volume = 0;
|
||||||
// Fade from 0.0 to 0.7 over 4 seconds
|
// Fade from 0.0 to 0.7 over 4 seconds
|
||||||
if (shouldFadeIn) FlxG.sound.music.fadeIn(4, 0, 0.7);
|
if (shouldFadeIn) FlxG.sound.music.fadeIn(4, 0, 0.7);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,11 @@ class ReloadAssetsDebugPlugin extends FlxBasic
|
||||||
{
|
{
|
||||||
super.update(elapsed);
|
super.update(elapsed);
|
||||||
|
|
||||||
|
#if html5
|
||||||
|
if (FlxG.keys.justPressed.FIVE && FlxG.keys.pressed.SHIFT)
|
||||||
|
#else
|
||||||
if (FlxG.keys.justPressed.F5)
|
if (FlxG.keys.justPressed.F5)
|
||||||
|
#end
|
||||||
{
|
{
|
||||||
funkin.modding.PolymodHandler.forceReloadAssets();
|
funkin.modding.PolymodHandler.forceReloadAssets();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue