diff --git a/spine-as3/spine-as3-example/lib/spine-as3.swc b/spine-as3/spine-as3-example/lib/spine-as3.swc index 69a9f5236..2839d51b4 100644 Binary files a/spine-as3/spine-as3-example/lib/spine-as3.swc and b/spine-as3/spine-as3-example/lib/spine-as3.swc differ diff --git a/spine-as3/spine-as3/.settings/com.powerflasher.fdt.core.prefs b/spine-as3/spine-as3/.settings/com.powerflasher.fdt.core.prefs index dc2df9e0f..653c8279c 100644 --- a/spine-as3/spine-as3/.settings/com.powerflasher.fdt.core.prefs +++ b/spine-as3/spine-as3/.settings/com.powerflasher.fdt.core.prefs @@ -14,7 +14,7 @@ com.powerflasher.fdt.core.PassManifests=true com.powerflasher.fdt.core.PassRsls=false com.powerflasher.fdt.core.PassSwcs=true com.powerflasher.fdt.core.PlatformType=WEB -com.powerflasher.fdt.core.PlayerVersion=23.0 +com.powerflasher.fdt.core.PlayerVersion=30.0 com.powerflasher.fdt.core.ProjectTypeHint=Web com.powerflasher.fdt.core.Runtime=Flash_Player com.powerflasher.fdt.core.SdkName=Flex 4.6.0 diff --git a/spine-as3/spine-as3/.settings/launch/spine-as3.swc.launch b/spine-as3/spine-as3/.settings/launch/spine-as3.swc.launch index 2eae8bac8..94a8145e7 100644 --- a/spine-as3/spine-as3/.settings/launch/spine-as3.swc.launch +++ b/spine-as3/spine-as3/.settings/launch/spine-as3.swc.launch @@ -1,23 +1,24 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spine-as3/spine-as3/.settings/org.eclipse.core.resources.prefs b/spine-as3/spine-as3/.settings/org.eclipse.core.resources.prefs index bba54d7ec..eb6c724eb 100644 --- a/spine-as3/spine-as3/.settings/org.eclipse.core.resources.prefs +++ b/spine-as3/spine-as3/.settings/org.eclipse.core.resources.prefs @@ -1,6 +1,9 @@ eclipse.preferences.version=1 +encoding//src/spine/IkConstraint.as=UTF-8 +encoding//src/spine/IkConstraintData.as=UTF-8 encoding//src/spine/Interpolation.as=UTF-8 encoding//src/spine/MathUtils.as=UTF-8 +encoding//src/spine/Skeleton.as=UTF-8 encoding//src/spine/SkeletonClipping.as=UTF-8 encoding//src/spine/SkeletonJson.as=UTF-8 encoding//src/spine/Triangulator.as=UTF-8 diff --git a/spine-as3/spine-as3/src/spine/IkConstraint.as b/spine-as3/spine-as3/src/spine/IkConstraint.as index 9c2836ede..6656383ee 100644 --- a/spine-as3/spine-as3/src/spine/IkConstraint.as +++ b/spine-as3/spine-as3/src/spine/IkConstraint.as @@ -33,8 +33,9 @@ package spine { internal var _data : IkConstraintData; public var bones : Vector.; public var target : Bone; - public var mix : Number; public var bendDirection : int; + public var stretch: Boolean; + public var mix : Number; public function IkConstraint(data : IkConstraintData, skeleton : Skeleton) { if (data == null) throw new ArgumentError("data cannot be null."); @@ -42,6 +43,7 @@ package spine { _data = data; mix = data.mix; bendDirection = data.bendDirection; + stretch = data.stretch; bones = new Vector.(); for each (var boneData : BoneData in data.bones) @@ -56,10 +58,10 @@ package spine { public function update() : void { switch (bones.length) { case 1: - apply1(bones[0], target.worldX, target.worldY, mix); + apply1(bones[0], target.worldX, target.worldY, stretch, mix); break; case 2: - apply2(bones[0], bones[1], target.worldX, target.worldY, bendDirection, mix); + apply2(bones[0], bones[1], target.worldX, target.worldY, bendDirection, stretch, mix); break; } } @@ -78,7 +80,7 @@ package spine { /** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world * coordinate system. */ - static public function apply1(bone : Bone, targetX : Number, targetY : Number, alpha : Number) : void { + static public function apply1(bone : Bone, targetX : Number, targetY : Number, stretch : Boolean, alpha : Number) : void { if (!bone.appliedValid) bone.updateAppliedTransform(); var p : Bone = bone.parent; var id : Number = 1 / (p.a * p.d - p.b * p.c); @@ -89,20 +91,25 @@ package spine { if (rotationIK > 180) rotationIK -= 360; else if (rotationIK < -180) rotationIK += 360; - bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, bone.ascaleX, bone.ascaleY, bone.ashearX, bone.ashearY); + var sx : Number = bone.ascaleX; + if (stretch) { + var b : Number = bone.data.length * sx, dd : Number = Math.sqrt(tx * tx + ty * ty); + if (dd > b && b > 0.0001) sx *= (dd / b - 1) * alpha + 1; + } + bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, bone.ascaleY, bone.ashearX, bone.ashearY); } /** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The * target is specified in the world coordinate system. * @param child Any descendant bone of the parent. */ - static public function apply2(parent : Bone, child : Bone, targetX : Number, targetY : Number, bendDir : int, alpha : Number) : void { + static public function apply2(parent : Bone, child : Bone, targetX : Number, targetY : Number, bendDir : int, stretch : Boolean, alpha : Number) : void { if (alpha == 0) { child.updateWorldTransform(); return; } if (!parent.appliedValid) parent.updateAppliedTransform(); if (!child.appliedValid) child.updateAppliedTransform(); - var px : Number = parent.ax, py : Number = parent.ay, psx : Number = parent.ascaleX, psy : Number = parent.ascaleY, csx : Number = child.ascaleX; + var px : Number = parent.ax, py : Number = parent.ay, psx : Number = parent.ascaleX, sx : Number = psx, psy : Number = parent.ascaleY, csx : Number = child.ascaleX; var os1 : int, os2 : int, s2 : int; if (psx < 0) { psx = -psx; @@ -138,7 +145,7 @@ package spine { c = pp.c; d = pp.d; var id : Number = 1 / (a * d - b * c), x : Number = targetX - pp.worldX, y : Number = targetY - pp.worldY; - var tx : Number = (x * d - y * b) * id - px, ty : Number = (y * a - x * c) * id - py; + var tx : Number = (x * d - y * b) * id - px, ty : Number = (y * a - x * c) * id - py, dd : Number = tx * tx + ty * ty; x = cwx - pp.worldX; y = cwy - pp.worldY; var dx : Number = (x * d - y * b) * id - px, dy : Number = (y * a - x * c) * id - py; @@ -146,10 +153,13 @@ package spine { outer: if (u) { l2 *= psx; - var cos : Number = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); + var cos : Number = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2); if (cos < -1) cos = -1; - else if (cos > 1) cos = 1; + else if (cos > 1) { + cos = 1; + if (stretch && l1 + l2 > 0.0001) sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1; + } a2 = Math.acos(cos) * bendDir; a = l1 + l2 * cos; b = l2 * Math.sin(a2); @@ -157,7 +167,7 @@ package spine { } else { a = psx * l2; b = psy * l2; - var aa : Number = a * a, bb : Number = b * b, dd : Number = tx * tx + ty * ty, ta : Number = Math.atan2(ty, tx); + var aa : Number = a * a, bb : Number = b * b, ta : Number = Math.atan2(ty, tx); c = bb * l1 * l1 + aa * dd - aa * bb; var c1 : Number = -2 * bb * l1, c2 : Number = bb - aa; d = c1 * c1 - 4 * c2 * c; @@ -209,7 +219,7 @@ package spine { if (a1 > 180) a1 -= 360; else if (a1 < -180) a1 += 360; - parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.ascaleX, parent.ascaleY, 0, 0); + parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, sx, parent.ascaleY, 0, 0); rotation = child.arotation; a2 = ((a2 + os) * MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation; if (a2 > 180) diff --git a/spine-as3/spine-as3/src/spine/IkConstraintData.as b/spine-as3/spine-as3/src/spine/IkConstraintData.as index ba4dd5184..f1aae4df6 100644 --- a/spine-as3/spine-as3/src/spine/IkConstraintData.as +++ b/spine-as3/spine-as3/src/spine/IkConstraintData.as @@ -34,8 +34,9 @@ package spine { public var order : Number; public var bones : Vector. = new Vector.(); public var target : BoneData; - public var bendDirection : int = 1; public var mix : Number = 1; + public var bendDirection : int = 1; + public var stretch : Boolean = false; public function IkConstraintData(name : String) { if (name == null) throw new ArgumentError("name cannot be null."); diff --git a/spine-as3/spine-as3/src/spine/Skeleton.as b/spine-as3/spine-as3/src/spine/Skeleton.as index b66f6e9ca..9204b71e2 100644 --- a/spine-as3/spine-as3/src/spine/Skeleton.as +++ b/spine-as3/spine-as3/src/spine/Skeleton.as @@ -291,6 +291,7 @@ package spine { for each (var ikConstraint : IkConstraint in ikConstraints) { ikConstraint.bendDirection = ikConstraint._data.bendDirection; + ikConstraint.stretch = ikConstraint._data.stretch; ikConstraint.mix = ikConstraint._data.mix; } diff --git a/spine-as3/spine-as3/src/spine/SkeletonJson.as b/spine-as3/spine-as3/src/spine/SkeletonJson.as index 5d022a611..8ea2a2e33 100644 --- a/spine-as3/spine-as3/src/spine/SkeletonJson.as +++ b/spine-as3/spine-as3/src/spine/SkeletonJson.as @@ -158,6 +158,7 @@ package spine { if (!ikConstraintData.target) throw new Error("Target bone not found: " + constraintMap["target"]); ikConstraintData.bendDirection = (!constraintMap.hasOwnProperty("bendPositive") || constraintMap["bendPositive"]) ? 1 : -1; + ikConstraintData.stretch = (!constraintMap.hasOwnProperty("stretch") || constraintMap["stretch"]); ikConstraintData.mix = constraintMap.hasOwnProperty("mix") ? constraintMap["mix"] : 1; skeletonData.ikConstraints.push(ikConstraintData); @@ -531,7 +532,8 @@ package spine { for each (valueMap in values) { var mix : Number = valueMap.hasOwnProperty("mix") ? valueMap["mix"] : 1; var bendDirection : int = (!valueMap.hasOwnProperty("bendPositive") || valueMap["bendPositive"]) ? 1 : -1; - ikTimeline.setFrame(frameIndex, valueMap["time"], mix, bendDirection); + var stretch : Boolean = (!valueMap.hasOwnProperty("stretch") || valueMap["stretch"]); + ikTimeline.setFrame(frameIndex, valueMap["time"], mix, bendDirection, stretch); readCurve(valueMap, ikTimeline, frameIndex); frameIndex++; } diff --git a/spine-as3/spine-as3/src/spine/animation/IkConstraintTimeline.as b/spine-as3/spine-as3/src/spine/animation/IkConstraintTimeline.as index f4078e98f..66b35379c 100644 --- a/spine-as3/spine-as3/src/spine/animation/IkConstraintTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/IkConstraintTimeline.as @@ -34,9 +34,9 @@ package spine.animation { import spine.Skeleton; public class IkConstraintTimeline extends CurveTimeline { - static public const ENTRIES : int = 3; - static internal const PREV_TIME : int = -3, PREV_MIX : int = -2, PREV_BEND_DIRECTION : int = -1; - static internal const MIX : int = 1, BEND_DIRECTION : int = 2; + static public const ENTRIES : int = 4; + static internal const PREV_TIME : int = -4, PREV_MIX : int = -3, PREV_BEND_DIRECTION : int = -2, PREV_STRETCH : int = -1; + static internal const MIX : int = 1, BEND_DIRECTION : int = 2, STRETCH : int = 3; public var ikConstraintIndex : int; public var frames : Vector.; // time, mix, bendDirection, ... @@ -50,11 +50,12 @@ package spine.animation { } /** Sets the time, mix and bend direction of the specified keyframe. */ - public function setFrame(frameIndex : int, time : Number, mix : Number, bendDirection : int) : void { + public function setFrame(frameIndex : int, time : Number, mix : Number, bendDirection : int, stretch: Boolean) : void { frameIndex *= ENTRIES; frames[frameIndex] = time; frames[int(frameIndex + MIX)] = mix; frames[int(frameIndex + BEND_DIRECTION)] = bendDirection; + frames[int(frameIndex + STRETCH)] = stretch ? 1 : 0; } override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector., alpha : Number, blend : MixBlend, direction : MixDirection) : void { @@ -64,10 +65,12 @@ package spine.animation { case MixBlend.setup: constraint.mix = constraint.data.mix; constraint.bendDirection = constraint.data.bendDirection; + constraint.stretch = constraint.data.stretch; return; case MixBlend.first: constraint.mix += (constraint.data.mix - constraint.mix) * alpha; constraint.bendDirection = constraint.data.bendDirection; + constraint.stretch = constraint.data.stretch; } return; } @@ -75,10 +78,20 @@ package spine.animation { if (time >= frames[int(frames.length - ENTRIES)]) { // Time is after last frame. if (blend == MixBlend.setup) { constraint.mix = constraint.data.mix + (frames[frames.length + PREV_MIX] - constraint.data.mix) * alpha; - constraint.bendDirection = direction == MixDirection.Out ? constraint.data.bendDirection : int(frames[frames.length + PREV_BEND_DIRECTION]); + + if (direction == MixDirection.Out) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.stretch = constraint.data.stretch; + } else { + constraint.bendDirection = int(frames[frames.length + PREV_BEND_DIRECTION]); + constraint.stretch = int(frames[frames.length + PREV_STRETCH]) != 0; + } } else { constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha; - if (direction == MixDirection.In) constraint.bendDirection = int(frames[frames.length + PREV_BEND_DIRECTION]); + if (direction == MixDirection.In) { + constraint.bendDirection = int(frames[frames.length + PREV_BEND_DIRECTION]); + constraint.stretch = int(frames[frames.length + PREV_STRETCH]) != 0; + } } return; } @@ -91,10 +104,19 @@ package spine.animation { if (blend == MixBlend.setup) { constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha; - constraint.bendDirection = direction == MixDirection.Out ? constraint.data.bendDirection : int(frames[frame + PREV_BEND_DIRECTION]); + if (direction == MixDirection.Out) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.stretch = constraint.data.stretch; + } else { + constraint.bendDirection = int(frames[frame + PREV_BEND_DIRECTION]); + constraint.stretch = int(frames[frame + PREV_STRETCH]) != 0; + } } else { constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; - if (direction == MixDirection.In) constraint.bendDirection = int(frames[frame + PREV_BEND_DIRECTION]); + if (direction == MixDirection.In) { + constraint.bendDirection = int(frames[frame + PREV_BEND_DIRECTION]); + constraint.stretch = int(frames[frame + PREV_STRETCH]) != 0; + } } } } diff --git a/spine-starling/spine-starling-example/.settings/org.eclipse.core.resources.prefs b/spine-starling/spine-starling-example/.settings/org.eclipse.core.resources.prefs index adcfe1dd6..e42e88a4f 100644 --- a/spine-starling/spine-starling-example/.settings/org.eclipse.core.resources.prefs +++ b/spine-starling/spine-starling-example/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,5 @@ eclipse.preferences.version=1 +encoding//src/spine/examples/StretchymanStrechyIkExample.as=UTF-8 encoding//src/spine/examples/TankExample.as=UTF-8 encoding//src/spine/examples/TwoColorExample.as=UTF-8 encoding/=UTF-8 diff --git a/spine-starling/spine-starling-example/lib/spine-as3.swc b/spine-starling/spine-starling-example/lib/spine-as3.swc index e479cc0aa..2839d51b4 100644 Binary files a/spine-starling/spine-starling-example/lib/spine-as3.swc and b/spine-starling/spine-starling-example/lib/spine-as3.swc differ diff --git a/spine-starling/spine-starling-example/src/spine/examples/StretchymanExample.as b/spine-starling/spine-starling-example/src/spine/examples/StretchymanExample.as index c1df82617..03bdbdf2e 100644 --- a/spine-starling/spine-starling-example/src/spine/examples/StretchymanExample.as +++ b/spine-starling/spine-starling-example/src/spine/examples/StretchymanExample.as @@ -104,7 +104,7 @@ package spine.examples { if (touch && touch.phase == TouchPhase.BEGAN) { var parent: DisplayObjectContainer = this.parent; this.removeFromParent(true); - parent.addChild(new CoinExample()); + parent.addChild(new StretchymanStrechyIkExample()); } } } diff --git a/spine-starling/spine-starling-example/src/spine/examples/StretchymanStrechyIkExample.as b/spine-starling/spine-starling-example/src/spine/examples/StretchymanStrechyIkExample.as new file mode 100644 index 000000000..d8550bd3d --- /dev/null +++ b/spine-starling/spine-starling-example/src/spine/examples/StretchymanStrechyIkExample.as @@ -0,0 +1,111 @@ +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 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 THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +package spine.examples { + import starling.display.DisplayObjectContainer; + import starling.events.TouchPhase; + import starling.events.Touch; + import starling.events.TouchEvent; + import spine.*; + import spine.animation.AnimationStateData; + import spine.animation.TrackEntry; + import spine.atlas.Atlas; + import spine.attachments.AtlasAttachmentLoader; + import spine.attachments.AttachmentLoader; + import spine.starling.SkeletonAnimation; + import spine.starling.StarlingTextureLoader; + + import starling.core.Starling; + import starling.display.Sprite; + + public class StretchymanStrechyIkExample extends Sprite { + [Embed(source = "/stretchyman-stretchy-ik.json", mimeType = "application/octet-stream")] + static public const StretchymanJson : Class; + + [Embed(source = "/stretchyman.atlas", mimeType = "application/octet-stream")] + static public const StretchymanAtlas : Class; + + [Embed(source = "/stretchyman.png")] + static public const StretchymanAtlasTexture : Class; + private var skeleton : SkeletonAnimation; + + public function StretchymanStrechyIkExample() { + var spineAtlas : Atlas = new Atlas(new StretchymanAtlas(), new StarlingTextureLoader(new StretchymanAtlasTexture())); + var attachmentLoader : AttachmentLoader = new AtlasAttachmentLoader(spineAtlas); + var json : SkeletonJson = new SkeletonJson(attachmentLoader); + json.scale = 0.4; + var skeletonData : SkeletonData = json.readSkeletonData(new StretchymanJson()); + + var stateData : AnimationStateData = new AnimationStateData(skeletonData); + + skeleton = new SkeletonAnimation(skeletonData, stateData); + skeleton.x = 100; + skeleton.y = 560; + + skeleton.state.timeScale = 0.1; + + skeleton.state.onStart.add(function(entry : TrackEntry) : void { + trace(entry.trackIndex + " start: " + entry.animation.name); + }); + skeleton.state.onInterrupt.add(function(entry : TrackEntry) : void { + trace(entry.trackIndex + " interrupt: " + entry.animation.name); + }); + skeleton.state.onEnd.add(function(entry : TrackEntry) : void { + trace(entry.trackIndex + " end: " + entry.animation.name); + }); + skeleton.state.onComplete.add(function(entry : TrackEntry) : void { + trace(entry.trackIndex + " complete: " + entry.animation.name); + }); + skeleton.state.onDispose.add(function(entry : TrackEntry) : void { + trace(entry.trackIndex + " dispose: " + entry.animation.name); + }); + skeleton.state.onEvent.add(function(entry : TrackEntry, event : Event) : void { + trace(entry.trackIndex + " event: " + entry.animation.name + ", " + event.data.name + ": " + event.intValue + ", " + event.floatValue + ", " + event.stringValue); + }); + + skeleton.skeleton.setToSetupPose(); + skeleton.state.setAnimationByName(0, "sneak", true); + + addChild(skeleton); + Starling.juggler.add(skeleton); + + addEventListener(TouchEvent.TOUCH, onClick); + } + + private function onClick(event : TouchEvent) : void { + var touch : Touch = event.getTouch(this); + if (touch && touch.phase == TouchPhase.BEGAN) { + var parent: DisplayObjectContainer = this.parent; + this.removeFromParent(true); + parent.addChild(new CoinExample()); + } + } + } +} \ No newline at end of file diff --git a/spine-starling/spine-starling/lib/spine-as3.swc b/spine-starling/spine-starling/lib/spine-as3.swc index e479cc0aa..2839d51b4 100644 Binary files a/spine-starling/spine-starling/lib/spine-as3.swc and b/spine-starling/spine-starling/lib/spine-as3.swc differ