Game Development Community

dev|Pro Game Development Curriculum

Twillex: Tweening for Torque

by Charlie Patterson · 01/25/2012 (11:54 pm) · 53 comments

Hi everyone! I thought I'd throw out my first resource to the community. I hope you like it. It's Twillex, a Tweening engine for Torque (2D and iTorque) written entirely in TorqueScript. Tweening is animating motion in more ways than just "linear." Give it a start and end point, and an "easing function" and it will make a pretty motion for you. You can tween positions, rotations, sizes, *colors*, alphas, your own variables...

Well here, see a video first (link).




And here is the Twillex home page on SourceForge where you can download the source and the test project used to make the movie (zipped up).

To make a Tween, you typically do a one-liner like so:

Tweener.to(1000, %this, "position:100 50, a:0.5", "ease:bounce_out flipflop:true");

The entire Twillex engine is a single TorqueScript file, to make it easier to add to your project. There are docs in the source file, an example project, and a wiki you can add to. It probably works on most version of Torque and most releases.

I'm pretty proud of it. Let me know if you find it fun!

Twillex Home Page

P.S. Check the comments on this post for any updates.

(Also, if you enjoy this resource, please consider "paying forward" with a click on my game's like button, here: facebook.com/RednecksVsRobots. Gonna look for some funding soon and likes will help, I hope!)
#21
02/17/2012 (12:52 pm)
Awesome. Very useful. Thanks a bunch.
#22
02/17/2012 (3:25 pm)
Anyone else got this library to work?

@Charlie -
I was able to add your library fine and ran this command on an object but nothing happened:

%t = myTweenEngine.toOnce(500, myObject, "x:100, y:0, myVar:0.01", "yoyo:true");

I echo out the Tween::interpolateSpecialField function call and see that it is calling it many times, but the %ft and %this.diffValueX values never changes (it's always the same value).

Also noticed that %star and %diff value is always the same in Tween::interpolate

Myobject is a t2dsceneobject.

Do you have any idea what i'm doing wrong?
#23
02/17/2012 (7:26 pm)
@Johnny, did your object happen to start AT "100 0". Because then it has nowhere to go! If you had a control parameter of "relative:true" then it would go 100 more from wherever it currently is, though.

Because you bravely debugged into Twillex, I'll mention that %this.diffValueX should not change in any case. However, if it was 0 the whole time, that's proof that it had a distance of 0 to go.

But the %ft not changing sounds weird. That should definitely vary. Hmm, maybe you are creating a new Tween for every frame? In that case, maybe you are seeing new start values each time.

Make sure you set up your onUpdate correctly and create one Tween. Not saying you don't know that, but I'm flying blind here.

I started using T2D/TGB at 1.7.5 so maybe something has changed from an older version? I doubt it, but maybe.
#24
02/19/2012 (10:04 pm)
@Charlie

Just wanted to give you props. We started playing with this about an hour ago and love it.

T2D needs this as a permanent fixture..... :-)
#25
02/20/2012 (11:50 pm)
Thanks @George. My ego is growing uncomfortably large. :)
#26
02/28/2012 (12:21 am)
Fantastic Work! I finally got around to playing with this in iT2D, and it is wonderful!

I will definitely be using this in upcoming projects!

Many Thanks!
#27
02/28/2012 (9:41 pm)
Thanks @Ray! Glad to hear it works in iT2D. I was sure it would.
#28
04/19/2012 (4:55 am)
Does this work in T3D or will i have to port it? :D
And does it only work on GUI elements or would it work on any object, like a particle emitter node? :P Could make some awesome effects with it :)
#29
04/19/2012 (11:11 am)
Hi Lukas.

It works generically on objects, GUIs, or whatever, and is only limited by any Torque limitations. (Like you can adjust color and alpha of an object but not a GUI.)

While I do not own T3D, I am not aware of a reason it would not work. Torque tends to work on string "vectors" like "0 -100" and so a 3-vector is probably "0 -100 100" in T3D?

The only thing that comes to mind is that there are some "semantic sugars" in Twillex. Instead of tweening "position" like "100 200" you can tween "x" and "y" individually and there is some code to support this. I didn't make a "z". That might be the only problem.

So give it a try and let ME know! :)
#30
04/25/2012 (12:39 pm)
Am i right if i believe that if i were to add a Z value it would be in the two interpolation functions?:
initInterpolationRangeSpecialField
And
interpolateSpecialField

Haven't come around to test it yet. One of the uses i could see for it would be to animate a particle emitter node. Could make a nice swirling spellbolt like effect :D
#31
04/25/2012 (1:23 pm)
Affirmative @Lukas,

Or you could just use position as a 3-vector ("position:0 100 0") and it should just work.

Nice! Would like to see some swirling bolts!
#32
04/25/2012 (2:32 pm)
SO i can confirm it working in T3D, although some small changes has to be done. But i made it scale an arrow to ridiculous proportions, so somethings working atm! :)
#33
04/25/2012 (8:40 pm)
Woohoo! thanks for trying it out!

If you found a few issues you fixed that you'd like moved into the official version, lemme know.
#34
04/26/2012 (3:06 am)
Well the only really important "issue" is that I couldn't find a onTick or onUpdate function in T3D. So instead i made this
function twillexUpdate(%twill)
{
   if(isObject(%twill))
   {
      myTweenEngine.onUpdate();
      schedule(32, 0, twillexUpdate, myTweenEngine);
   }
}

exec("./Twillex.cs");
Twillex::create(myTweenEngine);
twillexUpdate(myTweenEngine);
Might want that embedded into the Twillex class in a sort of: Help me i have no idea about what to do with twillexUpdate function :)

Still working on hacking the projectile class so i can access the projectiles particleEmitter :) If i make it work, i can create some nice showcases of how this can be utilized !
#35
05/01/2012 (1:12 pm)
Thanks Lukas. I didn't know that t3d didn't have a scene update method. I'll add a choice to use a "schedule" like you did.

Have fun! And remember that you can update almost any variable you can get to. If your change to particle emitters is something that torque script can see, you can probably tween it without c++. (Although if you are thinking of tweening 100s of particles at once, you may need a C++ tween!)

If you look at the test project that comes with Twillex, you'll see ways to Tween GUIs, scene objects as one-off buttons, colors, even a crazy one that tween a general float value and uses it to change animation frames during onUpdate.
#36
05/07/2012 (1:33 pm)
Unfortunately i am short in time atm (exams) so i haven't come around to play with the swirling projectiles yet.
But i found a really cool feature i think would be awesome to implement, animated shaders.
However i believe it needs some tailoring for it to be working properly ( it needs to call setShaderConst )
#37
05/11/2012 (9:56 pm)
that's cool. also, if you could, please port the shaders to Torque 2D. :P
#38
05/12/2012 (3:54 am)
Update:
Got the animated shaders working, had to make a couple of adjustments :)
Video:

Edit:
I don't know anything about T2D shaders, but it is just a simple pixel shader i couldn't imagine T2D using another format than T3D for pixelshaders.

You can try it and see if it works:

#include "../common/postFx/postFx.hlsl"
#include "../common/torque.hlsl"

uniform float amount;		//The amount of scaling of each sample, will be defined in script
uniform float direction;		//The number of samples, will also be defined in script
uniform sampler2D backBuffer : register(S0);

float4 main( PFXVertToPix IN ) : COLOR
{   
	float b = 0;	//this variable is the offset we have to apply to center each individual image after scaling
	
	float4 c0 = tex2D(backBuffer, IN.uv0);
	float2 uv = IN.uv0;
	if(direction  == 0 )
		uv.y = uv.y  + (sin(uv.y*100)*amount);
	if(direction  == 1 )
		uv.x = uv.x  + (sin(uv.x*100)*amount);
	if(direction  == 2 )
	{
		uv.x = uv.x  + (sin(uv.x*100)*amount);
		uv.y = uv.y  + (sin(uv.y*100)*amount);
	}
	c0 = tex2Dlod( backBuffer , float4(uv.x,uv.y,0,0));
	c0.b = c0.b*2;
	return c0;
}

If you can post an example of a fullscreen T2D shader i think i can port it if the above is not working.

Posted the changes here: Report you can use winmerge to merge it or just copy it right over :) Feel free to add it to the original resource if you please!

Yet another edit:
Thought i would add the scripts aswell:
PostFX file
$TestFX::direction = 0;
$TestFX::amount = 0.01;

singleton ShaderData( PFX_TestFXShader )  
{     
   DXVertexShaderFile   = "shaders/common/postFx/postFxV.hlsl";  //as we don't need a specialized vertex shader, we use the bare-bones postFxV.hlsl
   DXPixelShaderFile    = "shaders/custom/FxTest.hlsl";  //our new pixel shader
        
   samplerNames[0] = "$inputTex";  
     
   pixVersion = 3.0;  
};  

singleton PostEffect(TestFX)  
{  
   renderTime = "PFXAfterDiffuse";  
        
   shader = PFX_TestFXShader;  
   stateBlock = PFX_DefaultStateBlock;  
   texture[0] = "$backbuffer";  
};

function TestFX::setShaderConsts( %this )
{
	%this.setShaderConst( "$direction", $TestFX::direction );	
	%this.setShaderConst( "$amount", $TestFX::amount );
}

The tweener code
function twillexUpdate(%twill)
{
   if(isObject(%twill))
   {
      myTweenEngine.onUpdate();
      schedule(32, 0, twillexUpdate, myTweenEngine);
   }
}

exec("./Twillex.cs");
Twillex::create(myTweenEngine);
twillexUpdate(myTweenEngine);

$t = MyTweenEngine.to(8000, "globals", "$TestFX::amount=0.04", "loop=true, yoyo=true"); // Only supports 1 global at the time atm even tho the syntax was created to support more globals at a time :) Support for more globals might come along later
$t.play();
TestFX.enable();
#39
05/12/2012 (9:59 am)
Wow @Lukas! I'm awed by that video!

As for T2D and shaders, I was making a joke because t2D does not have any shaders. If you wanted to port the whole thing... :) (just kidding about porting, of course)

Nevertheless, I'm gonna study your code to get an idea of how Twillex helps out. This is so cool!
#40
05/12/2012 (12:47 pm)
Made a little extra modification, now it is possible to queue the tweens.
Btw sorry for the low quality, i haven't got the right codex's installed on my computer yet >.<
The video shows an example of queueing several particle animations right after each other.
The modification:
In Tween::onUpdate (around line 860)
if (%this.tweenData.onComplete !$= "")
   {
      %args = "";
      if(%this.tweenData.onCompleteArgs !$= "")
         %args = ", " @ %this.tweenData.onCompleteArgs;
      eval(%this.tweenData.onComplete @ "( " @ %this.target @ ", %this" @ %args @ " );");
      echo(%this.tweenData.onComplete @ "( " @ %this.target @ ", %this" @ %args @ " );");
   }
The call method only worked with locally scoped methods had to change it to eval.
Edit - Changed from global to local variables to show that it isn't restricted to global variables
Particle animation and queing
%p1 = MyTweenEngine.to(4000, testEmitter.emitter, "phiVariance:360", "");
%p2 = MyTweenEngine.to(5000, testEmitter.emitter, "ejectionOffset:0", "");
%p3 = MyTweenEngine.to(2000, testEmitter.emitter, "ejectionVelocity:2", "");

%p1.tweenData.onComplete = %p2@".play";
%p2.tweenData.onComplete = %p3@".play";
Then when the animation should be played just play %p1:
%p1.play();
//Remember that %p1 is just an integer representing a Tween so if you want to call it from the console or elsewhere call it $p1 instead