From 03d723e155c555b0b074c04f03ee201b84195c3f Mon Sep 17 00:00:00 2001 From: lunarcleint <88809950+lunarcleint@users.noreply.github.com> Date: Tue, 4 Jun 2024 02:48:55 -0700 Subject: [PATCH] a buncha characcter editor stuff --- .../editors/character/CharacterAnimButton.hx | 244 +++++++++++++++-- .../editors/character/CharacterAnimButtons.hx | 92 ------- .../editors/character/CharacterAnimsWindow.hx | 24 +- .../editors/character/CharacterEditor.hx | 259 +----------------- .../character/CharacterGhostsHandler.hx | 75 ----- .../editors/character/CharacterInfoScreen.hx | 199 -------------- source/funkin/editors/ui/UISliceSprite.hx | 4 + 7 files changed, 245 insertions(+), 652 deletions(-) delete mode 100644 source/funkin/editors/character/CharacterAnimButtons.hx delete mode 100644 source/funkin/editors/character/CharacterGhostsHandler.hx delete mode 100644 source/funkin/editors/character/CharacterInfoScreen.hx diff --git a/source/funkin/editors/character/CharacterAnimButton.hx b/source/funkin/editors/character/CharacterAnimButton.hx index 50bfbce1..2dd828c0 100644 --- a/source/funkin/editors/character/CharacterAnimButton.hx +++ b/source/funkin/editors/character/CharacterAnimButton.hx @@ -1,10 +1,20 @@ package funkin.editors.character; +import flxanimate.animate.FlxSymbol; +import flxanimate.animate.FlxElement; +import flxanimate.animate.SymbolParameters; +import flxanimate.animate.FlxKeyFrame; +import flxanimate.animate.FlxTimeline; +import flixel.graphics.frames.FlxFrame; +import flxanimate.animate.FlxAnim.SymbolStuff; +import flixel.animation.FlxAnimation; import openfl.geom.Rectangle; import funkin.backend.utils.XMLUtil.AnimData; import flixel.math.FlxPoint; import flixel.util.FlxColor; +using StringTools; + class CharacterAnimButton extends UIButton { public var anim:String = null; public var data:AnimData = null; @@ -32,6 +42,9 @@ class CharacterAnimButton extends UIButton { public var labels:Map = []; + public var foldableButtons:Array = []; + public var closed:Bool = true; + public function new(x:Float, y:Float, animData:AnimData, parent:CharacterAnimsWindow) { this.anim = animData.name; this.data = animData; @@ -51,40 +64,72 @@ class CharacterAnimButton extends UIButton { frames = Paths.getFrames('editors/ui/inputbox'); field.fieldWidth = 0; framesOffset = 9; field.size = 14; - // field.visible = false; animationDisplayBG = new UISliceSprite(x+12, y+12+18+12, 128, 128, 'editors/ui/inputbox-small'); members.push(animationDisplayBG); + foldableButtons.push(animationDisplayBG); nameTextBox = new UITextBox(animationDisplayBG.x+126+16, animationDisplayBG.y, animData.name, 116, 22, false, true); + nameTextBox.onChange = (newName:String) -> {this.changeName(newName);}; members.push(nameTextBox); + foldableButtons.push(nameTextBox); addLabelOn(nameTextBox, "Name", 12); animTextBox = new UITextBox(nameTextBox.x + 100 + 12, nameTextBox.y, animData.anim, 146, 22, false, true); + animTextBox.onChange = (newAnim:String) -> {this.changeAnim(newAnim);}; members.push(animTextBox); + foldableButtons.push(animTextBox); addLabelOn(animTextBox, "Animation", 12); positionXStepper = new UINumericStepper(animTextBox.x, animTextBox.y+32+18, animData.x, 0.001, 2, null, null, 64, 22, true); + positionXStepper.onChange = (text:String) -> { + @:privateAccess positionXStepper.__onChange(text); + this.changeOffset(positionXStepper.value, null); + }; members.push(positionXStepper); + foldableButtons.push(positionXStepper); addLabelOn(positionXStepper, "Position (X,Y)", 12); members.push(XYComma = new UIText(positionXStepper.x+104-32+0, positionXStepper.y + 9, 0, ",", 18)); + foldableButtons.push(XYComma); positionYStepper = new UINumericStepper(positionXStepper.x+104-32+26, positionXStepper.y, animData.y, 0.001, 2, null, null, 64, 22, true); + positionYStepper.onChange = (text:String) -> { + @:privateAccess positionYStepper.__onChange(text); + this.changeOffset(null, positionYStepper.value); + }; members.push(positionYStepper); + foldableButtons.push(positionYStepper); - fpsStepper = new UINumericStepper(animTextBox.x + 200 + 26, animTextBox.y, 0, 0.1, 2, animData.fps, 100, 52, 22, true); + fpsStepper = new UINumericStepper(animTextBox.x + 200 + 26, animTextBox.y, animData.fps, 0.1, 2, 1, 100, 52, 22, true); + fpsStepper.onChange = (text:String) -> { + @:privateAccess fpsStepper.__onChange(text); + this.changeFPS(fpsStepper.value); + }; members.push(fpsStepper); + foldableButtons.push(fpsStepper); addLabelOn(fpsStepper, "FPS", 12); loopedCheckbox = new UICheckbox(fpsStepper.x + 82 - 32 + 26, fpsStepper.y, "Looping?", animData.loop, 0, true); + loopedCheckbox.onChecked = (newLooping:Bool) -> {this.changeLooping(newLooping);}; members.push(loopedCheckbox); + foldableButtons.push(loopedCheckbox); addLabelOn(loopedCheckbox, "Looped", 12); loopedCheckbox.x += 8; loopedCheckbox.y += 6; indicesTextBox = new UITextBox(nameTextBox.x, nameTextBox.y, animData.indices.getDefault([]).join(","), 278, 22, false, true); + indicesTextBox.onChange = (text:String) -> { + var indices:Array = []; + for(indice in text.split(",")) { + var i = Std.parseInt(indice.trim()); + if (i != null) indices.push(i); + } + + this.changeIndicies(indices); + } members.push(indicesTextBox); + foldableButtons.push(indicesTextBox); addLabelOn(indicesTextBox, "Indices (frames)", 12); playIcon = new FlxSprite(x-(10+16), y+8).loadGraphic(Paths.image("editors/character/play")); @@ -102,7 +147,7 @@ class CharacterAnimButton extends UIButton { deleteIcon.antialiasing = false; members.push(deleteIcon); - editButton = new UIButton(0, 0, "", null, 28,24); + editButton = new UIButton(0, 0, "", () -> {this.closed = !this.closed; this.update(0);}, 28,24); editButton.frames = Paths.getFrames("editors/ui/grayscale-button"); editButton.color = 0xFFAFAA12; members.push(editButton); @@ -128,49 +173,208 @@ class CharacterAnimButton extends UIButton { } public override function update(elapsed:Float) { - playIcon.follow(this, 22, 19); - field.follow(this, 22+15+8, 16); + bHeight = closed ? 52 : 208; - deleteButton.follow(this, (500-16-32)-16-(28*2), 14); + playIcon.follow(this, 22, (52/2) - (playIcon.height/2)); + field.follow(this, 22+16+10, (52/2) - (field.height/2) + 1); + + deleteButton.follow(this, 380, 14); deleteIcon.follow(deleteButton, (deleteButton.bWidth/2)-6.5, (deleteButton.bHeight/2)-6); - editButton.follow(this, (500-16-32)-16-(28*2)-12-28, 14); + editButton.follow(this, 340, 14); editIcon.follow(editButton, (editButton.bWidth/2)-8, (editButton.bHeight/2)-6); - ghostButton.follow(this, (500-16-32)-16-(28*2)-12-28-12-28, 14); + ghostButton.follow(this, 300, 14); ghostIcon.follow(ghostButton, (ghostButton.bWidth/2)-8, (ghostButton.bHeight/2)-6); - animationDisplayBG.follow(this, 16, 8+32+8+2+11); - nameTextBox.follow(this, 14+128+16, 8+32+8+2+8+14); - animTextBox.follow(this, 14+128+12+116+20, 8+32+8+2+8+14); + animationDisplayBG.follow(this, 16, 61); + nameTextBox.follow(this, 158, 72); + animTextBox.follow(this, 290, 72); - positionXStepper.follow(this, 14+128+16, 8+32+8+2+8+10+24+26); - positionYStepper.follow(this, 14+128+16+64-32+28, 8+32+8+2+8+10+24+26); + positionXStepper.follow(this, 158, 118); + positionYStepper.follow(this, 218, 118); XYComma.follow(positionXStepper, 64-24, 6); - fpsStepper.follow(this, 14+128+16+64-32+28+64-22+20, 8+32+8+2+8+10+24+26); - loopedCheckbox.follow(this, 14+128+16+64-32+28+64-22+20+52-22+18+8, 8+32+8+2+8+10+24+32); + fpsStepper.follow(this, 280, 118); + loopedCheckbox.follow(this, 336, 124); - indicesTextBox.follow(this, 14+128+16, 8+32+8+2+8+10+24+26+24+22); + indicesTextBox.follow(this, 158, 164); - for (ui => text in labels) + for (button in foldableButtons) + button.visible = button.active = !closed; + + for (ui => text in labels) { text.follow(ui, -(2+(ui is UICheckbox?12:0)), -(18+(ui is UICheckbox?6:0))); + text.visible = text.active = ui.visible; + } super.update(elapsed); } + public function changeName(newName:String) @:privateAccess { + if (newName == anim) return; + + if (parent.character.animateAtlas != null) { + var animSymbol:SymbolStuff = parent.character.animateAtlas.anim.animsMap[anim]; + + parent.character.animateAtlas.anim.animsMap.remove(anim); + parent.character.animateAtlas.anim.animsMap.set(newName, animSymbol); + } else { + var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; + flxAnimation.name = newName; + + parent.character.animation._animations.remove(anim); + parent.character.animation._animations.set(newName, flxAnimation); + } + + var animData:AnimData = parent.character.animDatas[anim]; + animData.name = newName; + + parent.character.animDatas.remove(anim); + parent.character.animDatas.set(newName, animData); + + var animOffset:FlxPoint = parent.character.animOffsets[anim]; + parent.character.animOffsets.remove(anim); + parent.character.animOffsets.set(newName, animOffset); + + var displayFrame:{scale:Float, animBounds:Rectangle, frame:Int} = parent.displayAnimsFramesList[anim]; + parent.displayAnimsFramesList.remove(anim); + parent.displayAnimsFramesList.set(newName, displayFrame); + + this.anim = newName; + field.text = '${animData.name} (${animData.x}, ${animData.y})'; + } + + public function changeAnim(newAnim:String) @:privateAccess { + var animData:AnimData = parent.character.animDatas[anim]; + if (newAnim == animData.anim) return; + + animData.anim = newAnim; + if (parent.character.animateAtlas != null) { + var animSymbol:SymbolStuff = parent.character.animateAtlas.anim.animsMap[anim]; + refreshSymbolKeyFrames(animSymbol, animData); + } else { + var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; + flxAnimation.prefix = newAnim; + + refreshFlxAnimationFrames(flxAnimation, animData); + parent.buildAnimDisplay(anim, flxAnimation); + } + + if (parent.character.getAnimName() == anim) + CharacterEditor.instance.playAnimation(anim); + } + + public function changeOffset(newOffsetX:Null, newOffsetY:Null) { + var animData:AnimData = parent.character.animDatas[anim]; + + if (newOffsetX != null && newOffsetY != null && newOffsetX == animData.x && newOffsetY == animData.y) + return; + else { + if (newOffsetX != null && newOffsetX == animData.x) return; + if (newOffsetY != null && newOffsetY == animData.y) return; + } + + if (newOffsetX != null) animData.x = newOffsetX; + if (newOffsetY != null) animData.y = newOffsetY; + + parent.character.animOffsets[anim].set(animData.x, animData.y); + + if (parent.character.getAnimName() == anim) + CharacterEditor.instance.playAnimation(anim); + + field.text = '${animData.name} (${animData.x}, ${animData.y})'; + } + + public function changeFPS(newFPS:Float) @:privateAccess { + var animData:AnimData = parent.character.animDatas[anim]; + animData.fps = newFPS; + + if (parent.character.animateAtlas != null) { + var animSymbol:SymbolStuff = parent.character.animateAtlas.anim.animsMap[anim]; + animSymbol.frameRate = newFPS; + } else { + var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; + flxAnimation.frameRate = newFPS; + } + + if (parent.character.getAnimName() == anim) + CharacterEditor.instance.playAnimation(anim); + } + + public function changeLooping(newLooping:Bool) @:privateAccess { + var animData:AnimData = parent.character.animDatas[anim]; + animData.loop = newLooping; + + if (parent.character.animateAtlas != null) { + var animSymbol:SymbolStuff = parent.character.animateAtlas.anim.animsMap[anim]; + animSymbol.instance.symbol.loop = animData.loop ? Loop : PlayOnce; + } else { + var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; + flxAnimation.looped = animData.loop; + } + + if (parent.character.getAnimName() == anim) + CharacterEditor.instance.playAnimation(anim); + } + + public function changeIndicies(indicies:Array) @:privateAccess { + var animData:AnimData = parent.character.animDatas[anim]; + animData.indices = indicies; + + if (parent.character.animateAtlas != null) { + var animSymbol:SymbolStuff = parent.character.animateAtlas.anim.animsMap[anim]; + refreshSymbolKeyFrames(animSymbol, animData); + } else { + var flxAnimation:FlxAnimation = parent.character.animation._animations[anim]; + refreshFlxAnimationFrames(flxAnimation, animData); + } + + if (parent.character.getAnimName() == anim) + CharacterEditor.instance.playAnimation(anim); + } + + public inline function refreshFlxAnimationFrames(flxAnimation:FlxAnimation, animData:AnimData) @:privateAccess { + try { + if (animData.indices.length > 0) { + var frameIndices:Array = new Array(); + parent.character.animation.byIndicesHelper(frameIndices, flxAnimation.prefix, animData.indices, ""); + + flxAnimation.frames = frameIndices; + } else { + final animFrames:Array = new Array(); + parent.character.animation.findByPrefix(animFrames, flxAnimation.prefix); + + final frameIndices:Array = []; + parent.character.animation.byPrefixHelper(frameIndices, animFrames, flxAnimation.prefix); + + flxAnimation.frames = frameIndices; + } + } catch (e) { + trace('TODO: ERROR HANDLING $e'); + } + } + + public inline function refreshSymbolKeyFrames(symbol:SymbolStuff, 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;} + } + } + public override function draw() { super.draw(); - if (parent.displayAnimsFramesList.exists(anim)) { + if (!closed && parent.displayAnimsFramesList.exists(anim)) { var displayData:{frame:Int, scale:Float, animBounds:Rectangle} = parent.displayAnimsFramesList.get(anim); parent.displayWindowSprite.frame = parent.displayWindowSprite.frames.frames[displayData.frame]; parent.displayWindowSprite.scale.x = parent.displayWindowSprite.scale.y = displayData.scale; parent.displayWindowSprite.updateHitbox(); - // parent.displayWindowSprite.origin.set(); - parent.displayWindowSprite.follow( this, 16+(128/2)-((parent.displayWindowSprite.frame.sourceSize.x*displayData.scale)/2), 8+32+8+2+11+(128/2)-((parent.displayWindowSprite.frame.sourceSize.y*displayData.scale)/2) diff --git a/source/funkin/editors/character/CharacterAnimButtons.hx b/source/funkin/editors/character/CharacterAnimButtons.hx deleted file mode 100644 index 01ba60d4..00000000 --- a/source/funkin/editors/character/CharacterAnimButtons.hx +++ /dev/null @@ -1,92 +0,0 @@ -package funkin.editors.character; - -import flixel.math.FlxPoint; -import flixel.util.FlxColor; - -class CharacterAnimButtons extends UIButton { - public var anim:String = ""; - - public var editButton:UIButton; - public var editIcon:FlxSprite; - - public var ghostButton:UIButton; - public var ghostIcon:FlxSprite; - - public var deleteButton:UIButton; - public var deleteIcon:FlxSprite; - - public function new(x:Float,y:Float,anim:String, offset:FlxPoint) { - this.anim = anim; - super(x,y, '$anim (${offset.x}, ${offset.y})', function () { - CharacterEditor.instance.playAnimation(this.anim); - }, 282); - autoAlpha = false; - - ghostButton = new UIButton(x+282+17, y, "", function () { - CharacterEditor.instance.ghostAnim(this.anim); - }, 32); - ghostButton.autoAlpha = false; - members.push(ghostButton); - - ghostIcon = new FlxSprite(ghostButton.x + 8, ghostButton.y + 8).loadGraphic(Paths.image('editors/character/ghost-button'), true, 16, 16); - ghostIcon.animation.add("alive", [0]); - ghostIcon.animation.add("dead", [1]); - ghostIcon.animation.play("dead"); ghostIcon.alpha = 0.5; - ghostIcon.antialiasing = false; - ghostIcon.updateHitbox(); - members.push(ghostIcon); - - editButton = new UIButton(ghostButton.x+32+17, y, "", function () { - CharacterEditor.instance.editAnimWithUI(this.anim); - }, 32); - editButton.frames = Paths.getFrames("editors/ui/grayscale-button"); - editButton.color = FlxColor.YELLOW; - editButton.autoAlpha = false; - members.push(editButton); - - editIcon = new FlxSprite(editButton.x + 8, editButton.y + 8).loadGraphic(Paths.image('editors/character/edit-button'), true, 16, 16); - editIcon.animation.add("edit", [0]); - editIcon.animation.add("advanced", [1]); - editIcon.animation.play("edit"); - editIcon.antialiasing = false; - members.push(editIcon); - - deleteButton = new UIButton(editButton.x+32+17, y, "", function () { - CharacterEditor.instance.deleteAnim(this.anim); - }, 32); - deleteButton.color = FlxColor.RED; - deleteButton.autoAlpha = false; - members.push(deleteButton); - - deleteIcon = new FlxSprite(deleteButton.x + (15/2), deleteButton.y + 8).loadGraphic(Paths.image('editors/delete-button')); - deleteIcon.antialiasing = false; - members.push(deleteIcon); - } - - public override function update(elapsed:Float) { - editButton.selectable = ghostButton.selectable = deleteButton.selectable = selectable; - editButton.shouldPress = ghostButton.shouldPress = deleteButton.shouldPress = shouldPress; - - hovered = !deleteButton.hovered; - updatePos(); - super.update(elapsed); - } - - public function updateInfo(anim:String, offset:FlxPoint, ghost:Bool) { - this.anim = anim; - - field.text = '$anim (${offset.x}, ${offset.y})'; - ghostIcon.animation.play(ghost ? "alive" : "dead"); - ghostIcon.alpha = ghost ? 1 : 0.5; - } - - public inline function updatePos() { - // buttons - deleteButton.x = (editButton.x = (ghostButton.x = (x+282+17))+32+17)+32+17; - deleteButton.y = editButton.y = ghostButton.y = y; - // icons - ghostIcon.x = ghostButton.x + 8; ghostIcon.y = ghostButton.y + 8; - editIcon.x = editButton.x + 8; editIcon.y = editButton.y + 8; - deleteIcon.x = deleteButton.x + (15/2); deleteIcon.y = deleteButton.y + 8; - } -} \ No newline at end of file diff --git a/source/funkin/editors/character/CharacterAnimsWindow.hx b/source/funkin/editors/character/CharacterAnimsWindow.hx index 7454079d..0aaacce1 100644 --- a/source/funkin/editors/character/CharacterAnimsWindow.hx +++ b/source/funkin/editors/character/CharacterAnimsWindow.hx @@ -1,5 +1,6 @@ package funkin.editors.character; +import flixel.animation.FlxAnimation; import flixel.graphics.FlxGraphic; import openfl.geom.Rectangle; import flixel.graphics.frames.FlxFrame; @@ -31,17 +32,22 @@ class CharacterAnimsWindow extends UIButtonList { displayWindowSprite.flipX = character.flipX; @:privateAccess - for (name => anim in displayWindowSprite.animation._animations) { - var frameIndex:Int = anim.frames.getDefault([0])[0]; - var frame:FlxFrame = displayWindowSprite.frames.frames[frameIndex]; - - var frameRect:Rectangle = new Rectangle(frame.offset.x, frame.offset.y, frame.sourceSize.x, frame.sourceSize.y); - var animBounds:Rectangle = displayWindowGraphic != null ? displayWindowGraphic.bitmap.bounds(frameRect) : frameRect; - - displayAnimsFramesList.set(name, {frame: anim.frames.getDefault([0])[0], scale: 104/animBounds.height, animBounds: animBounds}); - } + for (name => anim in displayWindowSprite.animation._animations) + buildAnimDisplay(name, anim); for (anim in character.getAnimOrder()) add(new CharacterAnimButton(0,0, character.animDatas.get(anim), this)); + + this.character = character; + } + + public function buildAnimDisplay(name:String, anim:FlxAnimation) { + var frameIndex:Int = anim.frames.getDefault([0])[0]; + var frame:FlxFrame = displayWindowSprite.frames.frames[frameIndex]; + + var frameRect:Rectangle = new Rectangle(frame.offset.x, frame.offset.y, frame.sourceSize.x, frame.sourceSize.y); + var animBounds:Rectangle = displayWindowGraphic != null ? displayWindowGraphic.bitmap.bounds(frameRect) : frameRect; + + displayAnimsFramesList.set(name, {frame: anim.frames.getDefault([0])[0], scale: 104/animBounds.height, animBounds: animBounds}); } } \ No newline at end of file diff --git a/source/funkin/editors/character/CharacterEditor.hx b/source/funkin/editors/character/CharacterEditor.hx index 6ba80df1..ac2f5114 100644 --- a/source/funkin/editors/character/CharacterEditor.hx +++ b/source/funkin/editors/character/CharacterEditor.hx @@ -14,8 +14,6 @@ class CharacterEditor extends UIState { static var __character:String; public var character:Character; - public var ghosts:CharacterGhostsHandler; - public static var instance(get, null):CharacterEditor; private static inline function get_instance() @@ -38,8 +36,6 @@ class CharacterEditor extends UIState { public var charCamera:FlxCamera; public var uiCamera:FlxCamera; - public var undos:UndoList = new UndoList(); - public function new(character:String) { super(); if (character != null) __character = character; @@ -84,12 +80,10 @@ class CharacterEditor extends UIState { { label: "Undo", keybind: [CONTROL, Z], - onSelect: _edit_undo }, { label: "Redo", keybinds: [[CONTROL, Y], [CONTROL, SHIFT, Z]], - onSelect: _edit_redo } ] }, @@ -99,21 +93,17 @@ class CharacterEditor extends UIState { { label: "New Animation", keybind: [CONTROL, N], - onSelect: _char_add_anim, }, { label: "Edit Animation", - onSelect: _char_edit_anim, }, { label: "Delete Animation", keybind: [DELETE], - onSelect: _char_remove_anim, }, null, { label: "Edit Info", - onSelect: _char_edit_info, } ] }, @@ -137,49 +127,40 @@ class CharacterEditor extends UIState { { label: "Move Left", keybind: [LEFT], - onSelect: _offsets_left, }, { label: "Move Up", keybind: [UP], - onSelect: _offsets_up, }, { label: "Move Down", keybind: [DOWN], - onSelect: _offsets_down, }, { label: "Move Right", keybind: [RIGHT], - onSelect: _offsets_right, }, null, { label: "Move Extra Left", keybind: [SHIFT, LEFT], - onSelect: _offsets_extra_left, }, { label: "Move Extra Up", keybind: [SHIFT, UP], - onSelect: _offsets_extra_up, }, { label: "Move Extra Down", keybind: [SHIFT, DOWN], - onSelect: _offsets_extra_down, }, { label: "Move Extra Right", keybind: [SHIFT, RIGHT], - onSelect: _offsets_extra_right, }, null, { label: "Clear Offsets", keybind: [CONTROL, R], - onSelect: _offsets_clear, } ] }, @@ -226,10 +207,6 @@ class CharacterEditor extends UIState { character.debugMode = true; character.cameras = [charCamera]; - ghosts = new CharacterGhostsHandler(character); - ghosts.cameras = [charCamera]; - - add(ghosts); add(character); uiGroup.cameras = [uiCamera]; @@ -305,16 +282,13 @@ class CharacterEditor extends UIState { characterBG.scale.set(characterBG.scale.x / charCamera.zoom, characterBG.scale.y / charCamera.zoom); super.update(elapsed); - - WindowUtils.prefix = undos.unsaved ? "* " : ""; - SaveWarning.showWarning = undos.unsaved; } // TOP MENU OPTIONS #if REGION function _file_exit(_) { - if (undos.unsaved) SaveWarning.triggerWarning(); - else FlxG.switchState(new CharacterSelection()); + /*if (undos.unsaved) SaveWarning.triggerWarning(); + else*/ FlxG.switchState(new CharacterSelection()); } function _file_new(_) { @@ -326,7 +300,6 @@ class CharacterEditor extends UIState { '${Paths.getAssetsRoot()}/data/characters/${character.curCharacter}.xml', buildCharacter() ); - undos.save(); #else _file_saveas(_); #end @@ -336,7 +309,6 @@ class CharacterEditor extends UIState { openSubState(new SaveSubstate(buildCharacter(), { defaultSaveFile: '${character.curCharacter}.xml' })); - undos.save(); } function buildCharacter():String { @@ -352,162 +324,6 @@ class CharacterEditor extends UIState { return "\n" + Printer.print(charXML, true); } - function _edit_undo(_) { - var undo = undos.undo(); - switch(undo) { - case null: - // do nothing - case CEditInfo(oldInfo, newInfo): - editInfo(oldInfo, false); - case CCreateAnim(animID, animData): - deleteAnim(animData.name, false); - case CEditAnim(name, oldData, animData): - editAnim(name, oldData, false); - case CDeleteAnim(animID, animData): - createAnim(animData, animID, false); - case CChangeOffset(name, change): - changeOffset(name, change * -1, false); - case CResetOffsets(oldOffsets): - for (anim => offsets in oldOffsets) { - character.animOffsets.set(anim, offsets.clone()); - ghosts.setOffsets(anim, offsets.clone()); - } - - changeOffset(character.getAnimName(), FlxPoint.get(0, 0), false); // apply da new offsets - } - } - - function _edit_redo(_) { - var redo = undos.redo(); - switch(redo) { - case null: - // do nothing - case CEditInfo(oldInfo, newInfo): - editInfo(newInfo, false); - case CCreateAnim(animID, animData): - createAnim(animData, animID, false); - case CEditAnim(name, oldData, animData): - editAnim(oldData.name, animData, false); - case CDeleteAnim(animID, animData): - deleteAnim(animData.name, false); - case CChangeOffset(name, change): - changeOffset(name, change, false); - case CResetOffsets(oldOffsets): - clearOffsets(false); - } - } - - function _char_add_anim(_) { - createAnimWithUI(); - } - - function _char_edit_anim(_) { - editAnimWithUI(character.getAnimName()); - } - - function _char_remove_anim(_) { - deleteAnim(character.getAnimName()); - } - - function _char_edit_info(_) { - editInfoWithUI(); - } - - public function createAnimWithUI() { - - } - - public function editAnimWithUI(name:String) { - - } - - public function createAnim(animData:AnimData, animID:Int = -1, addtoUndo:Bool = true) { - /* - XMLUtil.addAnimToSprite(character, animData); - ghosts.createGhost(animData.name); - var newButton = new CharacterAnimButton(0, 0, animData.name, FlxPoint.get(animData.x,animData.y)); - if (animID == -1) characterAnimsWindow.add(newButton); - else characterAnimsWindow.insert(newButton, animID); - - playAnimation(animData.name); - - if (addtoUndo) - undos.addToUndo(CCreateAnim(character.getNameList().length, animData)); - */ - } - - public function editAnim(name:String, animData:AnimData, addtoUndo:Bool = true) { - var oldAnimData:AnimData = character.animDatas.get(name); - var buttoner:CharacterAnimButton = null; - for (button in characterAnimsWindow.buttons.members) - if (button.anim == name) buttoner = button; - - ghosts.removeGhost(name); - XMLUtil.addAnimToSprite(character, animData); - ghosts.createGhost(animData.name); - - if (character.getAnimName() == animData.name) // update anim ifs its currently selected - playAnimation(animData.name); - - if (addtoUndo) - undos.addToUndo(CEditAnim(animData.name, oldAnimData, animData)); - } - - public function deleteAnim(name:String, addtoUndo:Bool = true) { - var animOrder:Array = [ - for (button in characterAnimsWindow.buttons.members) - button.anim - ]; - - if (character.getNameList().length-1 == 0) - @:privateAccess character.animation._curAnim = null; - else - playAnimation(animOrder[Std.int(Math.abs(animOrder.indexOf(name)-1))]); - - for(button in characterAnimsWindow.buttons.members) - if(button.anim == name) characterAnimsWindow.remove(button); - - // undo shit blah blah - var oldID:Int = animOrder.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); - - if (addtoUndo) - undos.addToUndo(CDeleteAnim(oldID, oldAnimData)); - } - - public function editInfoWithUI() { - FlxG.state.openSubState(new CharacterInfoScreen(character, (_) -> { - if (_ != null) editInfo(_); - })); - } - - public function editInfo(newInfo:Xml, addtoUndo:Bool = true) { - var lastAnim:String = character.getAnimName(); - - var oldInfo = character.buildXML(); - character.applyXML(new Access(newInfo)); - ghosts.updateInfos(newInfo); - - playAnimation(lastAnim); - - if (addtoUndo) - undos.addToUndo(CEditInfo(oldInfo, newInfo)); - } - - public function ghostAnim(anim:String) { - var ghost:Character = ghosts.animGhosts.get(anim); - ghost.visible = !ghost.visible; - - var animButton:CharacterAnimButton = null; - for (button in characterAnimsWindow.buttons.members) - if (button.anim == anim) animButton = button; - } - function _playback_play_anim(_) { if (character.getNameList().length != 0) playAnimation(character.getAnimName()); @@ -525,68 +341,6 @@ class CharacterEditor extends UIState { i.alpha = i.anim == anim ? 1 : 0.25; } - function _offsets_left(_) { - changeOffset(character.getAnimName(), FlxPoint.get(!character.isFlippedOffsets() ? 1 : -1, 0)); - } - - function _offsets_up(_) { - changeOffset(character.getAnimName(), FlxPoint.get(0, 1)); - } - - function _offsets_down(_) { - changeOffset(character.getAnimName(), FlxPoint.get(0, -1)); - } - - function _offsets_right(_) { - changeOffset(character.getAnimName(), FlxPoint.get(!character.isFlippedOffsets() ? -1 : 1, 0)); - } - - function _offsets_extra_left(_) { - changeOffset(character.getAnimName(), FlxPoint.get(!character.isFlippedOffsets() ? 5 : -5, 0)); - } - - function _offsets_extra_up(_) { - changeOffset(character.getAnimName(), FlxPoint.get(0, 5)); - } - - function _offsets_extra_down(_) { - changeOffset(character.getAnimName(), FlxPoint.get(0, -5)); - } - - function _offsets_extra_right(_) { - changeOffset(character.getAnimName(), FlxPoint.get(!character.isFlippedOffsets() ? -5 : 5, 0)); - } - - function _offsets_clear(_) { - clearOffsets(); - } - - function changeOffset(anim:String, change:FlxPoint, addtoUndo:Bool = true) { - if (character.getNameList().length == 0) return; - - character.animOffsets.set(anim, character.getAnimOffset(anim) + change); - character.frameOffset.set(character.getAnimOffset(anim).x, character.getAnimOffset(anim).y); - - ghosts.updateOffsets(anim, change); - - if (addtoUndo) - undos.addToUndo(CChangeOffset(anim, change)); - } - - function clearOffsets(addtoUndo:Bool = true) { - if (character.getNameList().length == 0) return; - - var oldOffsets:Map = [ - for (anim => offsets in character.animOffsets) - anim => offsets.clone() - ]; - changeOffset(character.getAnimName(), FlxPoint.get(), false); - ghosts.clearOffsets(); - - if (addtoUndo) - undos.addToUndo(CResetOffsets(oldOffsets)); - } - var zoom(default, set):Float = 0; var __camZoom(default, set):Float = 1; function set_zoom(val:Float) { @@ -619,13 +373,4 @@ class CharacterEditor extends UIState { characterMidpoint.put(); } #end -} - -enum CharacterChange { - CEditInfo(oldInfo:Xml, newInfo:Xml); - CCreateAnim(animID:Int, animData:AnimData); - CEditAnim(name:String, oldData:AnimData, animData:AnimData); - CDeleteAnim(animID:Int, animData:AnimData); - CChangeOffset(name:String, change:FlxPoint); - CResetOffsets(oldOffsets:Map); } \ No newline at end of file diff --git a/source/funkin/editors/character/CharacterGhostsHandler.hx b/source/funkin/editors/character/CharacterGhostsHandler.hx deleted file mode 100644 index fe823898..00000000 --- a/source/funkin/editors/character/CharacterGhostsHandler.hx +++ /dev/null @@ -1,75 +0,0 @@ -package funkin.editors.character; - -import flixel.math.FlxPoint; -import funkin.game.Character; -import haxe.xml.Access; - -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 if (ghost != null) { - 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(name:String, change:FlxPoint) { - for (anim => ghost in animGhosts) - ghost.animOffsets.set(name, ghost.getAnimOffset(name) + change); - - rePositionGhosts(); - } - - public function setOffsets(name:String, offset:FlxPoint) { - for (anim => ghost in animGhosts) - ghost.animOffsets.set(name, 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/editors/character/CharacterInfoScreen.hx b/source/funkin/editors/character/CharacterInfoScreen.hx deleted file mode 100644 index 805bfeaa..00000000 --- a/source/funkin/editors/character/CharacterInfoScreen.hx +++ /dev/null @@ -1,199 +0,0 @@ -package funkin.editors.character; - -import flixel.math.FlxPoint; -import funkin.editors.extra.PropertyButton; -import funkin.game.Character; -import haxe.xml.Access; - -class CharacterInfoScreen extends UISubstateWindow { - public var character:Character; - - public var spriteTextBox:UITextBox; - public var iconTextBox:UITextBox; - public var iconSprite:FlxSprite; - public var gameOverCharTextBox:UITextBox; - public var antialiasingCheckbox:UICheckbox; - public var flipXCheckbox:UICheckbox; - public var iconColorWheel:UIColorwheel; - public var positionXStepper:UINumericStepper; - public var positionYStepper:UINumericStepper; - public var cameraXStepper:UINumericStepper; - public var cameraYStepper:UINumericStepper; - public var scaleStepper:UINumericStepper; - public var singTimeStepper:UINumericStepper; - public var customPropertiesButtonList:UIButtonList; - public var isPlayerCheckbox:UICheckbox; - - public var saveButton:UIButton; - public var closeButton:UIButton; - - public var onSave:(xml:Xml) -> Void = null; - - public function new(character:Character, ?onSave:(xml:Xml) -> Void) { - this.character = character; - this.onSave = onSave; - super(); - } - - public override function create() { - winTitle = "Editing Character"; - winWidth = 1014; - winHeight = 600; - - super.create(); - - function addLabelOn(ui:UISprite, text:String) - add(new UIText(ui.x, ui.y - 24, 0, text)); - - var title:UIText; - add(title = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, "Sprite Data", 28)); - - spriteTextBox = new UITextBox(title.x, title.y + title.height + 38, character.sprite, 200); - add(spriteTextBox); - addLabelOn(spriteTextBox, "Sprite"); - - iconTextBox = new UITextBox(spriteTextBox.x + 200 + 26, spriteTextBox.y, character.getIcon(), 150); - iconTextBox.onChange = (newIcon:String) -> {updateIcon(newIcon);} - add(iconTextBox); - addLabelOn(iconTextBox, "Icon"); - - updateIcon(character.getIcon()); - - gameOverCharTextBox = new UITextBox(iconTextBox.x + 150 + (75 + 12), iconTextBox.y, character.gameOverCharacter, 200); - add(gameOverCharTextBox); - addLabelOn(gameOverCharTextBox, "Game Over Character"); - - antialiasingCheckbox = new UICheckbox(spriteTextBox.x, spriteTextBox.y + 10 + 32 + 28, "Antialiasing", character.antialiasing); - add(antialiasingCheckbox); - addLabelOn(antialiasingCheckbox, "Antialiased"); - - flipXCheckbox = new UICheckbox(antialiasingCheckbox.x + 172, spriteTextBox.y + 10 + 32 + 28, "FlipX", character.flipX); - add(flipXCheckbox); - addLabelOn(flipXCheckbox, "Flipped"); - - iconColorWheel = new UIColorwheel(gameOverCharTextBox.x + 200 + 20, gameOverCharTextBox.y, character.iconColor); - add(iconColorWheel); - addLabelOn(iconColorWheel, "Icon Color"); - - add(title = new UIText(spriteTextBox.x, spriteTextBox.y + 10 + 46 + 84, 0, "Character Data", 28)); - - positionXStepper = new UINumericStepper(title.x, title.y + title.height + 36, character.globalOffset.x, 0.001, 2, null, null, 84); - add(positionXStepper); - addLabelOn(positionXStepper, "Position (X,Y)"); - - add(new UIText(positionXStepper.x + 84 - 32 + 0, positionXStepper.y + 9, 0, ",", 22)); - - positionYStepper = new UINumericStepper(positionXStepper.x + 84 - 32 + 26, positionXStepper.y, character.globalOffset.y, 0.001, 2, null, null, 84); - add(positionYStepper); - - cameraXStepper = new UINumericStepper(positionYStepper.x + 36 + 84 - 32, positionYStepper.y, character.cameraOffset.x, 0.001, 2, null, null, 84); - add(cameraXStepper); - addLabelOn(cameraXStepper, "Camera Position (X,Y)"); - - add(new UIText(cameraXStepper.x + 84 - 32 + 0, cameraXStepper.y + 9, 0, ",", 22)); - - cameraYStepper = new UINumericStepper(cameraXStepper.x + 84 - 32 + 26, cameraXStepper.y, character.cameraOffset.y, 0.001, 2, null, null, 84); - add(cameraYStepper); - - scaleStepper = new UINumericStepper(cameraYStepper.x + 84 - 32 + 90, cameraYStepper.y, character.scale.x, 0.001, 2, null, null, 74); - add(scaleStepper); - addLabelOn(scaleStepper, "Scale"); - - singTimeStepper = new UINumericStepper(scaleStepper.x + 74 - 32 + 36, scaleStepper.y, character.holdTime, 0.001, 2, null, null, 74); - add(singTimeStepper); - addLabelOn(singTimeStepper, "Sing Duration (Steps)"); - - customPropertiesButtonList = new UIButtonList(singTimeStepper.x + singTimeStepper.width + 200, singTimeStepper.y, 290, 200, '', FlxPoint.get(280, 35), null, 5); - customPropertiesButtonList.frames = Paths.getFrames('editors/ui/inputbox'); - customPropertiesButtonList.cameraSpacing = 0; - customPropertiesButtonList.addButton.callback = function() { - customPropertiesButtonList.add(new PropertyButton("newProperty", "valueHere", customPropertiesButtonList)); - } - for (prop=>val in character.extra) - customPropertiesButtonList.add(new PropertyButton(prop, val, customPropertiesButtonList)); - add(customPropertiesButtonList); - addLabelOn(customPropertiesButtonList, "Custom Values (Advanced)"); - - isPlayerCheckbox = new UICheckbox(positionXStepper.x, positionXStepper.y + 10 + 32 + 28, "isPlayer", character.playerOffsets); - add(isPlayerCheckbox); - addLabelOn(isPlayerCheckbox, "Is Player"); - - for (checkbox in [isPlayerCheckbox, antialiasingCheckbox, flipXCheckbox]) - {checkbox.y += 4; checkbox.x += 6;} - - saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight- 20, "Save & Close", function() { - saveCharacterInfo(); - close(); - }, 125); - saveButton.x -= saveButton.bWidth; - saveButton.y -= saveButton.bHeight; - - closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Close", function() { - if (onSave != null) onSave(null); - close(); - }, 125); - closeButton.x -= closeButton.bWidth; - closeButton.color = 0xFFFF0000; - add(closeButton); - add(saveButton); - } - - function updateIcon(icon:String) { - if (iconSprite == null) add(iconSprite = new FlxSprite()); - - if (iconSprite.animation.exists(icon)) return; - @:privateAccess iconSprite.animation.clearAnimations(); - - var path:String = Paths.image('icons/$icon'); - if (!Assets.exists(path)) path = Paths.image('icons/face'); - - iconSprite.loadGraphic(path, true, 150, 150); - iconSprite.animation.add(icon, [0], 0, false); - iconSprite.antialiasing = true; - iconSprite.animation.play(icon); - - iconSprite.scale.set(0.5, 0.5); - iconSprite.updateHitbox(); - iconSprite.setPosition(iconTextBox.x + 150 + 8, (iconTextBox.y + 16) - (iconSprite.height/2)); - } - - function saveCharacterInfo() { - for (stepper in [positionXStepper, positionYStepper, cameraXStepper, cameraYStepper, singTimeStepper, scaleStepper]) - @:privateAccess stepper.__onChange(stepper.label.text); - - var xml = Xml.createElement("character"); - xml.set("isPlayer", isPlayerCheckbox.checked ? "true" : "false"); - xml.set("x", Std.string(positionXStepper.value)); - xml.set("y", Std.string(positionYStepper.value)); - xml.set("gameOverChar", gameOverCharTextBox.label.text); - xml.set("camx", Std.string(cameraXStepper.value)); - xml.set("camy", Std.string(cameraYStepper.value)); - xml.set("holdTime", Std.string(singTimeStepper.value)); - xml.set("flipX", Std.string(flipXCheckbox.checked)); - xml.set("icon", iconTextBox.label.text); - xml.set("scale", Std.string(scaleStepper.value)); - xml.set("antialiasing", antialiasingCheckbox.checked ? "true" : "false"); - xml.set("sprite", spriteTextBox.label.text); - if (iconColorWheel.colorChanged) - xml.set("color", iconColorWheel.curColor.toWebString()); - for (val in customPropertiesButtonList.buttons.members) - xml.set(val.propertyText.label.text, val.valueText.label.text); - - for (anim in character.animDatas) - { - var animXml:Xml = Xml.createElement('anim'); - animXml.set("name", anim.name); - animXml.set("anim", anim.anim); - animXml.set("loop", Std.string(anim.loop)); - animXml.set("fps", Std.string(anim.fps)); - var offset:FlxPoint = character.getAnimOffset(anim.name); - animXml.set("x", Std.string(offset.x)); - animXml.set("y", Std.string(offset.y)); - if (anim.indices.length > 0) - animXml.set("indices", anim.indices.join(",")); - xml.addChild(animXml); - } - - if (onSave != null) onSave(xml); - } -} \ No newline at end of file diff --git a/source/funkin/editors/ui/UISliceSprite.hx b/source/funkin/editors/ui/UISliceSprite.hx index 8cc6ab2d..ec45484a 100644 --- a/source/funkin/editors/ui/UISliceSprite.hx +++ b/source/funkin/editors/ui/UISliceSprite.hx @@ -87,6 +87,9 @@ class UISliceSprite extends UISprite { } public override function draw() @:privateAccess { + var lastPixelPerfect:Bool = cameras[0].pixelPerfectRender; + cameras[0].pixelPerfectRender = false; + var x:Float = this.x; var y:Float = this.y; @@ -184,6 +187,7 @@ class UISliceSprite extends UISprite { } alpha = oldAlpha; } + cameras[0].pixelPerfectRender = true; setPosition(x, y); super.drawMembers();