April
---
2003




Animation in Flash vs. Animation in C#, round I

Well, this experiment is posted to show the similarities between Actionscript and C#.

In June 2000, Microsoft announced both the .NET platform and a new programming language called C#. C# is a strongly-typed object-oriented language designed to give the optimum blend of simplicity, expressiveness, and performance. The C# language was built with the hindsight of many languages, but most notably Java and C++. The syntax is somewhat similar to AS and therefore I have attempted this experiment: Replicate some scripted animation I had made in Flash to C#.

Download zip file and execute both files and compare the two programs side-by-side.

One obvious difference is that the C# exe is only 28k and the Flash exe is 522k! (because it contains the Flash player embedded. Also, please note that these two columns of code are not identical in design: i.e.: the Flash method allows for either a single property (such as _x) or an array of properties (such as [_x, _y, _xscale, _yscale]) to be passed and still work. The C# code does not handle this as it is currently written.

The true purpose of this experiment was to show the similarities in syntax and design.

Thanks to Robert Penner for supplying his exceptional easing equations in Actionscript, and to Zeh Fernando for inspiring me with his Flash tween(); method to create this experiment in C#.


shot shot

Download (13kb)

Download (508kb)


as code

 MovieClip.prototype.tween = function(
	prop,
	propDest,
	timeSeconds,
	animType,
	delay,
	callback, 
	clickid){

   if (timeSeconds < 0.01){timeSeconds = 2;}
   if (
	animType == undefined || 
	animType == ""){animType = "easeOutExpo";} // default equation!
   if (delay == undefined){delay = 0;}

   var properties = new Array(); // Properties. Ex, "_x"
   var oldProperties = new Array(); // Old value. Ex, 0
   var newProperties = new Array(); // New (target) value. Ex, 100

   if (typeof(prop) == "string") {
       properties.unshift(prop);
      oldProperties.unshift(this[prop]);
      newProperties.unshift(propDest);
   }else {
      for (var i in prop) oldProperties.unshift (this[prop[i]]);
      for (var i in prop) properties.unshift (prop[i]);
      for (var i in propDest) newProperties.unshift (propDest[i]);
   }

   for (var i=0; i< oldProperties.length; i++) {
	if (newProperties[i] != undefined) {
	  this.$_tweenCount++;
	    var newMC = "_doTweenHolderMovieClip_"+properties[i];
		if (this[newMC]) {
		  this[newMC].removeMovieClip();
		  this.$_tweenCount--;
		}

		this.createEmptyMovieClip(newMC, ++this.$_tweenIndex);
		this[newMC]._prop = properties[i];
		this[newMC]._propStart = oldProperties[i];
		this[newMC]._propDest = newProperties[i];
		this[newMC]._timeStart = getTimer();
		this[newMC]._timeDest = getTimer()+(timeSeconds*1000);
		this[newMC]._animType = animType;
		this[newMC]._delay = delay;
		this[newMC]._callback = i == 0 ? callback : undefined;
		this[newMC]._clickid = clickid;

		//simulates a Timer function call as it 
		//performs function call on every frame pass
		this[newMC].onEnterFrame = function() {
		  if (this._timeDest + (this._delay*1000) <= getTimer()) {
		    if (!this.ended) {
		      _parent[this._prop] = this._propDest;
		      
		        if (this._callback != undefined) {
		          _parent._parent[this._callback](this._clickid);
		        }
		        
		        this.ended = true; //Flags it to be deleted next frame
		        
		        }else{
		          this._parent.$_tweenCount--;
		          this.removeMovieClip();
		        }
		      }else{
				this.ended = false;
				this._parent[this._prop] = findTweenValue (
					this._propStart, 
					this._propDest, 
					this._timeStart, 
					getTimer()-(this._delay*1000), 
					this._timeDest, this._animType);
				}
			}
		}
	}
}

//This is the method that calculates the interum values 
//and returns them to the interval 
this.findTweenValue = function (
	_propStart, 
	_propDest, 
	_timeStart, 
	_timeNow, 
	_timeDest, 
	_animType) {
	
   var t = _timeNow - _timeStart;
   var b = _propStart;
   var c = _propDest - _propStart;
   var d = _timeDest - _timeStart;
   
   switch (_animType.toLowerCase()) {
      case "linear":
      // simple linear tweening - no easing
         return c*t/d + b;
      break;
      case "easeinquad":
      // quadratic (t^2) easing in - accelerating from zero velocity
         return c*(t/=d)*t + b;
      break;
      case "easeoutquad":
      // quadratic (t^2) easing out - decelerating to zero velocity
         return -c *(t/=d)*(t-2) + b;
      break;
      case "easeinoutquad":
      if ((t/=d/2) < 1) return c/2*t*t + b;
         return -c/2 * ((--t)*(t-2) - 1) + b;
      break;
      case "easeincubic":
         return c*(t/=d)*t*t + b;
      break;
      case "easeoutcubic":
         return c*((t=t/d-1)*t*t + 1) + b;
      break;
      case "easeinquart":
         return c*(t/=d)*t*t*t + b;
      break;
      case "easeinoutcubic":
      if ((t/=d/2) < 1) return c/2*t*t*t + b;
         return c/2*((t-=2)*t*t + 2) + b;
      break;
      case "easeinexpo":
      // exponential (2^t) easing in - accelerating from zero velocity
         return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
      break;
      case "easeoutexpo": //selected by default
      // exponential (2^t) easing out - decelerating to zero velocity
         return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
      break;
   }
}
		

cs code

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApplication1 {
   public class TweenLibrary {
   private int counter = 0;
   private int timeStart;
   private int timeDest;
   private string animType;

   private float t;
   private float d;
   private float b;
   private float c;

   private int[] Arr_startPos = new int[]{0,0};
   private int[] Arr_destPos = new int[]{0,0};

   private System.Windows.Forms.Timer objTimer;
   private System.Windows.Forms.Control objHolder;

   private System.ComponentModel.IContainer components;
   private System.Windows.Forms.Timer timer1;

   public void startTweenEvent(object _objHolder, 
	int _destXpos, 
	int _destYpos, 
	string _animType, 
	int _timeInterval){

   counter = 0;
   timeStart = counter;
   timeDest = _timeInterval;
   animType = _animType;

   this.components = new System.ComponentModel.Container();
   this.timer1 = new System.Windows.Forms.Timer(this.components);
   this.timer1.Interval = 1;
   this.timer1.Tick += new System.EventHandler(this.timer1_Tick);

   objHolder = new System.Windows.Forms.Control();
   objHolder = (Control) _objHolder;
   objTimer = this.timer1;

   Arr_startPos[0] = objHolder.Location.X;
   Arr_startPos[1] = objHolder.Location.Y;
   Arr_destPos[0] = _destXpos;
   Arr_destPos[1] = _destYpos;

   objTimer.Stop();
   objTimer.Enabled = false;
   objTimer.Enabled = true;
   }

//This is the method that gets called every tick interval
   public void timer1_Tick(object sender, System.EventArgs e) {
      if(
      objHolder.Location.X==Arr_destPos[0] && 
      objHolder.Location.Y==Arr_destPos[1]){
         objTimer.Stop();
         objTimer.Enabled = false;
      }else{
         objHolder.Location = 
         new System.Drawing.Point(tween(0), tween(1));
         counter++;
      }
   }

//This is the method that calculates the interum values 
//and returns them to the Timer
   private int tween(int prop){
      t = (float)counter - timeStart;
      b = (float)Arr_startPos[prop];
      c = (float)Arr_destPos[prop] - Arr_startPos[prop];
      d = (float)timeDest - timeStart;

      return getFormula(animType, t, b, d, c);
   }

   private int getFormula(
	string animType, 
	float t, 
	float b, 
	float d, 
	float c){
      
      switch (animType) {
         case "linear":
            // simple linear tweening - no easing
            return (int)(c*t/d+b);

         case "easeinquad":
            // quadratic (t^2) easing in - accelerating from zero velocity
            return (int)(c*(t/=d)*t + b);

         case "easeoutquad":
            // quadratic (t^2) easing out - decelerating to zero velocity
            return (int)(-c*(t=t/d)*(t-2)+b);

         case "easeinoutquad":
            // quadratic easing in/out - 
            //acceleration until halfway, then deceleration
            if ((t/=d/2)<1) return (int)(c/2*t*t+b); else 
            return (int)(-c/2*((--t)*(t-2)-1)+b);

         case "easeincubic":
            // cubic easing in - accelerating from zero velocity
            return (int)(c*(t/=d)*t*t + b);

         case "easeoutcubic":
            // cubic easing in - accelerating from zero velocity
            return (int)(c*((t=t/d-1)*t*t + 1) + b);

         case "easeinoutcubic":
            // cubic easing in - accelerating from zero velocity
            if ((t/=d/2) < 1)return (int)(c/2*t*t*t+b);else 
            return (int)(c/2*((t-=2)*t*t + 2)+b);

         case "easeinquart":
            // quartic easing in - accelerating from zero velocity
            return (int)(c*(t/=d)*t*t*t + b);

         case "easeinexpo":
            // exponential (2^t) easing in - accelerating from zero velocity
            if (t==0) return (int)b; else 
            return (int)(c*Math.Pow(2,(10*(t/d-1)))+b);

         case "easeoutexpo":
            // exponential (2^t) easing out - decelerating to zero velocity
            if (t==d) return (int)(b+c); else 
            return (int)(c * (-Math.Pow(2,-10*t/d)+1)+b);

         default:
            return 0;
         }
      }
   }
}