diff --git a/source/funkin/ui/haxeui/components/CharacterPlayer.hx b/source/funkin/ui/haxeui/components/CharacterPlayer.hx index c45aac35e..0e6981535 100644 --- a/source/funkin/ui/haxeui/components/CharacterPlayer.hx +++ b/source/funkin/ui/haxeui/components/CharacterPlayer.hx @@ -1,25 +1,19 @@ package funkin.ui.haxeui.components; -import flixel.FlxSprite; -import flixel.graphics.frames.FlxAtlasFrames; -import flixel.graphics.frames.FlxFramesCollection; -import flixel.math.FlxRect; -import funkin.modding.events.ScriptEvent; -import funkin.modding.IScriptedClass.IPlayStateScriptedClass; +import funkin.modding.events.ScriptEvent.GhostMissNoteScriptEvent; +import funkin.modding.events.ScriptEvent.NoteScriptEvent; +import funkin.modding.events.ScriptEvent.SongTimeScriptEvent; +import funkin.modding.events.ScriptEvent.UpdateScriptEvent; +import haxe.ui.core.IDataComponent; import funkin.play.character.BaseCharacter; import funkin.play.character.CharacterData.CharacterDataParser; import haxe.ui.containers.Box; import haxe.ui.core.Component; -import haxe.ui.core.IDataComponent; -import haxe.ui.data.DataSource; import haxe.ui.events.AnimationEvent; -import haxe.ui.events.UIEvent; import haxe.ui.geom.Size; import haxe.ui.layouts.DefaultLayout; -import haxe.ui.styles.Style; -import openfl.Assets; -private typedef AnimationInfo = +typedef AnimationInfo = { var name:String; var prefix:String; @@ -29,6 +23,10 @@ private typedef AnimationInfo = var flipY:Null; // default false } +/** + * A variant of SparrowPlayer which loads a BaseCharacter instead. + * This allows it to play appropriate animations based on song events. + */ @:composite(Layout) class CharacterPlayer extends Box { @@ -37,7 +35,7 @@ class CharacterPlayer extends Box public function new(?defaultToBf:Bool = true) { super(); - this._overrideSkipTransformChildren = false; + _overrideSkipTransformChildren = false; if (defaultToBf) { @@ -45,52 +43,39 @@ class CharacterPlayer extends Box } } - var _charId:String; - public var charId(get, set):String; function get_charId():String { - return _charId; + return character.characterId; } function set_charId(value:String):String { - _charId = value; - loadCharacter(_charId); + loadCharacter(value); return value; } - var _redispatchLoaded:Bool = false; // possible haxeui bug: if listener is added after event is dispatched, event is "lost"... needs thinking about, is it smart to "collect and redispatch"? Not sure - var _redispatchStart:Bool = false; // possible haxeui bug: if listener is added after event is dispatched, event is "lost"... needs thinking about, is it smart to "collect and redispatch"? Not sure + public var charName(get, null):String; - public override function onReady() + function get_charName():String { - super.onReady(); - - invalidateComponentLayout(); - - if (_redispatchLoaded) - { - _redispatchLoaded = false; - dispatch(new AnimationEvent(AnimationEvent.LOADED)); - } - - if (_redispatchStart) - { - _redispatchStart = false; - dispatch(new AnimationEvent(AnimationEvent.START)); - } - - parentComponent._overrideSkipTransformChildren = false; + return character.characterName; } - public function loadCharacter(id:String) + // possible haxeui bug: if listener is added after event is dispatched, event is "lost"... is it smart to "collect and redispatch"? Not sure + var _redispatchLoaded:Bool = false; + // possible haxeui bug: if listener is added after event is dispatched, event is "lost"... is it smart to "collect and redispatch"? Not sure + var _redispatchStart:Bool = false; + var _characterLoaded:Bool = false; + + /** + * Loads a character by ID. + * @param id The ID of the character to load. + */ + public function loadCharacter(id:String):Void { - if (id == null) - { - return; - } + if (id == null) return; if (character != null) { @@ -99,34 +84,24 @@ class CharacterPlayer extends Box character = null; } - var newCharacter:BaseCharacter = CharacterDataParser.fetchCharacter(id); - - if (newCharacter == null) - { - return; - } + // Prevent script issues by fetching with debug=true. + var newCharacter:BaseCharacter = CharacterDataParser.fetchCharacter(id, true); + if (newCharacter == null) return; // Fail if character doesn't exist. + // Assign character. character = newCharacter; - if (_characterType != null) - { - character.characterType = _characterType; - } - if (flip) - { - character.flipX = !character.flipX; - } - character.scale.x *= _scale; - character.scale.y *= _scale; + // Set character properties. + if (characterType != null) character.characterType = characterType; + if (flip) character.flipX = !character.flipX; + if (targetScale != 1.0) character.setScale(targetScale); - character.animation.callback = function(name:String = "", frameNumber:Int = -1, frameIndex:Int = -1) - { + character.animation.callback = function(name:String = '', frameNumber:Int = -1, frameIndex:Int = -1) { @:privateAccess character.onAnimationFrame(name, frameNumber, frameIndex); dispatch(new AnimationEvent(AnimationEvent.FRAME)); }; - character.animation.finishCallback = function(name:String = "") - { + character.animation.finishCallback = function(name:String = '') { @:privateAccess character.onAnimationFinished(name); dispatch(new AnimationEvent(AnimationEvent.END)); @@ -145,28 +120,15 @@ class CharacterPlayer extends Box } } - override function repositionChildren() + /** + * The character type (such as BF, Dad, GF, etc). + */ + public var characterType(default, set):CharacterType; + + function set_characterType(value:CharacterType):CharacterType { - super.repositionChildren(); - - @:privateAccess - var animOffsets = character.animOffsets; - - character.x = this.screenX + ((this.width / 2) - (character.frameWidth / 2)); - character.x -= animOffsets[0]; - character.y = this.screenY + ((this.height / 2) - (character.frameHeight / 2)); - character.y -= animOffsets[1]; - } - - var _characterType:CharacterType; - - public function setCharacterType(value:CharacterType) - { - _characterType = value; - if (character != null) - { - character.characterType = value; - } + if (character != null) character.characterType = value; + return characterType = value; } public var flip(default, set):Bool; @@ -183,89 +145,133 @@ class CharacterPlayer extends Box return flip = value; } - var _scale:Float = 1.0; + public var targetScale(default, set):Float = 1.0; - public function setScale(value) + function set_targetScale(value:Float):Float { - _scale = value; + if (value == targetScale) return value; + if (character != null) { - character.scale.x *= _scale; - character.scale.y *= _scale; + character.setScale(value); } + + return targetScale = value; } - public function onUpdate(event:UpdateScriptEvent) + function onFrame(name:String, frameNumber:Int, frameIndex:Int):Void + { + dispatch(new AnimationEvent(AnimationEvent.FRAME)); + } + + function onFinish(name:String):Void + { + dispatch(new AnimationEvent(AnimationEvent.END)); + } + + override function repositionChildren():Void + { + super.repositionChildren(); + character.x = this.screenX; + character.y = this.screenY; + + // Apply animation offsets, so the character is positioned correctly based on the animation. + @:privateAccess var animOffsets:Array = character.animOffsets; + + character.x -= animOffsets[0] * targetScale * (flip ? -1 : 1); + character.y -= animOffsets[1] * targetScale; + } + + /** + * Called when an update event is hit in the song. + * Used to play character animations. + * @param event The event. + */ + public function onUpdate(event:UpdateScriptEvent):Void { if (character != null) character.onUpdate(event); } + /** + * Called when an beat is hit in the song + * Used to play character animations. + * @param event The event. + */ public function onBeatHit(event:SongTimeScriptEvent):Void { if (character != null) character.onBeatHit(event); - - this.repositionChildren(); } + /** + * Called when a step is hit in the song + * Used to play character animations. + * @param event The event. + */ public function onStepHit(event:SongTimeScriptEvent):Void { if (character != null) character.onStepHit(event); } + /** + * Called when a note is hit in the song + * Used to play character animations. + * @param event The event. + */ public function onNoteHit(event:NoteScriptEvent):Void { if (character != null) character.onNoteHit(event); - - this.repositionChildren(); } + /** + * Called when a note is missed in the song + * Used to play character animations. + * @param event The event. + */ public function onNoteMiss(event:NoteScriptEvent):Void { if (character != null) character.onNoteMiss(event); - - this.repositionChildren(); } + /** + * Called when a key is pressed but no note is hit in the song + * Used to play character animations. + * @param event The event. + */ public function onNoteGhostMiss(event:GhostMissNoteScriptEvent):Void { if (character != null) character.onNoteGhostMiss(event); - - this.repositionChildren(); } } @:access(funkin.ui.haxeui.components.CharacterPlayer) private class Layout extends DefaultLayout { - public override function repositionChildren() + public override function resizeChildren():Void { - var player = cast(_component, CharacterPlayer); - var sprite:BaseCharacter = player.character; - if (sprite == null) + super.resizeChildren(); + + var player:CharacterPlayer = cast(_component, CharacterPlayer); + var character:BaseCharacter = player.character; + if (character == null) { - return super.repositionChildren(); + return super.resizeChildren(); } - @:privateAccess - var animOffsets = sprite.animOffsets; - - sprite.x = _component.screenLeft + ((_component.width / 2) - (sprite.frameWidth / 2)); - sprite.x += animOffsets[0]; - sprite.y = _component.screenTop + ((_component.height / 2) - (sprite.frameHeight / 2)); - sprite.y += animOffsets[1]; + character.cornerPosition.set(0, 0); + // character.setGraphicSize(Std.int(innerWidth), Std.int(innerHeight)); } public override function calcAutoSize(exclusions:Array = null):Size { - var player = cast(_component, CharacterPlayer); - var sprite = player.character; - if (sprite == null) + var player:CharacterPlayer = cast(_component, CharacterPlayer); + var character:BaseCharacter = player.character; + if (character == null) { return super.calcAutoSize(exclusions); } - var size = new Size(); - size.width = sprite.frameWidth + paddingLeft + paddingRight; - size.height = sprite.frameHeight + paddingTop + paddingBottom; + var size:Size = new Size(); + size.width = character.width + paddingLeft + paddingRight; + size.height = character.height + paddingTop + paddingBottom; return size; } }