diff --git a/source/funkin/editors/character/CharacterAnimsWindow.hx b/source/funkin/editors/character/CharacterAnimsWindow.hx index da13606d..eafa2de1 100644 --- a/source/funkin/editors/character/CharacterAnimsWindow.hx +++ b/source/funkin/editors/character/CharacterAnimsWindow.hx @@ -118,7 +118,9 @@ class CharacterAnimButtons extends UIButton { CharacterEditor.instance.playAnimation(this.anim); }, 282); - ghostButton = new UIButton(x+282+17, y, "", null, 32); + ghostButton = new UIButton(x+282+17, y, "", function () { + CharacterEditor.instance.ghostAnim(this.anim); + }, 32); members.push(ghostButton); ghostIcon = new FlxSprite(ghostButton.x + 8, ghostButton.y + 8).loadGraphic(Paths.image('editors/character/ghost-button'), true, 16, 16); diff --git a/source/funkin/editors/character/CharacterEditor.hx b/source/funkin/editors/character/CharacterEditor.hx index 5faf7d59..b055224b 100644 --- a/source/funkin/editors/character/CharacterEditor.hx +++ b/source/funkin/editors/character/CharacterEditor.hx @@ -14,6 +14,8 @@ class CharacterEditor extends UIState { var __character:String; public var character:Character; + public var ghosts:CharacterGhostsHandler; + public static var instance(get, null):CharacterEditor; private static inline function get_instance() @@ -224,6 +226,11 @@ class CharacterEditor extends UIState { character = new Character(0,0,__character); character.debugMode = true; character.cameras = [charCamera]; + + ghosts = new CharacterGhostsHandler(character); + ghosts.cameras = [charCamera]; + + add(ghosts); add(character); topMenuSpr = new UITopMenu(topMenu); @@ -291,7 +298,7 @@ class CharacterEditor extends UIState { ); charCamera.zoom = lerp(charCamera.zoom, __camZoom, 0.125); - + characterBG.scale.set(FlxG.width/characterBG.width, FlxG.height/characterBG.height); characterBG.scale.set(characterBG.scale.x / charCamera.zoom, characterBG.scale.y / charCamera.zoom); } @@ -352,11 +359,13 @@ class CharacterEditor extends UIState { case CChangeOffset(name, change): changeOffset(name, change * -1, false); case CResetOffsets(oldOffsets): - for (anim => offsets in oldOffsets) + for (anim => offsets in oldOffsets) { character.animOffsets.set(anim, offsets.clone()); + ghosts.setOffsets(anim, offsets.clone()); + } for (anim in character.getNameList()) - characterAnimsWindow.animButtons[anim].updateInfo(anim, character.getAnimOffset(anim), false); + characterAnimsWindow.animButtons[anim].updateInfo(anim, character.getAnimOffset(anim), ghosts.animGhosts[anim].visible); changeOffset(character.getAnimName(), FlxPoint.get(0, 0), false); // apply da new offsets } @@ -416,6 +425,7 @@ class CharacterEditor extends UIState { public function createAnim(animData:AnimData, animID:Int = -1, addtoUndo:Bool = true) { XMLUtil.addAnimToSprite(character, animData); + ghosts.createGhost(animData.name); characterAnimsWindow.createNewButton(animData.name, FlxPoint.get(animData.x,animData.y), false, animID); playAnimation(animData.name); @@ -428,8 +438,10 @@ class CharacterEditor extends UIState { var oldAnimData:AnimData = character.animDatas.get(name); var button:CharacterAnimButtons = characterAnimsWindow.animButtons[name]; + ghosts.removeGhost(name); XMLUtil.addAnimToSprite(character, animData); - button.updateInfo(animData.name, character.getAnimOffset(animData.name), false); + ghosts.createGhost(animData.name); + button.updateInfo(animData.name, character.getAnimOffset(animData.name), ghosts.animGhosts[animData.name].visible); if (character.getAnimName() == animData.name) // update anim ifs its currently selected playAnimation(animData.name); @@ -448,6 +460,7 @@ class CharacterEditor extends UIState { var oldID:Int = character.getNameList().indexOf(name); var oldAnimData:AnimData = character.animDatas.get(name); + ghosts.removeGhost(name); character.removeAnimation(name); if (character.animOffsets.exists(name)) character.animOffsets.remove(name); if (character.animDatas.exists(name)) character.animDatas.remove(name); @@ -468,6 +481,7 @@ class CharacterEditor extends UIState { var oldInfo = character.buildXML(); character.applyXML(new Access(newInfo)); + ghosts.updateInfos(newInfo); playAnimation(lastAnim); @@ -475,6 +489,14 @@ class CharacterEditor extends UIState { addToUndo(CEditInfo(oldInfo, newInfo)); } + public function ghostAnim(anim:String) { + var ghost:Character = ghosts.animGhosts.get(anim); + ghost.visible = !ghost.visible; + + var button:CharacterAnimButtons = characterAnimsWindow.animButtons[anim]; + button.updateInfo(anim, character.getAnimOffset(anim), ghost.visible); + } + function _playback_play_anim(_) { if (character.getNameList().length != 0) playAnimation(character.getAnimName()); @@ -530,9 +552,11 @@ class CharacterEditor extends UIState { if (character.getNameList().length == 0) return; character.animOffsets.set(anim, character.getAnimOffset(anim) + change); - characterAnimsWindow.animButtons[anim].updateInfo(anim, character.getAnimOffset(anim), false); + characterAnimsWindow.animButtons[anim].updateInfo(anim, character.getAnimOffset(anim), ghosts.animGhosts[anim].visible); character.frameOffset.set(character.getAnimOffset(anim).x, character.getAnimOffset(anim).y); + ghosts.updateOffsets(anim, change); + if (addtoUndo) addToUndo(CChangeOffset(anim, change)); } @@ -547,9 +571,11 @@ class CharacterEditor extends UIState { for (anim in character.getNameList()) { character.animOffsets[anim].zero(); - characterAnimsWindow.animButtons[anim].updateInfo(anim, character.getAnimOffset(anim), false); + characterAnimsWindow.animButtons[anim].updateInfo(anim, character.getAnimOffset(anim), ghosts.animGhosts[anim].visible); } + ghosts.clearOffsets(); + if (addtoUndo) addToUndo(CResetOffsets(oldOffsets)); } diff --git a/source/funkin/editors/character/CharacterGhostsHandler.hx b/source/funkin/editors/character/CharacterGhostsHandler.hx new file mode 100644 index 00000000..8d72adfe --- /dev/null +++ b/source/funkin/editors/character/CharacterGhostsHandler.hx @@ -0,0 +1,73 @@ +package funkin.editors.character; + +import haxe.xml.Access; +import flixel.math.FlxPoint; +import funkin.game.Character; + +class CharacterGhostsHandler extends FlxTypedGroup { + public var character:Character; + public var animGhosts:Map = []; + + public function new(character:Character) { + this.character = character; + super(); + + for (anim in character.getNameList()) + createGhost(anim); + } + + public function createGhost(anim:String) { + var ghost:Character = new Character(0,0, character.curCharacter); + ghost.applyXML(character.xml); // apply cur character stuff + ghost.playAnim(anim); + ghost.stopAnimation(); + ghost.alpha = 0.5; + ghost.visible = false; + add(ghost); + + animGhosts.set(anim, ghost); + } + + public function removeGhost(anim:String) { + var ghost:Character = animGhosts.get(anim); + @:privateAccess ghost.animation._curAnim = null; + animGhosts.remove(anim); + ghost.destroy(); + } + + public function updateInfos(xml:Xml) { + for (anim => ghost in animGhosts) { + ghost.applyXML(new Access(xml)); + ghost.playAnim(anim); + ghost.stopAnimation(); + } + + rePositionGhosts(); + } + + public function updateOffsets(anim:String, change:FlxPoint) { + for (anim => ghost in animGhosts) + ghost.animOffsets.set(anim, ghost.getAnimOffset(anim) + change); + + rePositionGhosts(); + } + + public function setOffsets(anim:String, offset:FlxPoint) { + for (anim => ghost in animGhosts) + ghost.animOffsets.set(anim, offset); + + rePositionGhosts(); + } + + public function clearOffsets() { + for (anim => ghost in animGhosts) + ghost.animOffsets[anim].zero(); + + rePositionGhosts(); + } + + inline function rePositionGhosts() { + for (ghost in animGhosts) + ghost.frameOffset.set(ghost.getAnimOffset(ghost.getAnimName()).x, ghost.getAnimOffset(ghost.getAnimName()).y); + } +} \ No newline at end of file diff --git a/source/funkin/game/Character.hx b/source/funkin/game/Character.hx index 504838fe..a06a42c3 100644 --- a/source/funkin/game/Character.hx +++ b/source/funkin/game/Character.hx @@ -421,6 +421,8 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset animXml.set("indices", anim.indices.join(",")); xml.addChild(animXml); } + + this.xml = new Access(xml); return xml; }