Test12 - Pool Demo

From Flare3D - WIKI
Jump to: navigation, search
package
{
	import flare.basic.*;
	import flare.core.Lines3D;
	import flare.core.Pivot3D;
	import flare.physics.collision.*;
	import flare.physics.core.PhysicsMesh;
	import flare.physics.core.PhysicsSphere;
	import flare.physics.core.PhysicsSystemManager;
	import flare.physics.core.RigidBody;
	import flare.physics.tools.Math3D;
	import flare.primitives.*;
	import flare.system.Input3D;
	import flare.utils.Vector3DUtils;
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
 
	public class Test12_poolDemo extends Sprite 
	{
		private var scene: Scene3D;
		private var physics: PhysicsSystemManager;		
		private var whiteBallPhysics: RigidBody;		
		private var resetPosition:Vector3D;
		private var resetPositionOthersBall:Vector.<Vector3D>;		
 
		private var dirIndicator:Lines3D;		
		private var focusedShow:MovieClip;
		private var stick:Pivot3D;
 
		[SWF(frameRate = 25, backgroundColor = 0xFFFFFF, width = 800, height = 600 )]
		public function Test12_poolDemo() 
		{
			//Create the scene...
			//Load the visual representation of the Scene
			scene = new Viewer3D(this, "../resources/pool.f3d");
 
			//Load the physical representation of the table
			scene.addChildFromFile("../resources/pool_geom.f3d");				
 
			//load the pool stick
			scene.addChildFromFile("../resources/poolStick.f3d");				
 
			//Define load complete event
			scene.addEventListener( Scene3D.COMPLETE_EVENT, completeEvent );						
 
			//Set the expected frame rate
			scene.frameRate = 30;
 
			//Stop playback of the scene
			scene.pause();
 
			//Initialize the physics manager			
			//Set the world dimensions. It's used for collisions classification
			physics = PhysicsSystemManager.getInstance(new Vector3D(400, 400, 400), 20);	
 
			//Set the gravity acceleration
			//By default, it is set to 9.81 mts. As this demo use centimeters, so gravity is set to 981 cms.
			physics.gravity = new Vector3D(0, -981, 0);						
			// Set Physics Solver Accuracy. The greater the accuracy, the slower the system
			physics.accuracy = PhysicsSystemManager.HIGH_ACCURACY;
 
			//Create a label to show instructions
			var controls: TextField = new TextField();			
			controls.autoSize = TextFieldAutoSize.LEFT;
			controls.defaultTextFormat = new TextFormat( "Helvetica" , 14, 0xffffff);
			addChild(controls);
			controls.htmlText =	"ARROWS: Set shot direction & power (+SHIFT move faster, +CTRL move slower)" + String.fromCharCode(13) +
								"SPACE: Hit" + String.fromCharCode(13) + 																
								"R: Reset white ball" + String.fromCharCode(13) +
								"T: Reset all";
			controls.x = 5;
			controls.y = 5;			
 
			//Create the direction indicator
			dirIndicator = new Lines3D();
			dirIndicator.lineStyle( 1, 0xFFFFFF );			
			scene.addChild(dirIndicator);						
 
			//Variable to indicate when Scene has focus
			focusedShow = new MovieClip();			
		}	
 
		private function completeEvent(e:Event):void 
		{
			//Remove the complete listener			
			scene.removeEventListener(Scene3D.COMPLETE_EVENT, completeEvent);			
 
			//Hide the physics geometry of the table
			scene.getChildByName("cloth").visible = false;
			scene.getChildByName("rails").visible = false;
			scene.getChildByName("table").visible = false;
 
			//Get the reference to the stick 
			stick = scene.getChildByName("poolStick.f3d");
 
			//Get parts of the 3D Table and balls, and assign Restitution/Friction real properties:
			//
			//		The restitution value indicate how much velocity is lost when two objects collide:
			//						value equals to 0 represents a plastic collision (all velocity is lost, the object not bounce) and
			//						value equals to 1 represents a elastic collision (all velocity is conservated, the object has max bounce)
			//		NOTE: the final restitution is 0.5 * (restitution_object1 + restitution_object2)
 
 
			//		The friction property indicates how this object displace over other objects	
			//		The greater the friction then less the displacement
			//		NOTE: the final friction is 0.5 * (friction_object1 + friction_object2)
 
			//		According this article (http://billiards.colostate.edu/threads/physics.html) we define the material properties
 
 
			var cloth:Pivot3D = scene.getChildByName("cloth");						
			//Create a physical representation (a TriangleMesh) for the cloth 			
			cloth.addComponent( new PhysicsMesh() );					
			(cloth.components[0] as RigidBody).restitution = 0.05;
			(cloth.components[0] as RigidBody).friction = 0.55;			
 
			var rails:Pivot3D = scene.getChildByName("rails");			
			//Create a physical representation (a TriangleMesh) for the rails of the table 			
			rails.addComponent( new PhysicsMesh() );					
			(rails.components[0] as RigidBody).restitution = 0.45;
			(rails.components[0] as RigidBody).friction = 0.95;
 
			var holes:Pivot3D = scene.getChildByName("table");			
			//Create a physical representation (a TriangleMesh) for the rest of table (as holes)			
			holes.addComponent( new PhysicsMesh() );					
			(holes.components[0] as RigidBody).restitution = 0.05;
			(holes.components[0] as RigidBody).friction = 0.5;
 
			//Get the white ball reference
			var whiteBall:Pivot3D = scene.getChildByName("poolballq");
			//Create a physical representation (a Sphere) for the white ball 			
			whiteBall.addComponent(new PhysicsSphere());
			whiteBallPhysics = whiteBall.components[0] as RigidBody;
			whiteBallPhysics.mass = 194; //Set weight of the ball
			whiteBallPhysics.restitution = 0.95; //Set restitution property of the ball
			whiteBallPhysics.friction = 0.05;	 //Set friction property of the ball
 
 
			//Set max velocity to prevents penetrations
			whiteBallPhysics.maxLinVelocities.setTo(500, 500, 500);
 
			//Save the initial position for white ball for reset
			resetPosition = whiteBall.getPosition();
 
			//Create the other balls physical representation
			resetPositionOthersBall = new Vector.<Vector3D>(15);
			for (var i:int = 1; i <= 15; i++ ) 
			{
				var tmp:Pivot3D = scene.getChildByName("poolball" + i);					
				tmp.addComponent(new PhysicsSphere());	
				(tmp.components[0] as RigidBody).mass = 160; //Set weight of the ball
				(tmp.components[0] as RigidBody).restitution = 0.95; //Set restitution property of the ball	
				(tmp.components[0] as RigidBody).friction = 0.05; //Set friction property of the ball
 
				//Save its initial position for reset
				resetPositionOthersBall[i - 1] = tmp.getPosition();			
			}							
 
			// Canvas color and size
			focusedShow.graphics.beginFill(0x000000, 0.6);
            focusedShow.graphics.drawRect(0,0,scene.viewPort.width,scene.viewPort.height);
            focusedShow.graphics.endFill();
			stage.addChild(focusedShow);			
 
			//Define an update event
			scene.addEventListener( Scene3D.UPDATE_EVENT, updateEvent );	
 
			//Start playback of the scene
			scene.resume();
		}			
 
		private function updateEvent(e:Event):void 
		{	
			// Reset white ball positions (event if it's moving)
			if ( Input3D.keyDown( Input3D.R ) ) 								
				resetWhiteBall();
 
			// Reset position for all balls(event if it's moving)
			if ( Input3D.keyDown( Input3D.T ) ) 		
			{				
				//reset others balls
				for (var i:int = 1; i <= resetPositionOthersBall.length; i++ )
				{
					var tmp:Pivot3D = scene.getChildByName("poolball" + i); //get ball reference
					(tmp.components[0] as RigidBody).setPosition(resetPositionOthersBall[i - 1].x, 
																 resetPositionOthersBall[i - 1].y, 
																 resetPositionOthersBall[i - 1].z); //copy position from reset position 		
					(tmp.components[0] as RigidBody).setLinearVelocity(Vector3DUtils.ZERO);  //Set linear velocity to zero
					(tmp.components[0] as RigidBody).setAngularVelocity(Vector3DUtils.ZERO); //Set angle velocity to zero
					(tmp.components[0] as RigidBody).setActive(true);                          //Set active for next physics step
				}					
				//Reset white ball
				resetWhiteBall();				
			}				
 
 
			//If the application does not has focus, pause the physics update
			focusedShow.visible = physics.paused;
 
			//Handle shot
			//Check if I can hit white ball
			if (canHitBall()) {
				configureShot();							
			}			
 
			//Update physics engine
			physics.step();
		}		
 
 
	//Put white ball on the start point
		private function resetWhiteBall(): void 
		{
			whiteBallPhysics.setPosition(resetPosition.x, resetPosition.y, resetPosition.z);							
			whiteBallPhysics.setLinearVelocity(Vector3DUtils.ZERO);
			whiteBallPhysics.setAngularVelocity(Vector3DUtils.ZERO);
			whiteBallPhysics.setActive(true);	
		}
 
		//Check if it's posible hit the white ball. 		
		//If the ball is still moving, I can't hit
		private function canHitBall():Boolean {
			//If white ball speed is lower than 0.15 cm/s, then it is stopped (to avoid rounding errors); or is into a hole or outside the table
			if (Math.abs(whiteBallPhysics.getVelocity().length) < 0.15 || whiteBallPhysics.y < 75) { 
				//reset others balls
				for (var i:int = 1; i <= resetPositionOthersBall.length; i++ )
				{
					var tmp:Pivot3D = scene.getChildByName("poolball" + i);
					//Again, if speed is lower than 0.15 cm/s, then it is stopped; or is into a hole or outside the table
					if (Math.abs((tmp.components[0] as RigidBody).getVelocity().length) > 0.15 && (tmp.components[0] as RigidBody).y >= 75) {
						return false;						
					}
				}			
			} else return false;
 
			return true;
		}
 
		private var angleShot:Number = 0;
		private var powerShot:Number = 0.5;						
		private var multiplier:Number;
		private var directionVector:Vector3D = new Vector3D();		
		private var posStick:Vector3D = new Vector3D();		
		private function configureShot():void {
			//Check if the white ball goes into a hole or outside the table (height is lower than cloth height). If it's true, I must reset its position.
			if (whiteBallPhysics.y < 75)  
			{
				resetWhiteBall();				
				angleShot = 0;
				powerShot = 0.5;
			}
 
			//Show the pool stick
			stick.visible = true;				
 
			//Process these key events...						
			//Change shot indicator speed (faster or slower)
			if ( Input3D.keyDown( Input3D.SHIFT ) )	multiplier = 10;
			else if ( Input3D.keyDown( Input3D.CONTROL ) )	multiplier = 0.2;
			else multiplier = 1;
 
			//Set shot direction
			if ( Input3D.keyDown( Input3D.RIGHT ) ) 						
				angleShot += 0.4 * multiplier;			
			if ( Input3D.keyDown( Input3D.LEFT ) ) 						
				angleShot -= 0.4 * multiplier;															
 
			//Set shot power
			if ( Input3D.keyDown( Input3D.DOWN ) ) 						
				powerShot = Math.min(powerShot + (0.005) * multiplier, 1.0);								
			if ( Input3D.keyDown( Input3D.UP ) ) 						
				powerShot = Math.max(powerShot - (0.005) * multiplier, 0.1);	
 
 
			//Calculate the shot direction 
			directionVector.setTo( -1, 0, 0);
			directionVector.normalize();
			directionVector = Math3D.getRotationMatrix(0, 1, 0, angleShot).transformVector(directionVector);		
 
			//Render the shot Indicator (GUI)
			dirIndicator.clear();
			dirIndicator.moveTo(whiteBallPhysics.x, whiteBallPhysics.y, whiteBallPhysics.z);
			dirIndicator.lineTo(whiteBallPhysics.x + directionVector.x * powerShot * 100, whiteBallPhysics.y, whiteBallPhysics.z + directionVector.z * powerShot * 100);
			dirIndicator.draw();											
 
			//Set stick position and orientation				
			posStick.setTo(0, 0, 0);				
			posStick.x += -directionVector.x * powerShot * 20;
			posStick.y += -directionVector.y * powerShot * 20;			
			posStick.z += -directionVector.z * powerShot * 20;					
			stick.setRotation(0, angleShot, 0);				
			stick.rotateZ(7.5);								
			stick.setPosition(whiteBallPhysics.x + posStick.x, whiteBallPhysics.y + posStick.y, whiteBallPhysics.z + posStick.z);	
 
 
			//Do the SHOT. Apply a linear velocity to white ball (0~500 cm/s)
			if ( Input3D.keyHit( Input3D.SPACE ) ) 		
			{	
				//Calculate the magnitude of velocity
				directionVector.scaleBy(powerShot * 500);
				//Apply the velocity to white ball
				whiteBallPhysics.setLinearVelocity(directionVector);									
 
				//Clear direction indicator
				dirIndicator.clear();
 
				//Hide the pool stick					
				stick.visible = false;					
			}		
		}
	}
}
blog comments powered by Disqus
Personal tools
Namespaces
Variants
Actions
Navigation
Survival kit
Flare3D Physics (Beta)
Toolbox