From 872f7c93e8e70df55a7ca46681d5e49e91c08062 Mon Sep 17 00:00:00 2001 From: EliteMasterEric <ericmyllyoja@gmail.com> Date: Fri, 26 May 2023 17:10:08 -0400 Subject: [PATCH] Added onAdd event so GF character can fix position in Tutorial --- source/funkin/charting/ChartingState.hx | 10 +- source/funkin/modding/IScriptedClass.hx | 12 ++ source/funkin/modding/events/ScriptEvent.hx | 8 ++ .../modding/events/ScriptEventDispatcher.hx | 11 ++ .../play/character/AnimateAtlasCharacter.hx | 2 +- source/funkin/play/character/BaseCharacter.hx | 70 ++++++++---- source/funkin/play/character/CharacterData.hx | 18 ++- .../play/character/MultiSparrowCharacter.hx | 4 +- source/funkin/play/stage/Bopper.hx | 34 +++--- source/funkin/play/stage/Stage.hx | 106 ++++++++++++++++-- source/funkin/play/stage/StageProp.hx | 23 +++- 11 files changed, 240 insertions(+), 58 deletions(-) diff --git a/source/funkin/charting/ChartingState.hx b/source/funkin/charting/ChartingState.hx index e8402727f..3cfac53be 100644 --- a/source/funkin/charting/ChartingState.hx +++ b/source/funkin/charting/ChartingState.hx @@ -1104,17 +1104,17 @@ class ChartingState extends MusicBeatState // leftIcon.animation.curAnim.curFrame = p1Muted ? 1 : 0; // rightIcon.animation.curAnim.curFrame = p2Muted ? 1 : 0; - - leftIcon.playAnimation(p1Muted ? LOSING : IDLE); - rightIcon.playAnimation(p2Muted ? LOSING : IDLE); + // + // leftIcon.playAnimation(p1Muted ? LOSING : IDLE); + // rightIcon.playAnimation(p2Muted ? LOSING : IDLE); } else { leftIcon.characterId = (_song.player2); rightIcon.characterId = (_song.player1); - leftIcon.playAnimation(p2Muted ? LOSING : IDLE); - rightIcon.playAnimation(p1Muted ? LOSING : IDLE); + // leftIcon.playAnimation(p2Muted ? LOSING : IDLE); + // rightIcon.playAnimation(p1Muted ? LOSING : IDLE); // leftIcon.animation.curAnim.curFrame = p2Muted ? 1 : 0; // rightIcon.animation.curAnim.curFrame = p1Muted ? 1 : 0; diff --git a/source/funkin/modding/IScriptedClass.hx b/source/funkin/modding/IScriptedClass.hx index d6a5e3300..1450f8045 100644 --- a/source/funkin/modding/IScriptedClass.hx +++ b/source/funkin/modding/IScriptedClass.hx @@ -30,6 +30,18 @@ interface IStateChangingScriptedClass extends IScriptedClass public function onSubstateCloseEnd(event:SubStateScriptEvent):Void; } +/** + * Defines a set of callbacks available to scripted classes which can be added to the current state. + * Generally requires the class to be an instance of FlxBasic. + */ +interface IStateStageProp extends IScriptedClass +{ + /** + * Called when the relevant element is added to the game state. + */ + public function onAdd(event:ScriptEvent):Void; +} + /** * Defines a set of callbacks available to scripted classes which represent notes. */ diff --git a/source/funkin/modding/events/ScriptEvent.hx b/source/funkin/modding/events/ScriptEvent.hx index 5ee0c42ea..c99db1d0f 100644 --- a/source/funkin/modding/events/ScriptEvent.hx +++ b/source/funkin/modding/events/ScriptEvent.hx @@ -32,6 +32,14 @@ class ScriptEvent */ public static inline final DESTROY:ScriptEventType = "DESTROY"; + /** + * Called when the relevent object is added to the game state. + * This assumes all data is loaded and ready to go. + * + * This event is not cancelable. + */ + public static inline final ADDED:ScriptEventType = 'ADDED'; + /** * Called during the update function. * This is called every frame, so be careful! diff --git a/source/funkin/modding/events/ScriptEventDispatcher.hx b/source/funkin/modding/events/ScriptEventDispatcher.hx index 05a3fb36e..18181a1d1 100644 --- a/source/funkin/modding/events/ScriptEventDispatcher.hx +++ b/source/funkin/modding/events/ScriptEventDispatcher.hx @@ -34,6 +34,17 @@ class ScriptEventDispatcher return; } + if (Std.isOfType(target, IStateStageProp)) + { + var t:IStateStageProp = cast(target, IStateStageProp); + switch (event.type) + { + case ScriptEvent.ADDED: + t.onAdd(cast event); + return; + } + } + if (Std.isOfType(target, IPlayStateScriptedClass)) { var t = cast(target, IPlayStateScriptedClass); diff --git a/source/funkin/play/character/AnimateAtlasCharacter.hx b/source/funkin/play/character/AnimateAtlasCharacter.hx index 7e7a979a4..f0ce48a32 100644 --- a/source/funkin/play/character/AnimateAtlasCharacter.hx +++ b/source/funkin/play/character/AnimateAtlasCharacter.hx @@ -81,7 +81,7 @@ class AnimateAtlasCharacter extends BaseCharacter super.onCreate(event); } - public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false):Void + public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reverse:Bool = false):Void { if ((!canPlayOtherAnims && !ignoreOther)) return; diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index 01156dfab..f47f384a3 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -21,7 +21,12 @@ class BaseCharacter extends Bopper /** * Whether the player is an active character (Boyfriend) or not. */ - public var characterType:CharacterType = OTHER; + public var characterType(default, set):CharacterType = OTHER; + + function set_characterType(value:CharacterType):CharacterType + { + return this.characterType = value; + } /** * Tracks how long, in seconds, the character has been playing the current `sing` animation. @@ -30,8 +35,18 @@ class BaseCharacter extends Bopper */ public var holdTimer:Float = 0; + /** + * Set to true when the character dead. Part of the handling for death animations. + */ public var isDead:Bool = false; - public var debugMode:Bool = false; + + /** + * Set to true when the character being used in a special way. + * This includes the Chart Editor and the Animation Editor. + * + * Used by scripts to ensure that they don't try to run code to interact with the stage when the stage doesn't actually exist. + */ + public var debug:Bool = false; /** * This character plays a given animation when hitting these specific combo numbers. @@ -44,7 +59,7 @@ class BaseCharacter extends Bopper public var dropNoteCounts(default, null):Array<Int>; final _data:CharacterData; - final singTimeCrochet:Float; + final singTimeSec:Float; /** * The offset between the corner of the sprite and the origin of the sprite (at the character's feet). @@ -102,14 +117,14 @@ class BaseCharacter extends Bopper */ public var cameraFocusPoint(default, null):FlxPoint = new FlxPoint(0, 0); - override function set_animOffsets(value:Array<Float>) + override function set_animOffsets(value:Array<Float>):Array<Float> { if (animOffsets == null) value = [0, 0]; - if (animOffsets == value) return value; + if ((animOffsets[0] == value[0]) && (animOffsets[1] == value[1])) return value; // Make sure animOffets are halved when scale is 0.5. - var xDiff = (animOffsets[0] * this.scale.x) - value[0]; - var yDiff = (animOffsets[1] * this.scale.y) - value[1]; + var xDiff = (animOffsets[0] * this.scale.x / (this.isPixel ? 6 : 1)) - value[0]; + var yDiff = (animOffsets[1] * this.scale.y / (this.isPixel ? 6 : 1)) - value[1]; // Call the super function so that camera focus point is not affected. super.set_x(this.x + xDiff); @@ -164,7 +179,7 @@ class BaseCharacter extends Bopper { this.characterName = _data.name; this.name = _data.name; - this.singTimeCrochet = _data.singTime; + this.singTimeSec = _data.singTime; this.globalOffsets = _data.offsets; this.flipX = _data.flipX; } @@ -229,7 +244,7 @@ class BaseCharacter extends Bopper * Set the sprite scale to the appropriate value. * @param scale */ - function setScale(scale:Null<Float>):Void + public function setScale(scale:Null<Float>):Void { if (scale == null) scale = 1.0; @@ -257,7 +272,7 @@ class BaseCharacter extends Bopper super.onCreate(event); // Make sure we are playing the idle animation... - this.dance(); + this.dance(true); // ...then update the hitbox so that this.width and this.height are correct. this.updateHitbox(); // Without the above code, width and height (and therefore character position) @@ -291,7 +306,9 @@ class BaseCharacter extends Bopper if (PlayState.instance.iconP1 == null) { trace('[WARN] Player 1 health icon not found!'); + return; } + PlayState.instance.iconP1.isPixel = _data.healthIcon?.isPixel ?? false; PlayState.instance.iconP1.characterId = _data.healthIcon.id; PlayState.instance.iconP1.size.set(_data.healthIcon.scale, _data.healthIcon.scale); PlayState.instance.iconP1.offset.x = _data.healthIcon.offsets[0]; @@ -303,12 +320,14 @@ class BaseCharacter extends Bopper if (PlayState.instance.iconP2 == null) { trace('[WARN] Player 2 health icon not found!'); + return; } + PlayState.instance.iconP2.isPixel = _data.healthIcon?.isPixel ?? false; PlayState.instance.iconP2.characterId = _data.healthIcon.id; PlayState.instance.iconP2.size.set(_data.healthIcon.scale, _data.healthIcon.scale); PlayState.instance.iconP2.offset.x = _data.healthIcon.offsets[0]; PlayState.instance.iconP2.offset.y = _data.healthIcon.offsets[1]; - PlayState.instance.iconP1.flipX = _data.healthIcon.flipX; + PlayState.instance.iconP2.flipX = _data.healthIcon.flipX; } } @@ -328,13 +347,16 @@ class BaseCharacter extends Bopper return; } - // This logic turns the idle animation into a "lead-in" animation. - if (hasAnimation('idle-hold') && getCurrentAnimation() == 'idle' && isAnimationFinished()) playAnimation('idle-hold'); + // If there is an animation, and another animation with the same name + "-hold" exists, + // the second animation will play (and be looped if configured to do so) after the first animation finishes. + // This is good for characters that need to hold a pose while maintaining an animation, like the parents (this keeps their eyes flickering) + // and Darnell (this keeps the flame on his lighter flickering). + // Works for idle, singLEFT/RIGHT/UP/DOWN, alt singing animations, and anything else really. - if (hasAnimation('singLEFT-hold') && getCurrentAnimation() == 'singLEFT' && isAnimationFinished()) playAnimation('singLEFT-hold'); - if (hasAnimation('singDOWN-hold') && getCurrentAnimation() == 'singDOWN' && isAnimationFinished()) playAnimation('singDOWN-hold'); - if (hasAnimation('singUP-hold') && getCurrentAnimation() == 'singUP' && isAnimationFinished()) playAnimation('singUP-hold'); - if (hasAnimation('singRIGHT-hold') && getCurrentAnimation() == 'singRIGHT' && isAnimationFinished()) playAnimation('singRIGHT-hold'); + if (!getCurrentAnimation().endsWith('-hold') && hasAnimation(getCurrentAnimation() + '-hold') && isAnimationFinished()) + { + playAnimation(getCurrentAnimation() + '-hold'); + } // Handle character note hold time. if (getCurrentAnimation().startsWith('sing')) @@ -345,18 +367,18 @@ class BaseCharacter extends Bopper // This lets you add frames to the end of the sing animation to ease back into the idle! holdTimer += event.elapsed; - var singTimeMs:Float = singTimeCrochet * (Conductor.crochet * 0.001); // x beats, to ms. + var singTimeSec:Float = singTimeSec * (Conductor.crochet * 0.001); // x beats, to ms. - if (getCurrentAnimation().endsWith('miss')) singTimeMs *= 2; // makes it feel more awkward when you miss + if (getCurrentAnimation().endsWith('miss')) singTimeSec *= 2; // makes it feel more awkward when you miss // Without this check here, the player character would only play the `sing` animation // for one beat, as opposed to holding it as long as the player is holding the button. var shouldStopSinging:Bool = (this.characterType == BF) ? !isHoldingNote() : true; - FlxG.watch.addQuick('singTimeMs-${characterId}', singTimeMs); - if (holdTimer > singTimeMs && shouldStopSinging) + FlxG.watch.addQuick('singTimeSec-${characterId}', singTimeSec); + if (holdTimer > singTimeSec && shouldStopSinging) { - // trace('holdTimer reached ${holdTimer}sec (> ${singTimeMs}), stopping sing animation'); + // trace('holdTimer reached ${holdTimer}sec (> ${singTimeSec}), stopping sing animation'); holdTimer = 0; dance(true); } @@ -370,7 +392,7 @@ class BaseCharacter extends Bopper } /** - * Since no `onBeatHit` or `dance` calls happen in GameOverSubstate, + * Since no `onBeatHit` or `dance` calls happen in GameOverSubState, * this regularly gets called instead. * * @param force Force the deathLoop animation to play, even if `firstDeath` is still playing. @@ -386,7 +408,7 @@ class BaseCharacter extends Bopper override function dance(force:Bool = false):Void { // Prevent default dancing behavior. - if (debugMode || isDead) return; + if (isDead) return; if (!force) { diff --git a/source/funkin/play/character/CharacterData.hx b/source/funkin/play/character/CharacterData.hx index 28763710f..886047ec2 100644 --- a/source/funkin/play/character/CharacterData.hx +++ b/source/funkin/play/character/CharacterData.hx @@ -189,7 +189,7 @@ class CharacterDataParser * @param charId The character ID to fetch. * @return The character instance, or null if the character was not found. */ - public static function fetchCharacter(charId:String):Null<BaseCharacter> + public static function fetchCharacter(charId:String, ?debug:Bool = false):Null<BaseCharacter> { if (charId == null || charId == '' || !characterCache.exists(charId)) { @@ -246,7 +246,9 @@ class CharacterDataParser return null; } - trace('Successfully instantiated character: ${charId}'); + trace('Successfully instantiated character (${debug ? 'debug' : 'stable'}): ${charId}'); + + char.debug = debug; // Call onCreate only in the fetchCharacter() function, not at application initialization. ScriptEventDispatcher.callEvent(char, new ScriptEvent(ScriptEvent.CREATE)); @@ -419,6 +421,7 @@ class CharacterDataParser id: null, scale: null, flipX: null, + isPixel: null, offsets: null }; } @@ -458,6 +461,11 @@ class CharacterDataParser input.isPixel = DEFAULT_ISPIXEL; } + if (input.healthIcon.isPixel == null) + { + input.healthIcon.isPixel = input.isPixel; + } + if (input.danceEvery == null) { input.danceEvery = DEFAULT_DANCEEVERY; @@ -674,6 +682,12 @@ typedef HealthIconData = */ var flipX:Null<Bool>; + /** + * Multiply scale by 6 and disable antialiasing + * @default false + */ + var isPixel:Null<Bool>; + /** * The offset of the health icon, in pixels. * @default [0, 25] diff --git a/source/funkin/play/character/MultiSparrowCharacter.hx b/source/funkin/play/character/MultiSparrowCharacter.hx index 974a1c431..5d4deee5d 100644 --- a/source/funkin/play/character/MultiSparrowCharacter.hx +++ b/source/funkin/play/character/MultiSparrowCharacter.hx @@ -179,14 +179,14 @@ class MultiSparrowCharacter extends BaseCharacter trace('[MULTISPARROWCHAR] Successfully loaded ${animNames.length} animations for ${characterId}'); } - public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false):Void + public override function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reverse:Bool = false):Void { // Make sure we ignore other animations if we're currently playing a forced one, // unless we're forcing a new animation. if (!this.canPlayOtherAnims && !ignoreOther) return; loadFramesByAnimName(name); - super.playAnimation(name, restart, ignoreOther); + super.playAnimation(name, restart, ignoreOther, reverse); } override function set_frames(value:FlxFramesCollection):FlxFramesCollection diff --git a/source/funkin/play/stage/Bopper.hx b/source/funkin/play/stage/Bopper.hx index 623660af7..9b5d1f314 100644 --- a/source/funkin/play/stage/Bopper.hx +++ b/source/funkin/play/stage/Bopper.hx @@ -42,6 +42,18 @@ class Bopper extends StageProp implements IPlayStateScriptedClass */ public var idleSuffix(default, set):String = ''; + /** + * If this bopper is rendered with pixel art, + * disable anti-aliasing and render at 6x scale. + */ + public var isPixel(default, set):Bool = false; + + function set_isPixel(value:Bool):Bool + { + if (isPixel == value) return value; + return isPixel = value; + } + /** * Whether this bopper should bop every beat. By default it's true, but when used * for characters/players, it should be false so it doesn't cut off their animations!!!!! @@ -80,7 +92,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass function set_animOffsets(value:Array<Float>):Array<Float> { if (animOffsets == null) animOffsets = [0, 0]; - if (animOffsets == value) return value; + if ((animOffsets[0] == value[0]) && (animOffsets[1] == value[1])) return value; var xDiff = animOffsets[0] - value[0]; var yDiff = animOffsets[1] - value[1]; @@ -213,7 +225,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass * Will gracefully check for name, then name with stripped suffixes, then 'idle', then fail to play. * @param name */ - function correctAnimationName(name:String) + function correctAnimationName(name:String):String { // If the animation exists, we're good. if (hasAnimation(name)) return name; @@ -248,16 +260,16 @@ class Bopper extends StageProp implements IPlayStateScriptedClass * @param name The name of the animation to play. * @param restart Whether to restart the animation if it is already playing. * @param ignoreOther Whether to ignore all other animation inputs, until this one is done playing + * @param reversed If true, play the animation backwards, from the last frame to the first. */ - public function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false):Void + public function playAnimation(name:String, restart:Bool = false, ?ignoreOther:Bool = false, ?reversed:Bool = false):Void { if (!canPlayOtherAnims && !ignoreOther) return; var correctName = correctAnimationName(name); if (correctName == null) return; - this.animation.paused = false; - this.animation.play(correctName, restart, false, 0); + this.animation.play(correctName, restart, reversed, 0); if (ignoreOther) { @@ -291,10 +303,10 @@ class Bopper extends StageProp implements IPlayStateScriptedClass }, 1); } - function applyAnimationOffsets(name:String) + function applyAnimationOffsets(name:String):Void { var offsets = animationOffsets.get(name); - if (offsets != null) + if (offsets != null && !(offsets[0] == 0 && offsets[1] == 0)) { this.animOffsets = [offsets[0] + globalOffsets[0], offsets[1] + globalOffsets[1]]; } @@ -325,14 +337,6 @@ class Bopper extends StageProp implements IPlayStateScriptedClass return this.animation.curAnim.name; } - public function onScriptEvent(event:ScriptEvent) {} - - public function onCreate(event:ScriptEvent) {} - - public function onDestroy(event:ScriptEvent) {} - - public function onUpdate(event:UpdateScriptEvent) {} - public function onPause(event:PauseScriptEvent) {} public function onResume(event:ScriptEvent) {} diff --git a/source/funkin/play/stage/Stage.hx b/source/funkin/play/stage/Stage.hx index e58a9fa84..71ba522c0 100644 --- a/source/funkin/play/stage/Stage.hx +++ b/source/funkin/play/stage/Stage.hx @@ -77,7 +77,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass // Reset positions of characters. if (getBoyfriend() != null) { - getBoyfriend().resetCharacter(false); + getBoyfriend().resetCharacter(true); } else { @@ -85,11 +85,11 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass } if (getGirlfriend() != null) { - getGirlfriend().resetCharacter(false); + getGirlfriend().resetCharacter(true); } if (getDad() != null) { - getDad().resetCharacter(false); + getDad().resetCharacter(true); } // Reset positions of named props. @@ -286,6 +286,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass */ override function preAdd(Sprite:FlxSprite):Void { + if (Sprite == null) return; var sprite:FlxSprite = cast Sprite; sprite.x += x; sprite.y += y; @@ -377,22 +378,36 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass // Add the character to the scene. this.add(character); + ScriptEventDispatcher.callEvent(character, new ScriptEvent(ScriptEvent.ADDED, false)); + #if debug debugIconGroup.add(debugIcon); debugIconGroup.add(debugIcon2); #end } + /** + * Get the position of the girlfriend character, as defined in the stage data. + * @return An FlxPoint position. + */ public inline function getGirlfriendPosition():FlxPoint { return new FlxPoint(_data.characters.gf.position[0], _data.characters.gf.position[1]); } + /** + * Get the position of the boyfriend character, as defined in the stage data. + * @return An FlxPoint position. + */ public inline function getBoyfriendPosition():FlxPoint { return new FlxPoint(_data.characters.bf.position[0], _data.characters.bf.position[1]); } + /** + * Get the position of the dad character, as defined in the stage data. + * @return An FlxPoint position. + */ public inline function getDadPosition():FlxPoint { return new FlxPoint(_data.characters.dad.position[0], _data.characters.dad.position[1]); @@ -409,6 +424,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass /** * Retrieve the Boyfriend character. * @param pop If true, the character will be removed from the stage as well. + * @return The Boyfriend character. */ public function getBoyfriend(?pop:Bool = false):BaseCharacter { @@ -428,14 +444,70 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass } } - public function getGirlfriend():BaseCharacter + /** + * Retrieve the player/Boyfriend character. + * @param pop If true, the character will be removed from the stage as well. + * @return The player/Boyfriend character. + */ + public function getPlayer(?pop:Bool = false):BaseCharacter { - return getCharacter('gf'); + return getBoyfriend(pop); } - public function getDad():BaseCharacter + /** + * Retrieve the Girlfriend character. + * @param pop If true, the character will be removed from the stage as well. + * @return The Girlfriend character. + */ + public function getGirlfriend(?pop:Bool = false):BaseCharacter { - return getCharacter('dad'); + if (pop) + { + var girlfriend:BaseCharacter = getCharacter('gf'); + + // Remove the character from the stage. + this.remove(girlfriend); + this.characters.remove('gf'); + + return girlfriend; + } + else + { + return getCharacter('gf'); + } + } + + /** + * Retrieve the Dad character. + * @param pop If true, the character will be removed from the stage as well. + * @return The Dad character. + */ + public function getDad(?pop:Bool = false):BaseCharacter + { + if (pop) + { + var dad:BaseCharacter = getCharacter('dad'); + + // Remove the character from the stage. + this.remove(dad); + this.characters.remove('dad'); + + return dad; + } + else + { + return getCharacter('dad'); + } + } + + /** + * Retrieve the opponent/Dad character. + * @param pop If true, the character will be removed from the stage as well. + * @return The opponent character. + */ + public function getOpponent(?pop:Bool = false):BaseCharacter + { + return getDad(pop); } /** @@ -448,6 +520,26 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass return this.namedProps.get(name); } + /** + * Pause the animations of ALL sprites in this group. + */ + public function pause():Void + { + forEachAlive(function(prop:FlxSprite) { + if (prop.animation != null) prop.animation.pause(); + }); + } + + /** + * Resume the animations of ALL sprites in this group. + */ + public function resume():Void + { + forEachAlive(function(prop:FlxSprite) { + if (prop.animation != null) prop.animation.resume(); + }); + } + /** * Retrieve a list of all the asset paths required to load the stage. * Override this in a scripted class to ensure that all necessary assets are loaded! diff --git a/source/funkin/play/stage/StageProp.hx b/source/funkin/play/stage/StageProp.hx index 0cce506d1..58de55293 100644 --- a/source/funkin/play/stage/StageProp.hx +++ b/source/funkin/play/stage/StageProp.hx @@ -1,13 +1,32 @@ package funkin.play.stage; +import funkin.modding.events.ScriptEvent; import flixel.FlxSprite; +import funkin.modding.IScriptedClass.IStateStageProp; -class StageProp extends FlxSprite +class StageProp extends FlxSprite implements IStateStageProp { - public var name:String = ""; + /** + * An internal name for this prop. + */ + public var name:String = ''; public function new() { super(); } + + /** + * Called when this prop is added to the stage. + * @param event + */ + public function onAdd(event:ScriptEvent):Void {} + + public function onScriptEvent(event:ScriptEvent) {} + + public function onCreate(event:ScriptEvent) {} + + public function onDestroy(event:ScriptEvent) {} + + public function onUpdate(event:UpdateScriptEvent) {} }