diff --git a/source/funkin/FunkinMemory.hx b/source/funkin/FunkinMemory.hx index fb055446015..580fac58997 100644 --- a/source/funkin/FunkinMemory.hx +++ b/source/funkin/FunkinMemory.hx @@ -274,6 +274,7 @@ class FunkinMemory public static function cacheNoteStyle(style:NoteStyle):Void { // TODO: Texture paths should fall back to the default values. + cacheTexture(Paths.image(style.getHealthBarAssetPath(true) ?? "healthBar")); cacheTexture(Paths.image(style.getNoteAssetPath() ?? "note")); cacheTexture(style.getHoldNoteAssetPath() ?? "noteHold"); cacheTexture(Paths.image(style.getStrumlineAssetPath() ?? "strumline")); diff --git a/source/funkin/data/notestyle/NoteStyleData.hx b/source/funkin/data/notestyle/NoteStyleData.hx index e89ebcaf297..de1bcd636fc 100644 --- a/source/funkin/data/notestyle/NoteStyleData.hx +++ b/source/funkin/data/notestyle/NoteStyleData.hx @@ -75,6 +75,12 @@ typedef NoteStyleAssetsData = @:optional var holdNoteCover:NoteStyleAssetData; + /** + * The sprites for the healthbar + */ + @:optional + var healthBar:NoteStyleAssetData; + /** * The THREE sound (and an optional pre-READY graphic). */ @@ -223,6 +229,12 @@ typedef NoteStyleData_HoldNote = {} typedef NoteStyleData_Judgement = {} typedef NoteStyleData_ComboNum = {} +typedef NoteStyleData_HealthBar = +{ + @:optional + var padding:Null>; +} + /** * Data on animations for each direction of the strumline. */ diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index dcf9ae21364..b113d397ea8 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -42,6 +42,7 @@ import funkin.play.components.Subtitles; import funkin.play.cutscene.dialogue.Conversation; import funkin.play.cutscene.VanillaCutscenes; import funkin.play.cutscene.VideoCutscene; +import funkin.play.notes.HealthBar; import funkin.play.notes.NoteDirection; import funkin.play.notes.notekind.NoteKindManager; import funkin.play.notes.notekind.NoteKind; @@ -502,16 +503,10 @@ class PlayState extends MusicBeatSubState var scoreText:FlxText; /** - * The bar which displays the player's health. - * Dynamically updated based on the value of `healthLerp` (which is based on `health`). + * The sprite group that displays the player's health. + * Dynamically updated. */ - public var healthBar:FlxBar; - - /** - * The background image used for the health bar. - * Emma says the image is slightly skewed so I'm leaving it as an image instead of a `createGraphic`. - */ - public var healthBarBG:FunkinSprite; + public var healthBar:HealthBar; /** * A sprite group for subtitle display. @@ -749,8 +744,7 @@ class PlayState extends MusicBeatSubState opponentStrumline = new Strumline(noteStyle, false, currentChart?.scrollSpeed); // Healthbar - healthBarBG = FunkinSprite.create(0, 0, 'healthBar'); - healthBar = new FlxBar(0, 0, RIGHT_TO_LEFT, Std.int(healthBarBG.width - 8), Std.int(healthBarBG.height - 8), null, 0, 2); + healthBar = new HealthBar(noteStyle, isBotPlayMode); scoreText = new FlxText(0, 0, 0, '', 20); // Combo & Pop Up @@ -980,7 +974,8 @@ class PlayState extends MusicBeatSubState super.update(elapsed); - updateHealthBar(); + healthBar.updateHealthBar(health); + updateScoreText(); // Handle restarting the song when needed (player death or pressing Retry) @@ -1387,9 +1382,9 @@ class PlayState extends MusicBeatSubState updateScoreText(); health = Constants.HEALTH_STARTING; - healthLerp = health; + healthBar.healthLerp = health; - healthBar.value = healthLerp; + healthBar.healthBar.value = healthLerp; if (!isMinimalMode) { @@ -1896,26 +1891,11 @@ class PlayState extends MusicBeatSubState && !ControlsHandler.usingExternalInputDevice) || #end Preferences.downscroll; - var healthBarYPos:Float = isDownscroll ? FlxG.height * 0.1 : FlxG.height * 0.9; - - healthBarBG.y = healthBarYPos; - healthBarBG.screenCenter(X); - healthBarBG.scrollFactor.set(0, 0); - healthBarBG.zIndex = 800; - add(healthBarBG); - - healthBar.x = healthBarBG.x + 4; - healthBar.y = healthBarBG.y + 4; - healthBar.parent = this; - healthBar.parentVariable = 'healthLerp'; - healthBar.scrollFactor.set(); - healthBar.createFilledBar(Constants.COLOR_HEALTH_BAR_RED, Constants.COLOR_HEALTH_BAR_GREEN); - healthBar.zIndex = 801; add(healthBar); // The score text below the health bar. - scoreText.x = healthBarBG.x + healthBarBG.width - 190; - scoreText.y = healthBarBG.y + 30; + scoreText.x = healthBar.healthBar.x + healthBar.healthBar.width - 190; + scoreText.y = healthBar.healthBar.y + 30; scoreText.setFormat(Paths.font('vcr.ttf'), 16, FlxColor.WHITE, RIGHT, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK); scoreText.scrollFactor.set(); scoreText.zIndex = 802; @@ -1923,7 +1903,6 @@ class PlayState extends MusicBeatSubState // Move the health bar to the HUD camera. healthBar.cameras = [camHUD]; - healthBarBG.cameras = [camHUD]; scoreText.cameras = [camHUD]; // Create subtitles if they are enabled. @@ -2054,7 +2033,7 @@ class PlayState extends MusicBeatSubState // OPPONENT HEALTH ICON // iconP2 = new HealthIcon('dad', 1); - iconP2.y = healthBar.y - (iconP2.height / 2); + iconP2.y = healthBar.healthBar.y - (iconP2.height / 2); dad.initHealthIcon(true); // Apply the character ID here iconP2.zIndex = 850; add(iconP2); @@ -2077,7 +2056,7 @@ class PlayState extends MusicBeatSubState // PLAYER HEALTH ICON // iconP1 = new HealthIcon('bf', 0); - iconP1.y = healthBar.y - (iconP1.height / 2); + iconP1.y = healthBar.healthBar.y - (iconP1.height / 2); boyfriend.initHealthIcon(false); // Apply the character ID here iconP1.zIndex = 850; add(iconP1); @@ -2603,21 +2582,6 @@ class PlayState extends MusicBeatSubState } } - /** - * Updates the values of the health bar. - */ - function updateHealthBar():Void - { - if (isBotPlayMode) - { - healthLerp = Constants.HEALTH_MAX; - } - else - { - healthLerp = FlxMath.lerp(healthLerp, health, 0.15); - } - } - /** * Callback executed when one of the note keys is pressed. */ diff --git a/source/funkin/play/components/HealthIcon.hx b/source/funkin/play/components/HealthIcon.hx index 13a57dbf441..487df872187 100644 --- a/source/funkin/play/components/HealthIcon.hx +++ b/source/funkin/play/components/HealthIcon.hx @@ -267,18 +267,19 @@ class HealthIcon extends FunkinSprite // Update the animation based on the current state. updateHealthIcon(PlayState.instance.health); // Update the position to match the health bar. - this.x = PlayState.instance.healthBar.x - + (PlayState.instance.healthBar.width * (FlxMath.remapToRange(PlayState.instance.healthBar.value, 0, 2, 100, 0) * 0.01) - POSITION_OFFSET); + this.x = PlayState.instance.healthBar.healthBar.x + + (PlayState.instance.healthBar.healthBar.width * (FlxMath.remapToRange(PlayState.instance.healthBar.healthBar.value, 0, 2, 100, 0) * 0.01) + - POSITION_OFFSET); case 1: // Dad // Update the animation based on the current state. updateHealthIcon(MAXIMUM_HEALTH - PlayState.instance.health); // Update the position to match the health bar. - this.x = PlayState.instance.healthBar.x - + (PlayState.instance.healthBar.width * (FlxMath.remapToRange(PlayState.instance.healthBar.value, 0, 2, 100, 0) * 0.01)) + this.x = PlayState.instance.healthBar.healthBar.x + + (PlayState.instance.healthBar.healthBar.width * (FlxMath.remapToRange(PlayState.instance.healthBar.healthBar.value, 0, 2, 100, 0) * 0.01)) - (this.width - POSITION_OFFSET); } // Keep the icon centered vertically on the health bar. - this.y = PlayState.instance.healthBar.y - (this.height / 2); // - (PlayState.instance.healthBar.height / 2) + this.y = PlayState.instance.healthBar.healthBar.y - (this.height / 2); // - (PlayState.instance.healthBar.height / 2) } } diff --git a/source/funkin/play/notes/HealthBar.hx b/source/funkin/play/notes/HealthBar.hx new file mode 100644 index 00000000000..c05daaadb29 --- /dev/null +++ b/source/funkin/play/notes/HealthBar.hx @@ -0,0 +1,78 @@ +package funkin.play.notes; + +import flixel.group.FlxSpriteGroup; +import flixel.math.FlxMath; +import flixel.ui.FlxBar; +import funkin.graphics.FunkinSprite; +import funkin.play.notes.notestyle.NoteStyle; + +class HealthBar extends FlxSpriteGroup +{ + final noteStyle:NoteStyle; + + public var healthBar:FlxBar; + public var healthBarBG:FunkinSprite; + public var isBotPlayMode:Bool; + + final isDownscroll:Bool = #if mobile (Preferences.controlsScheme == FunkinHitboxControlSchemes.Arrows + && !ControlsHandler.usingExternalInputDevice) + || #end Preferences.downscroll; + + public var healthLerp:Float = Constants.HEALTH_STARTING; + + public function new(noteStyle, isBotPlayMode:Bool = false):Void + { + super(0, 0); + this.noteStyle = noteStyle; + this.isBotPlayMode = isBotPlayMode; + var padding = noteStyle.getHealthBarPadding(); + trace(noteStyle.getHealthBarAssetPath()); + var assetPath = Paths.image(noteStyle.getHealthBarAssetPath() ?? "healthBar"); + healthBarBG = FunkinSprite.create(0, 0, assetPath); + healthBar = new FlxBar(0, 0, RIGHT_TO_LEFT, Std.int(healthBarBG.width - padding[0]), Std.int(healthBarBG.height - padding[1]), this, 'healthLerp', 0, 2); + var scale = noteStyle.getHealthBarScale(); + if (healthBarBG != null) + { + healthBarBG.scale.set(scale, scale); + healthBarBG.y = isDownscroll ? FlxG.height * 0.1 : FlxG.height * 0.9; + healthBarBG.screenCenter(X); + healthBarBG.scrollFactor.set(0, 0); + healthBarBG.zIndex = 800; + noteStyle.applyHealthBarOffsets(this); + this.add(healthBarBG); + } + else + { + healthBarBG = FunkinSprite.create(0, 0, 'healthBar'); + healthBarBG.scale.set(scale, scale); + healthBarBG.y = isDownscroll ? FlxG.height * 0.1 : FlxG.height * 0.9; + healthBarBG.screenCenter(X); + healthBarBG.scrollFactor.set(0, 0); + healthBarBG.zIndex = 800; + noteStyle.applyHealthBarOffsets(this); + this.add(healthBarBG); + } + + healthBar.x = healthBarBG.x + padding[0] / 2; + healthBar.y = healthBarBG.y + padding[1] / 2; + healthBar.scrollFactor.set(); + healthBar.createFilledBar(Constants.COLOR_HEALTH_BAR_RED, Constants.COLOR_HEALTH_BAR_GREEN); + healthBar.zIndex = 801; + this.add(healthBar); + } + + /** + * Updates the values of the health bar. + */ + public function updateHealthBar(health:Float):Void + { + if (isBotPlayMode) + { + healthLerp = Constants.HEALTH_MAX; + } + else + { + healthLerp = FlxMath.lerp(healthLerp, health, 0.15); + } + } +} diff --git a/source/funkin/play/notes/notestyle/NoteStyle.hx b/source/funkin/play/notes/notestyle/NoteStyle.hx index de3927f6f42..73bf0807118 100644 --- a/source/funkin/play/notes/notestyle/NoteStyle.hx +++ b/source/funkin/play/notes/notestyle/NoteStyle.hx @@ -1157,6 +1157,43 @@ class NoteStyle implements IRegistryEntry return _data?.assets?.holdNoteCover?.offsets ?? fallback?.getHoldCoverOffsets() ?? [0.0, 0.0]; } + public function getHealthBarAssetPath(raw:Bool = false):Null + { + if (raw) + { + var rawPath:Null = _data?.assets?.healthBar?.assetPath; + if (rawPath == null) return fallback?.getHealthBarAssetPath(true); + return rawPath; + } + // library:path + var parts = getHealthBarAssetPath(true)?.split(Constants.LIBRARY_SEPARATOR) ?? []; + if (parts.length == 0) return null; + if (parts.length == 1) return getHealthBarAssetPath(true); + return parts[1]; + } + + public function getHealthBarOffsets():Array + { + return _data?.assets?.healthBar?.offsets ?? fallback?.getHealthBarOffsets() ?? [0.0, 0.0]; + } + + public function applyHealthBarOffsets(target:HealthBar):Void + { + var offsets = getHealthBarOffsets(); + target.x += offsets[0]; + target.y += offsets[1]; + } + + public function getHealthBarScale():Float + { + return _data.assets?.healthBar?.scale ?? fallback?.getHealthBarScale() ?? 1.0; + } + + public function getHealthBarPadding():Array + { + return _data?.assets?.healthBar?.data?.padding ?? fallback?.getHealthBarPadding() ?? [8.0, 8.0]; + } + public function destroy():Void {} /**