Tweaks and improvements to the animation editor

This commit is contained in:
EliteMasterEric 2023-06-13 17:13:14 -04:00
parent c17d48f39e
commit 338342ad5e
4 changed files with 128 additions and 47 deletions

View file

@ -58,6 +58,7 @@ class BaseCharacter extends Bopper
*/ */
public var dropNoteCounts(default, null):Array<Int>; public var dropNoteCounts(default, null):Array<Int>;
@:allow(funkin.ui.animDebugShit.DebugBoundingState)
final _data:CharacterData; final _data:CharacterData;
final singTimeSec:Float; final singTimeSec:Float;

View file

@ -85,6 +85,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
return globalOffsets = value; return globalOffsets = value;
} }
@:allow(funkin.ui.animDebugShit.DebugBoundingState)
var animOffsets(default, set):Array<Float> = [0, 0]; var animOffsets(default, set):Array<Float> = [0, 0];
public var originalPosition:FlxPoint = new FlxPoint(0, 0); public var originalPosition:FlxPoint = new FlxPoint(0, 0);

View file

@ -32,6 +32,9 @@ import openfl.net.FileReference;
import openfl.net.URLLoader; import openfl.net.URLLoader;
import openfl.net.URLRequest; import openfl.net.URLRequest;
import openfl.utils.ByteArray; import openfl.utils.ByteArray;
import funkin.input.Cursor;
import funkin.play.character.CharacterData.CharacterDataParser;
import funkin.util.SortUtil;
using flixel.util.FlxSpriteUtil; using flixel.util.FlxSpriteUtil;
@ -71,7 +74,7 @@ class DebugBoundingState extends FlxState
{ {
Paths.setCurrentLevel('week1'); Paths.setCurrentLevel('week1');
var str = Paths.xml('ui/offset-editor-view'); var str = Paths.xml('ui/animation-editor/offset-editor-view');
uiStuff = RuntimeComponentBuilder.fromAsset(str); uiStuff = RuntimeComponentBuilder.fromAsset(str);
// uiStuff.findComponent("btnViewSpriteSheet").onClick = _ -> curView = SPRITESHEET; // uiStuff.findComponent("btnViewSpriteSheet").onClick = _ -> curView = SPRITESHEET;
@ -109,6 +112,8 @@ class DebugBoundingState extends FlxState
initSpritesheetView(); initSpritesheetView();
initOffsetView(); initOffsetView();
Cursor.show();
uiStuff.cameras = [hudCam]; uiStuff.cameras = [hudCam];
add(uiStuff); add(uiStuff);
@ -124,7 +129,7 @@ class DebugBoundingState extends FlxState
spriteSheetView = new FlxGroup(); spriteSheetView = new FlxGroup();
add(spriteSheetView); add(spriteSheetView);
var tex = Paths.getSparrowAtlas('characters/temp'); var tex = Paths.getSparrowAtlas('characters/BOYFRIEND');
// tex.frames[0].uv // tex.frames[0].uv
bf = new FlxSprite(); bf = new FlxSprite();
@ -239,11 +244,15 @@ class DebugBoundingState extends FlxState
txtOffsetShit.cameras = [hudCam]; txtOffsetShit.cameras = [hudCam];
offsetView.add(txtOffsetShit); offsetView.add(txtOffsetShit);
animDropDownMenu = new FlxUIDropDownMenu(630, 20, FlxUIDropDownMenu.makeStrIdLabelArray(['weed'], true)); animDropDownMenu = new FlxUIDropDownMenu(0, 0, FlxUIDropDownMenu.makeStrIdLabelArray(['weed'], true));
animDropDownMenu.cameras = [hudCam]; animDropDownMenu.cameras = [hudCam];
// Move to bottom right corner
animDropDownMenu.x = FlxG.width - animDropDownMenu.width - 20;
animDropDownMenu.y = FlxG.height - animDropDownMenu.height - 20;
offsetView.add(animDropDownMenu); offsetView.add(animDropDownMenu);
var characters:Array<String> = CoolUtil.coolTextFile(Paths.txt('characterList')); var characters:Array<String> = CharacterDataParser.listCharacterIds();
characters.sort(SortUtil.alphabetically);
var charDropdown:DropDown = cast uiStuff.findComponent('characterDropdown'); var charDropdown:DropDown = cast uiStuff.findComponent('characterDropdown');
for (char in characters) for (char in characters)
@ -265,19 +274,16 @@ class DebugBoundingState extends FlxState
{ {
if (FlxG.mouse.justPressed) if (FlxG.mouse.justPressed)
{ {
mouseOffset.set(FlxG.mouse.x - -swagChar.offset.x, FlxG.mouse.y - -swagChar.offset.y); mouseOffset.set(FlxG.mouse.x - -swagChar.animOffsets[0], FlxG.mouse.y - -swagChar.animOffsets[1]);
// oldPos.set(swagChar.offset.x, swagChar.offset.y);
// oldPos.set(FlxG.mouse.x, FlxG.mouse.y);
} }
if (FlxG.mouse.pressed) if (FlxG.mouse.pressed)
{ {
swagChar.offset.x = (FlxG.mouse.x - mouseOffset.x) * -1; swagChar.animOffsets = [(FlxG.mouse.x - mouseOffset.x) * -1, (FlxG.mouse.y - mouseOffset.y) * -1];
swagChar.offset.y = (FlxG.mouse.y - mouseOffset.y) * -1;
swagChar.animationOffsets.set(animDropDownMenu.selectedLabel, [Std.int(swagChar.offset.x), Std.int(swagChar.offset.y)]); swagChar.animationOffsets.set(animDropDownMenu.selectedLabel, swagChar.animOffsets);
txtOffsetShit.text = 'Offset: ' + swagChar.offset; txtOffsetShit.text = 'Offset: ' + swagChar.animOffsets;
} }
} }
} }
@ -292,6 +298,11 @@ class DebugBoundingState extends FlxState
swagText.text = str + ": " + Std.string(value); swagText.text = str + ": " + Std.string(value);
} }
function clearInfo()
{
txtGrp.clear();
}
function checkLibrary(library:String) function checkLibrary(library:String)
{ {
trace(Assets.hasLibrary(library)); trace(Assets.hasLibrary(library));
@ -321,7 +332,7 @@ class DebugBoundingState extends FlxState
{ {
var lv:DropDown = cast uiStuff.findComponent("swapper"); var lv:DropDown = cast uiStuff.findComponent("swapper");
lv.selectedIndex = 1; lv.selectedIndex = 1;
curView = OFFSETSHIT; curView = ANIMATIONS;
if (swagChar != null) if (swagChar != null)
{ {
FlxG.camera.focusOn(swagChar.getMidpoint()); FlxG.camera.focusOn(swagChar.getMidpoint());
@ -335,7 +346,7 @@ class DebugBoundingState extends FlxState
spriteSheetView.visible = true; spriteSheetView.visible = true;
offsetView.visible = false; offsetView.visible = false;
offsetView.active = false; offsetView.active = false;
case OFFSETSHIT: case ANIMATIONS:
spriteSheetView.visible = false; spriteSheetView.visible = false;
offsetView.visible = true; offsetView.visible = true;
offsetView.active = true; offsetView.active = true;
@ -365,14 +376,14 @@ class DebugBoundingState extends FlxState
+ 1); + 1);
else else
animDropDownMenu.selectedId = Std.string(0); animDropDownMenu.selectedId = Std.string(0);
animDropDownMenu.callback(animDropDownMenu.selectedId); playCharacterAnimation(animDropDownMenu.selectedId, true);
} }
if (FlxG.keys.justPressed.LBRACKET || FlxG.keys.justPressed.Q) if (FlxG.keys.justPressed.LBRACKET || FlxG.keys.justPressed.Q)
{ {
if (Std.parseInt(animDropDownMenu.selectedId) - 1 >= 0) animDropDownMenu.selectedId = Std.string(Std.parseInt(animDropDownMenu.selectedId) - 1); if (Std.parseInt(animDropDownMenu.selectedId) - 1 >= 0) animDropDownMenu.selectedId = Std.string(Std.parseInt(animDropDownMenu.selectedId) - 1);
else else
animDropDownMenu.selectedId = Std.string(animDropDownMenu.length - 1); animDropDownMenu.selectedId = Std.string(animDropDownMenu.length - 1);
animDropDownMenu.callback(animDropDownMenu.selectedId); playCharacterAnimation(animDropDownMenu.selectedId, true);
} }
// Keyboards controls for general WASD "movement" // Keyboards controls for general WASD "movement"
@ -380,16 +391,29 @@ class DebugBoundingState extends FlxState
// and then it's just played and updated from the animDropDownMenu callback, which is set in the loadAnimShit() function probabbly // and then it's just played and updated from the animDropDownMenu callback, which is set in the loadAnimShit() function probabbly
if (FlxG.keys.justPressed.W || FlxG.keys.justPressed.S || FlxG.keys.justPressed.D || FlxG.keys.justPressed.A) if (FlxG.keys.justPressed.W || FlxG.keys.justPressed.S || FlxG.keys.justPressed.D || FlxG.keys.justPressed.A)
{ {
var missShit:String = ''; var suffix:String = '';
var targetLabel:String = '';
if (FlxG.keys.pressed.SHIFT) missShit = 'miss'; if (FlxG.keys.pressed.SHIFT) suffix = 'miss';
if (FlxG.keys.justPressed.W) animDropDownMenu.selectedLabel = 'singUP' + missShit; if (FlxG.keys.justPressed.W) targetLabel = 'singUP$suffix';
if (FlxG.keys.justPressed.S) animDropDownMenu.selectedLabel = 'singDOWN' + missShit; if (FlxG.keys.justPressed.S) targetLabel = 'singDOWN$suffix';
if (FlxG.keys.justPressed.A) animDropDownMenu.selectedLabel = 'singLEFT' + missShit; if (FlxG.keys.justPressed.A) targetLabel = 'singLEFT$suffix';
if (FlxG.keys.justPressed.D) animDropDownMenu.selectedLabel = 'singRIGHT' + missShit; if (FlxG.keys.justPressed.D) targetLabel = 'singRIGHT$suffix';
animDropDownMenu.callback(animDropDownMenu.selectedId); if (targetLabel != animDropDownMenu.selectedLabel)
{
// Play the new animation if the IDs are the different.
// Override the onion skin.
animDropDownMenu.selectedLabel = targetLabel;
playCharacterAnimation(animDropDownMenu.selectedId, true);
}
else
{
// Replay the current animation if the IDs are the same.
// Don't override the onion skin.
playCharacterAnimation(animDropDownMenu.selectedId, false);
}
} }
if (FlxG.keys.justPressed.F) if (FlxG.keys.justPressed.F)
@ -401,16 +425,16 @@ class DebugBoundingState extends FlxState
if (FlxG.keys.justPressed.SPACE) if (FlxG.keys.justPressed.SPACE)
{ {
animDropDownMenu.selectedLabel = 'idle'; animDropDownMenu.selectedLabel = 'idle';
animDropDownMenu.callback(animDropDownMenu.selectedId); playCharacterAnimation(animDropDownMenu.selectedId, true);
} }
// Playback the animation // Playback the animation
if (FlxG.keys.justPressed.ENTER) animDropDownMenu.callback(animDropDownMenu.selectedId); if (FlxG.keys.justPressed.ENTER) playCharacterAnimation(animDropDownMenu.selectedId, false);
if (FlxG.keys.justPressed.RIGHT || FlxG.keys.justPressed.LEFT || FlxG.keys.justPressed.UP || FlxG.keys.justPressed.DOWN) if (FlxG.keys.justPressed.RIGHT || FlxG.keys.justPressed.LEFT || FlxG.keys.justPressed.UP || FlxG.keys.justPressed.DOWN)
{ {
var animName = animDropDownMenu.selectedLabel; var animName = animDropDownMenu.selectedLabel;
var coolValues:Array<Float> = swagChar.animationOffsets.get(animName); var coolValues:Array<Float> = swagChar.animationOffsets.get(animName).copy();
var multiplier:Int = 5; var multiplier:Int = 5;
@ -432,6 +456,13 @@ class DebugBoundingState extends FlxState
} }
if (FlxG.keys.justPressed.ESCAPE) if (FlxG.keys.justPressed.ESCAPE)
{
var outputString = FlxG.keys.pressed.CTRL ? buildOutputStringOld() : buildOutputStringNew();
saveOffsets(outputString, FlxG.keys.pressed.CTRL ? swagChar.characterId + "Offsets.txt" : swagChar.characterId + ".json");
}
}
function buildOutputStringOld():String
{ {
var outputString:String = ""; var outputString:String = "";
@ -441,8 +472,21 @@ class DebugBoundingState extends FlxState
} }
outputString.trim(); outputString.trim();
saveOffsets(outputString);
return outputString;
} }
function buildOutputStringNew():String
{
var charData:CharacterData = swagChar._data.copy();
for (charDataAnim in animations)
{
var animName:String = charDataAnim.name;
charDataAnim.offsets = swagChar.animationOffsets.get(animName);
}
return SerializerUtil.toJson(charData, true);
} }
var swagChar:BaseCharacter; var swagChar:BaseCharacter;
@ -467,35 +511,51 @@ class DebugBoundingState extends FlxState
generateOutlines(swagChar.frames.frames); generateOutlines(swagChar.frames.frames);
bf.pixels = swagChar.pixels; bf.pixels = swagChar.pixels;
var animThing:Array<String> = []; clearInfo();
addInfo(swagChar._data.assetPath, "");
addInfo('Width', bf.width);
addInfo('Height', bf.height);
characterAnimNames = [];
for (i in swagChar.animationOffsets.keys()) for (i in swagChar.animationOffsets.keys())
{ {
animThing.push(i); characterAnimNames.push(i);
trace(i); trace(i);
trace(swagChar.animationOffsets[i]); trace(swagChar.animationOffsets[i]);
} }
animDropDownMenu.setData(FlxUIDropDownMenu.makeStrIdLabelArray(animThing, true)); animDropDownMenu.setData(FlxUIDropDownMenu.makeStrIdLabelArray(characterAnimNames, true));
animDropDownMenu.callback = function(str:String) { animDropDownMenu.callback = function(str:String) {
playCharacterAnimation(str, true);
};
txtOffsetShit.text = 'Offset: ' + swagChar.animOffsets;
dropDownSetup = true;
}
private var characterAnimNames:Array<String>;
function playCharacterAnimation(str:String, setOnionSkin:Bool = true)
{
if (setOnionSkin)
{
// clears the canvas // clears the canvas
onionSkinChar.pixels.fillRect(new Rectangle(0, 0, FlxG.width * 2, FlxG.height * 2), 0x00000000); onionSkinChar.pixels.fillRect(new Rectangle(0, 0, FlxG.width * 2, FlxG.height * 2), 0x00000000);
onionSkinChar.stamp(swagChar, Std.int(swagChar.x - swagChar.offset.x), Std.int(swagChar.y - swagChar.offset.y)); onionSkinChar.stamp(swagChar, Std.int(swagChar.x), Std.int(swagChar.y));
onionSkinChar.alpha = 0.6; onionSkinChar.alpha = 0.6;
}
var animName = animThing[Std.parseInt(str)]; var animName = characterAnimNames[Std.parseInt(str)];
swagChar.playAnimation(animName, true); // trace(); swagChar.playAnimation(animName, true); // trace();
trace(swagChar.animationOffsets.get(animName)); trace(swagChar.animationOffsets.get(animName));
txtOffsetShit.text = 'Offset: ' + swagChar.offset; txtOffsetShit.text = 'Offset: ' + swagChar.animOffsets;
};
dropDownSetup = true;
} }
var _file:FileReference; var _file:FileReference;
function saveOffsets(saveString:String) function saveOffsets(saveString:String, fileName:String)
{ {
if ((saveString != null) && (saveString.length > 0)) if ((saveString != null) && (saveString.length > 0))
{ {
@ -503,7 +563,7 @@ class DebugBoundingState extends FlxState
_file.addEventListener(Event.COMPLETE, onSaveComplete); _file.addEventListener(Event.COMPLETE, onSaveComplete);
_file.addEventListener(Event.CANCEL, onSaveCancel); _file.addEventListener(Event.CANCEL, onSaveCancel);
_file.addEventListener(IOErrorEvent.IO_ERROR, onSaveError); _file.addEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file.save(saveString, swagChar.characterId + "Offsets.txt"); _file.save(saveString,);
} }
} }
@ -543,5 +603,5 @@ class DebugBoundingState extends FlxState
enum abstract ANIMDEBUGVIEW(String) enum abstract ANIMDEBUGVIEW(String)
{ {
var SPRITESHEET; var SPRITESHEET;
var OFFSETSHIT; var ANIMATIONS;
} }

View file

@ -26,4 +26,23 @@ class SortUtil
{ {
return FlxSort.byValues(order, a.data.strumTime, b.data.strumTime); return FlxSort.byValues(order, a.data.strumTime, b.data.strumTime);
} }
public static inline function alphabetically(a:String, b:String)
{
a = a.toUpperCase();
b = b.toUpperCase();
if (a < b)
{
return -1;
}
else if (a > b)
{
return 1;
}
else
{
return 0;
}
}
} }