Well, ok the name needs some work, but temporarily I’ll call it this since I’m using GoASAP under the hood of Go3D Tween classes. The idea is simple: Write a tween class specifically catering to a DisplayObject3D with x, y, z, rotationX, rotationY, rotationZ properties. What I ended up with was Tween3D (again, the name will likely change as this is a bit generic).
Now, after all my rants about untyped objects blah blah blah, I’ve really come to at least appreciate *why* people use this approach. It certainly is faster to type and get something up and running. But, I didn’t want to walk down that path with this one AND I wanted something reusable. I think there are situations where you can waste alot of time recreating these transient tweens within the body of your code that could easily be re-executed after being created one time. Tween3D does this.
It’s not a magic trick by any means, I’m simply initializing the “start” values when a Tween3D actually “starts”. It’s very simple and allows for reuse and instantiation.
I really wanted to take this on for a couple of reasons, but mainly to get into writing my own tween classes using Go. I’ve had the pleasure of being able to sit and talk to Moses at length about what Go is and the first thing I wanted to do ever since was try my hand at creating a strongly typed API. So far so good, but I think there’s room for improving the amount of code you have to write. It’s actually pretty compact and very easy to understand, but still, I’d like to see some even shorter ways of creating strongly typed tweens.
As you might expect, if you’ve used Fuse or Tweener in the past, a strongly typed tween might look like this:
[as]
var tween:Tween3D = new Tween3D(target:DisplayObject3D, duration:Number, easing:Function, delay:Number);
tween.x = 2000;
tween.y = 1000;
tween.start();
[/as]
As you can see, its alot like a Tweener call, except the properties aren’t in an untyped object, they set after instantiation. This setup is good for a few reasons:
1. Faster – always faster to set properties after instantiation than it is through the constructor
2. Strict typing – easy to understand what you can and can’t do with the Tween3D
3. reusable – you can create once, and reuse the tween over and over. This is nice in a situation where tweens are kept in a manager class that someone else maintains through out a project. Single point of management can be a very cool thing. This can also keep the CPU hit down when you need a tween.
Another thing about GoASAP is the Sequencing classes that come with it. Alot of times I’ve used Fuse for sequencing events, not necessarily animation tweens
The sequencing is a very strong and abstract part of GoASAP. If you need it, great, hook it up. If you don’t, then it’s not there apart of the payload. Adding your own custom managers is a snap as well. if you need the OverlapManager that comes with Go, you can hook it in with one line of code. You can also create your own or just leave it out altogether.
I’ll be covering Go3D at the classes in Vancouver (this weekend) and Toronto in June, but you can get the source here and the Rolodex demo files here. Its definitely in early stages, but I think it’d be great to get some input if anyone’s interested. You’ll also need to sync or download GoASAP here. Tween3D is written specifically for use with Papervision3D’s DisplayObject3D, so if you’re gonna play, you obviously need to use it with a 3D scene and 3D objects
+++++++ [ shameless classes plug ]++++++++++
Vancouver: May 3rd & 4th
Toronto: June 7th & 8th
This demo below is something I converted from Tweener to using Go3D. The lines of code were more for sure, but thats because of what GoASAP isn’t assuming for me like other animation engines would have to. So, I had to add a Sequence and an OverlapManager to acheive the same effect. Ok so it’s more complexx, but it’s also a ton more flexible. if I didn’t like Moses’ OverlapManager, i could write my own. if I didn’t like his sequencer, I could write my own and plug it in. The point is, I can completely customize any portion of the Tween engine to my project, company or general tastes at any given level. Companies can actually dictate the API and have maximum control over *what* the tween/sequence engine is doing in their application. I think once people realize what GoASAP is, we’ll see alot of uses for it in many ways we’re not even able to comprehend yet.
[kml_flashembed movie="http://www.rockonflash.com/papervision3d/Go3D/RolodexGODemo.swf" width="550" height="500"/]
Code for this animation sequence:
[as]package {
import com.rockonflash.go3d.Tween3D;
import com.rockonflash.go3d.utils.Equations;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.utils.getDefinitionByName;
import org.goasap.GoEngine;
import org.goasap.events.GoEvent;
import org.goasap.managers.OverlapMonitor;
import org.goasap.utils.SequenceCA;
import org.goasap.utils.SequenceStepCA;
import org.goasap.utils.customadvance.OnDurationComplete;
import org.papervision3d.cameras.FreeCamera3D;
import org.papervision3d.materials.MovieMaterial;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
//import com.rockonflash.go3d.utils.Equations;
public class RolodexGODemo extends Sprite
{
public var target
lane;
public var viewport :Viewport3D;
public var scene :Scene3D = new Scene3D();
public var camera :FreeCamera3D = new FreeCamera3D(11);
public var renderer :BasicRenderEngine = new BasicRenderEngine();
public var sequence :SequenceCA;
public var tween_0 :Tween3D;
public var tween_0b :Tween3D;
public var tween_1 :Tween3D;
public var tween_2 :Tween3D;
protected var doLoop :Boolean = true;
public function RolodexGODemo()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
init();
}
public function init():void
{
GoEngine.addManager(new OverlapMonitor());
viewport = new Viewport3D(0, 0, true, false);
addChild(viewport);
var cls:Class = getDefinitionByName(“rolodex”) as Class;
var rolodex:Sprite = new cls() as Sprite;
var mat:MovieMaterial = new MovieMaterial(rolodex, true, false);
mat.smooth = true;
target = new Plane(mat, 292, 168, 4, 4);
scene.addChild(target);
reset();
createTween();
finalizeInit();
}
protected function finalizeInit():void
{
stage.addEventListener(MouseEvent.CLICK, handleClick);
stage.addEventListener(Event.ENTER_FRAME, loop);
loop();
doLoop = false;
}
protected function loop(e:Event=null):void
{
if( !doLoop ) return; // only render when we have to
renderer.renderScene(scene, camera, viewport);
}
protected function handleClick(e:MouseEvent):void
{
doTween();
}
protected function createTween():void
{
sequence = new SequenceCA();
sequence.addEventListener(GoEvent.COMPLETE, handleSequenceComplete, false, 0, true);
tween_0 = new Tween3D(target, 1, Equations.easeOutCubic);
tween_0.x = 0;
tween_0.y = 50;
tween_0.rotationZ = 0;
sequence.addStep(tween_0);
sequence.lastStep.advance = new OnDurationComplete(.2); // advance early/overlap
tween_0b = new Tween3D(target, 1, Equations.easeOutCubic);
tween_0b.z = 200;
sequence.addStep(tween_0b, true); // 2nd param groups it with previous step. param is “addToLastStep”
tween_1 = new Tween3D(target, 1, Equations.easeOutCubic);
tween_1.x = -10;
tween_1.y = 85;
tween_1.rotationZ = 15;
sequence.addStep(tween_1);
sequence.lastStep.advance = new OnDurationComplete(.25); // advance early/overlap
tween_2 = new Tween3D(target, 1, Equations.easeOutBounce);
tween_2.rotationX = 0;
tween_2.rotationY = 0;
sequence.addStep(tween_2);
}
protected function handleSequenceComplete(e:GoEvent):void
{
doLoop = false;
}
protected function reset():void
{
target.x = (Math.random() * (stage.stageWidth*.5));
target.y = -350;
target.z = -1000;
target.rotationY = 30;
target.rotationX = 30;
target.rotationZ = Math.random() *-180;//-10;
loop();
}
protected function doTween():void
{
reset();
//createTween();
doLoop = true;
sequence.start();
}
}
}
[/as]
I gotta say a huge thanks to Moses for putting up with my questions and debugging
It was FUN non the less!