diff --git a/spine-haxe/example/src/BasicExample.hx b/spine-haxe/example/src/BasicExample.hx index b59a7034d..ad65061b3 100644 --- a/spine-haxe/example/src/BasicExample.hx +++ b/spine-haxe/example/src/BasicExample.hx @@ -27,6 +27,7 @@ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +import Scene.SceneManager; import openfl.utils.Assets; import spine.SkeletonData; import spine.animation.AnimationStateData; @@ -57,13 +58,16 @@ class BasicExample extends Scene { addChild(skeletonSprite); juggler.add(skeletonSprite); + addText("Click anywhere for next scene"); + addEventListener(TouchEvent.TOUCH, onTouch); } public function onTouch(e:TouchEvent) { var touch = e.getTouch(this); + trace(touch); if (touch != null && touch.phase == TouchPhase.ENDED) { - trace("Mouse clicked"); + SceneManager.getInstance().switchScene(new SequenceExample()); } } } diff --git a/spine-haxe/example/src/Main.hx b/spine-haxe/example/src/Main.hx index 63712f6ab..3f0f5aafc 100644 --- a/spine-haxe/example/src/Main.hx +++ b/spine-haxe/example/src/Main.hx @@ -49,6 +49,6 @@ class Main extends Sprite { starlingSingleton.start(); Starling.current.stage.color = 0x000000; - SceneManager.getInstance().switchScene(new BasicExample()); + SceneManager.getInstance().switchScene(new VineExample()); } } diff --git a/spine-haxe/example/src/MixAndMatchExample.hx b/spine-haxe/example/src/MixAndMatchExample.hx new file mode 100644 index 000000000..198bead50 --- /dev/null +++ b/spine-haxe/example/src/MixAndMatchExample.hx @@ -0,0 +1,83 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated July 28, 2023. Replaces all prior versions. + * + * Copyright (c) 2013-2023, Esoteric Software LLC + * + * Integration of the Spine Runtimes into software or otherwise creating + * derivative works of the Spine Runtimes is permitted under the terms and + * conditions of Section 2 of the Spine Editor License Agreement: + * http://esotericsoftware.com/spine-editor-license + * + * Otherwise, it is permitted to integrate the Spine Runtimes into software or + * otherwise create derivative works of the Spine Runtimes (collectively, + * "Products"), provided that each user of the Products must obtain their own + * Spine Editor license and redistribution of the Products in any form must + * include this license and copyright notice. + * + * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, + * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE + * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*****************************************************************************/ + +import spine.Skin; +import Scene.SceneManager; +import openfl.utils.Assets; +import spine.SkeletonData; +import spine.animation.AnimationStateData; +import spine.atlas.TextureAtlas; +import spine.starling.SkeletonSprite; +import spine.starling.StarlingTextureLoader; +import starling.core.Starling; +import starling.events.TouchEvent; +import starling.events.TouchPhase; + +class MixAndMatchExample extends Scene { + var loadBinary = false; + + public function load():Void { + var atlas = new TextureAtlas(Assets.getText("assets/mix-and-match.atlas"), new StarlingTextureLoader("assets/mix-and-match.atlas")); + var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/mix-and-match-pro.skel") : Assets.getText("assets/mix-and-match-pro.json"), atlas); + var animationStateData = new AnimationStateData(data); + animationStateData.defaultMix = 0.25; + + var skeletonSprite = new SkeletonSprite(data, animationStateData); + var customSkin = new Skin("custom"); + var skinBase = data.findSkin("skin-base"); + customSkin.addSkin(skinBase); + customSkin.addSkin(data.findSkin("nose/short")); + customSkin.addSkin(data.findSkin("eyelids/girly")); + customSkin.addSkin(data.findSkin("eyes/violet")); + customSkin.addSkin(data.findSkin("hair/brown")); + customSkin.addSkin(data.findSkin("clothes/hoodie-orange")); + customSkin.addSkin(data.findSkin("legs/pants-jeans")); + customSkin.addSkin(data.findSkin("accessories/bag")); + customSkin.addSkin(data.findSkin("accessories/hat-red-yellow")); + skeletonSprite.skeleton.skin = customSkin; + + var bounds = skeletonSprite.skeleton.getBounds(); + skeletonSprite.scale = Starling.current.stage.stageHeight / bounds.height * 0.5; + skeletonSprite.x = Starling.current.stage.stageWidth / 2; + skeletonSprite.y = Starling.current.stage.stageHeight * 0.9; + skeletonSprite.state.setAnimationByName(0, "dance", true); + + addChild(skeletonSprite); + juggler.add(skeletonSprite); + + addEventListener(TouchEvent.TOUCH, onTouch); + } + + public function onTouch(e:TouchEvent) { + var touch = e.getTouch(this); + if (touch != null && touch.phase == TouchPhase.ENDED) { + SceneManager.getInstance().switchScene(new TankExample()); + } + } +} diff --git a/spine-haxe/example/src/Scene.hx b/spine-haxe/example/src/Scene.hx index bd6d7148b..a654b2723 100644 --- a/spine-haxe/example/src/Scene.hx +++ b/spine-haxe/example/src/Scene.hx @@ -27,6 +27,9 @@ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +import starling.display.Quad; +import starling.geom.Rectangle; +import starling.text.TextField; import starling.core.Starling; import starling.display.Sprite; @@ -60,8 +63,14 @@ class SceneManager { abstract class Scene extends Sprite { var juggler = new starling.animation.Juggler(); + public var background:Quad; + public function new() { super(); + var stageWidth = Starling.current.stage.stageWidth; + var stageHeight = Starling.current.stage.stageHeight; + background = new Quad(stageWidth, stageHeight, 0x0); + this.addChild(background); Starling.current.juggler.add(juggler); } @@ -72,4 +81,13 @@ abstract class Scene extends Sprite { Starling.current.juggler.remove(juggler); super.dispose(); } + + public function addText(text:String) { + var textField = new TextField(200, 30, text); + textField.x = 10; + textField.y = 10; + textField.format.color = 0xffffffff; + addChild(textField); + return textField; + } } diff --git a/spine-haxe/example/src/SequenceExample.hx b/spine-haxe/example/src/SequenceExample.hx index 721d044fc..3eb20360b 100644 --- a/spine-haxe/example/src/SequenceExample.hx +++ b/spine-haxe/example/src/SequenceExample.hx @@ -27,6 +27,7 @@ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +import Scene.SceneManager; import openfl.utils.Assets; import spine.SkeletonData; import spine.animation.AnimationStateData; @@ -50,7 +51,7 @@ class SequenceExample extends Scene { var bounds = skeletonSprite.skeleton.getBounds(); skeletonSprite.scale = Starling.current.stage.stageWidth / bounds.width * 0.5; skeletonSprite.x = Starling.current.stage.stageWidth / 2; - skeletonSprite.y = Starling.current.stage.stageHeight * 0.9; + skeletonSprite.y = Starling.current.stage.stageHeight * 0.5; skeletonSprite.state.setAnimationByName(0, "flying", true); addChild(skeletonSprite); @@ -62,7 +63,7 @@ class SequenceExample extends Scene { public function onTouch(e:TouchEvent) { var touch = e.getTouch(this); if (touch != null && touch.phase == TouchPhase.ENDED) { - trace("Mouse clicked"); + SceneManager.getInstance().switchScene(new MixAndMatchExample()); } } } diff --git a/spine-haxe/example/src/TankExample.hx b/spine-haxe/example/src/TankExample.hx new file mode 100644 index 000000000..52e6f39ff --- /dev/null +++ b/spine-haxe/example/src/TankExample.hx @@ -0,0 +1,70 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated July 28, 2023. Replaces all prior versions. + * + * Copyright (c) 2013-2023, Esoteric Software LLC + * + * Integration of the Spine Runtimes into software or otherwise creating + * derivative works of the Spine Runtimes is permitted under the terms and + * conditions of Section 2 of the Spine Editor License Agreement: + * http://esotericsoftware.com/spine-editor-license + * + * Otherwise, it is permitted to integrate the Spine Runtimes into software or + * otherwise create derivative works of the Spine Runtimes (collectively, + * "Products"), provided that each user of the Products must obtain their own + * Spine Editor license and redistribution of the Products in any form must + * include this license and copyright notice. + * + * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, + * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE + * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*****************************************************************************/ + +import Scene.SceneManager; +import openfl.utils.Assets; +import spine.SkeletonData; +import spine.animation.AnimationStateData; +import spine.atlas.TextureAtlas; +import spine.starling.SkeletonSprite; +import spine.starling.StarlingTextureLoader; +import starling.core.Starling; +import starling.events.TouchEvent; +import starling.events.TouchPhase; + +class TankExample extends Scene { + var loadBinary = false; + + public function load():Void { + background.color = 0xffffffff; + var atlas = new TextureAtlas(Assets.getText("assets/tank.atlas"), new StarlingTextureLoader("assets/tank.atlas")); + var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/tank-pro.skel") : Assets.getText("assets/tank-pro.json"), atlas); + var animationStateData = new AnimationStateData(skeletondata); + animationStateData.defaultMix = 0.25; + + var skeletonSprite = new SkeletonSprite(skeletondata, animationStateData); + var bounds = skeletonSprite.skeleton.getBounds(); + skeletonSprite.scale = Starling.current.stage.stageWidth / bounds.width; + skeletonSprite.x = Starling.current.stage.stageWidth / 2; + skeletonSprite.y = Starling.current.stage.stageHeight * 0.5; + skeletonSprite.state.setAnimationByName(0, "drive", true); + + addChild(skeletonSprite); + juggler.add(skeletonSprite); + + addEventListener(TouchEvent.TOUCH, onTouch); + } + + public function onTouch(e:TouchEvent) { + var touch = e.getTouch(this); + if (touch != null && touch.phase == TouchPhase.ENDED) { + SceneManager.getInstance().switchScene(new VineExample()); + } + } +} diff --git a/spine-haxe/example/src/VineExample.hx b/spine-haxe/example/src/VineExample.hx new file mode 100644 index 000000000..67346cb89 --- /dev/null +++ b/spine-haxe/example/src/VineExample.hx @@ -0,0 +1,70 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated July 28, 2023. Replaces all prior versions. + * + * Copyright (c) 2013-2023, Esoteric Software LLC + * + * Integration of the Spine Runtimes into software or otherwise creating + * derivative works of the Spine Runtimes is permitted under the terms and + * conditions of Section 2 of the Spine Editor License Agreement: + * http://esotericsoftware.com/spine-editor-license + * + * Otherwise, it is permitted to integrate the Spine Runtimes into software or + * otherwise create derivative works of the Spine Runtimes (collectively, + * "Products"), provided that each user of the Products must obtain their own + * Spine Editor license and redistribution of the Products in any form must + * include this license and copyright notice. + * + * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, + * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE + * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*****************************************************************************/ + +import Scene.SceneManager; +import openfl.utils.Assets; +import spine.SkeletonData; +import spine.animation.AnimationStateData; +import spine.atlas.TextureAtlas; +import spine.starling.SkeletonSprite; +import spine.starling.StarlingTextureLoader; +import starling.core.Starling; +import starling.events.TouchEvent; +import starling.events.TouchPhase; + +class VineExample extends Scene { + var loadBinary = false; + + public function load():Void { + background.color = 0xffffffff; + var atlas = new TextureAtlas(Assets.getText("assets/vine.atlas"), new StarlingTextureLoader("assets/vine.atlas")); + var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/vine-pro.skel") : Assets.getText("assets/vine-pro.json"), atlas); + var animationStateData = new AnimationStateData(skeletondata); + animationStateData.defaultMix = 0.25; + + var skeletonSprite = new SkeletonSprite(skeletondata, animationStateData); + skeletonSprite.skeleton.updateWorldTransform(); + var bounds = skeletonSprite.skeleton.getBounds(); + skeletonSprite.scale = Starling.current.stage.stageWidth / bounds.width; + skeletonSprite.x = Starling.current.stage.stageWidth / 2; + skeletonSprite.y = Starling.current.stage.stageHeight * 0.5; + + addChild(skeletonSprite); + juggler.add(skeletonSprite); + + addEventListener(TouchEvent.TOUCH, onTouch); + } + + public function onTouch(e:TouchEvent) { + var touch = e.getTouch(this); + if (touch != null && touch.phase == TouchPhase.ENDED) { + SceneManager.getInstance().switchScene(new BasicExample()); + } + } +} diff --git a/spine-haxe/spine-haxe/spine/ArrayUtils.hx b/spine-haxe/spine-haxe/spine/ArrayUtils.hx new file mode 100644 index 000000000..8575852b9 --- /dev/null +++ b/spine-haxe/spine-haxe/spine/ArrayUtils.hx @@ -0,0 +1,13 @@ +package spine; + +class ArrayUtils { + public static function resize(array:Array, count:Int, value:T) { + if (count < 0) + count = 0; + array.resize(count); + for (i in 0...count) { + array[i] = value; + } + return array; + } +} diff --git a/spine-haxe/spine-haxe/spine/PathConstraint.hx b/spine-haxe/spine-haxe/spine/PathConstraint.hx index 163fbefd5..00a0b1acf 100644 --- a/spine-haxe/spine-haxe/spine/PathConstraint.hx +++ b/spine-haxe/spine-haxe/spine/PathConstraint.hx @@ -86,18 +86,16 @@ class PathConstraint implements Updatable { return; var data:PathConstraintData = _data; - var percentSpacing:Bool = data.spacingMode == SpacingMode.percent; - var rotateMode:RotateMode = data.rotateMode; - var fTangents:Bool = rotateMode == RotateMode.tangent, - fScale:Bool = rotateMode == RotateMode.chainScale; - + var fTangents:Bool = data.rotateMode == RotateMode.tangent, + fScale:Bool = data.rotateMode == RotateMode.chainScale; var boneCount:Int = _bones.length; var spacesCount:Int = fTangents ? boneCount : boneCount + 1; - var bones:Array = _bones; - _spaces.resize(spacesCount); + ArrayUtils.resize(_spaces, spacesCount, 0); + if (fScale) { + ArrayUtils.resize(_lengths, boneCount, 0); + } - if (fScale) - _lengths.resize(boneCount); + var bones:Array = _bones; var i:Int, n:Int, @@ -254,7 +252,7 @@ class PathConstraint implements Updatable { private function computeWorldPositions(path:PathAttachment, spacesCount:Int, tangents:Bool):Array { var position:Float = this.position; - _positions.resize(spacesCount * 3 + 2); + ArrayUtils.resize(_positions, spacesCount * 3 + 2, 0); var out:Array = _positions, world:Array; var closed:Bool = path.closed; var verticesLength:Int = path.worldVerticesLength; @@ -277,7 +275,7 @@ class PathConstraint implements Updatable { multiplier = 1; } - _world.resize(8); + ArrayUtils.resize(_world, 8, 0); world = _world; var i:Int = 0; var o:Int = 0; @@ -343,7 +341,7 @@ class PathConstraint implements Updatable { // World vertices. if (closed) { verticesLength += 2; - _world.resize(verticesLength); + ArrayUtils.resize(_world, verticesLength, 0); world = _world; path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2); path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2); @@ -352,13 +350,13 @@ class PathConstraint implements Updatable { } else { curveCount--; verticesLength -= 4; - _world.resize(verticesLength); + ArrayUtils.resize(_world, verticesLength, 0); world = _world; path.computeWorldVertices(target, 2, verticesLength, world, 0, 2); } // Curve lengths. - _curves.resize(curveCount); + ArrayUtils.resize(_curves, curveCount, 0); var curves:Array = _curves; var pathLength:Float = 0; var x1:Float = world[0], diff --git a/spine-sfml/cpp/example/testbed.cpp b/spine-sfml/cpp/example/testbed.cpp index a883ba146..aa5767864 100644 --- a/spine-sfml/cpp/example/testbed.cpp +++ b/spine-sfml/cpp/example/testbed.cpp @@ -71,10 +71,10 @@ class NullAttachmentLoader : public AttachmentLoader { int main(void) { String atlasFile(""); - String skeletonFile("/Users/badlogic/Downloads/catsanddogs2.json"); + String skeletonFile("/Users/badlogic/workspaces/spine-runtimes/spine-haxe/example/assets/vine-pro.json"); String animation = ""; - float scale = 0.6f; + float scale = 1.0f; SFMLTextureLoader textureLoader; NullAttachmentLoader nullLoader; Atlas *atlas = atlasFile.length() == 0 ? nullptr : new Atlas(atlasFile, &textureLoader); @@ -103,6 +103,7 @@ int main(void) { AnimationStateData stateData(skeletonData); SkeletonDrawable drawable(skeletonData, &stateData); + drawable.skeleton->updateWorldTransform(); drawable.skeleton->setPosition(320, 590); if (animation.length() > 0) drawable.state->setAnimation(0, animation, true); diff --git a/spine-ts/spine-phaser/src/SpinePlugin.ts b/spine-ts/spine-phaser/src/SpinePlugin.ts index 951bc2021..446fac955 100644 --- a/spine-ts/spine-phaser/src/SpinePlugin.ts +++ b/spine-ts/spine-phaser/src/SpinePlugin.ts @@ -193,6 +193,7 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin { gameDestroy () { this.pluginManager.removeGameObject((window as any).SPINE_GAME_OBJECT_TYPE ? (window as any).SPINE_GAME_OBJECT_TYPE : SPINE_GAME_OBJECT_TYPE, true, true); if (this.webGLRenderer) this.webGLRenderer.dispose(); + SpinePlugin.gameWebGLRenderer = null; } /** Returns the TextureAtlas instance for the given key */