Browse Source

fix : when not looping, don't call multiple onAnimEnd + currentFrame will be set to maxFrames.

ncannasse 11 years ago
parent
commit
c23009139e
3 changed files with 63 additions and 52 deletions
  1. 10 5
      h2d/Anim.hx
  2. 36 30
      h3d/anim/Animation.hx
  3. 17 17
      h3d/anim/LinearAnimation.hx

+ 10 - 5
h2d/Anim.hx

@@ -30,18 +30,23 @@ class Anim extends Drawable {
 
 	override function sync( ctx : RenderContext ) {
 		super.sync(ctx);
+		var prev = currentFrame;
 		currentFrame += speed * ctx.elapsedTime;
 		if( currentFrame < frames.length )
 			return;
-		if( loop )
+		if( loop ) {
 			currentFrame %= frames.length;
-		else if( currentFrame >= frames.length )
-			currentFrame = frames.length - 0.00001;
-		onAnimEnd();
+			onAnimEnd();
+		} else if( currentFrame >= frames.length ) {
+			currentFrame = frames.length;
+			if( currentFrame != prev ) onAnimEnd();
+		}
 	}
 
 	public function getFrame() {
-		return frames[Std.int(currentFrame)];
+		var i = Std.int(currentFrame);
+		if( i == frames.length ) i--;
+		return frames[i];
 	}
 
 	override function draw( ctx : RenderContext ) {

+ 36 - 30
h3d/anim/Animation.hx

@@ -1,20 +1,20 @@
 package h3d.anim;
 
 class AnimatedObject {
-	
+
 	public var objectName : String;
 	public var targetObject : h3d.scene.Object;
 	public var targetSkin : h3d.scene.Skin;
 	public var targetJoint : Int;
-	
+
 	public function new(name) {
 		this.objectName = name;
 	}
-	
+
 	public function clone() {
 		return new AnimatedObject(objectName);
 	}
-	
+
 }
 
 private class AnimWait {
@@ -29,24 +29,24 @@ private class AnimWait {
 }
 
 class Animation {
-	
+
 	static inline var EPSILON = 0.000001;
-	
+
 	public var name : String;
 	public var frameCount(default, null) : Int;
 	public var sampling(default,null) : Float;
 	public var frame(default, null) : Float;
-	
+
 	public var speed : Float;
 	public var onAnimEnd : Void -> Void;
-	
+
 	public var pause : Bool;
 	public var loop : Bool;
-	
+
 	var waits : AnimWait;
 	var isInstance : Bool;
 	var objects : Array<AnimatedObject>;
-	
+
 	function new(name, frameCount, sampling) {
 		this.name = name;
 		this.frameCount = frameCount;
@@ -57,7 +57,14 @@ class Animation {
 		loop = true;
 		pause = false;
 	}
-	
+
+	inline function getIFrame() {
+		var f = Std.int(frame);
+		var max = endFrame();
+		if( f == max ) f--;
+		return f;
+	}
+
 	/**
 		Register a callback function that will be called once when a frame is reached.
 	**/
@@ -76,19 +83,19 @@ class Animation {
 		else
 			prev.next = new AnimWait(f, callb, prev.next);
 	}
-	
+
 	/**
 		Remove all frame listeners
 	**/
 	public function clearWaits() {
 		waits = null;
 	}
-	
+
 	public function setFrame( f : Float ) {
 		frame = f % frameCount;
 		if( frame < 0 ) frame += frameCount;
 	}
-	
+
 	function clone( ?a : Animation ) : Animation {
 		if( a == null )
 			a = new Animation(name, frameCount, sampling);
@@ -98,11 +105,11 @@ class Animation {
 		a.pause = pause;
 		return a;
 	}
-	
+
 	function initInstance() {
 		isInstance = true;
 	}
-	
+
 	public function createInstance( base : h3d.scene.Object ) {
 		var currentSkin : h3d.scene.Skin = null;
 		var objects = [for( a in this.objects ) a.clone()];
@@ -112,7 +119,7 @@ class Animation {
 		a.initInstance();
 		return a;
 	}
-	
+
 	/**
 		If one of the animated object has been changed, it is necessary to call bind() so the animation can keep with the change.
 	**/
@@ -141,7 +148,7 @@ class Animation {
 			}
 		}
 	}
-	
+
 	/**
 		Synchronize the target object matrix.
 		If decompose is true, then the rotation quaternion is stored in [m12,m13,m21,m23] instead of mixed with the scale.
@@ -150,7 +157,7 @@ class Animation {
 		// should be overridden in subclass
 		throw "assert";
 	}
-	
+
 	function isPlaying() {
 		return !pause && (speed < 0 ? -speed : speed) > EPSILON;
 	}
@@ -158,14 +165,14 @@ class Animation {
 	function endFrame() {
 		return frameCount;
 	}
-	
+
 	public function update(dt:Float) : Float {
 		if( !isInstance )
 			throw "You must instanciate this animation first";
-		
+
 		if( !isPlaying() )
 			return 0;
-		
+
 		// check waits
 		var w = waits;
 		var prev = null;
@@ -188,18 +195,17 @@ class Animation {
 			w.callb();
 			return dt;
 		}
-		
+
 		// check on anim end
 		if( onAnimEnd != null ) {
 			var end = endFrame();
 			var et = (end - frame) / (speed * sampling);
-			if( et <= dt ) {
-				var f = end - EPSILON;
-				frame = f;
+			if( et <= dt && et > 0 ) {
+				frame = end;
 				dt -= et;
 				onAnimEnd();
 				// if we didn't change the frame or paused the animation, let's end it
-				if( frame == f && isPlaying() ) {
+				if( frame == end && isPlaying() ) {
 					if( loop ) {
 						frame = 0;
 					} else {
@@ -210,16 +216,16 @@ class Animation {
 				return dt;
 			}
 		}
-		
+
 		// update frame
 		frame += dt * speed * sampling;
 		if( frame >= frameCount ) {
 			if( loop )
 				frame %= frameCount;
 			else
-				frame = frameCount - EPSILON;
+				frame = frameCount;
 		}
 		return 0;
 	}
-	
+
 }

+ 17 - 17
h3d/anim/LinearAnimation.hx

@@ -33,7 +33,7 @@ class LinearObject extends AnimatedObject {
 		return o;
 	}
 }
-	
+
 class LinearAnimation extends Animation {
 
 	var syncFrame : Float;
@@ -42,7 +42,7 @@ class LinearAnimation extends Animation {
 		super(name,frame,sampling);
 		syncFrame = -1;
 	}
-	
+
 	public function addCurve( objName, frames, hasRot, hasScale ) {
 		var f = new LinearObject(objName);
 		f.frames = frames;
@@ -50,7 +50,7 @@ class LinearAnimation extends Animation {
 		f.hasScale = hasScale;
 		objects.push(f);
 	}
-	
+
 	public function addAlphaCurve( objName, alphas ) {
 		var f = new LinearObject(objName);
 		f.alphas = alphas;
@@ -62,11 +62,11 @@ class LinearAnimation extends Animation {
 		f.uvs = uvs;
 		objects.push(f);
 	}
-	
+
 	inline function getFrames() : Array<LinearObject> {
 		return cast objects;
 	}
-	
+
 	override function initInstance() {
 		super.initInstance();
 		for( a in getFrames() ) {
@@ -76,23 +76,23 @@ class LinearAnimation extends Animation {
 				throw a.objectName + " should be a mesh";
 		}
 	}
-	
+
 	override function clone(?a:Animation) {
 		if( a == null )
 			a = new LinearAnimation(name, frameCount, sampling);
 		super.clone(a);
 		return a;
 	}
-	
+
 	override function endFrame() {
 		return loop ? frameCount : frameCount - 1;
 	}
-	
+
 	@:access(h3d.scene.Skin)
 	override function sync( decompose = false ) {
 		if( frame == syncFrame && !decompose )
 			return;
-		var frame1 = Std.int(frame);
+		var frame1 = getIFrame();
 		var frame2 = (frame1 + 1) % frameCount;
 		var k2 = frame - frame1;
 		var k1 = 1 - k2;
@@ -120,13 +120,13 @@ class LinearAnimation extends Animation {
 				continue;
 			}
 			var f1 = o.frames[frame1], f2 = o.frames[frame2];
-			
+
 			var m = o.matrix;
-			
+
 			m._41 = f1.tx * k1 + f2.tx * k2;
 			m._42 = f1.ty * k1 + f2.ty * k2;
 			m._43 = f1.tz * k1 + f2.tz * k2;
-			
+
 			if( o.hasRotation ) {
 				// qlerp nearest
 				var dot = f1.qx * f2.qx + f1.qy * f2.qy + f1.qz * f2.qz + f1.qw * f2.qw;
@@ -141,7 +141,7 @@ class LinearAnimation extends Animation {
 				qy *= ql;
 				qz *= ql;
 				qw *= ql;
-				
+
 				if( decompose ) {
 					m._12 = qx;
 					m._13 = qy;
@@ -187,14 +187,14 @@ class LinearAnimation extends Animation {
 						m._33 *= sz;
 					}
 				}
-				
+
 			} else if( o.hasScale ) {
 				m._11 = f1.sx * k1 + f2.sx * k2;
 				m._22 = f1.sy * k1 + f2.sy * k2;
 				m._33 = f1.sz * k1 + f2.sz * k2;
 			}
-			
-			
+
+
 			if( o.targetSkin != null ) {
 				o.targetSkin.currentRelPose[o.targetJoint] = o.matrix;
 				o.targetSkin.jointsUpdated = true;
@@ -202,5 +202,5 @@ class LinearAnimation extends Animation {
 				o.targetObject.defaultTransform = o.matrix;
 		}
 	}
-	
+
 }