Erain 3D
--> FDT Pure coding comfort


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

Motion in one direction Part II :dynamic animation

Objective of the tutorial

In the previous tutorial we saw how to make a ball bouncing using tweenings. Let’s now make it bouncing using equations.
In order to model a bouncing ball we need to model:

  1. The gravity that pull the ball down (as Newton told us!)
  2. The friction of the ball otherwise the ball could roll forever (this will come handy in the next tutorial but I will introduce it here)
  3. The elastic force that make the ball bounce

Let’s see how to do all this.

How to

Set up

The Document class must be changed to Example012.as The name of the class in the .as file and the name of the constructor now is: Example012. In this tutorial we will use the same asset as the prevoius tutorial to model out tennis court.

example012.rar

Update after rel 3.0.1

example012_b.rar

Update after rel 3.1.1

example012_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.*;
   
   public class Example012 extends Sprite 
   {
      private var scene:Scene3D;
	  private var camera:Camera3D;
	  private var sphere:Sphere;
	  private var bottom:Plane3D;
	  private var wilson:Plane3D;
	  
	  private var isBouncing:Boolean = false;
	  private var bounce:Number = -0.70;
	  private var friction:Number = 0.98;
	  private var gravity:Number = -0.50;
	  private var vx:Number = 0.00;
	  private var vy:Number = 0.00;
	  private var vz:Number = 0.00;
	  
	  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 Example012():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 = 0;
		 sphere.y = 20;
		 sphere.rotateY = 110;
			 
		 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 Event.ENTER_FRAME event handler tells the Scene3D to render
      private function enterFrameHandler( event : Event ) : void
      {
		 if(isBouncing)
		 {
		  if(sphere.y < 20)
		  {
		   vy *= bounce;
		   sphere.y = 20;
		  }
		  else
		  {
		   vy += gravity;
		   vy *= friction;
		  }
		  sphere.y += vy;
		 }
		 if(Math.sqrt(Math.sqrt(vy*vy))< 0.5 && sphere.y < 21)
		  isBouncing = false;
		 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:
				    sphere.y = 150;
					vy = -10;
					isBouncing = true;
					break;
			}
        }
	 
   }
}

Examining the code

The first part of the code is identical of the previous tutorial, so we will not discuss how to build the Tennis court. Let’s focus on the important stuff: the motion.
You will notice that there is not tweenings, so how did we model the motions? First we define some important variables:

private var isBouncing:Boolean = false;
private var bounce:Number = -0.70;
private var friction:Number = 0.98;
private var gravity:Number = -0.50;
private var vx:Number = 0.00;
private var vy:Number = 0.00;
private var vz:Number = 0.00;

I have put here more variables that we need right now, but you will get the idea on what you need to model motion. The three main variables are:

The Boolean variable isBouncing has been introduced to avoid infinite loop calculation from the engine.
The other three important variables are vx, vy and vz that models the velocity of the ball in each direction.
Now that we have declared the right variables, let’s move to the equation, that can be found in the enterFrameHandler(..) function. It has been placed there since this code must run every time the engine fire a new frame.

if(isBouncing)
 {
   if(sphere.y < 20)
   {
     vy *= bounce;
     sphere.y = 20;
   }
   else
   {
    vy += gravity;
    vy *= friction;
   }
   sphere.y += vy;
 }
 
if(Math.sqrt(Math.sqrt(vy*vy))< 0.5 && sphere.y < 21)
  isBouncing = false;

Well this is a lot of code, and we might get confused by the “if” condition I have placed to save infinite computation when the ball is almost stopped. So let’s clean the code to just highlight what is really important:

  if(sphere.y < 20)
       vy *= bounce;
  vy += gravity;
  vy *= friction;
 sphere.y += vy;

Now this is much better. These are core line we need to concentrate:

I let you understand all the control I have introduce to mess up this simple code.

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.