Erain 3D
--> FDT Pure coding comfort


Author: Max Pellizzaro
Date: November 12th 2007
Update: July 12th 2009
version: 3.1.1

Motion in multiple direction Part I :tweenings

Objective of the tutorial

In the tutorial #11 you have learned how to apply tweenings in one direction, now we want to learn how we can apply the same technique in multiple directions and at the same time. Based on our tennis example we will learn how to “serve” the tennis ball.

How to

Set up

The Document class must be changed to Example013.as The name of the class in the .as file and the name of the constructor now is: Example013.

example013.rar

Update after rel 3.0.1

example013_b.rar

Update after rel 3.1.1

example013_v3.1.1.zip

The AS Code

package
{
   import flash.display.*;
   import flash.net.URLRequest;
 
   import flash.events.*;
   import flash.ui.*;
   import sandy.core.Scene3D;
   import sandy.core.data.*;
   import sandy.core.scenegraph.*;
   import sandy.materials.*;
   import sandy.materials.attributes.*;
   import sandy.primitive.*;
   import sandy.util.*;
   import sandy.events.*;

   import caurina.transitions.*;
   
   public class Example013 extends Sprite 
   {
      private var scene:Scene3D;
	  private var camera:Camera3D;
	  private var sphere:Sphere;
	  private var bottom:Plane3D;
	  private var wilson:Plane3D;
	  
	  private var img:MyBall=new MyBall();
	  private var bitmap:Bitmap=new Bitmap(img);
	  private var imgCrt:MyCourt=new MyCourt();
	  private var bitmapCrt:Bitmap=new Bitmap(imgCrt);
	  private var imgWils:MyWilson=new MyWilson();
	  private var bitmapWils:Bitmap=new Bitmap(imgWils);
	  
	  public function Example013():void
      {  
		 // We create the camera
		 camera = new Camera3D( 600, 300 );
		 camera.z = -300;
		 camera.x = 0;
		 camera.y = 150;
		 camera.lookAt(0,0,0);
		 
		 // We create the "group" that is the tree of all the visible objects
         var root:Group = createScene();
		 // We create a Scene and we add the camera and the objects tree 
	     scene = new Scene3D( "scene", this, camera, root );
		 
		 // Listen to the heart beat and render the scene
         addEventListener( Event.ENTER_FRAME, enterFrameHandler );
		 stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
      }
	 
      // Create the scene graph based on the root Group of the scene
      private function createScene():Group
      {
         // Create the root Group
         var g:Group = new Group();
		 
         // Create the tennis court
         bottom = new Plane3D('bottom', 300, 530, 20, 20, 
							Plane3D.ZX_ALIGNED,'quad');
		 
		 // we define the texture for the tennis court
		 var materialCrt:BitmapMaterial = new BitmapMaterial( bitmapCrt.bitmapData );
		 materialCrt.lightingEnable = true;
	     var appCrt:Appearance = new Appearance( materialCrt );
		
		 bottom.enableBackFaceCulling = false;
		 bottom.useSingleContainer = false;
		 bottom.appearance = appCrt;
		  
		 // Create the wilson poster
         wilson = new Plane3D('wilson', 160, 40, 20, 20, 
							Plane3D.YZ_ALIGNED ,'quad');
		 wilson.rotateZ = 195;
		 wilson.y = 22;
		 wilson.x = -200;
		 
		 // we define the texture for the tennis court
		 var materialWils:BitmapMaterial = new BitmapMaterial( bitmapWils.bitmapData );
		 materialWils.lightingEnable = true;
	     var appWils:Appearance = new Appearance( materialWils );
		
		 wilson.enableBackFaceCulling = false;
		 wilson.useSingleContainer = false;
		 wilson.appearance = appWils;
		 
		 // we define the tennis ball 
		 sphere = new Sphere("sphere", 20,20,20);
		 sphere.z = 0;
		 sphere.x = 200;
		 sphere.y = 100;
		 sphere.rotateY = 90;
			 
		 var materialImg:BitmapMaterial = new BitmapMaterial( bitmap.bitmapData );
		 materialImg.lightingEnable = true;
	     var appImg:Appearance = new Appearance( materialImg );
		 
		 sphere.enableBackFaceCulling = false;
		 sphere.useSingleContainer = false;
		 sphere.appearance = appImg; 
		 
		 g.addChild( sphere);
		 g.addChild( bottom );
		 g.addChild( wilson );
          
		  return g;
      }

      // The rotataion of the ball
      private function rotateSphere() : void
      {
		 sphere.rotateX -=15;
		 sphere.rotateZ -=15;
		
      }
	  
	   private function rotate2Sphere() : void
      {
		 sphere.rotateZ +=15;
		 sphere.rotateX +=15;
	  }
	  
	  // The Event.ENTER_FRAME event handler tells the Scene3D to render
      private function enterFrameHandler( event : Event ) : void
      {
		scene.render();
      }
	 
	  private function keyPressed(event:KeyboardEvent):void {
            switch(event.keyCode) {
				case Keyboard.PAGE_DOWN:
					camera.z -=5;
					break;
				case Keyboard.PAGE_UP:
					camera.z +=5;
					break;
				case Keyboard.CONTROL:
				    Tweener.removeAllTweens();
					sphere.z = 0;
					sphere.x = 200;
		            sphere.y = 100;
					Tweener.addTween(sphere, {y:20, time:2, transition:"easeOutBounce"});
		 			Tweener.addTween(sphere, {x:-190, time:2, transition:"linear", onUpdate:rotateSphere});
		 			Tweener.addTween(sphere, {x:200, time:2, delay:2, transition:"linear", onUpdate:rotate2Sphere});
					break;
			}
        }
	 
   }
}

Examining the code

Combining tweens is pretty easy: you just add the motion you want to have on your object, the Tweener class will take care of everything. Now serving a ball on tennis means that we need a Y movement (from top to bottom) and an X movement (from one side of the court to the other). I’ll let you introduce the Z movement to simulate a non straight serve. As simple as it might sound you just use two lines of code:

Tweener.addTween(sphere, {y:20, time:2, transition:"easeOutBounce"});
Tweener.addTween(sphere, {x:-190, time:2, transition:"linear", onUpdate:rotateSphere});
Tweener.addTween(sphere, {x:200, time:2, delay:2, transition:"linear", onUpdate:rotate2Sphere});

The first line model the Y direction, the second the X direction. There is a third line of code that models the fact the ball is coming back to the right side of the court. Since we need to call the third tweening only after the first two took place, you introduce a delay of 2 second (delay:2), that is the time needed to the ball to move from right to left. But we want something more: the ball spin, roll when it’ moves, so we must find a way to model this. I have model this by calling a function on each update of the Tweener class: onUpdate:rotateSphere. The code is pretty easy to understand:

private function rotateSphere() : void
 {
   sphere.rotateX -=15;
   sphere.rotateZ -=15;
 }

There is another function called rotate2Sphere that just model the rotation of the ball in the other direction.

So let’s see the result !!

The output

Get the focus of the flash and use the ctrl key (Apple key on Mac) to make the ball bounce and compare the result with the previous tutorial.