Character editor work in progress i think pls test
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 193 B |
Binary file not shown.
|
After Width: | Height: | Size: 246 B |
Binary file not shown.
|
After Width: | Height: | Size: 287 B |
@@ -135,7 +135,7 @@ class XMLUtil {
|
||||
if (anim.has.name) animData.name = anim.att.name;
|
||||
if (anim.has.type) animData.animType = XMLAnimType.fromString(anim.att.type, animData.animType);
|
||||
if (anim.has.anim) animData.anim = anim.att.anim;
|
||||
if (anim.has.fps) animData.fps = Std.parseInt(anim.att.fps);
|
||||
if (anim.has.fps) animData.fps = Std.parseFloat(anim.att.fps);
|
||||
if (anim.has.x) animData.x = Std.parseFloat(anim.att.x);
|
||||
if (anim.has.y) animData.y = Std.parseFloat(anim.att.y);
|
||||
if (anim.has.loop) animData.loop = anim.att.loop == "true";
|
||||
@@ -208,7 +208,7 @@ class XMLUtil {
|
||||
typedef AnimData = {
|
||||
var name:String;
|
||||
var anim:String;
|
||||
var fps:Int;
|
||||
var fps:Float;
|
||||
var loop:Bool;
|
||||
var x:Float;
|
||||
var y:Float;
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.backend.utils.XMLUtil.AnimData;
|
||||
import funkin.game.Character;
|
||||
|
||||
class AddAnimScreen extends UISubstateWindow
|
||||
{
|
||||
public var char:Character;
|
||||
public var ghostChar:Character;
|
||||
|
||||
public var addButton:UIButton;
|
||||
public var cancelButton:UIButton;
|
||||
public var editor:CharacterEditor;
|
||||
|
||||
public var animName:UITextBox;
|
||||
public var animPrefix:UITextBox;
|
||||
public var fps:UITextBox;
|
||||
public var loop:UICheckbox;
|
||||
public var indices:UITextBox;
|
||||
|
||||
public function new(char:Character, ghostChar, editor:CharacterEditor)
|
||||
{
|
||||
super();
|
||||
this.char = char;
|
||||
this.ghostChar = ghostChar;
|
||||
}
|
||||
|
||||
public override function create()
|
||||
{
|
||||
winTitle = "Add new Animation";
|
||||
winWidth = 960;
|
||||
|
||||
super.create();
|
||||
|
||||
// Animation Properties
|
||||
var y_ofs = 60;
|
||||
var y_text_ofs = 20;
|
||||
|
||||
animName = new UITextBox(windowSpr.x + 50, windowSpr.y + y_ofs, "");
|
||||
add(animName);
|
||||
add(new UIText(animName.x, animName.y - y_text_ofs, -1, "Animation Name: "));
|
||||
|
||||
animPrefix = new UITextBox(animName.x, animName.y + y_ofs, "");
|
||||
add(animPrefix);
|
||||
add(new UIText(animPrefix.x, animPrefix.y - y_text_ofs, -1, "Animation on XML/Atlas file: "));
|
||||
|
||||
fps = new UITextBox(animPrefix.x, animPrefix.y + y_ofs, "24");
|
||||
add(fps);
|
||||
add(new UIText(fps.x, fps.y - y_text_ofs, -1, "Framerate: "));
|
||||
|
||||
loop = new UICheckbox(fps.x, fps.y + y_ofs, "Looped", false);
|
||||
add(loop);
|
||||
|
||||
indices = new UITextBox(loop.x, loop.y + y_ofs, "");
|
||||
add(indices);
|
||||
add(new UIText(indices.x, indices.y - y_text_ofs, -1, "Indices (0, 1, 2, 3): "));
|
||||
|
||||
// Add / Cancel Buttons
|
||||
addButton = new UIButton(windowSpr.x + 1, windowSpr.y + 31, "", function()
|
||||
{
|
||||
newAnimation(animName.label.text, animPrefix.label.text, Std.parseInt(fps.label.text), loop.checked, indices.label.text);
|
||||
close();
|
||||
});
|
||||
addButton.bWidth = addButton.bHeight = 30;
|
||||
add(addButton);
|
||||
|
||||
var addButtonIcon = new FlxSprite(addButton.x, addButton.y, Paths.image('editors/charter/add-button'));
|
||||
addButtonIcon.x += (30 - addButtonIcon.width) / 2;
|
||||
addButtonIcon.y += (30 - addButtonIcon.height) / 2;
|
||||
add(addButtonIcon);
|
||||
|
||||
cancelButton = new UIButton(addButton.x - 10, addButton.y, "Cancel", function()
|
||||
{
|
||||
close();
|
||||
});
|
||||
cancelButton.x -= cancelButton.bWidth;
|
||||
add(cancelButton);
|
||||
}
|
||||
|
||||
public function newAnimation(name:String, anim:String, ?fps:Int = 24, ?looped:Bool = false, ?indices:String)
|
||||
{
|
||||
var animType:XMLAnimType = NONE;
|
||||
|
||||
var animData:AnimData = {
|
||||
name: name,
|
||||
anim: anim,
|
||||
fps: fps,
|
||||
loop: looped,
|
||||
animType: animType,
|
||||
indices: [],
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
|
||||
if (indices != "" && indices != null)
|
||||
{
|
||||
var indicesSplit = indices.split(",");
|
||||
|
||||
for (indice in indicesSplit)
|
||||
{
|
||||
var i = Std.parseInt(indice.trim());
|
||||
if (i != null)
|
||||
animData.indices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
XMLUtil.addAnimToSprite(char, animData);
|
||||
XMLUtil.addAnimToSprite(ghostChar, animData);
|
||||
char.characterData.animations.push(animData);
|
||||
ghostChar.characterData.animations.push(animData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.animation.FlxAnimation;
|
||||
|
||||
class CharacterAnimScreen extends UISubstateWindow {
|
||||
public var animName:Null<String>;
|
||||
public var offset:FlxPoint;
|
||||
public var flxanim:FlxAnimation;
|
||||
|
||||
public var saveButton:UIButton;
|
||||
public var closeButton:UIButton;
|
||||
|
||||
private var onSave:(animName:Null<String>, offset:FlxPoint, flxanim:FlxAnimation) -> Void = null;
|
||||
|
||||
public function new(animName:Null<String>, ?offset:FlxPoint, ?flxanim:FlxAnimation, ?onSave:(animName:Null<String>, offset:FlxPoint, flxanim:FlxAnimation) -> Void) {
|
||||
this.animName = animName;
|
||||
this.offset = offset;
|
||||
this.flxanim = flxanim;
|
||||
this.onSave = onSave;
|
||||
super();
|
||||
}
|
||||
|
||||
public override function create() {
|
||||
var creatingAnim:Bool = animName == null;
|
||||
|
||||
if (creatingAnim) {
|
||||
animName = "";
|
||||
offset = FlxPoint.get(0,0);
|
||||
flxanim = new FlxAnimation(CharacterEditor.instance.character.animation, animName, []);
|
||||
}
|
||||
|
||||
winTitle = creatingAnim ? 'Creating Animation' : 'Animation $animName properties';
|
||||
winWidth = 690; winHeight = 334;
|
||||
|
||||
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, creatingAnim ? "Create New Animation" : "Edit Animation Properties", 28));
|
||||
|
||||
saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20 - 125, windowSpr.y + windowSpr.bHeight - 16 - 32, "Save & Close", function() {
|
||||
// saveStrumline();
|
||||
close();
|
||||
}, 125);
|
||||
add(saveButton);
|
||||
|
||||
closeButton = new UIButton(saveButton.x - 20, saveButton.y, creatingAnim ? "Cancel" : "Close", function() {
|
||||
if (creatingAnim) onSave(null, null, null);
|
||||
close();
|
||||
}, 125);
|
||||
add(closeButton);
|
||||
closeButton.x -= closeButton.bWidth;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import flixel.group.FlxGroup;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.game.Character;
|
||||
|
||||
class CharacterAnimsWindow extends UIWindow {
|
||||
public var character:Character;
|
||||
|
||||
public var buttons:FlxGroup = new FlxGroup();
|
||||
public var animButtons:Map<String, CharacterAnimButtons> = [];
|
||||
|
||||
public var addButton:UIButton;
|
||||
public var addIcon:FlxSprite;
|
||||
|
||||
public function new(character:Character) {
|
||||
super(800-23,140+23+46,450+23,511-23, "Character Animations");
|
||||
this.character = character;
|
||||
|
||||
createButtons();
|
||||
buttons.cameras = [CharacterEditor.instance.animsCamera];
|
||||
members.push(buttons);
|
||||
}
|
||||
|
||||
public function createButtons() {
|
||||
for (i=>anim in character.animation.getNameList())
|
||||
createNewButton(anim, character.getAnimOffset(anim), false, -1, false);
|
||||
|
||||
addButton = new UIButton(25, 16+((32+16)*(character.animation.getNameList().length)), "", null, 429);
|
||||
addButton.cameras = [CharacterEditor.instance.animsCamera];
|
||||
addButton.color = FlxColor.GREEN;
|
||||
|
||||
addIcon = new FlxSprite(addButton.x + (440/2) - 8, addButton.y + (32/2) - 8).loadGraphic(Paths.image('editors/charter/add-button'));
|
||||
addIcon.cameras = [CharacterEditor.instance.animsCamera];
|
||||
addIcon.antialiasing = false;
|
||||
addButton.members.push(addIcon);
|
||||
|
||||
members.push(addButton);
|
||||
updateButtonsPos();
|
||||
}
|
||||
|
||||
public function createNewButton(anim:String, offset:FlxPoint, ghost:Bool = false, id:Int = -1, updatePos:Bool = true) {
|
||||
var button = new CharacterAnimButtons(0,0, anim, offset);
|
||||
if (id == -1) buttons.add(button);
|
||||
else buttons.members.insert(id, button);
|
||||
animButtons.set(anim,button);
|
||||
|
||||
if (updatePos)
|
||||
updateButtonsPos();
|
||||
}
|
||||
|
||||
public function removeButton(anim:String) {
|
||||
var button:CharacterAnimButtons = animButtons.get(anim);
|
||||
buttons.members.remove(button);
|
||||
button.destroy();
|
||||
|
||||
updateButtonsPos();
|
||||
}
|
||||
|
||||
public function updateButtonsPos() {
|
||||
for (i => button in buttons.members)
|
||||
cast(button, CharacterAnimButtons).updatePos(23,16+((32+16)*i));
|
||||
|
||||
addButton.y = 16+((32+16)*(character.animation.getNameList().length));
|
||||
addIcon.x = addButton.x + (440/2) - 8; addIcon.y = addButton.y + (32/2) - 8;
|
||||
}
|
||||
|
||||
public inline function changeCurAnim(anim:String) {
|
||||
for (_anim => button in animButtons)
|
||||
button.alpha = _anim == anim ? 1 : 0.25;
|
||||
}
|
||||
|
||||
var scrollY:Float = 0;
|
||||
|
||||
public override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
|
||||
__rect.x = x; __rect.y = y;
|
||||
__rect.width = bWidth; __rect.height = bHeight;
|
||||
if(UIState.state.isOverlapping(this, __rect)) {
|
||||
var nextscrollY = scrollY - FlxG.mouse.wheel * 12;
|
||||
if (nextscrollY >= 0 && nextscrollY + CharacterEditor.instance.animsCamera.height <= (addButton.y +32 +26))
|
||||
scrollY = nextscrollY;
|
||||
hovered = true;
|
||||
} else
|
||||
hovered = false;
|
||||
|
||||
CharacterEditor.instance.animsCamera.scroll.y = FlxMath.lerp(CharacterEditor.instance.animsCamera.scroll.y, scrollY, 1/3);
|
||||
|
||||
//addButtonIndicator.y = CharacterEditor.instance.animsCamera.height - addButtonIndicator.width + CharacterEditor.instance.animsCamera.scroll.y;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ghostButton = new UIButton(x+282+17, y, "", null, 32);
|
||||
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, "", null, 32);
|
||||
members.push(editButton);
|
||||
|
||||
editIcon = new FlxSprite(editButton.x + 8, editButton.y + 8).loadGraphic(Paths.image('editors/character/edit-button'));
|
||||
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;
|
||||
members.push(deleteButton);
|
||||
|
||||
deleteIcon = new FlxSprite(deleteButton.x + (15/2), deleteButton.y + 8).loadGraphic(Paths.image('editors/character/delete-button'));
|
||||
deleteIcon.antialiasing = false;
|
||||
members.push(deleteIcon);
|
||||
}
|
||||
|
||||
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(x:Float, y:Float) {
|
||||
// buttons
|
||||
this.x = x; this.y = ghostButton.y = editButton.y = deleteButton.y = y;
|
||||
deleteButton.x = (editButton.x = (ghostButton.x = (x+282+17))+32+17)+32+17;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import haxe.xml.Printer;
|
||||
import sys.io.File;
|
||||
import sys.FileSystem;
|
||||
import flixel.group.FlxGroup;
|
||||
import haxe.xml.Access;
|
||||
import haxe.Exception;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.game.Character.CharacterData;
|
||||
|
||||
class CharacterConfig extends FlxTypedGroup<FlxBasic>
|
||||
{
|
||||
public static var DEFAULT_CHARACTER = "bf";
|
||||
|
||||
public static function loadCharacterData(character:String):CharacterData
|
||||
{
|
||||
var xml:Access;
|
||||
|
||||
var charData:CharacterData = {
|
||||
offsetY: 0,
|
||||
offsetX: 0,
|
||||
camOffsetY: 0,
|
||||
camOffsetX: 0,
|
||||
quickDancer: false,
|
||||
icon: character,
|
||||
iconColor: FlxColor.fromRGB(94, 94, 94),
|
||||
scale: 1,
|
||||
isPlayer: false,
|
||||
isGF: false,
|
||||
holdTime: 4,
|
||||
flipX: false,
|
||||
antialiasing: true,
|
||||
sprite: "bf",
|
||||
name: character,
|
||||
animations: []
|
||||
}
|
||||
|
||||
var xmlPath = Paths.xml('characters/$character');
|
||||
|
||||
var plainXML = Assets.getText(xmlPath);
|
||||
try
|
||||
{
|
||||
var charXML = Xml.parse(plainXML).firstElement();
|
||||
if (charXML == null)
|
||||
throw new Exception("Missing \"character\" node in XML.");
|
||||
xml = new Access(charXML);
|
||||
}
|
||||
|
||||
charData = xmlToData(charData, xml);
|
||||
|
||||
return charData;
|
||||
}
|
||||
|
||||
public static function xmlToData(charData:CharacterData, xml:Access):CharacterData
|
||||
{
|
||||
if (xml.has.isPlayer)
|
||||
charData.isPlayer = (xml.att.isPlayer == "true");
|
||||
if (xml.has.isGF)
|
||||
charData.isGF = (xml.att.isGF == "true");
|
||||
if (xml.has.x)
|
||||
charData.offsetX = Std.parseFloat(xml.att.x);
|
||||
if (xml.has.y)
|
||||
charData.offsetY = Std.parseFloat(xml.att.y);
|
||||
if (xml.has.gameOverChar)
|
||||
charData.gameOverChar = xml.att.gameOverChar;
|
||||
if (xml.has.camx)
|
||||
charData.camOffsetX = Std.parseFloat(xml.att.camx);
|
||||
if (xml.has.camy)
|
||||
charData.camOffsetY = Std.parseFloat(xml.att.camy);
|
||||
if (xml.has.holdTime)
|
||||
charData.holdTime = CoolUtil.getDefault(Std.parseFloat(xml.att.holdTime), 4);
|
||||
if (xml.has.flipX)
|
||||
charData.flipX = (xml.att.flipX == "true");
|
||||
if (xml.has.icon)
|
||||
charData.icon = xml.att.icon;
|
||||
if (xml.has.iconColor)
|
||||
charData.iconColor = stringToRGB(xml.att.iconColor);
|
||||
if (xml.has.scale)
|
||||
{
|
||||
var scale = Std.parseFloat(xml.att.scale).getDefault(1);
|
||||
charData.scale = scale;
|
||||
}
|
||||
if (xml.has.antialiasing)
|
||||
charData.antialiasing = (xml.att.antialiasing == "true");
|
||||
if (xml.has.sprite)
|
||||
charData.sprite = xml.att.sprite;
|
||||
else
|
||||
charData.sprite = charData.name;
|
||||
|
||||
for (anim in xml.nodes.anim)
|
||||
{
|
||||
var animType:XMLAnimType = NONE;
|
||||
var animloop = false;
|
||||
if (anim.has.loop)
|
||||
animloop = (anim.att.loop == "true");
|
||||
charData.animations.push(XMLUtil.extractAnimFromXML(anim, animType, animloop));
|
||||
}
|
||||
return charData;
|
||||
}
|
||||
|
||||
public static function dataToXml(charData:CharacterData):Access
|
||||
{
|
||||
var root = Xml.createElement("character");
|
||||
root.set("x", Std.string(Math.floor(charData.offsetX)));
|
||||
root.set("y", Std.string(Math.floor(charData.offsetY)));
|
||||
root.set("gameOverChar", Std.string(charData.gameOverChar));
|
||||
root.set("camx", Std.string(Math.floor(charData.camOffsetX)));
|
||||
root.set("camy", Std.string(Math.floor(charData.camOffsetY)));
|
||||
root.set("holdTime", Std.string(charData.holdTime));
|
||||
root.set("flipX", Std.string(charData.flipX));
|
||||
root.set("icon", charData.icon);
|
||||
root.set("iconColor", Std.string(charData.iconColor));
|
||||
root.set("scale", Std.string(charData.scale));
|
||||
root.set("antialiasing", Std.string(charData.antialiasing));
|
||||
root.set("sprite", Std.string(charData.sprite));
|
||||
root.set("isPlayer", Std.string(charData.isPlayer));
|
||||
root.set("isGF", Std.string(charData.isGF));
|
||||
|
||||
for (anim in charData.animations)
|
||||
{
|
||||
var child:Xml = Xml.createElement('anim');
|
||||
child.set("name", Std.string(anim.name));
|
||||
child.set("anim", Std.string(anim.anim));
|
||||
child.set("loop", Std.string(anim.loop));
|
||||
child.set("fps", Std.string(anim.fps));
|
||||
child.set("x", Std.string(anim.x));
|
||||
child.set("y", Std.string(anim.y));
|
||||
child.set("indices", Std.string(anim.indices));
|
||||
root.addChild(child);
|
||||
}
|
||||
var xml = new Access(Xml.parse('${root.toString()}'));
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
public static function stringToRGB(rgbColor:String):FlxColor
|
||||
{
|
||||
var colorSplit = rgbColor.split(",");
|
||||
if (colorSplit[0] != null && colorSplit[1] != null && colorSplit[2] != null)
|
||||
return FlxColor.fromRGB(Std.parseInt(colorSplit[0]), Std.parseInt(colorSplit[1]), Std.parseInt(colorSplit[2]));
|
||||
else
|
||||
return FlxColor.fromRGB(90,90,90);
|
||||
}
|
||||
|
||||
public static function rgbToString(color:FlxColor):String
|
||||
return '${color.red}, ${color.green}, ${color.blue}';
|
||||
/**
|
||||
* @return Saves the character to the specific song folder path.
|
||||
*/
|
||||
public static function save(character:String, xml:String):String
|
||||
{
|
||||
var charPath = '';
|
||||
var data = '$xml';
|
||||
#if sys
|
||||
var charPath = '${character}';
|
||||
|
||||
File.saveContent(charPath, data);
|
||||
|
||||
// idk how null reacts to it so better be sure
|
||||
#end
|
||||
return xml;
|
||||
}
|
||||
|
||||
public static function generateCharXML(xml:Xml):String
|
||||
{
|
||||
return '<!DOCTYPE codename-engine-character>\n${Printer.print(xml, true)}';
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,125 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import funkin.game.Character;
|
||||
|
||||
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 positionXStepper:UINumericStepper;
|
||||
public var positionYStepper:UINumericStepper;
|
||||
public var cameraXStepper:UINumericStepper;
|
||||
public var cameraYStepper:UINumericStepper;
|
||||
public var scaleStepper:UINumericStepper;
|
||||
public var singTimeStepper:UINumericStepper;
|
||||
public var isPlayerCheckbox:UICheckbox;
|
||||
public var isGFCheckbox:UICheckbox;
|
||||
public var flipXCheckbox:UICheckbox;
|
||||
public var antialiasingCheckbox:UICheckbox;
|
||||
|
||||
public var saveButton:UIButton;
|
||||
public var closeButton:UIButton;
|
||||
|
||||
public function new(character:Character) {
|
||||
super();
|
||||
this.character = character;
|
||||
}
|
||||
|
||||
public override function create() {
|
||||
winTitle = "Editing Character";
|
||||
winWidth = 960;
|
||||
|
||||
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 + 16), iconTextBox.y, character.gameOverCharacter, 200);
|
||||
add(gameOverCharTextBox);
|
||||
addLabelOn(gameOverCharTextBox, "Game Over Character");
|
||||
|
||||
add(title = new UIText(spriteTextBox.x, spriteTextBox.y + 10 + 46, 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 Time");
|
||||
|
||||
isPlayerCheckbox = new UICheckbox(positionXStepper.x, positionXStepper.y + 10 + 32 + 26, "isPlayer", character.playerOffsets);
|
||||
add(isPlayerCheckbox);
|
||||
addLabelOn(isPlayerCheckbox, "Is Player");
|
||||
|
||||
for (checkbox in [isPlayerCheckbox])
|
||||
{checkbox.y += 6; checkbox.x += 4;}
|
||||
|
||||
saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight- 20, "Save & Close", function() {
|
||||
close();
|
||||
}, 125);
|
||||
saveButton.x -= saveButton.bWidth;
|
||||
saveButton.y -= saveButton.bHeight;
|
||||
|
||||
closeButton = new UIButton(saveButton.x - 20, saveButton.y, "Close", function() {
|
||||
close();
|
||||
}, 125);
|
||||
closeButton.x -= closeButton.bWidth;
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.backend.utils.XMLUtil.AnimData;
|
||||
import funkin.game.Character;
|
||||
|
||||
class CharacterProperties extends UISubstateWindow
|
||||
{
|
||||
public var char:Character;
|
||||
public var ghostChar:Character;
|
||||
public var charData:CharacterData;
|
||||
|
||||
public var applyButton:UIButton;
|
||||
public var cancelButton:UIButton;
|
||||
public var editor:CharacterEditor;
|
||||
|
||||
public var curAnimData:AnimData;
|
||||
|
||||
public var spriteFile:UITextBox;
|
||||
public var gameOverChar:UITextBox;
|
||||
public var healthIcon:UITextBox;
|
||||
public var iconColor:UITextBox;
|
||||
public var flipX:UICheckbox;
|
||||
public var isPlayer:UICheckbox;
|
||||
public var isGF:UICheckbox;
|
||||
public var antialiasing:UICheckbox;
|
||||
public var scale:UITextBox;
|
||||
public var holdTime:UITextBox;
|
||||
|
||||
public function new(char:Character, ghostChar, editor:CharacterEditor)
|
||||
{
|
||||
super();
|
||||
this.char = char;
|
||||
this.ghostChar = ghostChar;
|
||||
this.charData = char.characterData;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
public override function create()
|
||||
{
|
||||
winTitle = 'Character Properties';
|
||||
winWidth = 960;
|
||||
|
||||
super.create();
|
||||
|
||||
// Offsets
|
||||
var y_ofs = 60;
|
||||
var x_ofs = 60;
|
||||
var y_text_ofs = 20;
|
||||
|
||||
// Character Properties
|
||||
spriteFile = new UITextBox(windowSpr.x + 50, windowSpr.y + 10 + y_ofs, charData.sprite);
|
||||
add(spriteFile);
|
||||
add(new UIText(spriteFile.x, spriteFile.y - y_text_ofs, -1, "Image/Atlas file: "));
|
||||
|
||||
gameOverChar = new UITextBox(spriteFile.x + spriteFile.bWidth + x_ofs, spriteFile.y, charData.gameOverChar);
|
||||
add(gameOverChar);
|
||||
add(new UIText(gameOverChar.x, gameOverChar.y - y_text_ofs, -1, "Game Over character: "));
|
||||
|
||||
healthIcon = new UITextBox(spriteFile.x, spriteFile.y + y_ofs, charData.icon);
|
||||
add(healthIcon);
|
||||
add(new UIText(healthIcon.x, healthIcon.y - y_text_ofs, -1, "Health Icon: "));
|
||||
|
||||
iconColor = new UITextBox(healthIcon.x + healthIcon.bWidth + x_ofs, healthIcon.y, CharacterConfig.rgbToString(charData.iconColor));
|
||||
add(iconColor);
|
||||
add(new UIText(iconColor.x, iconColor.y - y_text_ofs, -1, "Icon color (RGB): "));
|
||||
|
||||
flipX = new UICheckbox(healthIcon.x, healthIcon.y + y_ofs, "Flip X", charData.flipX);
|
||||
add(flipX);
|
||||
|
||||
antialiasing = new UICheckbox(flipX.x + flipX.field.width + x_ofs, flipX.y, "Antialiasing", charData.antialiasing);
|
||||
add(antialiasing);
|
||||
|
||||
isPlayer = new UICheckbox(flipX.x, flipX.y + y_ofs, "Playable Character", charData.isPlayer);
|
||||
add(isPlayer);
|
||||
|
||||
isGF = new UICheckbox(isPlayer.x + isPlayer.field.width + x_ofs, isPlayer.y, "GF Character", charData.isGF);
|
||||
add(isGF);
|
||||
|
||||
scale = new UITextBox(isPlayer.x, isPlayer.y + y_ofs, Std.string(charData.scale));
|
||||
add(scale);
|
||||
add(new UIText(scale.x, scale.y - y_text_ofs, -1, "Scale: "));
|
||||
|
||||
holdTime = new UITextBox(scale.x + scale.bWidth + y_ofs, scale.y, Std.string(charData.holdTime));
|
||||
add(holdTime);
|
||||
add(new UIText(holdTime.x, holdTime.y - y_text_ofs, -1, "Hold time: "));
|
||||
|
||||
// Apply / Cancel buttons
|
||||
applyButton = new UIButton(windowSpr.x - x_ofs - 70, windowSpr.y, "Apply", function()
|
||||
{
|
||||
updateProperties(spriteFile.label.text, healthIcon.label.text, CharacterConfig.stringToRGB(healthIcon.label.text), flipX.checked,
|
||||
antialiasing.checked, isPlayer.checked, isGF.checked, Std.parseFloat(scale.label.text), Std.parseFloat(holdTime.label.text), gameOverChar.label.text);
|
||||
});
|
||||
add(applyButton);
|
||||
|
||||
cancelButton = new UIButton(applyButton.x, applyButton.y + y_ofs, "Cancel", function()
|
||||
{
|
||||
close();
|
||||
});
|
||||
add(cancelButton);
|
||||
}
|
||||
|
||||
public function updateProperties(sprite:String, healthIcon:String, iconColor:FlxColor, flipX:Bool, antialiasing:Bool, isPlayer:Bool, isGF:Bool,
|
||||
scale:Float, holdTime:Float, gameOverChar:String)
|
||||
{
|
||||
// Character Data
|
||||
charData.sprite = sprite;
|
||||
charData.icon = healthIcon;
|
||||
charData.iconColor = iconColor;
|
||||
charData.flipX = flipX;
|
||||
charData.antialiasing = antialiasing;
|
||||
charData.isPlayer = isPlayer;
|
||||
charData.isGF = isGF;
|
||||
charData.scale = scale;
|
||||
charData.holdTime = holdTime;
|
||||
charData.gameOverChar = gameOverChar;
|
||||
|
||||
editor.reloadChar(!char.isPlayer, charData);
|
||||
editor.reloadStage();
|
||||
editor.loadCross();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
class CharacterPropertiesWindow extends UIWindow {
|
||||
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package funkin.editors.character;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.game.Character;
|
||||
import funkin.backend.chart.Chart;
|
||||
import funkin.game.Character.CharacterData;
|
||||
import funkin.options.type.TextOption;
|
||||
import funkin.options.type.IconOption;
|
||||
import funkin.options.OptionsScreen;
|
||||
@@ -11,77 +10,18 @@ import sys.FileSystem;
|
||||
|
||||
class CharacterSelection extends EditorTreeMenu
|
||||
{
|
||||
public var characterList:CharactersList;
|
||||
|
||||
public override function create()
|
||||
{
|
||||
bgType = "charter";
|
||||
|
||||
super.create();
|
||||
|
||||
characterList = CharactersList.get();
|
||||
|
||||
main = new OptionsScreen("Character Editor", "Select a character to edit", [
|
||||
for (s in characterList.characters)
|
||||
new IconOption(s.name, "Press ACCEPT to edit this character.", s.icon, function()
|
||||
{
|
||||
FlxG.switchState(new CharacterEditor(s.name));
|
||||
for (char in Character.getList())
|
||||
new IconOption(char, "Press ACCEPT to edit this character.", Character.getIconFromCharName(char),
|
||||
function() {
|
||||
FlxG.switchState(new CharacterEditor(char));
|
||||
})
|
||||
]);
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float)
|
||||
{
|
||||
super.update(elapsed);
|
||||
}
|
||||
|
||||
public override function onMenuChange() {
|
||||
super.onMenuChange();
|
||||
if (optionsTree.members.length > 1) { // selected a song
|
||||
// small flashbang
|
||||
var color:FlxColor = characterList.characters[main.curSelected].iconColor.getDefault(0xFFFFFFFF);
|
||||
|
||||
bg.colorTransform.redOffset = 0.25 * color.red;
|
||||
bg.colorTransform.greenOffset = 0.25 * color.green;
|
||||
bg.colorTransform.blueOffset = 0.25 * color.blue;
|
||||
bg.colorTransform.redMultiplier = FlxMath.lerp(1, color.redFloat, 0.25);
|
||||
bg.colorTransform.greenMultiplier = FlxMath.lerp(1, color.greenFloat, 0.25);
|
||||
bg.colorTransform.blueMultiplier = FlxMath.lerp(1, color.blueFloat, 0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CharactersList
|
||||
{
|
||||
public var characters:Array<CharacterData> = [];
|
||||
|
||||
public function new()
|
||||
{
|
||||
}
|
||||
|
||||
public function getCharactersFromSource(source:funkin.backend.assets.AssetsLibraryList.AssetSource)
|
||||
{
|
||||
var charactersFound:Array<String> = [];
|
||||
|
||||
charactersFound = Paths.getFolderContent('data/characters', false, source);
|
||||
|
||||
if (charactersFound.length > 0)
|
||||
{
|
||||
for (s in charactersFound)
|
||||
if (s.endsWith(".xml"))
|
||||
characters.push(CharacterConfig.loadCharacterData(s.replace(".xml", "")));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function get()
|
||||
{
|
||||
var characterList = new CharactersList();
|
||||
|
||||
if (!characterList.getCharactersFromSource(MODS))
|
||||
characterList.getCharactersFromSource(SOURCE);
|
||||
|
||||
return characterList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import flixel.math.FlxRandom;
|
||||
import cpp.Random;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.backend.utils.XMLUtil.AnimData;
|
||||
import funkin.game.Character;
|
||||
|
||||
class DeleteAnimScreen extends UISubstateWindow
|
||||
{
|
||||
public var char:Character;
|
||||
public var ghostChar:Character;
|
||||
|
||||
public var editor:CharacterEditor;
|
||||
|
||||
public var animButtons:FlxTypedSpriteGroup<UIButton> = new FlxTypedSpriteGroup<UIButton>(365, -10);
|
||||
|
||||
public var closeButton:UIButton;
|
||||
|
||||
public function new(char:Character, ghostChar:Character, editor:CharacterEditor)
|
||||
{
|
||||
super();
|
||||
this.char = char;
|
||||
this.ghostChar = ghostChar;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
public override function create()
|
||||
{
|
||||
winTitle = "Delete Animation";
|
||||
winWidth = 480;
|
||||
winHeight = 700;
|
||||
|
||||
super.create();
|
||||
|
||||
add(animButtons);
|
||||
|
||||
var y_adder = 60;
|
||||
for (anim in char.characterData.animations)
|
||||
{
|
||||
var newbutton = new UIButton(animButtons.x - 550, animButtons.y + y_adder, anim.name, function()
|
||||
{
|
||||
removeAnimation(anim);
|
||||
close();
|
||||
});
|
||||
animButtons.add(newbutton);
|
||||
y_adder += 45;
|
||||
}
|
||||
|
||||
closeButton = new UIButton(windowSpr.x - 120, windowSpr.y + 20, "Close", function() {
|
||||
close();
|
||||
});
|
||||
add(closeButton);
|
||||
}
|
||||
|
||||
public function removeAnimation(anim:AnimData)
|
||||
{
|
||||
var refreshAnim:Bool = false;
|
||||
if (char.animation.curAnim != null && anim.name == char.animation.curAnim.name)
|
||||
refreshAnim = true;
|
||||
|
||||
if (char.animation.getByName(anim.name) != null)
|
||||
char.animation.remove(anim.name);
|
||||
if (char.animOffsets.exists(anim.name))
|
||||
char.animOffsets.remove(anim.name);
|
||||
char.characterData.animations.remove(anim);
|
||||
|
||||
if (refreshAnim && char.characterData.animations.length > 0)
|
||||
char.playAnim(char.characterData.animations[0].name, true);
|
||||
|
||||
editor.reloadGhost();
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
class HelpControls extends UISubstateWindow
|
||||
{
|
||||
|
||||
var helpTextTitles:Array<String> = [
|
||||
"Camera:",
|
||||
"Offset:",
|
||||
"Animation:"
|
||||
];
|
||||
var helpTexts:Array<String> = [
|
||||
"\n\n- WASD: Move camera\n\n- I & O: Zoom In & Out.",
|
||||
"\n\n- Arrows keys: Move the offset of the current\nanimation.\n\n- Left Click: Move the offset of the character",
|
||||
"\n\n- K & L: Switch to previous & next animation\n\n- SPACE: Play current animation.\n\n"
|
||||
];
|
||||
|
||||
var curPage:Int = 0;
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public override function create()
|
||||
{
|
||||
winTitle = 'Help: Controls';
|
||||
winWidth = 960;
|
||||
|
||||
super.create();
|
||||
|
||||
var helpTextTitle = new UIText(windowSpr.x + 25, windowSpr.y + 45, -1, helpTextTitles[0], 36);
|
||||
add(helpTextTitle);
|
||||
|
||||
var helpText = new UIText(windowSpr.x + 25, windowSpr.y + 50, -1, helpTexts[0], 24);
|
||||
add(helpText);
|
||||
|
||||
var pageText = new UIText(855, windowSpr.y + 460, -1, '${curPage+1}/${helpTexts.length}', 24);
|
||||
add(pageText);
|
||||
|
||||
var rightButton = new UIButton(885, windowSpr.y + 500, ">", function()
|
||||
{
|
||||
if(curPage == helpTexts.length-1)
|
||||
curPage = 0;
|
||||
else
|
||||
curPage++;
|
||||
|
||||
pageText.text = '${curPage+1}/${helpTexts.length}';
|
||||
helpText.text = helpTexts[curPage];
|
||||
helpTextTitle.text = helpTextTitles[curPage];
|
||||
}, 32);
|
||||
|
||||
var leftButton = new UIButton(845, windowSpr.y + 500, "<", function()
|
||||
{
|
||||
if(curPage == 0)
|
||||
curPage = helpTexts.length-1;
|
||||
else
|
||||
curPage--;
|
||||
|
||||
pageText.text = '${curPage+1}/${helpTexts.length}';
|
||||
helpText.text = helpTexts[curPage];
|
||||
helpTextTitle.text = helpTextTitles[curPage];
|
||||
}, 32);
|
||||
|
||||
var closeButton = new UIButton(helpText.x, windowSpr.y + 500, "Close", function()
|
||||
{
|
||||
close();
|
||||
});
|
||||
add(closeButton);
|
||||
add(leftButton);
|
||||
add(rightButton);
|
||||
}
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.backend.utils.XMLUtil.AnimData;
|
||||
import funkin.game.Character;
|
||||
import funkin.editors.character.DeleteAnimScreen;
|
||||
|
||||
class NewCharacter extends UISubstateWindow
|
||||
{
|
||||
public var char:Character;
|
||||
public var ghostChar:Character;
|
||||
public var charData:CharacterData;
|
||||
|
||||
public var applyButton:UIButton;
|
||||
public var nextButton:UIButton;
|
||||
public var cancelButton:UIButton;
|
||||
public var editor:CharacterEditor;
|
||||
|
||||
public var curAnimData:AnimData;
|
||||
|
||||
public var spriteFile:UITextBox;
|
||||
public var gameOverChar:UITextBox;
|
||||
public var healthIcon:UITextBox;
|
||||
public var iconColor:UITextBox;
|
||||
public var flipX:UICheckbox;
|
||||
public var isPlayer:UICheckbox;
|
||||
public var isGF:UICheckbox;
|
||||
public var antialiasing:UICheckbox;
|
||||
public var scale:UITextBox;
|
||||
public var holdTime:UITextBox;
|
||||
|
||||
public function new(char:Character, ghostChar, editor:CharacterEditor)
|
||||
{
|
||||
super();
|
||||
this.char = char;
|
||||
this.ghostChar = ghostChar;
|
||||
this.charData = char.characterData;
|
||||
this.editor = editor;
|
||||
|
||||
//TO DO: Generate and Save
|
||||
//----
|
||||
|
||||
|
||||
//Delete old Animaitons
|
||||
}
|
||||
|
||||
public override function create()
|
||||
{
|
||||
winTitle = 'Create New Character';
|
||||
winWidth = 960;
|
||||
|
||||
super.create();
|
||||
|
||||
// Offsets
|
||||
var y_ofs = 60;
|
||||
var x_ofs = 60;
|
||||
var y_text_ofs = 20;
|
||||
|
||||
// Character Properties
|
||||
spriteFile = new UITextBox(windowSpr.x + 50, windowSpr.y + 10 + y_ofs, charData.sprite);
|
||||
add(spriteFile);
|
||||
add(new UIText(spriteFile.x, spriteFile.y - y_text_ofs, -1, "Image/Atlas file: "));
|
||||
|
||||
gameOverChar = new UITextBox(spriteFile.x + spriteFile.bWidth + x_ofs, spriteFile.y, charData.gameOverChar);
|
||||
add(gameOverChar);
|
||||
add(new UIText(gameOverChar.x, gameOverChar.y - y_text_ofs, -1, "Game Over character: "));
|
||||
|
||||
healthIcon = new UITextBox(spriteFile.x, spriteFile.y + y_ofs, charData.icon);
|
||||
add(healthIcon);
|
||||
add(new UIText(healthIcon.x, healthIcon.y - y_text_ofs, -1, "Health Icon: "));
|
||||
|
||||
iconColor = new UITextBox(healthIcon.x + healthIcon.bWidth + x_ofs, healthIcon.y, CharacterConfig.rgbToString(charData.iconColor));
|
||||
add(iconColor);
|
||||
add(new UIText(iconColor.x, iconColor.y - y_text_ofs, -1, "Icon color (RGB): "));
|
||||
|
||||
flipX = new UICheckbox(healthIcon.x, healthIcon.y + y_ofs, "Flip X", charData.flipX);
|
||||
add(flipX);
|
||||
|
||||
antialiasing = new UICheckbox(flipX.x + flipX.field.width + x_ofs, flipX.y, "Antialiasing", charData.antialiasing);
|
||||
add(antialiasing);
|
||||
|
||||
isPlayer = new UICheckbox(flipX.x, flipX.y + y_ofs, "Playable Character", charData.isPlayer);
|
||||
add(isPlayer);
|
||||
|
||||
isGF = new UICheckbox(isPlayer.x + isPlayer.field.width + x_ofs, isPlayer.y, "GF Character", charData.isGF);
|
||||
add(isGF);
|
||||
|
||||
scale = new UITextBox(isPlayer.x, isPlayer.y + y_ofs, Std.string(charData.scale));
|
||||
add(scale);
|
||||
add(new UIText(scale.x, scale.y - y_text_ofs, -1, "Scale: "));
|
||||
|
||||
holdTime = new UITextBox(scale.x + scale.bWidth + y_ofs, scale.y, Std.string(charData.holdTime));
|
||||
add(holdTime);
|
||||
add(new UIText(holdTime.x, holdTime.y - y_text_ofs, -1, "Hold time: "));
|
||||
|
||||
// Apply / Cancel buttons
|
||||
|
||||
|
||||
applyButton = new UIButton(windowSpr.x - x_ofs - 70, windowSpr.y, "Apply", function()
|
||||
{
|
||||
|
||||
updateProperties(spriteFile.label.text, healthIcon.label.text, CharacterConfig.stringToRGB(healthIcon.label.text), flipX.checked,
|
||||
antialiasing.checked, isPlayer.checked, isGF.checked, Std.parseFloat(scale.label.text), Std.parseFloat(holdTime.label.text), gameOverChar.label.text);
|
||||
|
||||
//TO DO: Add a Animation
|
||||
});
|
||||
add(applyButton);
|
||||
|
||||
cancelButton = new UIButton(applyButton.x, applyButton.y + y_ofs, "Cancel", function()
|
||||
{
|
||||
close();
|
||||
});
|
||||
add(cancelButton);
|
||||
}
|
||||
|
||||
public function updateProperties(sprite:String, healthIcon:String, iconColor:FlxColor, flipX:Bool, antialiasing:Bool, isPlayer:Bool, isGF:Bool,
|
||||
scale:Float, holdTime:Float, gameOverChar:String)
|
||||
{
|
||||
// Character Data
|
||||
charData.sprite = sprite;
|
||||
charData.icon = healthIcon;
|
||||
charData.iconColor = iconColor;
|
||||
charData.flipX = flipX;
|
||||
charData.antialiasing = antialiasing;
|
||||
charData.isPlayer = isPlayer;
|
||||
charData.isGF = isGF;
|
||||
charData.scale = scale;
|
||||
charData.holdTime = holdTime;
|
||||
charData.gameOverChar = gameOverChar;
|
||||
|
||||
//Bring Player Char to Default Position for User
|
||||
if(isPlayer)
|
||||
{
|
||||
charData.offsetX = 770;
|
||||
charData.offsetY = 410;
|
||||
}
|
||||
else if(isGF)
|
||||
{
|
||||
charData.offsetX = 400;
|
||||
charData.offsetY = 330;
|
||||
}
|
||||
else
|
||||
{
|
||||
charData.offsetX = 100;
|
||||
charData.offsetY = 410;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
editor.reloadChar(!char.isPlayer, charData);
|
||||
editor.reloadStage();
|
||||
editor.loadCross();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function removeAnimation(anim:AnimData)
|
||||
{
|
||||
var refreshAnim:Bool = false;
|
||||
if (char.animation.curAnim != null && anim.name == char.animation.curAnim.name)
|
||||
refreshAnim = true;
|
||||
|
||||
if (char.animation.getByName(anim.name) != null)
|
||||
char.animation.remove(anim.name);
|
||||
if (char.animOffsets.exists(anim.name))
|
||||
char.animOffsets.remove(anim.name);
|
||||
char.characterData.animations.remove(anim);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import flixel.math.FlxRandom;
|
||||
import cpp.Random;
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.backend.utils.XMLUtil.AnimData;
|
||||
import funkin.game.Character;
|
||||
|
||||
class SelectAnimUpdate extends UISubstateWindow
|
||||
{
|
||||
public var cancelButton:UIButton;
|
||||
|
||||
public var char:Character;
|
||||
public var ghostChar:Character;
|
||||
|
||||
public var editor:CharacterEditor;
|
||||
|
||||
public var animButtons:FlxTypedSpriteGroup<UIButton> = new FlxTypedSpriteGroup<UIButton>(365, -10);
|
||||
|
||||
public function new(char:Character, ghostChar:Character, editor:CharacterEditor)
|
||||
{
|
||||
super();
|
||||
this.char = char;
|
||||
this.ghostChar = ghostChar;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
public override function create()
|
||||
{
|
||||
winTitle = "Select an animation to update:";
|
||||
winWidth = 480;
|
||||
winHeight = 700;
|
||||
|
||||
super.create();
|
||||
|
||||
add(animButtons);
|
||||
|
||||
var y_ofs = 60;
|
||||
|
||||
for (anim in char.characterData.animations)
|
||||
{
|
||||
var newbutton = new UIButton(animButtons.x - 550, animButtons.y + y_ofs, anim.name, function()
|
||||
{
|
||||
openUpdateWindow(anim);
|
||||
});
|
||||
animButtons.add(newbutton);
|
||||
y_ofs += 45;
|
||||
}
|
||||
|
||||
cancelButton = new UIButton(windowSpr.x - 10, windowSpr.y + 20, "Cancel", function()
|
||||
{
|
||||
close();
|
||||
});
|
||||
cancelButton.x -= cancelButton.bWidth;
|
||||
add(cancelButton);
|
||||
}
|
||||
|
||||
public function openUpdateWindow(anim:AnimData)
|
||||
{
|
||||
openSubState(new UpdateAnimScreen(this.char, this.ghostChar, anim, this.editor));
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package funkin.editors.character;
|
||||
|
||||
import flixel.math.FlxPoint;
|
||||
import funkin.backend.utils.XMLUtil.AnimData;
|
||||
import funkin.game.Character;
|
||||
|
||||
class UpdateAnimScreen extends UISubstateWindow
|
||||
{
|
||||
public var char:Character;
|
||||
public var ghostChar:Character;
|
||||
|
||||
public var updateButton:UIButton;
|
||||
public var cancelButton:UIButton;
|
||||
public var editor:CharacterEditor;
|
||||
|
||||
public var curAnimData:AnimData;
|
||||
|
||||
public var animName:UITextBox;
|
||||
public var animPrefix:UITextBox;
|
||||
public var fps:UITextBox;
|
||||
public var loop:UICheckbox;
|
||||
public var indices:UITextBox;
|
||||
|
||||
public function new(char:Character, ghostChar, animData:AnimData, editor:CharacterEditor)
|
||||
{
|
||||
super();
|
||||
this.char = char;
|
||||
this.ghostChar = ghostChar;
|
||||
this.curAnimData = animData;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
public override function create()
|
||||
{
|
||||
winTitle = 'Update Animation: ${curAnimData.name}';
|
||||
winWidth = 960;
|
||||
|
||||
super.create();
|
||||
|
||||
// Animation Properties
|
||||
var y_ofs = 60;
|
||||
var y_text_ofs = 20;
|
||||
|
||||
animName = new UITextBox(windowSpr.x + 50, windowSpr.y + y_ofs, curAnimData.name);
|
||||
add(animName);
|
||||
add(new UIText(animName.x, animName.y - y_text_ofs, -1, "Animation Name: "));
|
||||
|
||||
animPrefix = new UITextBox(animName.x, animName.y + y_ofs, curAnimData.anim);
|
||||
add(animPrefix);
|
||||
add(new UIText(animPrefix.x, animPrefix.y - y_text_ofs, -1, "Animation on XML/Atlas file: "));
|
||||
|
||||
fps = new UITextBox(animPrefix.x, animPrefix.y + y_ofs, Std.string(curAnimData.fps));
|
||||
add(fps);
|
||||
add(new UIText(fps.x, fps.y - y_text_ofs, -1, "Framerate: "));
|
||||
|
||||
loop = new UICheckbox(fps.x, fps.y + y_ofs, "Looped", curAnimData.loop);
|
||||
add(loop);
|
||||
|
||||
indices = new UITextBox(loop.x, loop.y + y_ofs, Std.string(curAnimData.indices).replace("[", "").replace("]", ""));
|
||||
add(indices);
|
||||
add(new UIText(indices.x, indices.y - y_text_ofs, -1, "Indices (0, 1, 2, 3): "));
|
||||
|
||||
// Add / Cancel Buttons
|
||||
updateButton = new UIButton(windowSpr.x - 10, windowSpr.y + 31, "Update", function()
|
||||
{
|
||||
updateAnimation(animName.label.text, animPrefix.label.text, Std.parseInt(fps.label.text), loop.checked, indices.label.text);
|
||||
close();
|
||||
});
|
||||
updateButton.x -= updateButton.bWidth;
|
||||
add(updateButton);
|
||||
|
||||
cancelButton = new UIButton(updateButton.x, updateButton.y + y_ofs, "Cancel", function()
|
||||
{
|
||||
close();
|
||||
});
|
||||
add(cancelButton);
|
||||
}
|
||||
|
||||
public function updateAnimation(name:String, ?anim:String, ?fps:Int = 24, ?looped:Bool = false, ?indices:String)
|
||||
{
|
||||
var animType:XMLAnimType = NONE;
|
||||
|
||||
var selectedAnim:AnimData = null;
|
||||
var selectedAnimIndex = 0;
|
||||
|
||||
for (i in 0...char.characterData.animations.length)
|
||||
{
|
||||
if (char.characterData.animations[i].name == name)
|
||||
{
|
||||
selectedAnim = char.characterData.animations[i];
|
||||
selectedAnimIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedAnim == null)
|
||||
return;
|
||||
|
||||
var animData:AnimData = {
|
||||
name: name,
|
||||
anim: anim,
|
||||
fps: fps,
|
||||
loop: looped,
|
||||
animType: animType,
|
||||
indices: [],
|
||||
x: selectedAnim.x,
|
||||
y: selectedAnim.y
|
||||
};
|
||||
|
||||
if (indices != "" && indices != null)
|
||||
{
|
||||
var indicesSplit = indices.split(",");
|
||||
|
||||
for (indice in indicesSplit)
|
||||
{
|
||||
var i = Std.parseInt(indice.trim());
|
||||
if (i != null)
|
||||
animData.indices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
XMLUtil.addAnimToSprite(char, animData);
|
||||
char.characterData.animations[selectedAnimIndex] = animData;
|
||||
char.playAnim(name, true);
|
||||
}
|
||||
}
|
||||
@@ -317,7 +317,6 @@ class Charter extends UIState {
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
hitsound = FlxG.sound.load(Paths.sound('editors/charter/hitsound'));
|
||||
metronome = FlxG.sound.load(Paths.sound('editors/charter/metronome'));
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package funkin.editors.ui;
|
||||
|
||||
class UIWindow extends UISliceSprite {
|
||||
public var titleSpr:UIText;
|
||||
|
||||
public override function new(x:Float, y:Float, w:Int, h:Int, title:String) {
|
||||
super(x, y, w, h, "editors/ui/warning-popup");
|
||||
|
||||
members.push(titleSpr = new UIText(x + 25, y, bWidth - 50, title, 15, -1));
|
||||
titleSpr.y = y + ((30 - titleSpr.height) / 2);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package funkin.game;
|
||||
|
||||
import funkin.editors.character.CharacterConfig;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.backend.FunkinSprite;
|
||||
import flixel.graphics.frames.FlxFrame;
|
||||
@@ -23,27 +22,6 @@ import funkin.backend.scripting.events.PlayAnimEvent.PlayAnimContext;
|
||||
|
||||
using StringTools;
|
||||
|
||||
typedef CharacterData =
|
||||
{
|
||||
var offsetX:Float;
|
||||
var offsetY:Float;
|
||||
var camOffsetX:Float;
|
||||
var camOffsetY:Float;
|
||||
var quickDancer:Bool;
|
||||
var holdTime:Float;
|
||||
var isPlayer:Bool;
|
||||
var flipX:Bool;
|
||||
var antialiasing:Bool;
|
||||
var sprite:String;
|
||||
var name:String;
|
||||
var animations:Array<AnimData>;
|
||||
@:optional var isGF:Bool;
|
||||
@:optional var icon:String;
|
||||
@:optional var iconColor:FlxColor;
|
||||
@:optional var scale:Float;
|
||||
@:optional var gameOverChar:String;
|
||||
}
|
||||
|
||||
@:allow(funkin.desktop.editors.CharacterEditor)
|
||||
@:allow(funkin.game.StrumLine)
|
||||
@:allow(funkin.game.PlayState)
|
||||
@@ -67,6 +45,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
public var isPlayer:Bool = false;
|
||||
public var isGF:Bool = false;
|
||||
public var curCharacter:String = 'bf';
|
||||
public var sprite:String = 'bf';
|
||||
|
||||
public var lastHit:Float = Math.NEGATIVE_INFINITY;
|
||||
public var holdTime:Float = 4;
|
||||
@@ -82,21 +61,14 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
public var script:Script;
|
||||
public var xml:Access;
|
||||
|
||||
public var characterData:CharacterData;
|
||||
|
||||
public var shadowFrame:CharacterShadowFrame;
|
||||
|
||||
public inline function getCameraPosition()
|
||||
{
|
||||
var midpoint = getMidpoint();
|
||||
var event = EventManager.get(PointEvent)
|
||||
.recycle(midpoint.x
|
||||
+ (isPlayer ? -100 : 150)
|
||||
+ globalOffset.x
|
||||
+ cameraOffset.x, midpoint.y
|
||||
- 100
|
||||
+ globalOffset.y
|
||||
+ cameraOffset.y);
|
||||
var event = EventManager.get(PointEvent).recycle(
|
||||
midpoint.x + (isPlayer ? -100 : 150) + globalOffset.x + cameraOffset.x,
|
||||
midpoint.y - 100 + globalOffset.y + cameraOffset.y);
|
||||
script.call("onGetCamPos", [event]);
|
||||
midpoint.put();
|
||||
// this event cannot be cancelled
|
||||
@@ -141,59 +113,16 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
try
|
||||
{
|
||||
var charXML = Xml.parse(plainXML).firstElement();
|
||||
if (charXML == null)
|
||||
throw new Exception("Missing \"character\" node in XML.");
|
||||
if (charXML == null) throw new Exception("Missing \"character\" node in XML.");
|
||||
xml = new Access(charXML);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
} catch (e) {
|
||||
Logs.trace('Error while loading character ${curCharacter}: ${e}', ERROR);
|
||||
curCharacter = "bf";
|
||||
continue;
|
||||
}
|
||||
var sprite:String = curCharacter;
|
||||
applyXML(xml);
|
||||
|
||||
if (xml.has.isPlayer)
|
||||
playerOffsets = (xml.att.isPlayer == "true");
|
||||
if (xml.has.isGF)
|
||||
isGF = (xml.att.isGF == "true");
|
||||
if (xml.has.x)
|
||||
globalOffset.x = Std.parseFloat(xml.att.x);
|
||||
if (xml.has.y)
|
||||
globalOffset.y = Std.parseFloat(xml.att.y);
|
||||
if (xml.has.gameOverChar)
|
||||
gameOverCharacter = xml.att.gameOverChar;
|
||||
if (xml.has.camx)
|
||||
cameraOffset.x = Std.parseFloat(xml.att.camx);
|
||||
if (xml.has.camy)
|
||||
cameraOffset.y = Std.parseFloat(xml.att.camy);
|
||||
if (xml.has.holdTime)
|
||||
holdTime = CoolUtil.getDefault(Std.parseFloat(xml.att.holdTime), 4);
|
||||
if (xml.has.flipX)
|
||||
flipX = (xml.att.flipX == "true");
|
||||
if (xml.has.icon)
|
||||
icon = xml.att.icon;
|
||||
if (xml.has.scale)
|
||||
{
|
||||
var scale = Std.parseFloat(xml.att.scale).getDefault(1);
|
||||
this.scale.set(scale, scale);
|
||||
updateHitbox();
|
||||
}
|
||||
if (xml.has.antialiasing)
|
||||
antialiasing = (xml.att.antialiasing == "true");
|
||||
if (xml.has.sprite)
|
||||
sprite = xml.att.sprite;
|
||||
|
||||
loadSprite(Paths.image('characters/$sprite'));
|
||||
|
||||
for (anim in xml.nodes.anim)
|
||||
{
|
||||
XMLUtil.addXMLAnimation(this, anim);
|
||||
}
|
||||
|
||||
characterData = CharacterConfig.loadCharacterData(curCharacter);
|
||||
|
||||
// Loads the script and calls it's "create" function
|
||||
// Loads the script and calls it's "create" functions
|
||||
script = Script.create(Paths.script(Path.withoutExtension(xmlPath), null, true));
|
||||
script.setParent(this);
|
||||
script.load();
|
||||
@@ -226,7 +155,6 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
// flipX = true;
|
||||
|
||||
fixChar(true);
|
||||
|
||||
dance();
|
||||
script.call("postCreate");
|
||||
}
|
||||
@@ -242,6 +170,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
// [ true ][ false ][ true ]
|
||||
// [ false ][ true ][ true ]
|
||||
// [ true ][ true ][ false ]
|
||||
// bros provided evedince :skull:
|
||||
if (isPlayer != playerOffsets && switchAnims)
|
||||
{
|
||||
// character is flipped
|
||||
@@ -302,8 +231,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
|
||||
public function tryDance()
|
||||
{
|
||||
switch (lastAnimContext)
|
||||
{
|
||||
switch (lastAnimContext) {
|
||||
case SING | MISS:
|
||||
if (lastHit + (Conductor.stepCrochet * holdTime) < Conductor.songPosition)
|
||||
dance();
|
||||
@@ -328,8 +256,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
*/
|
||||
public var danceInterval:Int = 1;
|
||||
|
||||
public override function beatHit(curBeat:Int)
|
||||
{
|
||||
public override function beatHit(curBeat:Int) {
|
||||
script.call("beatHit", [curBeat]);
|
||||
if (danceInterval < 1)
|
||||
danceInterval = 1;
|
||||
@@ -340,16 +267,14 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
}
|
||||
}
|
||||
|
||||
public override function stepHit(curStep:Int)
|
||||
{
|
||||
public override function stepHit(curStep:Int) {
|
||||
script.call("stepHit", [curStep]);
|
||||
// nothing
|
||||
}
|
||||
|
||||
var __reverseDrawProcedure:Bool = false;
|
||||
|
||||
public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect
|
||||
{
|
||||
public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect {
|
||||
if (__reverseDrawProcedure)
|
||||
{
|
||||
scale.x *= -1;
|
||||
@@ -363,10 +288,8 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
var __drawingShadowFrame = false;
|
||||
var __oldColorTransform = new ColorTransform();
|
||||
|
||||
public override function draw()
|
||||
{
|
||||
if (!__drawingShadowFrame && shadowFrame != null)
|
||||
{
|
||||
public override function draw() {
|
||||
if (!__drawingShadowFrame && shadowFrame != null) {
|
||||
__drawingShadowFrame = true;
|
||||
|
||||
var oldFrame = _frame;
|
||||
@@ -436,17 +359,77 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
globalOffset.put();
|
||||
}
|
||||
|
||||
public inline function getIcon()
|
||||
{
|
||||
return (icon != null) ? icon : curCharacter;
|
||||
public function applyXML(xml:Access) {
|
||||
sprite = curCharacter;
|
||||
|
||||
if (xml.has.isPlayer) playerOffsets = (xml.att.isPlayer == "true");
|
||||
if (xml.has.isGF) isGF = (xml.att.isGF == "true");
|
||||
if (xml.has.x) globalOffset.x = Std.parseFloat(xml.att.x); //
|
||||
if (xml.has.y) globalOffset.y = Std.parseFloat(xml.att.y); //
|
||||
if (xml.has.gameOverChar) gameOverCharacter = xml.att.gameOverChar; //
|
||||
if (xml.has.camx) cameraOffset.x = Std.parseFloat(xml.att.camx); //
|
||||
if (xml.has.camy) cameraOffset.y = Std.parseFloat(xml.att.camy); //
|
||||
if (xml.has.holdTime) holdTime = CoolUtil.getDefault(Std.parseFloat(xml.att.holdTime), 4); //
|
||||
if (xml.has.flipX) flipX = (xml.att.flipX == "true");
|
||||
if (xml.has.icon) icon = xml.att.icon; //
|
||||
if (xml.has.scale) { //
|
||||
var scale = Std.parseFloat(xml.att.scale).getDefault(1);
|
||||
this.scale.set(scale, scale);
|
||||
updateHitbox();
|
||||
}
|
||||
if (xml.has.antialiasing) antialiasing = (xml.att.antialiasing == "true");
|
||||
if (xml.has.sprite) sprite = xml.att.sprite; //
|
||||
|
||||
loadSprite(Paths.image('characters/$sprite'));
|
||||
|
||||
animation.destroyAnimations();
|
||||
for (anim in xml.nodes.anim)
|
||||
{
|
||||
XMLUtil.addXMLAnimation(this, anim);
|
||||
}
|
||||
}
|
||||
|
||||
public function buildXML():Xml {
|
||||
var xml = Xml.createElement("character");
|
||||
xml.set("isPlayer", playerOffsets == true ? "true" : "false");
|
||||
xml.set("isGF", isGF == true ? "true" : "false");
|
||||
xml.set("x", Std.string(globalOffset.x));
|
||||
xml.set("y", Std.string(globalOffset.y));
|
||||
xml.set("gameOverChar", gameOverCharacter);
|
||||
xml.set("camx", Std.string(cameraOffset.x));
|
||||
xml.set("camy", Std.string(cameraOffset.y));
|
||||
xml.set("holdTime", Std.string(holdTime));
|
||||
xml.set("flipX", Std.string(flipX));
|
||||
xml.set("icon", icon);
|
||||
xml.set("scale", Std.string(scale.x));
|
||||
xml.set("antialiasing", antialiasing == true ? "true" : "false");
|
||||
xml.set("sprite", sprite);
|
||||
|
||||
for (anim in animation.getAnimationList())
|
||||
{
|
||||
var animXml:Xml = Xml.createElement('anim');
|
||||
animXml.set("name", anim.name);
|
||||
animXml.set("anim", anim.prefix);
|
||||
animXml.set("loop", Std.string(anim.looped));
|
||||
animXml.set("fps", Std.string(anim.frameRate));
|
||||
var offset:FlxPoint = getAnimOffset(anim.name);
|
||||
animXml.set("x", Std.string(offset.x));
|
||||
animXml.set("y", Std.string(offset.y));
|
||||
if (anim.usesIndicies)
|
||||
animXml.set("indices", anim.frames.join(","));
|
||||
xml.addChild(animXml);
|
||||
}
|
||||
return xml;
|
||||
}
|
||||
|
||||
public inline function getIcon()
|
||||
return (icon != null) ? icon : curCharacter;
|
||||
|
||||
public static function getIconFromCharName(?curCharacter:String) {
|
||||
if(curCharacter == null) return "face";
|
||||
var icon = curCharacter;
|
||||
while(true) {
|
||||
switch (curCharacter)
|
||||
{
|
||||
switch (curCharacter) {
|
||||
// case 'your-char': // To hardcode characters icons
|
||||
default:
|
||||
// load xml
|
||||
@@ -474,6 +457,13 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
public static function getList():Array<String> {
|
||||
return [
|
||||
for (path in Paths.getFolderContent('data/characters/', true, BOTH))
|
||||
if (Path.extension(path) == "xml") Path.withoutDirectory(Path.withoutExtension(path))
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
typedef CharacterShadowFrame =
|
||||
|
||||
Reference in New Issue
Block a user