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#.
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;
}
}
}
}