From a65c21edb700300593f8ba872dca9b23764c4c5f Mon Sep 17 00:00:00 2001 From: lunarcleint Date: Mon, 24 Feb 2025 14:17:12 -0700 Subject: [PATCH] Invalid Animation support!!! :D --- .../images/editors/character/anim-icons.png | Bin 0 -> 362 bytes assets/images/editors/character/play.png | Bin 210 -> 0 bytes .../editors/character/CharacterAnimButton.hx | 146 +++++++++++++----- .../editors/character/CharacterAnimsWindow.hx | 19 ++- .../editors/character/CharacterEditor.hx | 18 ++- .../editors/character/CharacterGhost.hx | 1 + source/funkin/editors/ui/UICheckbox.hx | 5 +- 7 files changed, 146 insertions(+), 43 deletions(-) create mode 100644 assets/images/editors/character/anim-icons.png delete mode 100644 assets/images/editors/character/play.png diff --git a/assets/images/editors/character/anim-icons.png b/assets/images/editors/character/anim-icons.png new file mode 100644 index 0000000000000000000000000000000000000000..765e3725b16135cec9647b4b98f5c7ac4d6c1b57 GIT binary patch literal 362 zcmV-w0hRuVP)Px$BuPX;R5*>DRIzHqFc5u){6I4Vku_u!bPBXn3tqc;YJQ_@e5ov6pO_Uk6LBWm&4^2L^L@@9y25&l&!})_aCwFgbjD$KMWQ&H@0i&EAIyA*HNI zO7(I7^Mi9PIQqC@&Vo4$YQ^jZ`ULERAnQV19w{ZMV|+Oq0p=MXq)$Y!xV3^g7dU?& zovaT}j{u@q!<`VgD@#C+97^F!2;7&Y!;KQ)5fT(ZDS>*|fRx_7j{->?9M=1k@F+wH zm>kCdfS;F>F-3L%rVYL7Ium+TaJ*3hHS22x|(sinkAp1`Pw%wj~k%( zM6C&2*B4AMPU+afYgOSEP3LWHw$w$xtIFb7SKzUyAo*AP3rEbb*08uLR{#J207*qo IM6N<$f(}uc4FCWD literal 0 HcmV?d00001 diff --git a/assets/images/editors/character/play.png b/assets/images/editors/character/play.png deleted file mode 100644 index 3bbac62a91f92217cf4df76c75a8817abcbf6d71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~e!3HF=pW8M9DaPU;cPEB*=VV?2IX#{(jv*Qo zr}l5;J>($3@?6!Np^-Vrg)`)XXpQE&BPC7@nnGJ19N}EDWusrkPu2bXpWT-4y?rq* zVOp2vgOJJ = []; @@ -125,10 +128,14 @@ class CharacterAnimButton extends UIButton { foldableButtons.push(indicesTextBox); addLabelOn(indicesTextBox, "Indices (frames)", 12); - playIcon = new FlxSprite(x-(10+16), y+8).loadGraphic(Paths.image("editors/character/play")); - // playIcon.color = 0xFFD60E0E; - playIcon.antialiasing = false; - members.push(playIcon); + animIcon = new FlxSprite(x-(10+16), y+8).loadGraphic(Paths.image("editors/character/anim-icons"), true, 16, 12); + animIcon.animation.add("play", [0]); + animIcon.animation.add("error", [1]); + // animIcon.color = 0xFFD60E0E; + animIcon.animation.play("play"); + animIcon.antialiasing = false; + animIcon.updateHitbox(); + members.push(animIcon); deleteButton = new UIButton(0, 0, null, () -> {parent.deleteAnimation(this);}, 28*2,24); deleteButton.frames = Paths.getFrames("editors/ui/grayscale-button"); @@ -164,10 +171,12 @@ class CharacterAnimButton extends UIButton { ghostIcon.antialiasing = false; ghostIcon.updateHitbox(); members.push(ghostIcon); + + checkValid(); } public inline function updateButtonsPos() { - playIcon.follow(this, 22, (52/2) - (playIcon.height/2)); + animIcon.follow(this, 22, (52/2) - (animIcon.height/2) + (animIcon.animation.name == "error" ? 2 : 0)); field.follow(this, 22+16+10, (52/2) - (field.height/2) + 1); deleteButton.follow(this, 380, 14); @@ -216,12 +225,12 @@ class CharacterAnimButton extends UIButton { } if (parent.character.animateAtlas != null) { - var animSymbol:FlxSymbolAnimation = parent.character.animateAtlas.anim.animsMap[anim]; + var animSymbol:FlxSymbolAnimation = __getAnimationSymbol(); parent.character.animateAtlas.anim.animsMap.remove(anim); parent.character.animateAtlas.anim.animsMap.set(newName, animSymbol); } else { - var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; + var flxAnimation:FlxAnimation = __getFlxAnimation(); flxAnimation.name = newName; parent.character.animation._animations.remove(anim); @@ -243,7 +252,7 @@ class CharacterAnimButton extends UIButton { parent.displayAnimsFramesList.set(newName, displayFrame); this.anim = newName; - field.text = '${animData.name} (${animData.x}, ${animData.y})'; + updateText(); } public function changeAnim(newAnim:String) @:privateAccess { @@ -251,15 +260,22 @@ class CharacterAnimButton extends UIButton { if (newAnim == animData.anim) return; animData.anim = newAnim; - if (parent.character.animateAtlas != null) { - var animSymbol:FlxSymbolAnimation = parent.character.animateAtlas.anim.animsMap[anim]; - refreshSymbolKeyFrames(animSymbol, animData); - } else { - var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; + + if (parent.character.animateAtlas != null) + __refreshAnimation(); + else { + var flxAnimation:FlxAnimation = __getFlxAnimation(); + trace(parent.character.animation._animations); flxAnimation.prefix = newAnim; refreshFlxAnimationFrames(flxAnimation, animData); - parent.buildAnimDisplay(anim, flxAnimation); + if (valid) { + parent.buildAnimDisplay(anim, flxAnimation); + animationDisplayBG.alpha = 1; + } else { + parent.removeAnimDisplay(anim); + animationDisplayBG.alpha = 0.4; + } } if (parent.character.getAnimName() == anim) @@ -280,7 +296,7 @@ class CharacterAnimButton extends UIButton { if (parent.character.getAnimName() == anim) CharacterEditor.instance.playAnimation(anim); - field.text = '${animData.name} (${positionXStepper.value = animData.x}, ${positionYStepper.value = animData.y})'; + updateText(); } public function changeFPS(newFPS:Float) @:privateAccess { @@ -288,10 +304,10 @@ class CharacterAnimButton extends UIButton { animData.fps = newFPS; if (parent.character.animateAtlas != null) { - var animSymbol:FlxSymbolAnimation = parent.character.animateAtlas.anim.animsMap[anim]; + var animSymbol:FlxSymbolAnimation = __getAnimationSymbol(); animSymbol.frameRate = newFPS; } else { - var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; + var flxAnimation:FlxAnimation = __getFlxAnimation(); flxAnimation.frameRate = newFPS; } @@ -304,10 +320,10 @@ class CharacterAnimButton extends UIButton { animData.loop = newLooping; if (parent.character.animateAtlas != null) { - var animSymbol:FlxSymbolAnimation = parent.character.animateAtlas.anim.animsMap[anim]; + var animSymbol:FlxSymbolAnimation = __getAnimationSymbol(); animSymbol.instance.symbol.loop = animData.loop ? Loop : PlayOnce; } else { - var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; + var flxAnimation:FlxAnimation = __getFlxAnimation(); flxAnimation.looped = animData.loop; } @@ -319,13 +335,7 @@ class CharacterAnimButton extends UIButton { var animData:AnimData = parent.character.animDatas[anim]; animData.indices = indicies; - if (parent.character.animateAtlas != null) { - var animSymbol:FlxSymbolAnimation = parent.character.animateAtlas.anim.animsMap[anim]; - refreshSymbolKeyFrames(animSymbol, animData); - } else { - var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; - refreshFlxAnimationFrames(flxAnimation, animData); - } + __refreshAnimation(); if (parent.character.getAnimName() == anim) CharacterEditor.instance.playAnimation(anim); @@ -347,23 +357,38 @@ class CharacterAnimButton extends UIButton { flxAnimation.frames = frameIndices; } + + if (flxAnimation.frames.length <= 0) invalidate(); + else validate(); } catch (e) { - trace('TODO: ERROR HANDLING $e'); + trace('$e'); + invalidate(); } } public inline function refreshSymbolKeyFrames(symbol:FlxSymbolAnimation, animData:AnimData) @:privateAccess { - if (animData.indices.length > 0) { - // keeps on crashing, look at flxanimate FlxAnim.hx for refrence - } else { - for (name in parent.character.animateAtlas.anim.symbolDictionary.keys()) - if (parent.character.animateAtlas.anim.startsWith(name, animData.anim)) - {symbol.instance.symbol.name = name; break;} + var wasRefreshed:Bool = false; + + try { + if (animData.indices.length > 0) { + // keeps on crashing, look at flxanimate FlxAnim.hx for refrence + } else { + for (name in parent.character.animateAtlas.anim.symbolDictionary.keys()) + if (parent.character.animateAtlas.anim.startsWith(name, animData.anim)) { + symbol.instance.symbol.name = name; + wasRefreshed = true; + break; + } + } + } catch (e) { + trace('$e'); } + + validate(wasRefreshed); } public function toggleGhost() { - if (parent.ghosts.indexOf(anim) == -1) { + if (valid && parent.ghosts.indexOf(anim) == -1) { parent.ghosts.push(anim); ghostIcon.animation.play("alive", true); ghostIcon.color = 0xFFFFFFFF; @@ -392,4 +417,55 @@ class CharacterAnimButton extends UIButton { parent.displayWindowSprite.draw(); } } + + public function updateText() { + field.applyMarkup( + '${anim} ' + (valid ? '(${parent.character.animOffsets[anim].x} ${parent.character.animOffsets[anim].y})' : "|(Invalid Animation!!!)|"), + [new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFF29797), "|")]); + } + + public function validate(isValid:Bool = true) { + var wasValid:Bool = valid; + this.valid = isValid; + + animIcon.animation.play(valid ? "play" :"error"); + color = valid ? 0xFFFFFFFF : 0xFFD60E0E; + + ghostIcon.visible = ghostButton.visible = isValid; + XYComma.alpha = isValid ? 1 : 0.4; + for (uiElement in [nameTextBox, positionXStepper, positionYStepper, fpsStepper, loopedCheckbox, indicesTextBox]) { + uiElement.selectable = isValid; + if (labels[uiElement] != null) + labels[uiElement].alpha = isValid ? 1 : 0.4; + } + if (!valid) toggleGhost(); + updateText(); + + if (!wasValid && isValid && CharacterEditor.instance.characterFakeAnim == anim) + CharacterEditor.instance.playAnimation(this.anim); + } + + public inline function invalidate() + validate(false); + + public inline function __getFlxAnimation():Null @:privateAccess { + if (parent.character.animation._animations[anim] == null) + XMLUtil.addAnimToSprite(parent.character, data); + return parent.character.animation._animations[anim]; + } + + public inline function __getAnimationSymbol():Null @:privateAccess { + if (parent.character.animateAtlas.anim.animsMap[anim] == null) + XMLUtil.addAnimToSprite(parent.character, data); + return parent.character.animateAtlas.anim.animsMap[anim]; + } + + + @:noCompletion function __refreshAnimation() @:privateAccess { + if (parent.character.animateAtlas != null) refreshSymbolKeyFrames(__getAnimationSymbol(), data); + else refreshFlxAnimationFrames(__getFlxAnimation(), data); + } + + public inline function checkValid() + __refreshAnimation(); } \ No newline at end of file diff --git a/source/funkin/editors/character/CharacterAnimsWindow.hx b/source/funkin/editors/character/CharacterAnimsWindow.hx index 5c31b1c5..b91e13af 100644 --- a/source/funkin/editors/character/CharacterAnimsWindow.hx +++ b/source/funkin/editors/character/CharacterAnimsWindow.hx @@ -52,6 +52,8 @@ class CharacterAnimsWindow extends UIButtonList { } public function buildAnimDisplay(name:String, anim:FlxAnimation) { + if (anim.frames.length <= 0) return; + var frameIndex:Int = anim.frames.getDefault([0])[0]; var frame:FlxFrame = displayWindowSprite.frames.frames[frameIndex]; @@ -61,6 +63,9 @@ class CharacterAnimsWindow extends UIButtonList { displayAnimsFramesList.set(name, {frame: anim.frames.getDefault([0])[0], scale: 104/animBounds.height, animBounds: animBounds}); } + public function removeAnimDisplay(name:String) + displayAnimsFramesList.remove(name); + public function deleteAnimation(button:CharacterAnimButton) { if (buttons.members.length <= 1) return; if (character.getAnimName() == button.anim) @@ -95,13 +100,21 @@ class CharacterAnimsWindow extends UIButtonList { } public function addAnimation(animData:AnimData, animID:Int = -1) @:privateAccess { - XMLUtil.addAnimToSprite(character, animData); - buildAnimDisplay(animData.name, character.animation._animations[animData.name]); - var newButton:CharacterAnimButton = new CharacterAnimButton(0, 0, animData, this); newButton.alpha = 0.25; animButtons.set(animData.name, newButton); if (animID == -1) add(newButton); else insert(newButton, animID); + + if (newButton.valid) { + XMLUtil.addAnimToSprite(character, animData); + buildAnimDisplay(animData.name, character.animation._animations[animData.name]); + } + } + + public function findValid():Null { + for (button in buttons) + if (button.valid) return button.anim; + return null; } } \ No newline at end of file diff --git a/source/funkin/editors/character/CharacterEditor.hx b/source/funkin/editors/character/CharacterEditor.hx index da6fc370..a207a3e2 100644 --- a/source/funkin/editors/character/CharacterEditor.hx +++ b/source/funkin/editors/character/CharacterEditor.hx @@ -684,20 +684,32 @@ class CharacterEditor extends UIState { playAnimation( characterAnimsWindow.animsList[ FlxMath.wrap( - characterAnimsWindow.animsList.indexOf(character.getAnimName()) - 1, + characterAnimsWindow.animsList.indexOf(characterFakeAnim) - 1, 0, characterAnimsWindow.animsList.length-1 )] ); function _animation_down(_) playAnimation( characterAnimsWindow.animsList[FlxMath.wrap( - characterAnimsWindow.animsList.indexOf(character.getAnimName()) + 1, + characterAnimsWindow.animsList.indexOf(characterFakeAnim) + 1, 0, characterAnimsWindow.animsList.length-1 )] ); + // The animation thats playing regardless if its valid or not + public var characterFakeAnim:String = ""; public function playAnimation(anim:String) { - character.playAnim(anim, true); + characterFakeAnim = anim; + if (characterAnimsWindow.animButtons[anim] != null && characterAnimsWindow.animButtons[anim].valid) { + character.playAnim(anim, true); + character.colorTransform.redMultiplier = character.colorTransform.greenMultiplier = character.colorTransform.blueMultiplier = character.colorTransform.alphaMultiplier = 1; + character.colorTransform.redOffset = character.colorTransform.greenOffset = character.colorTransform.blueOffset = character.colorTransform.alphaOffset = 0; + } else { + var validAnimation:String = characterAnimsWindow.findValid(); + if (validAnimation != null) character.playAnim(validAnimation, true); + _animation_stop(null); + character.colorTransform.color = 0xFFEF0202; + } for(i in characterAnimsWindow.buttons.members) i.alpha = i.anim == anim ? 1 : 0.25; diff --git a/source/funkin/editors/character/CharacterGhost.hx b/source/funkin/editors/character/CharacterGhost.hx index dda10294..141c533d 100644 --- a/source/funkin/editors/character/CharacterGhost.hx +++ b/source/funkin/editors/character/CharacterGhost.hx @@ -1,5 +1,6 @@ package funkin.editors.character; +import openfl.geom.ColorTransform; import flixel.animation.FlxAnimation; import funkin.game.Character; diff --git a/source/funkin/editors/ui/UICheckbox.hx b/source/funkin/editors/ui/UICheckbox.hx index e8d84f8f..edbbdd07 100644 --- a/source/funkin/editors/ui/UICheckbox.hx +++ b/source/funkin/editors/ui/UICheckbox.hx @@ -29,10 +29,11 @@ class UICheckbox extends UISprite { public override function update(elapsed:Float) { // ANIMATION HANDLING - animation.play(hovered ? (pressed ? "pressed" : "hover") : "normal"); + animation.play(hovered && selectable ? (pressed ? "pressed" : "hover") : "normal"); + this.alpha = field.alpha = selectable ? 1 : 0.4; // CHECKMARK HANDLING - check.alpha = checked ? 1 : 0; + check.alpha = selectable ? (checked ? 1 : 0) : 0; check.scale.x = CoolUtil.fpsLerp(check.scale.x, 1, 0.25); check.scale.y = CoolUtil.fpsLerp(check.scale.y, 1, 0.25);