From 01b9756eb81e1faa0de6f480bddb0c1f5a62ee7f Mon Sep 17 00:00:00 2001 From: fgnm Date: Thu, 29 Apr 2021 01:01:27 +0200 Subject: [PATCH] Tiled Plugin improvements. * Support animated tiles (Sprite and Spine animation) * Improve UI * Support custom cursors * Bug fixes --- CHANGES | 6 + assets/plugins/plugin-tiled-0.0.7.jar | Bin 53106 -> 65918 bytes hyperlap2d-common-api | 2 +- hyperlap2d-runtime-libgdx | 2 +- .../tile.png => pack/tile-cursor.png} | Bin .../tile-eraser-cursor.png} | Bin plugin-tiled/assets/pack/tiled.atlas | 25 +--- plugin-tiled/assets/pack/tiled.png | Bin 6419 -> 5731 bytes .../assets/textures/plugin-tab-active.9.png | Bin 187 -> 0 bytes .../assets/textures/plugin-tab-inactive.9.png | Bin 166 -> 0 bytes .../assets/textures/tab-back-line.9.png | Bin 81 -> 0 bytes plugin-tiled/build.gradle | 3 + .../editor/plugin/tiled/TiledPanel.java | 22 ++- .../plugin/tiled/TiledPanelMediator.java | 82 ++++++----- .../editor/plugin/tiled/TiledPlugin.java | 10 +- .../editor/plugin/tiled/data/TileVO.java | 2 + .../tiled/manager/ResourcesManager.java | 61 ++++++-- .../editor/plugin/tiled/save/DataToSave.java | 3 +- .../plugin/tiled/tools/DeleteTileTool.java | 7 +- .../plugin/tiled/tools/DrawTileTool.java | 139 ++++++++---------- .../tools/drawStrategy/BasicDrawStrategy.java | 34 +++++ .../tools/drawStrategy/IDrawStrategy.java | 8 + .../tools/drawStrategy/ImageDrawStrategy.java | 49 ++++++ .../tools/drawStrategy/SpineDrawStrategy.java | 57 +++++++ .../drawStrategy/SpriteDrawStrategy.java | 64 ++++++++ .../plugin/tiled/view/SpineDrawable.java | 108 ++++++++++++++ .../plugin/tiled/view/tabs/GridTilesTab.java | 47 ++++-- .../editor/controller/BootstrapCommand.java | 4 +- .../ReplaceRegionCommand.java} | 14 +- .../component/ReplaceSpineCommand.java | 94 ++++++++++++ .../ReplaceSpriteAnimationCommand.java | 100 +++++++++++++ 31 files changed, 766 insertions(+), 177 deletions(-) rename plugin-tiled/assets/{textures/tile.png => pack/tile-cursor.png} (100%) rename plugin-tiled/assets/{textures/tile-eraser.png => pack/tile-eraser-cursor.png} (100%) delete mode 100644 plugin-tiled/assets/textures/plugin-tab-active.9.png delete mode 100644 plugin-tiled/assets/textures/plugin-tab-inactive.9.png delete mode 100644 plugin-tiled/assets/textures/tab-back-line.9.png create mode 100644 plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/BasicDrawStrategy.java create mode 100644 plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/IDrawStrategy.java create mode 100644 plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/ImageDrawStrategy.java create mode 100644 plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/SpineDrawStrategy.java create mode 100644 plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/SpriteDrawStrategy.java create mode 100644 plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/SpineDrawable.java rename src/main/java/games/rednblack/editor/controller/commands/{UpdateRegionCommand.java => component/ReplaceRegionCommand.java} (78%) create mode 100644 src/main/java/games/rednblack/editor/controller/commands/component/ReplaceSpineCommand.java create mode 100644 src/main/java/games/rednblack/editor/controller/commands/component/ReplaceSpriteAnimationCommand.java diff --git a/CHANGES b/CHANGES index 200df555..078c291e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +[0.0.7] += Editor = +- Huge improvements to Tiled Plugin: + * Sprite and Spine animated Tiles + * UI improvements and general refactoring + [0.0.6] - Update libGDX to 1.10.0 - Add flipX and flipY flag diff --git a/assets/plugins/plugin-tiled-0.0.7.jar b/assets/plugins/plugin-tiled-0.0.7.jar index f0371d63c90fb063fa37b1675545dc27c8140cd9..8f3e9355229793e56bed054e049fbbfdcc1c021a 100644 GIT binary patch delta 48824 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 D)nn<#0=@$+@?Z_2s2>dk5fy-ET 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 delta 36346 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 YFxO{q_Z@gZ5QrT3xdR?kZ##4JKcxO_c>n+a diff --git a/hyperlap2d-common-api b/hyperlap2d-common-api index 0a0603bf..b0cca697 160000 --- a/hyperlap2d-common-api +++ b/hyperlap2d-common-api @@ -1 +1 @@ -Subproject commit 0a0603bf88af552d890c41f477392ef3ef618a3e +Subproject commit b0cca697ccccef0fcb6122ae7b876a415611b650 diff --git a/hyperlap2d-runtime-libgdx b/hyperlap2d-runtime-libgdx index 7108be03..f20262c4 160000 --- a/hyperlap2d-runtime-libgdx +++ b/hyperlap2d-runtime-libgdx @@ -1 +1 @@ -Subproject commit 7108be03aa2915daa65d17c75bcdab01b781db48 +Subproject commit f20262c4b5e39695a14b80835f7aaca0321b2899 diff --git a/plugin-tiled/assets/textures/tile.png b/plugin-tiled/assets/pack/tile-cursor.png similarity index 100% rename from plugin-tiled/assets/textures/tile.png rename to plugin-tiled/assets/pack/tile-cursor.png diff --git a/plugin-tiled/assets/textures/tile-eraser.png b/plugin-tiled/assets/pack/tile-eraser-cursor.png similarity index 100% rename from plugin-tiled/assets/textures/tile-eraser.png rename to plugin-tiled/assets/pack/tile-eraser-cursor.png diff --git a/plugin-tiled/assets/pack/tiled.atlas b/plugin-tiled/assets/pack/tiled.atlas index 97034614..dea196d0 100644 --- a/plugin-tiled/assets/pack/tiled.atlas +++ b/plugin-tiled/assets/pack/tiled.atlas @@ -2,29 +2,16 @@ tiled.png size: 512, 128 filter: Linear, Linear image-Box-active - bounds: 87, 22, 4, 4 + bounds: 25, 20, 4, 4 split: 1, 1, 1, 1 image-Box-inactive - bounds: 436, 31, 4, 4 + bounds: 435, 95, 4, 4 split: 1, 1, 1, 1 -plugin-tab-active - bounds: 436, 105, 73, 21 - split: 4, 4, 3, 0 -plugin-tab-inactive - bounds: 2, 5, 83, 21 - split: 3, 3, 2, 1 -tab-back-line - bounds: 2, 2, 2, 1 - split: 0, 0, 0, 0 -tile - bounds: 436, 71, 32, 32 -tile-eraser - bounds: 436, 37, 32, 32 tiles-drop-here-normal - bounds: 2, 28, 215, 98 + bounds: 1, 26, 215, 98 tiles-drop-here-over - bounds: 219, 28, 215, 98 + bounds: 218, 26, 215, 98 tool-tilebrush - bounds: 470, 80, 22, 23 + bounds: 1, 1, 22, 23 tool-tileeraser - bounds: 470, 55, 22, 23 + bounds: 435, 101, 22, 23 diff --git a/plugin-tiled/assets/pack/tiled.png b/plugin-tiled/assets/pack/tiled.png index b4327c44c23b4eeaf659f2613fb596fd9d220faf..8d5cc1fe927e8a7f3ca96d489091ba6910603ee2 100644 GIT binary patch literal 5731 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 Y5lMf;#fVe82Dumpw zH9KX`mVF;$Fwbvv-~Z43fB8Ibo;UOPopY}1I^XL$=Umr0-+6k$NSFBl&jA1c^EtgU zCIG;pPe4Q=pnqqz7OBv%lDk$>fk`Q;MdtiMZx(C+G+Lg#}ss44whNKj!r7_N*W$Mb@TWU`;R%r{bpw*PXoETE2eA^Uq|I%m2hVeeFs785fga zST^K#P4gnh*^AvAOrc3I;#=`&Z?9vU*83X~cQnLV@W6A5^*+xfHaIGs=0F=JI zJ{rIxJfc?|_r)(uaRHOwb29fCY3p;dc(L>+KObCA@XdGOAh%!lJ7?}Tpgl&bVg6rH z&LHcpqvvPF=CQ@{rNxJH_&jx?j89LWv9j@Jz3mn$v;jspEW`5rWwUKt3cA}~QP??b zj`Nhb(AlYc-mZiCyG#gnaarOH`T5*la7R3Euk`iHvrf&&L<=v9VS9`1cdw=YsebbH z1^!R9Iw(d4B+$~cNrjHM6~YB7uO(J9<2IxUwo1+)wN}Mw?^*F#z>D8J9k5@ zWt3TMaAqlfW#vNCF`a?f4oVO%c%Jl^wWv%4;D*^%ezx5#)0I>DIa%0e)BFjvA8eun zK}Q%JD3%?RCpZ)W8({DwmDv2>oz-+iAY(Uutg%0N=GL0VgVhP*Rw%CqRAm?Ag0Y(RK){1(6K7cQW{V3u&tx{UB;~J2L%aoFs!BIJ2B);#O>wKMV$)~W%rke zZ#3HjkCP92?JD(^Za=DcPd`9b=Vd>FQmeXRr6Z&0Yh^z~a^?XoBQsHoCB z{zK@=zu4e+txsqN(gRr+r(w?Cq8ZPT*wFra*(LbT=On$Gkl?Cui*Agwe9zPgWd|oZ=^Qd;$4`>W0sLe}wU~M^&-i&upygBk=Y$LPy$`=es+A0UjW6z~U z+fJ{c5m)TLbG9VYe1e)l@Q{q#Gf9;bJuoL5zK&$bU63JDkxLEol5BR?rxwmUTzq{8P8`?#S{)|-6X@pG6&XZlr zCMn;2q-rAlwHpr#td<>o)ErxI&8ZtCGwbKZxF57rb9JmrH5<8DG_0N(ut0}*t(f=n zsBATB9}u>_Z)=k-dkz)AwF-AQrca>WT@)t%|0?cMjXn0?netvRDE>8P(_h(D7ERUumh zx49zMN_~2$wMW!U^$0pzLd$|pNFu$Nal39>O-oCkQ7W@BFFp=j@D@<;d7X!rxa0j6 zt@>@6{LfOziv1NV!3!ohJ}OG#Pv_$?^(FBf#gFaq4BW@<5GbA+6eSW|L9sEvE* z_k9;)hVx_7>}OwQUfUzx?X{{TLECU)JX|C3^!9XWV~Tdr3(8`-bm?49xeozn)vI6H ztsN!(H@5hUH|gHwiD1hZXW{%7gBXW62TnL~*uQf4pA9zUcvu$KYHDO!?&EnTySd|Dy$-iD2Ux}Wm*@_X*MwLauR%hi^>hDhN?sp3JoWsBbO z2%@O%ncG%TW)sn;jPYfdaK%EJMdK9f$wyU(Wa`1_fTF(m+q#gwqQI483G;f;=D1!#HGwTxE6!WW4V)w@Jz`cSO#=OMRKvbrM2XnU+ws77!wY# zUU|rkLf$AX`h`Xe)hk_3-QfGszVqJqRDx!49WAG$wr>TiFQaT? zw(4EFs~qYUjNLKJrOt1(5@6M~N6;r7I-eyR4LGdLc}GG{T(ejrOL8hFm#kJ>fm3VW zp`Sz3BN?r1$tcU>FLI8SfYp(-67p0qW92=C?QX(bS>8YQ%X5A0VfnL2$-om+CXN># zxtU(FXt`=TcQ5!svv=|qQ!nNKnk~O-_E4T%IIbZN2sZeSW7zHA-x`TYp5qApF1}xt z5j0dfr3|2z)K*OkjjVHI2dgQ2AVvuZTu62WaUyKjX8Vg&DQ*ZW5Sy`D%0AY^ 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 diff --git a/plugin-tiled/assets/textures/plugin-tab-inactive.9.png b/plugin-tiled/assets/textures/plugin-tab-inactive.9.png deleted file mode 100644 index 25b6f1c4e75dcb27e6e62c7483db79862de1b835..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^p+GFo!3HF&QkiXmRIaCsV@SoVw>J&B8Wbej64x)w zyEt{PpW}3c<0qt!EO`3!;oLiN1;3nLtk2r<{IunI&82%oO~W?dPU`V)za_`-P`u&$ zd$|K=%D=X7iE4#7wsM6AEOZhLSrNbr;{N3|of5Qa-^*O)Eq#9LR;ov=_!%Sofng)i OVg^rFKbLh*2~7YJoIqCq diff --git a/plugin-tiled/assets/textures/tab-back-line.9.png b/plugin-tiled/assets/textures/tab-back-line.9.png deleted file mode 100644 index b00578769b509c44fd9eb6d91a3f9e3fa9698022..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c6!3HF^d|7u4NJ)6QIEGZ*N=|5K_#eRY@Xg)b f;yr;Zi82gE>v+;b_ihjXs$uYS^>bP0l+XkK6yX-C diff --git a/plugin-tiled/build.gradle b/plugin-tiled/build.gradle index a27c9769..992bb055 100644 --- a/plugin-tiled/build.gradle +++ b/plugin-tiled/build.gradle @@ -19,10 +19,13 @@ dependencies { implementation "com.badlogicgames.ashley:ashley:$ashleyVersion" implementation "com.kotcrab.vis:vis-ui:$visuiVersion" + implementation "com.esotericsoftware.spine:spine-libgdx:$spineVersion" + implementation 'net.mountainblade:modular:1.0' implementation project(":hyperlap2d-common-api") implementation project(":hyperlap2d-runtime-libgdx") + implementation project(":h2d-libgdx-spine-extension") testImplementation group: 'junit', name: 'junit', version: '4.12' } diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanel.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanel.java index 189ff2dc..ee8a8341 100644 --- a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanel.java +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanel.java @@ -21,6 +21,7 @@ package games.rednblack.editor.plugin.tiled; import com.badlogic.ashley.core.Engine; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Align; import com.kotcrab.vis.ui.VisUI; import com.kotcrab.vis.ui.widget.VisLabel; import com.kotcrab.vis.ui.widget.VisTable; @@ -40,11 +41,11 @@ import org.puremvc.java.interfaces.IFacade; */ public class TiledPanel extends UIDraggablePanel { - public static final float GRID_WIDTH = 200f; + public static final float GRID_WIDTH = 220f; public static final float GRID_HEIGHT = 250f; - public static final float DROP_WIDTH = 210f; + public static final float DROP_WIDTH = 220f; public static final float DROP_HEIGHT = 140f; - public static final float SETTINGS_WIDTH = 200f; + public static final float SETTINGS_WIDTH = 220f; public static final float SETTINGS_HEIGHT = 150f; public TiledPlugin tiledPlugin; @@ -79,11 +80,6 @@ public class TiledPanel extends UIDraggablePanel { this.resourcesManager = tiledPlugin.pluginRM; mainTable.clear(); - VisTextButton.VisTextButtonStyle btnStyle = new VisTextButton.VisTextButtonStyle(); - btnStyle.up = new TextureRegionDrawable(resourcesManager.getTextureRegion("plugin-tab-inactive")); - btnStyle.checked = new TextureRegionDrawable(resourcesManager.getTextureRegion("plugin-tab-active")); - btnStyle.font = VisUI.getSkin().getFont("default-font"); - btnStyle.fontColor = VisUI.getSkin().getColor("white"); tabbedPane = new ImageTabbedPane(); paneTable = tabbedPane.getTable(); @@ -127,9 +123,10 @@ public class TiledPanel extends UIDraggablePanel { .width(WIDTH) .height(HEIGHT) .row(); + float prevHeight = getHeight(); pack(); - - setFixedPosition(); + float heightDiff = getHeight() - prevHeight; + setY(getY() - heightDiff); } @Override @@ -161,8 +158,8 @@ public class TiledPanel extends UIDraggablePanel { settingsTab.resetGridCategory(); } - public void addTile(String tileName) { - tilesTab.addTile(tileName); + public void addTile(String tileName, int type) { + tilesTab.addTile(tileName, type); } public void selectTile(TileVO tileVO) { @@ -172,7 +169,6 @@ public class TiledPanel extends UIDraggablePanel { public void removeTile() { tilesTab.removeTile(); reInitTabTable(); - setFixedPosition(); tilesTab.scrollTiles(); } diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanelMediator.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanelMediator.java index ab1bd3d7..0861f232 100644 --- a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanelMediator.java +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanelMediator.java @@ -22,8 +22,11 @@ import com.badlogic.ashley.core.Engine; import com.badlogic.ashley.core.Entity; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; +import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.scenes.scene2d.utils.DragAndDrop; +import games.rednblack.editor.plugin.tiled.view.SpineDrawable; +import games.rednblack.editor.renderer.factory.EntityFactory; import games.rednblack.h2d.common.vo.CursorData; import games.rednblack.editor.plugin.tiled.data.TileVO; import games.rednblack.editor.plugin.tiled.tools.DeleteTileTool; @@ -46,6 +49,7 @@ public class TiledPanelMediator extends Mediator { public static final String NAME = TAG; private TiledPlugin tiledPlugin; + private DragAndDrop.Target target; public TiledPanelMediator(TiledPlugin tiledPlugin) { super(NAME, new TiledPanel(tiledPlugin)); @@ -63,7 +67,6 @@ public class TiledPanelMediator extends Mediator { TiledPlugin.ACTION_DELETE_TILE, TiledPlugin.ACTION_SET_GRID_SIZE_FROM_LIST, TiledPlugin.ACTION_SET_OFFSET, - TiledPlugin.PANEL_OPEN, TiledPlugin.OPEN_DROP_DOWN, TiledPlugin.GRID_CHANGED, SettingsTab.OK_BTN_CLICKED, @@ -87,7 +90,9 @@ public class TiledPanelMediator extends Mediator { tiledPlugin.initSaveData(); viewComponent.initView(); - DragAndDrop.Target target = new DragAndDrop.Target(viewComponent.getDropTable()) { + if (target != null) + tiledPlugin.facade.sendNotification(MsgAPI.REMOVE_TARGET, target); + target = new DragAndDrop.Target(viewComponent.getDropTable()) { @Override public boolean drag(DragAndDrop.Source source, DragAndDrop.Payload payload, float x, float y, int pointer) { return true; @@ -95,14 +100,14 @@ public class TiledPanelMediator extends Mediator { @Override public void drop(DragAndDrop.Source source, DragAndDrop.Payload payload, float x, float y, int pointer) { - ResourcePayloadObject resourcePayloadObject = (ResourcePayloadObject) payload.getObject(); - if (!resourcePayloadObject.className.endsWith(".ImageResource")) return; //only image resource can become a tile! + int type = mapClassNameToEntityType(resourcePayloadObject.className); + if (type == EntityFactory.UNKNOWN_TYPE) return; //only some resources can become a tile! String tileName = resourcePayloadObject.name; if (tiledPlugin.dataToSave.containsTile(tileName)) return; - tiledPlugin.facade.sendNotification(TiledPlugin.TILE_ADDED, tileName); + tiledPlugin.facade.sendNotification(TiledPlugin.TILE_ADDED, new Object[]{tileName, type}); } }; @@ -112,11 +117,12 @@ public class TiledPanelMediator extends Mediator { viewComponent.setFixedPosition(); break; case TiledPlugin.TILE_ADDED: - tileName = notification.getBody(); - viewComponent.addTile(tileName); - viewComponent.setFixedPosition(); + Object[] payload = notification.getBody(); + tileName = (String) payload[0]; + int type = (int) payload[1]; + viewComponent.addTile(tileName, type); - tiledPlugin.dataToSave.addTile(tileName); + tiledPlugin.dataToSave.addTile(tileName, type); tiledPlugin.saveDataManager.save(); break; case TiledPlugin.TILE_SELECTED: @@ -136,8 +142,20 @@ public class TiledPanelMediator extends Mediator { tiledPlugin.facade.sendNotification(TiledPlugin.ACTION_DELETE_TILE, tileName); break; case TiledPlugin.ACTION_SET_GRID_SIZE_FROM_LIST: - TextureRegion r = tiledPlugin.pluginRM.getTextureRegion(notification.getBody()); - tiledPlugin.dataToSave.setGrid(r.getRegionWidth() / tiledPlugin.getPixelToWorld(), r.getRegionHeight() / tiledPlugin.getPixelToWorld()); + float width = 0; + float height = 0; + TileVO t = tiledPlugin.dataToSave.getTile(notification.getBody()); + if (t.entityType == EntityFactory.SPINE_TYPE) { + SpineDrawable spineDrawable = tiledPlugin.pluginRM.getSpineDrawable(t.regionName); + width = spineDrawable.width; + height = spineDrawable.height; + } else { + TextureRegion r = tiledPlugin.pluginRM.getTextureRegion(t.regionName, t.entityType); + width = r.getRegionWidth(); + height = r.getRegionHeight(); + } + + tiledPlugin.dataToSave.setGrid(width / tiledPlugin.getPixelToWorld(), height / tiledPlugin.getPixelToWorld()); tiledPlugin.facade.sendNotification(TiledPlugin.GRID_CHANGED); break; case TiledPlugin.ACTION_DELETE_TILE: @@ -149,38 +167,25 @@ public class TiledPanelMediator extends Mediator { viewComponent.removeTile(); break; - case TiledPlugin.PANEL_OPEN: - if(viewComponent.isOpen) { - break; - } - - viewComponent.show(tiledPlugin.getAPI().getUIStage()); - - if(tiledPlugin.isSceneLoaded) { - viewComponent.setFixedPosition(); - } - break; case MsgAPI.TOOL_SELECTED: String body = notification.getBody(); - String cursorName = null; switch (body) { - case DrawTileTool.NAME: - cursorName = "tile"; - tiledPlugin.facade.sendNotification(TiledPlugin.PANEL_OPEN); - break; case DeleteTileTool.NAME: - cursorName = "tile-eraser"; + case DrawTileTool.NAME: + if(viewComponent.isOpen) { + break; + } + + viewComponent.show(tiledPlugin.getAPI().getUIStage()); + if(tiledPlugin.isSceneLoaded) { + viewComponent.setFixedPosition(); + } + break; default: viewComponent.hide(); break; } - if (cursorName != null) { - CursorData cursorData = new CursorData(cursorName, 14, 14); - TextureRegion region = tiledPlugin.pluginRM.getTextureRegion(cursorName); - //TODO A custom cursor has to be a Texture not a region of an atlas - //tiledPlugin.getAPI().setCursor(cursorData, region); - } break; case SettingsTab.OK_BTN_CLICKED: tiledPlugin.dataToSave.setParameterVO(notification.getBody()); @@ -207,5 +212,14 @@ public class TiledPanelMediator extends Mediator { } } + private int mapClassNameToEntityType(String className) { + if (className.endsWith(".ImageResource")) + return EntityFactory.IMAGE_TYPE; + else if (className.endsWith(".SpriteResource")) + return EntityFactory.SPRITE_TYPE; + else if (className.endsWith(".SpineResource")) + return EntityFactory.SPINE_TYPE; + return EntityFactory.UNKNOWN_TYPE; + } } diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPlugin.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPlugin.java index ebd6c35f..c5eb273a 100644 --- a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPlugin.java +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPlugin.java @@ -45,7 +45,6 @@ import net.mountainblade.modular.annotations.Implementation; import java.util.Set; - /** * Created by mariam on 2/2/2016. */ @@ -56,7 +55,6 @@ public class TiledPlugin extends H2DPluginAdapter { public static final String CLASS_NAME = "games.rednblack.editor.plugin.tiled"; public static final String TILE_ADDED = CLASS_NAME + ".TILE_ADDED"; public static final String TILE_SELECTED = CLASS_NAME + ".TILE_SELECTED"; - public static final String PANEL_OPEN = CLASS_NAME + ".PANEL_OPEN"; public static final String OPEN_DROP_DOWN = CLASS_NAME + ".OPEN_DROP_DOWN"; public static final String GRID_CHANGED = CLASS_NAME + ".GRID_CHANGED"; public static final String ACTION_DELETE_TILE = CLASS_NAME + ".ACTION_DELETE_TILE"; @@ -107,7 +105,7 @@ public class TiledPlugin extends H2DPluginAdapter { tileAddButtonStyle.down = skin.getDrawable("toolbar-down"); tileAddButtonStyle.checked = skin.getDrawable("toolbar-down"); tileAddButtonStyle.over = skin.getDrawable("toolbar-over"); - tileAddButtonStyle.imageUp = new TextureRegionDrawable(pluginRM.getTextureRegion("tool-tilebrush")); + tileAddButtonStyle.imageUp = new TextureRegionDrawable(pluginRM.getTextureRegion("tool-tilebrush", -1)); pluginAPI.addTool(DrawTileTool.NAME, tileAddButtonStyle, true, drawTileTool); VisImageButton.VisImageButtonStyle tileDeleteButtonStyle = new VisImageButton.VisImageButtonStyle(); @@ -115,7 +113,7 @@ public class TiledPlugin extends H2DPluginAdapter { tileDeleteButtonStyle.down = skin.getDrawable("toolbar-down"); tileDeleteButtonStyle.checked = skin.getDrawable("toolbar-down"); tileDeleteButtonStyle.over = skin.getDrawable("toolbar-over"); - tileDeleteButtonStyle.imageUp = new TextureRegionDrawable(pluginRM.getTextureRegion("tool-tileeraser")); + tileDeleteButtonStyle.imageUp = new TextureRegionDrawable(pluginRM.getTextureRegion("tool-tileeraser", -1)); pluginAPI.addTool(DeleteTileTool.NAME, tileDeleteButtonStyle, false, deleteTileTool); pluginAPI.setDropDownItemName(ACTION_SET_GRID_SIZE_FROM_ITEM, "Set tile grid size"); @@ -197,6 +195,10 @@ public class TiledPlugin extends H2DPluginAdapter { return selectedTileVO.regionName; } + public int getSelectedTileType() { + return selectedTileVO.entityType; + } + public Vector2 getSelectedTileGridOffset() { return selectedTileVO.gridOffset; } diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/TileVO.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/TileVO.java index 66b92a9d..39f93f53 100644 --- a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/TileVO.java +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/TileVO.java @@ -1,6 +1,7 @@ package games.rednblack.editor.plugin.tiled.data; import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.factory.EntityFactory; /** * Created by mariam on 5/13/16. @@ -9,6 +10,7 @@ public class TileVO { public String regionName = ""; public Vector2 gridOffset; + public int entityType = EntityFactory.IMAGE_TYPE; public TileVO() { gridOffset = new Vector2(); diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/manager/ResourcesManager.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/manager/ResourcesManager.java index 35eca2b6..20b62c18 100644 --- a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/manager/ResourcesManager.java +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/manager/ResourcesManager.java @@ -1,12 +1,19 @@ package games.rednblack.editor.plugin.tiled.manager; -import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.NinePatch; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.utils.ObjectMap; +import com.esotericsoftware.spine.Skeleton; +import com.esotericsoftware.spine.SkeletonData; +import com.esotericsoftware.spine.SkeletonJson; +import com.esotericsoftware.spine.SkeletonRenderer; import com.google.common.io.ByteStreams; import games.rednblack.editor.plugin.tiled.TiledPlugin; +import games.rednblack.editor.plugin.tiled.view.SpineDrawable; +import games.rednblack.editor.renderer.factory.EntityFactory; import java.io.File; import java.io.FileOutputStream; @@ -23,22 +30,36 @@ public class ResourcesManager { private TiledPlugin tiledPlugin; private TextureAtlas textureAtlas; + private final SkeletonRenderer skeletonRenderer = new SkeletonRenderer(); + + private final ObjectMap textureCache = new ObjectMap<>(); + private final ObjectMap spineDrawableCache = new ObjectMap<>(); + public ResourcesManager(TiledPlugin tiledPlugin) { this.tiledPlugin = tiledPlugin; + skeletonRenderer.setPremultipliedAlpha(true); init(); } private void init() { - FileHandle atlasTempFile = getResourceFileFromJar(".atlas"); - FileHandle pngTempFile = getResourceFileFromJar(".png"); + FileHandle atlasTempFile = getResourceFileFromJar(RESOURCES_FILE_NAME + ".atlas"); + FileHandle pngTempFile = getResourceFileFromJar(RESOURCES_FILE_NAME + ".png"); textureAtlas = new TextureAtlas(atlasTempFile); atlasTempFile.file().deleteOnExit(); pngTempFile.file().deleteOnExit(); + + loadTexture("tile-cursor"); + loadTexture("tile-eraser-cursor"); } - private FileHandle getResourceFileFromJar(String extension) { - String fileName = RESOURCES_FILE_NAME+extension; + private void loadTexture(String name) { + FileHandle file = getResourceFileFromJar(name + ".png"); + file.file().deleteOnExit(); + textureCache.put(name, new Texture(file)); + } + + private FileHandle getResourceFileFromJar(String fileName) { File tempFile = new File(tiledPlugin.getAPI().getCacheDir()+ File.separator + fileName); try { @@ -53,17 +74,37 @@ public class ResourcesManager { return new FileHandle(tempFile); } - public TextureRegion getTextureRegion(String name) { + public Texture getTexture(String name) { + return textureCache.get(name); + } + + public TextureRegion getTextureRegion(String name, int type) { TextureRegion region = textureAtlas.findRegion(name); // try to get region from plugin assets - if (region != null) { -// System.out.println("region: "+name+", "+region.getRegionWidth()+" "+region.getRegionHeight()); - } if (region == null) { // take the region from hyperlap assets - region = tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(name); + switch (type) { + case EntityFactory.IMAGE_TYPE: + region = tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(name); + break; + case EntityFactory.SPRITE_TYPE: + region = tiledPlugin.getAPI().getSceneLoader().getRm().getSpriteAnimation(name).getRegions().get(0); + break; + } } return region; } + public SpineDrawable getSpineDrawable(String name) { + if (spineDrawableCache.get(name) == null) { + SkeletonJson skeletonJson = new SkeletonJson(tiledPlugin.getAPI().getSceneLoader().getRm().getSkeletonAtlas(name)); + SkeletonData skeletonData = skeletonJson.readSkeletonData(tiledPlugin.getAPI().getSceneLoader().getRm().getSkeletonJSON(name)); + Skeleton skeleton = new Skeleton(skeletonData); + + spineDrawableCache.put(name, new SpineDrawable(skeleton, skeletonRenderer)); + } + + return spineDrawableCache.get(name); + } + public NinePatch getPluginNinePatch(String name) { TextureAtlas.AtlasRegion region = textureAtlas.findRegion(name); if(region == null) return null; diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/DataToSave.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/DataToSave.java index 539f6ffc..9819e409 100644 --- a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/DataToSave.java +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/DataToSave.java @@ -20,8 +20,9 @@ public class DataToSave { parameterVO = new ParameterVO(); } - public void addTile(String tileDrawableName) { + public void addTile(String tileDrawableName, int type) { TileVO newTile = new TileVO(tileDrawableName); + newTile.entityType = type; if (!tiles.contains(newTile, false)) { tiles.add(newTile); } diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DeleteTileTool.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DeleteTileTool.java index 01e86dd3..6229091a 100644 --- a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DeleteTileTool.java +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DeleteTileTool.java @@ -2,9 +2,12 @@ package games.rednblack.editor.plugin.tiled.tools; import com.badlogic.ashley.core.Entity; import com.badlogic.gdx.Input; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import games.rednblack.editor.plugin.tiled.TiledPlugin; import games.rednblack.h2d.common.MsgAPI; import games.rednblack.h2d.common.view.tools.Tool; +import games.rednblack.h2d.common.vo.CursorData; import org.puremvc.java.interfaces.INotification; import java.util.HashSet; @@ -14,7 +17,7 @@ import java.util.Set; * Created by mariam on 4/5/16. */ public class DeleteTileTool implements Tool { - + private static final CursorData CURSOR = new CursorData("tile-eraser-cursor", 14, 14); public static final String NAME = "TILE_DELETE_TOOL"; private TiledPlugin tiledPlugin; @@ -27,6 +30,8 @@ public class DeleteTileTool implements Tool { @Override public void initTool() { + Texture cursorTexture = tiledPlugin.pluginRM.getTexture(CURSOR.region); + tiledPlugin.getAPI().setCursor(CURSOR, new TextureRegion(cursorTexture)); } @Override diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DrawTileTool.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DrawTileTool.java index 41946134..52f5ad6f 100644 --- a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DrawTileTool.java +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DrawTileTool.java @@ -2,38 +2,51 @@ package games.rednblack.editor.plugin.tiled.tools; import com.badlogic.ashley.core.Entity; import com.badlogic.gdx.Input; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.MathUtils; -import com.badlogic.gdx.math.Vector2; import com.kotcrab.vis.ui.util.OsUtils; import games.rednblack.editor.plugin.tiled.TiledPlugin; -import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.plugin.tiled.tools.drawStrategy.IDrawStrategy; +import games.rednblack.editor.plugin.tiled.tools.drawStrategy.ImageDrawStrategy; +import games.rednblack.editor.plugin.tiled.tools.drawStrategy.SpineDrawStrategy; +import games.rednblack.editor.plugin.tiled.tools.drawStrategy.SpriteDrawStrategy; import games.rednblack.editor.renderer.components.TextureRegionComponent; import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.factory.EntityFactory; import games.rednblack.editor.renderer.utils.ComponentRetriever; import games.rednblack.h2d.common.command.TransformCommandBuilder; -import games.rednblack.h2d.common.command.UpdateRegionCommandBuilder; -import games.rednblack.h2d.common.factory.IFactory; import games.rednblack.h2d.common.view.tools.Tool; +import games.rednblack.h2d.common.vo.CursorData; import org.puremvc.java.interfaces.INotification; /** * Created by mariam on 3/29/16. */ public class DrawTileTool implements Tool { - + private static final CursorData CURSOR = new CursorData("tile-cursor", 14, 14); public static final String NAME = "TILE_ADD_TOOL"; private TiledPlugin tiledPlugin; private float gridWidth; private float gridHeight; + private final ImageDrawStrategy imageDrawStrategy; + private final SpriteDrawStrategy spriteDrawStrategy; + private final SpineDrawStrategy spineDrawStrategy; + private IDrawStrategy currentDrawStrategy; + public DrawTileTool(TiledPlugin tiledPlugin) { this.tiledPlugin = tiledPlugin; + imageDrawStrategy = new ImageDrawStrategy(tiledPlugin); + spriteDrawStrategy = new SpriteDrawStrategy(tiledPlugin); + spineDrawStrategy = new SpineDrawStrategy(tiledPlugin); } @Override public void initTool() { - + Texture cursorTexture = tiledPlugin.pluginRM.getTexture(CURSOR.region); + tiledPlugin.getAPI().setCursor(CURSOR, new TextureRegion(cursorTexture)); } @Override @@ -49,7 +62,7 @@ public class DrawTileTool implements Tool { @Override public boolean stageMouseDown(float x, float y) { initGridThings(); - drawImage(x, y); + drawTile(x, y); return true; } @@ -59,7 +72,7 @@ public class DrawTileTool implements Tool { @Override public void stageMouseDragged(float x, float y) { - drawImage(x, y); + drawTile(x, y); } @Override @@ -75,7 +88,10 @@ public class DrawTileTool implements Tool { @Override public boolean itemMouseDown(Entity entity, float x, float y) { initGridThings(); - drawOnEntity(entity, x, y); + if (entity == null) + drawTile(x, y); + else + drawOnEntity(entity); return true; } @@ -85,33 +101,27 @@ public class DrawTileTool implements Tool { @Override public void itemMouseDragged(Entity entity, float x, float y) { - drawImage(x, y); + drawTile(x, y); } @Override public void itemMouseDoubleClick(Entity entity, float x, float y) { if (!tiledPlugin.isOnCurrentSelectedLayer(entity)) return; - if (entity != null) { - TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); - if (textureRegionComponent != null && tiledPlugin.isTile(entity)) { - // there is already other tile under this one - if (textureRegionComponent.regionName.equals(tiledPlugin.getSelectedTileName())) { - //rotate - TransformCommandBuilder commandBuilder = new TransformCommandBuilder(); - commandBuilder.begin(entity); - TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); - if (transformComponent.scaleX > 0 && transformComponent.scaleY > 0) { - commandBuilder.setScale(transformComponent.scaleX * -1f, transformComponent.scaleY); - } else if (transformComponent.scaleX < 0 && transformComponent.scaleY > 0) { - commandBuilder.setScale(transformComponent.scaleX, transformComponent.scaleY * -1f); - } else if (transformComponent.scaleX < 0 && transformComponent.scaleY < 0) { - commandBuilder.setScale(transformComponent.scaleX * -1f, transformComponent.scaleY); - } else if (transformComponent.scaleX > 0 && transformComponent.scaleY < 0) { - commandBuilder.setScale(transformComponent.scaleX, transformComponent.scaleY * -1f); - } - commandBuilder.execute(tiledPlugin.facade); - } + if (entity != null && tiledPlugin.isTile(entity)) { + //rotate + TransformCommandBuilder commandBuilder = new TransformCommandBuilder(); + commandBuilder.begin(entity); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + if (transformComponent.scaleX > 0 && transformComponent.scaleY > 0) { + commandBuilder.setScale(transformComponent.scaleX * -1f, transformComponent.scaleY); + } else if (transformComponent.scaleX < 0 && transformComponent.scaleY > 0) { + commandBuilder.setScale(transformComponent.scaleX, transformComponent.scaleY * -1f); + } else if (transformComponent.scaleX < 0 && transformComponent.scaleY < 0) { + commandBuilder.setScale(transformComponent.scaleX * -1f, transformComponent.scaleY); + } else if (transformComponent.scaleX > 0 && transformComponent.scaleY < 0) { + commandBuilder.setScale(transformComponent.scaleX, transformComponent.scaleY * -1f); } + commandBuilder.execute(tiledPlugin.facade); } } @@ -143,9 +153,23 @@ public class DrawTileTool implements Tool { gridHeight = tiledPlugin.dataToSave.getParameterVO().gridHeight; } - private final Vector2 temp = new Vector2(); + private void chooseDrawStrategy() { + switch (tiledPlugin.getSelectedTileType()) { + case EntityFactory.IMAGE_TYPE: + currentDrawStrategy = imageDrawStrategy; + break; + case EntityFactory.SPRITE_TYPE: + currentDrawStrategy = spriteDrawStrategy; + break; + case EntityFactory.SPINE_TYPE: + currentDrawStrategy = spineDrawStrategy; + break; + default: + currentDrawStrategy = null; + } + } - private void drawImage(float x, float y) { + private void drawTile(float x, float y) { if (tiledPlugin.getSelectedTileName().equals("")) return; float newX = MathUtils.floor(x / gridWidth) * gridWidth + tiledPlugin.getSelectedTileGridOffset().x; @@ -153,53 +177,12 @@ public class DrawTileTool implements Tool { int row = MathUtils.floor(newY / gridHeight); int column = MathUtils.round(newX / gridWidth); - Entity underneathTile = tiledPlugin.getPluginEntityWithParams(row, column); - if (underneathTile != null) { - drawOnEntity(underneathTile, x, y); - return; - } - - IFactory itemFactory = tiledPlugin.getAPI().getItemFactory(); - temp.set(newX, newY); - if (itemFactory.createSimpleImage(tiledPlugin.getSelectedTileName(), temp)) { - Entity imageEntity = itemFactory.getCreatedEntity(); - MainItemComponent mainItemComponent = ComponentRetriever.get(imageEntity, MainItemComponent.class); - mainItemComponent.tags.add(TiledPlugin.TILE_TAG); - - mainItemComponent.setCustomVars(TiledPlugin.ROW, Integer.toString(row)); - mainItemComponent.setCustomVars(TiledPlugin.COLUMN, Integer.toString(column)); - - TransformComponent transformComponent = ComponentRetriever.get(imageEntity, TransformComponent.class); - transformComponent.x = newX; - transformComponent.y = newY; - } + chooseDrawStrategy(); + currentDrawStrategy.drawTile(newX, newY, row, column); } - private void drawOnEntity(Entity entity, float x, float y) { - if (!tiledPlugin.isOnCurrentSelectedLayer(entity)) return; - if (entity != null) { - TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); - if (textureRegionComponent != null && textureRegionComponent.regionName != null - && tiledPlugin.isTile(entity)) { - // there is already other tile under this one - if(textureRegionComponent.regionName.equals(tiledPlugin.getSelectedTileName())) { - return; - } else { - //replace - updateRegion(entity, tiledPlugin.getSelectedTileName()); - } - } - return; - } - drawImage(x, y); + private void drawOnEntity(Entity entity) { + chooseDrawStrategy(); + currentDrawStrategy.updateTile(entity); } - - private void updateRegion(Entity entity, String region) { - UpdateRegionCommandBuilder builder = new UpdateRegionCommandBuilder(); - builder.begin(entity); - builder.setRegion(tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(region)); - builder.setRegionName(tiledPlugin.getSelectedTileName()); - builder.execute(tiledPlugin.facade); - } - } diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/BasicDrawStrategy.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/BasicDrawStrategy.java new file mode 100644 index 00000000..583a4e8a --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/BasicDrawStrategy.java @@ -0,0 +1,34 @@ +package games.rednblack.editor.plugin.tiled.tools.drawStrategy; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.plugin.tiled.TiledPlugin; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +public abstract class BasicDrawStrategy implements IDrawStrategy { + protected TiledPlugin tiledPlugin; + protected final Vector2 temp = new Vector2(); + + public BasicDrawStrategy(TiledPlugin plugin) { + tiledPlugin = plugin; + } + + protected void postProcessEntity(Entity entity, float x, float y, int row, int column) { + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + mainItemComponent.tags.add(TiledPlugin.TILE_TAG); + + mainItemComponent.setCustomVars(TiledPlugin.ROW, Integer.toString(row)); + mainItemComponent.setCustomVars(TiledPlugin.COLUMN, Integer.toString(column)); + + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.x = x; + transformComponent.y = y; + } + + protected boolean checkValidTile(Entity entity) { + return tiledPlugin.isOnCurrentSelectedLayer(entity) && tiledPlugin.isTile(entity) + && ComponentRetriever.get(entity, MainItemComponent.class).entityType == tiledPlugin.getSelectedTileType(); + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/IDrawStrategy.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/IDrawStrategy.java new file mode 100644 index 00000000..41ee1ad1 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/IDrawStrategy.java @@ -0,0 +1,8 @@ +package games.rednblack.editor.plugin.tiled.tools.drawStrategy; + +import com.badlogic.ashley.core.Entity; + +public interface IDrawStrategy { + void drawTile(float x, float y, int row, int column); + void updateTile(Entity entity); +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/ImageDrawStrategy.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/ImageDrawStrategy.java new file mode 100644 index 00000000..3f90fca4 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/ImageDrawStrategy.java @@ -0,0 +1,49 @@ +package games.rednblack.editor.plugin.tiled.tools.drawStrategy; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.plugin.tiled.TiledPlugin; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.h2d.common.command.ReplaceRegionCommandBuilder; +import games.rednblack.h2d.common.factory.IFactory; + +public class ImageDrawStrategy extends BasicDrawStrategy { + private final ReplaceRegionCommandBuilder replaceRegionCommandBuilder = new ReplaceRegionCommandBuilder(); + + public ImageDrawStrategy(TiledPlugin plugin) { + super(plugin); + } + + @Override + public void drawTile(float x, float y, int row, int column) { + Entity underneathTile = tiledPlugin.getPluginEntityWithParams(row, column); + if (underneathTile != null) { + updateTile(underneathTile); + return; + } + + IFactory itemFactory = tiledPlugin.getAPI().getItemFactory(); + temp.set(x, y); + if (itemFactory.createSimpleImage(tiledPlugin.getSelectedTileName(), temp)) { + Entity imageEntity = itemFactory.getCreatedEntity(); + postProcessEntity(imageEntity, x, y, row, column); + } + } + + @Override + public void updateTile(Entity entity) { + if (!checkValidTile(entity)) return; + + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + if (textureRegionComponent != null && textureRegionComponent.regionName != null) { + // there is already other tile under this one + if (!textureRegionComponent.regionName.equals(tiledPlugin.getSelectedTileName())) { + String region = tiledPlugin.getSelectedTileName(); + replaceRegionCommandBuilder.begin(entity); + replaceRegionCommandBuilder.setRegion(tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(region)); + replaceRegionCommandBuilder.setRegionName(region); + replaceRegionCommandBuilder.execute(tiledPlugin.facade); + } + } + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/SpineDrawStrategy.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/SpineDrawStrategy.java new file mode 100644 index 00000000..514cbeca --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/SpineDrawStrategy.java @@ -0,0 +1,57 @@ +package games.rednblack.editor.plugin.tiled.tools.drawStrategy; + +import com.badlogic.ashley.core.Entity; +import com.esotericsoftware.spine.Skeleton; +import com.esotericsoftware.spine.SkeletonData; +import com.esotericsoftware.spine.SkeletonJson; +import games.rednblack.editor.plugin.tiled.TiledPlugin; +import games.rednblack.editor.renderer.components.SpineDataComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationStateComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.h2d.common.command.ReplaceSpineCommandBuilder; +import games.rednblack.h2d.common.factory.IFactory; +import games.rednblack.h2d.extention.spine.SpineObjectComponent; + +public class SpineDrawStrategy extends BasicDrawStrategy { + + private final ReplaceSpineCommandBuilder replaceSpineCommandBuilder = new ReplaceSpineCommandBuilder(); + + public SpineDrawStrategy(TiledPlugin plugin) { + super(plugin); + } + + @Override + public void drawTile(float x, float y, int row, int column) { + Entity underneathTile = tiledPlugin.getPluginEntityWithParams(row, column); + if (underneathTile != null) { + updateTile(underneathTile); + return; + } + + IFactory itemFactory = tiledPlugin.getAPI().getItemFactory(); + temp.set(x, y); + + if (itemFactory.createSpineAnimation(tiledPlugin.getSelectedTileName(), temp)) { + Entity imageEntity = itemFactory.getCreatedEntity(); + postProcessEntity(imageEntity, x, y, row, column); + } + } + + @Override + public void updateTile(Entity entity) { + if (!checkValidTile(entity)) return; + + SpineDataComponent spineDataComponent = ComponentRetriever.get(entity, SpineDataComponent.class); + if (!spineDataComponent.animationName.equals(tiledPlugin.getSelectedTileName())) { + replaceSpineCommandBuilder.begin(entity); + String animName = tiledPlugin.getSelectedTileName(); + replaceSpineCommandBuilder.setAnimationName(animName); + SkeletonJson skeletonJson = new SkeletonJson(tiledPlugin.getAPI().getSceneLoader().getRm().getSkeletonAtlas(animName)); + replaceSpineCommandBuilder.setSkeletonJson(skeletonJson); + SkeletonData skeletonData = skeletonJson.readSkeletonData((tiledPlugin.getAPI().getSceneLoader().getRm().getSkeletonJSON(animName))); + replaceSpineCommandBuilder.setSkeleton(new Skeleton(skeletonData)); + replaceSpineCommandBuilder.execute(tiledPlugin.facade); + } + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/SpriteDrawStrategy.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/SpriteDrawStrategy.java new file mode 100644 index 00000000..46b2e0c0 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/drawStrategy/SpriteDrawStrategy.java @@ -0,0 +1,64 @@ +package games.rednblack.editor.plugin.tiled.tools.drawStrategy; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.plugin.tiled.TiledPlugin; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.h2d.common.command.ReplaceSpriteAnimationCommandBuilder; +import games.rednblack.h2d.common.factory.IFactory; + +public class SpriteDrawStrategy extends BasicDrawStrategy { + ReplaceSpriteAnimationCommandBuilder replaceSpriteAnimationCommandBuilder = new ReplaceSpriteAnimationCommandBuilder(); + + public SpriteDrawStrategy(TiledPlugin plugin) { + super(plugin); + } + + @Override + public void drawTile(float x, float y, int row, int column) { + Entity underneathTile = tiledPlugin.getPluginEntityWithParams(row, column); + if (underneathTile != null) { + updateTile(underneathTile); + return; + } + + IFactory itemFactory = tiledPlugin.getAPI().getItemFactory(); + temp.set(x, y); + + if (itemFactory.createSpriteAnimation(tiledPlugin.getSelectedTileName(), temp)) { + Entity imageEntity = itemFactory.getCreatedEntity(); + postProcessEntity(imageEntity, x, y, row, column); + } + } + + @Override + public void updateTile(Entity entity) { + if (!checkValidTile(entity)) return; + + SpriteAnimationComponent spriteAnimationComponent = ComponentRetriever.get(entity, SpriteAnimationComponent.class); + + if (!spriteAnimationComponent.animationName.equals(tiledPlugin.getSelectedTileName())) { + Array regions = getRegions(tiledPlugin.getSelectedTileName()); + + replaceSpriteAnimationCommandBuilder.begin(entity); + replaceSpriteAnimationCommandBuilder.setAnimationName(tiledPlugin.getSelectedTileName()); + replaceSpriteAnimationCommandBuilder.setRegion(regions); + replaceSpriteAnimationCommandBuilder.execute(tiledPlugin.facade); + } + } + + private Array getRegions(String filter) { + // filtering regions by name + Array allRegions = tiledPlugin.getAPI().getSceneLoader().getRm().getSpriteAnimation(filter).getRegions(); + Array regions = new Array<>(); + for(TextureAtlas.AtlasRegion region: allRegions) { + if(region.name.contains(filter)) { + regions.add(region); + } + } + + return regions; + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/SpineDrawable.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/SpineDrawable.java new file mode 100644 index 00000000..a30dda35 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/SpineDrawable.java @@ -0,0 +1,108 @@ +package games.rednblack.editor.plugin.tiled.view; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.scenes.scene2d.utils.BaseDrawable; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.FloatArray; +import com.esotericsoftware.spine.*; +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; + +public class SpineDrawable extends BaseDrawable { + private float minX = 0; + private float minY = 0; + + private Skeleton skeleton; + private AnimationState animationState; + private SkeletonRenderer skeletonRenderer; + + public float width, height; + private FloatArray temp; + + public SpineDrawable(Skeleton skeleton, SkeletonRenderer skeletonRenderer) { + temp = new FloatArray(); + this.skeletonRenderer = skeletonRenderer; + + this.skeleton = skeleton; + AnimationStateData animationStateData = new AnimationStateData(skeleton.getData()); + animationState = new AnimationState(animationStateData); + + computeBoundBox(); + + float scaleFactor; + if (this.width > this.height) { + //scale by width + scaleFactor = 1.0f / (this.width / 40); + } else { + scaleFactor = 1.0f / (this.height / 40); + } + skeleton.setScale(scaleFactor, scaleFactor); + } + + public Skeleton getSkeleton() { + return skeleton; + } + + public AnimationState getAnimationState() { + return animationState; + } + + private void computeBoundBox() { + skeleton.updateWorldTransform(); + + Array drawOrder = skeleton.getDrawOrder(); + minX = Float.MAX_VALUE; + minY = Float.MAX_VALUE; + float maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE; + for (int i = 0, n = drawOrder.size; i < n; i++) { + Slot slot = drawOrder.get(i); + if (!slot.getBone().isActive()) continue; + int verticesLength = 0; + float[] vertices = null; + Attachment attachment = slot.getAttachment(); + if (attachment instanceof RegionAttachment) { + verticesLength = 8; + vertices = temp.setSize(8); + ((RegionAttachment)attachment).computeWorldVertices(slot.getBone(), vertices, 0, 2); + } else if (attachment instanceof MeshAttachment) { + MeshAttachment mesh = (MeshAttachment)attachment; + verticesLength = mesh.getWorldVerticesLength(); + vertices = temp.setSize(verticesLength); + mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2); + } + if (vertices != null) { + for (int ii = 0; ii < verticesLength; ii += 2) { + float x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + width = (maxX - minX); + height = (maxY - minY); + } + + @Override + public void draw(Batch batch, float x, float y, float width, float height) { + skeleton.updateWorldTransform(); + animationState.update(Gdx.graphics.getDeltaTime()); + animationState.apply(skeleton); + skeleton.setPosition(x, y - 20); + + Color color = skeleton.getColor(); + + float oldAlpha = color.a; + skeleton.getColor().a *= batch.getColor().a; + skeletonRenderer.draw(batch, skeleton); + color.a = oldAlpha; + + batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); + } +} + diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/GridTilesTab.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/GridTilesTab.java index 2f7d8be9..9fc0c72a 100644 --- a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/GridTilesTab.java +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/GridTilesTab.java @@ -2,6 +2,7 @@ package games.rednblack.editor.plugin.tiled.view.tabs; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.utils.Drawable; @@ -16,6 +17,8 @@ import games.rednblack.editor.plugin.tiled.TiledPanel; import games.rednblack.editor.plugin.tiled.TiledPlugin; import games.rednblack.editor.plugin.tiled.data.TileVO; import games.rednblack.editor.plugin.tiled.manager.ResourcesManager; +import games.rednblack.editor.plugin.tiled.view.SpineDrawable; +import games.rednblack.editor.renderer.factory.EntityFactory; import games.rednblack.h2d.common.view.ui.StandardWidgetsFactory; /** @@ -49,8 +52,8 @@ public class GridTilesTab extends DefaultTab { public void initView() { if (isDrop = savedTiles.size == 0) { VisImageButton.VisImageButtonStyle dropBoxStyle = new VisImageButton.VisImageButtonStyle(); - dropBoxStyle.up = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-normal")); - dropBoxStyle.imageOver = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-over")); + dropBoxStyle.up = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-normal", -1)); + dropBoxStyle.imageOver = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-over", -1)); VisImageButton dropRegion = new VisImageButton(dropBoxStyle); content.clear(); content.add(dropRegion) @@ -72,14 +75,14 @@ public class GridTilesTab extends DefaultTab { } } - public void addTile(String tileName) { + public void addTile(String tileName, int type) { if (pane != null) isBottomEdge = pane.isBottomEdge(); if (tileIndex == 0) { - setGridSizeToFirstTileSize(tileName); + setGridSizeToFirstTileSize(tileName, type); isDrop = false; panel.reInitTabTable(); } - initTiles(tileName); + initTiles(tileName, type); panel.pack(); scrollTiles(); tiles.get(tileIndex).setChecked(true); @@ -107,14 +110,25 @@ public class GridTilesTab extends DefaultTab { } } - private void setGridSizeToFirstTileSize(String tileName) { - float gridWidth = resourcesManager.getTextureRegion(tileName).getRegionWidth() / tiledPlugin.getPixelToWorld(); - float gridHeight = resourcesManager.getTextureRegion(tileName).getRegionHeight() / tiledPlugin.getPixelToWorld(); + private void setGridSizeToFirstTileSize(String tileName, int type) { + float width = 0; + float height = 0; + if (type == EntityFactory.SPINE_TYPE) { + SpineDrawable spineDrawable = tiledPlugin.pluginRM.getSpineDrawable(tileName); + width = spineDrawable.width; + height = spineDrawable.height; + } else { + TextureRegion r = tiledPlugin.pluginRM.getTextureRegion(tileName, type); + width = r.getRegionWidth(); + height = r.getRegionHeight(); + } + float gridWidth = width / tiledPlugin.getPixelToWorld(); + float gridHeight = height / tiledPlugin.getPixelToWorld(); tiledPlugin.dataToSave.setGrid(gridWidth, gridHeight); tiledPlugin.facade.sendNotification(TiledPlugin.GRID_CHANGED); } - private void initTiles(String tileName) { + private void initTiles(String tileName, int type) { content.clear(); tiles.clear(); @@ -140,10 +154,19 @@ public class GridTilesTab extends DefaultTab { imageBoxStyle.over = active; Drawable tileDrawable = null; if (i < savedTiles.size) { - tileDrawable = new TextureRegionDrawable(resourcesManager.getTextureRegion(savedTiles.get(i).regionName)); + int t = savedTiles.get(i).entityType; + if (t == EntityFactory.SPINE_TYPE) { + tileDrawable = resourcesManager.getSpineDrawable(savedTiles.get(i).regionName); + } else { + tileDrawable = new TextureRegionDrawable(resourcesManager.getTextureRegion(savedTiles.get(i).regionName, t)); + } } else if (!tileName.equals("")) { if (i == tileIndex) { - tileDrawable = new TextureRegionDrawable(resourcesManager.getTextureRegion(tileName)); + if (type == EntityFactory.SPINE_TYPE) { + tileDrawable = resourcesManager.getSpineDrawable(tileName); + } else { + tileDrawable = new TextureRegionDrawable(resourcesManager.getTextureRegion(tileName, type)); + } } } imageBoxStyle.imageUp = tileDrawable; @@ -198,6 +221,6 @@ public class GridTilesTab extends DefaultTab { } private void initTiles() { - initTiles(""); + initTiles("", -1); } } diff --git a/src/main/java/games/rednblack/editor/controller/BootstrapCommand.java b/src/main/java/games/rednblack/editor/controller/BootstrapCommand.java index ec29ceb6..391156d1 100644 --- a/src/main/java/games/rednblack/editor/controller/BootstrapCommand.java +++ b/src/main/java/games/rednblack/editor/controller/BootstrapCommand.java @@ -63,7 +63,9 @@ public class BootstrapCommand extends SimpleCommand { facade.registerCommand(MsgAPI.ACTION_ITEM_AND_CHILDREN_TO, ItemChildrenTransformCommand::new); facade.registerCommand(MsgAPI.ACTION_ITEM_TRANSFORM_TO, ItemTransformCommand::new); - facade.registerCommand(MsgAPI.ACTION_UPDATE_REGION_DATA, UpdateRegionCommand::new); + facade.registerCommand(MsgAPI.ACTION_REPLACE_REGION_DATA, ReplaceRegionCommand::new); + facade.registerCommand(MsgAPI.ACTION_REPLACE_SPRITE_ANIMATION_DATA, ReplaceSpriteAnimationCommand::new); + facade.registerCommand(MsgAPI.ACTION_REPLACE_SPINE_ANIMATION_DATA, ReplaceSpineCommand::new); facade.registerCommand(MsgAPI.ACTION_ADD_TO_LIBRARY, AddToLibraryCommand::new); facade.registerCommand(MsgAPI.ACTION_ADD_TO_LIBRARY_ACTION, AddToLibraryAction::new); facade.registerCommand(MsgAPI.ACTION_CONVERT_TO_BUTTON, ConvertToButtonCommand::new); diff --git a/src/main/java/games/rednblack/editor/controller/commands/UpdateRegionCommand.java b/src/main/java/games/rednblack/editor/controller/commands/component/ReplaceRegionCommand.java similarity index 78% rename from src/main/java/games/rednblack/editor/controller/commands/UpdateRegionCommand.java rename to src/main/java/games/rednblack/editor/controller/commands/component/ReplaceRegionCommand.java index 2924bd24..6ddb466c 100644 --- a/src/main/java/games/rednblack/editor/controller/commands/UpdateRegionCommand.java +++ b/src/main/java/games/rednblack/editor/controller/commands/component/ReplaceRegionCommand.java @@ -1,17 +1,19 @@ -package games.rednblack.editor.controller.commands; +package games.rednblack.editor.controller.commands.component; import com.badlogic.ashley.core.Entity; import com.badlogic.gdx.graphics.g2d.TextureRegion; import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.EntityModifyRevertibleCommand; import games.rednblack.editor.renderer.components.DimensionsComponent; import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.components.TransformComponent; import games.rednblack.editor.renderer.data.ProjectInfoVO; import games.rednblack.editor.renderer.utils.ComponentRetriever; import games.rednblack.editor.utils.runtime.EntityUtils; import games.rednblack.editor.view.stage.Sandbox; import games.rednblack.h2d.common.MsgAPI; -public class UpdateRegionCommand extends EntityModifyRevertibleCommand { +public class ReplaceRegionCommand extends EntityModifyRevertibleCommand { private Integer entityId; private String backupRegionName; @@ -28,6 +30,7 @@ public class UpdateRegionCommand extends EntityModifyRevertibleCommand { TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); DimensionsComponent size = ComponentRetriever.get(entity, DimensionsComponent.class); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); backupRegionName = textureRegionComponent.regionName; backupRegion = textureRegionComponent.region; @@ -39,6 +42,9 @@ public class UpdateRegionCommand extends EntityModifyRevertibleCommand { size.width = textureRegionComponent.region.getRegionWidth() / ppwu; size.height = textureRegionComponent.region.getRegionHeight() / ppwu; + transformComponent.originX = size.width / 2; + transformComponent.originY = size.height / 2; + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); } @@ -48,6 +54,7 @@ public class UpdateRegionCommand extends EntityModifyRevertibleCommand { TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); DimensionsComponent size = ComponentRetriever.get(entity, DimensionsComponent.class); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); textureRegionComponent.regionName = backupRegionName; textureRegionComponent.region = backupRegion; @@ -56,6 +63,9 @@ public class UpdateRegionCommand extends EntityModifyRevertibleCommand { size.width = textureRegionComponent.region.getRegionWidth() / ppwu; size.height = textureRegionComponent.region.getRegionHeight() / ppwu; + transformComponent.originX = size.width / 2; + transformComponent.originY = size.height / 2; + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); } } diff --git a/src/main/java/games/rednblack/editor/controller/commands/component/ReplaceSpineCommand.java b/src/main/java/games/rednblack/editor/controller/commands/component/ReplaceSpineCommand.java new file mode 100644 index 00000000..ff01a67b --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/component/ReplaceSpineCommand.java @@ -0,0 +1,94 @@ +package games.rednblack.editor.controller.commands.component; + +import com.badlogic.ashley.core.Entity; +import com.esotericsoftware.spine.*; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.EntityModifyRevertibleCommand; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.SpineDataComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.h2d.extention.spine.SpineObjectComponent; + +public class ReplaceSpineCommand extends EntityModifyRevertibleCommand { + + private Integer entityId; + private String backupAnimName; + private SkeletonJson backupSkeletonJson; + private Skeleton backupSkeleton; + + @Override + public void doAction() { + Object[] payload = getNotification().getBody(); + Entity entity = (Entity) payload[0]; + String animName = (String) payload[1]; + SkeletonJson skeletonJson = (SkeletonJson) payload[2]; + Skeleton skeleton = (Skeleton) payload[3]; + SkeletonData skeletonData = skeleton.getData(); + + entityId = EntityUtils.getEntityId(entity); + + SpineDataComponent spineDataComponent = ComponentRetriever.get(entity, SpineDataComponent.class); + SpineObjectComponent spineObjectComponent = ComponentRetriever.get(entity, SpineObjectComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + + backupAnimName = spineDataComponent.animationName; + backupSkeletonJson = spineObjectComponent.skeletonJson; + backupSkeleton = spineObjectComponent.skeleton; + + spineDataComponent.animationName = animName; + spineObjectComponent.skeletonJson = skeletonJson; + spineObjectComponent.skeletonData = skeletonData; + spineObjectComponent.skeleton = skeleton; + + AnimationStateData stateData = new AnimationStateData(skeletonData); + spineObjectComponent.state = new AnimationState(stateData); + + spineObjectComponent.computeBoundBox(dimensionsComponent); + dimensionsComponent.width *= spineObjectComponent.worldMultiplier; + dimensionsComponent.height *= spineObjectComponent.worldMultiplier; + + transformComponent.originX = dimensionsComponent.width / 2f; + transformComponent.originY = dimensionsComponent.height / 2f; + + String currentAnimName = skeletonData.getAnimations().get(0).getName(); + spineDataComponent.currentAnimationName = currentAnimName; + spineObjectComponent.setAnimation(currentAnimName); + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + @Override + public void undoAction() { + Entity entity = EntityUtils.getByUniqueId(entityId); + + SpineDataComponent spineDataComponent = ComponentRetriever.get(entity, SpineDataComponent.class); + SpineObjectComponent spineObjectComponent = ComponentRetriever.get(entity, SpineObjectComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + + spineDataComponent.animationName = backupAnimName; + spineObjectComponent.skeletonJson = backupSkeletonJson; + spineObjectComponent.skeletonData = backupSkeleton.getData(); + spineObjectComponent.skeleton = backupSkeleton; + + AnimationStateData stateData = new AnimationStateData(spineObjectComponent.skeletonData); + spineObjectComponent.state = new AnimationState(stateData); + + spineObjectComponent.computeBoundBox(dimensionsComponent); + dimensionsComponent.width *= spineObjectComponent.worldMultiplier; + dimensionsComponent.height *= spineObjectComponent.worldMultiplier; + + transformComponent.originX = dimensionsComponent.width / 2f; + transformComponent.originY = dimensionsComponent.height / 2f; + + String currentAnimName = spineObjectComponent.skeletonData.getAnimations().get(0).getName(); + spineDataComponent.currentAnimationName = currentAnimName; + spineObjectComponent.setAnimation(currentAnimName); + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/component/ReplaceSpriteAnimationCommand.java b/src/main/java/games/rednblack/editor/controller/commands/component/ReplaceSpriteAnimationCommand.java new file mode 100644 index 00000000..2d8eb4af --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/component/ReplaceSpriteAnimationCommand.java @@ -0,0 +1,100 @@ +package games.rednblack.editor.controller.commands.component; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Animation; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.EntityModifyRevertibleCommand; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationStateComponent; +import games.rednblack.editor.renderer.data.FrameRange; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.h2d.common.MsgAPI; + +public class ReplaceSpriteAnimationCommand extends EntityModifyRevertibleCommand { + + private Integer entityId; + private String backupAnimName; + private Array backupAnimRegions; + + @Override + public void doAction() { + Object[] payload = getNotification().getBody(); + Entity entity = (Entity) payload[0]; + String animName = (String) payload[1]; + Array regions = (Array) payload[2]; + + entityId = EntityUtils.getEntityId(entity); + + SpriteAnimationComponent spriteAnimationComponent = ComponentRetriever.get(entity, SpriteAnimationComponent.class); + SpriteAnimationStateComponent spriteAnimationStateComponent = ComponentRetriever.get(entity, SpriteAnimationStateComponent.class); + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + DimensionsComponent size = ComponentRetriever.get(entity, DimensionsComponent.class); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + + backupAnimName = spriteAnimationComponent.animationName; + backupAnimRegions = spriteAnimationStateComponent.allRegions; + + spriteAnimationComponent.animationName = animName; + spriteAnimationComponent.frameRangeMap.clear(); + + spriteAnimationComponent.frameRangeMap.put("Default", new FrameRange("Default", 0, regions.size-1)); + spriteAnimationComponent.currentAnimation = "Default"; + spriteAnimationComponent.playMode = Animation.PlayMode.LOOP; + + spriteAnimationStateComponent.setAllRegions(regions); + spriteAnimationStateComponent.set(spriteAnimationComponent); + + textureRegionComponent.region = regions.get(0); + + ProjectInfoVO projectInfoVO = Sandbox.getInstance().getSceneControl().sceneLoader.getRm().getProjectVO(); + float ppwu = projectInfoVO.pixelToWorld; + size.width = textureRegionComponent.region.getRegionWidth() / ppwu; + size.height = textureRegionComponent.region.getRegionHeight() / ppwu; + + transformComponent.originX = size.width / 2; + transformComponent.originY = size.height / 2; + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + @Override + public void undoAction() { + Entity entity = EntityUtils.getByUniqueId(entityId); + + SpriteAnimationComponent spriteAnimationComponent = ComponentRetriever.get(entity, SpriteAnimationComponent.class); + SpriteAnimationStateComponent spriteAnimationStateComponent = ComponentRetriever.get(entity, SpriteAnimationStateComponent.class); + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + DimensionsComponent size = ComponentRetriever.get(entity, DimensionsComponent.class); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + + spriteAnimationComponent.animationName = backupAnimName; + spriteAnimationComponent.frameRangeMap.clear(); + + spriteAnimationComponent.frameRangeMap.put("Default", new FrameRange("Default", 0, backupAnimRegions.size-1)); + spriteAnimationComponent.currentAnimation = "Default"; + spriteAnimationComponent.playMode = Animation.PlayMode.LOOP; + + spriteAnimationStateComponent.setAllRegions(backupAnimRegions); + spriteAnimationStateComponent.set(spriteAnimationComponent); + + textureRegionComponent.region = backupAnimRegions.get(0); + + ProjectInfoVO projectInfoVO = Sandbox.getInstance().getSceneControl().sceneLoader.getRm().getProjectVO(); + float ppwu = projectInfoVO.pixelToWorld; + size.width = textureRegionComponent.region.getRegionWidth() / ppwu; + size.height = textureRegionComponent.region.getRegionHeight() / ppwu; + + transformComponent.originX = size.width / 2; + transformComponent.originY = size.height / 2; + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } +}