Archive

Archive for April, 2009

JigLibFlash + Papervision3d : Quick run-through

April 3rd, 2009

Hi all:

So last night I got some time to set up a quick and dirty example demonstrating how easy it is to implement physics in 3D using the new “plugin” classes created by Bartek who, if I do say so myself, has done a beautiful job setting up the plugin system for both Papervision3D and Away3D [EDIT : he also set up a really cool post over in the project wiki!]. Check this out (use your arrow keys to move the sphere around):

And here is the code for it:

package
{
    import flash.display.Bitmap;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;
   
    import jiglib.geometry.JSphere;
    import jiglib.math.JNumber3D;
    import jiglib.physics.RigidBody;
    import jiglib.plugin.papervision3d.Papervision3DPhysics;
    import jiglib.plugin.papervision3d.Pv3dMesh;
   
    import org.papervision3d.cameras.CameraType;
    import org.papervision3d.cameras.SpringCamera3D;
    import org.papervision3d.core.math.Number3D;
    import org.papervision3d.lights.PointLight3D;
    import org.papervision3d.materials.BitmapMaterial;
    import org.papervision3d.materials.WireframeMaterial;
    import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Plane;
    import org.papervision3d.objects.primitives.Sphere;
    import org.papervision3d.view.BasicView;
    import org.papervision3d.view.layer.util.ViewportLayerSortMode;
   
    /**
     * Simple Papervision3D + JigLibFlash example
     * @author Reynaldo a.k.a. reyco1
     *
     */

    [SWF(width="900", height="700", backgroundColor="#000000", frameRate="60")]
    public class RandomObjects extends BasicView
    {
        [Embed(source="assets/earthTexture512x256.jpg")]
        public var EarthTexture:Class;
       
        private var physics:Papervision3DPhysics;
        private var sphereObject:Sphere;
        private var physicsObject:RigidBody;       
        private var keyRight:Boolean = false;
        private var keyLeft:Boolean = false;
        private var keyForward:Boolean = false;
        private var keyReverse:Boolean = false;
        private var keyUp:Boolean = false;     
        private var moveForce:Number = 10;     
        private var springCamera:SpringCamera3D;
        private var cameraTarget:DisplayObject3D;
        private var sceneLight:PointLight3D;
       
        public function RandomObjects()
        {
            super(stage.stageWidth, stage.stageHeight, true, false, CameraType.TARGET);
            viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;
            physics = new Papervision3DPhysics(scene, 1);
                       
            addKeyboardListeners();
            setupLighting();
            createFloor();
            setCamera();
            createSphere();
            createBoxes();     
            startRendering();
        }
       
        private function addKeyboardListeners():void
        {
            stage.addEventListener( KeyboardEvent.KEY_DOWN, keyDownHandler );
            stage.addEventListener( KeyboardEvent.KEY_UP, keyUpHandler );
        }
       
        private function setupLighting():void
        {
            sceneLight = new PointLight3D(true, true);
            sceneLight.x = 0;
            sceneLight.y = 400;
            sceneLight.z = -300;
        }
       
        private function setCamera():void
        {
            springCamera = new SpringCamera3D();
            springCamera.mass = 10;
            springCamera.damping = 10;
            springCamera.stiffness = 1;
               
            springCamera.lookOffset = new Number3D(0, 20, 30);
            springCamera.positionOffset = new Number3D(0, 100, -1500);
           
            springCamera.focus = 100;
            springCamera.zoom = 10;
        }
       
        private function createSphere():void
        {
            var earthMaterial:BitmapMaterial = new BitmapMaterial(Bitmap(new EarthTexture()).bitmapData, true);
            earthMaterial.tiled = true;
            earthMaterial.smooth = true;
           
            sphereObject = new Sphere(earthMaterial, 100, 13, 11);
            scene.addChild(sphereObject);
           
            physicsObject = new JSphere(new Pv3dMesh(sphereObject), 100);
            physicsObject.y = 200;
            physicsObject.restitution = 3;
            physicsObject.mass = 1
            physics.addBody(physicsObject);
           
            cameraTarget = new DisplayObject3D();
            cameraTarget.copyPosition(sphereObject);
            scene.addChild(cameraTarget);
           
            springCamera.target = cameraTarget;
        }
       
        private function createBoxes():void
        {
            var randomBox:RigidBody;
            var material:MaterialsList = new MaterialsList();
            material.addMaterial(new FlatShadeMaterial(sceneLight, 0x77ee77), "all");
            //material.addMaterial(new ColorMaterial(0x77ee77), "all");
           
            for(var a:Number = 0; a<10; a++)
            {
                randomBox = physics.createCube(material, 100, 100, 100);
                randomBox.z = 1000;
                randomBox.y = a*100 + 55;
                randomBox.mass = .2;
            }
        }
       
        private function createFloor():void
        {
            physics.createGround(new WireframeMaterial(0xFFFFFF, 0), 1800, 0);
           
            var floor:Plane = new Plane(new WireframeMaterial(0xFFFFFF), 10000, 10000, 10000*0.001, 10000*0.001);
            floor.rotationX = 90;
            floor.y = -150
            scene.addChild(floor);
           
           /*  var floorViewportLayer:ViewportLayer = new ViewportLayer(viewport, floor);
            floorViewportLayer.addDisplayObject3D(floor, true);
            floorViewportLayer.layerIndex = 1;
           
            viewport.containerSprite.addLayer(floorViewportLayer); */

        }
       
        private function keyDownHandler(event:KeyboardEvent):void
        {
            switch(event.keyCode)
            {
                case Keyboard.UP:
                    keyForward = true;
                    keyReverse = false;
                    break;
   
                case Keyboard.DOWN:
                    keyReverse = true;
                    keyForward = false;
                    break;
   
                case Keyboard.LEFT:
                    keyLeft = true;
                    keyRight = false;
                    break;
   
                case Keyboard.RIGHT:
                    keyRight = true;
                    keyLeft = false;
                    break;
                case Keyboard.SPACE:
                    keyUp = true;
                    break;
            }
        }
       
        private function keyUpHandler(event:KeyboardEvent):void
        {
            switch(event.keyCode)
            {
                case Keyboard.UP:
                    keyForward = false;
                    break;
   
                case Keyboard.DOWN:
                    keyReverse = false;
                    break;
   
                case Keyboard.LEFT:
                    keyLeft = false;
                    break;
   
                case Keyboard.RIGHT:
                    keyRight = false;
                    break;
                case Keyboard.SPACE:
                    keyUp=false;
            }
        }
       
        override protected function onRenderTick(event:Event = null):void
        {
            if(keyLeft)
            {
                physicsObject.addWorldForce(new JNumber3D(-moveForce, 0, 0), physicsObject.currentState.position);
            }
            if(keyRight)
            {
                physicsObject.addWorldForce(new JNumber3D(moveForce, 0, 0), physicsObject.currentState.position);
            }
            if(keyForward)
            {
                physicsObject.addWorldForce(new JNumber3D(0, 0, moveForce), physicsObject.currentState.position);
            }
            if(keyReverse)
            {
                physicsObject.addWorldForce(new JNumber3D(0, 0, -moveForce), physicsObject.currentState.position);
            }
            if(keyUp)
            {
                physicsObject.addWorldForce(new JNumber3D(0, moveForce, 0), physicsObject.currentState.position);
            }
           
            cameraTarget.copyPosition(sphereObject);
           
            physics.step();
            renderer.renderScene(scene, springCamera, viewport);
        }
       
    }
}

Stripping out all the usual stuff from the code above, these are snippets that integrate the physics:

First thing we need to is set up and instance of the physics plugin

physics = new Papervision3DPhysics();

Now, there are two ways to apply physics to your 3d objects using the plugin system. In the example, I use both. The “manual” approach can be seen in the createSphere method:

First the Papervision3D sphere is created and added to the scene

var earthMaterial:BitmapMaterial = new BitmapMaterial(Bitmap(new EarthTexture()).bitmapData, true);
earthMaterial.tiled = true;
earthMaterial.smooth = true;
           
sphereObject = new Sphere(earthMaterial, 100, 13, 11);
scene.addChild(sphereObject);

Then we create a physics sphere and add it to the physics engine:

physicsObject = new JSphere(new Pv3dMesh(sphereObject), 100);
physicsObject.y = 200;
physicsObject.restitution = 3;
physicsObject.mass = 1;
physics.addBody(physicsObject);

That’s basically it. You can go through all those steps (which aren’t many actually) or you can use the shortcut method which I used for creating the cubes in the createBoxes method:

randomBox = physics.createCube(material, 100, 100, 100);
randomBox.z = 1000;
randomBox.y = a*100 + 55;
randomBox.mass = .2;

Basically, both the 3d object and the physics object are created by the engine. Just pass the same arguments you would pass to the 3d Object class, in this case a Cube.

You can access the DisplayObject3D class anytime by using the following method from the plugin

physics.getMesh(randomBox)

Applying forces to your 3D/physics objects is pretty simple too. I’ll go over it more in detail in a later post, but this is the line that makes it happen:

physicsObject.addWorldForce(new JNumber3D(moveForce, 0, 0), physicsObject.currentState.position);

Where the first parameter is a vector or JNumber indicating in what direction the force should be applied and the second parameter is the current position of the physics object to which the force is being applied to.

I recommend you guys jump into the JigLibFlash repo and start exploring. There’ll be more examples to come soon!

JigLibFlash, Lab, papervision3d

Box2Dwrapper – More Examples with Joints

April 1st, 2009

Hi!

Here are a few examples on how to set up joints using Box2Dwrapper. More to come! Remember, you can grab the wrapper source here : https://box2dwrapper.googlecode.com/svn/trunk I’ll be posting more complex examples soon so stay tuned ;)

Prismatic Joint Example

package
{
    import Box2D.Common.Math.b2Vec2;
   
    import com.box2dwrapper.math.Vec;
    import com.box2dwrapper.object.Box;
    import com.box2dwrapper.object.Joint;
    import com.box2dwrapper.view.Box2DView;

    public class PrismaticJointExample extends Box2DView
    {
        public function PrismaticJointExample()
        {
            super();
            initialize();
        }
       
        private function initialize():void
        {
            createBoundingWalls();
            showDebug = true;
            allowDragging = true;
                       
            createObjects();
           
            startPhysicsRender();
        }
       
        private function createObjects():void
        {
            var plank:Box = new Box();
            plank.scale(100, 20);
            plank.position(stage.stageWidth * 0.5, stage.stageHeight * 0.5);
            plank.type = "dynamic";
            addBody(plank);
           
            var joint:Joint = new Joint(Joint.PRISMATIC);
            joint.initialize(world.GetGroundBody(), plank.body, plank.body.GetWorldCenter(), new b2Vec2(1, 0));
            joint.lowerTranslation = -3;
            joint.upperTranslation = 3
            joint.enableLimit = true;          
           
            joint.maxMotorForce = 100;
            joint.motorSpeed = 4.0;
            joint.enableMotor = true;          
           
            addJoint(joint);
        }
       
    }
}

Revolute Joint Example

package
{
    import com.box2dwrapper.math.Vec;
    import com.box2dwrapper.object.Box;
    import com.box2dwrapper.object.Circle;
    import com.box2dwrapper.object.Joint;
    import com.box2dwrapper.view.Box2DView;

    public class RevoluteJointExample extends Box2DView
    {
        public function RevoluteJointExample()
        {
            super();
            initialize();
        }
       
        private function initialize():void
        {
            createBoundingWalls();
            showDebug = true;
            allowDragging = true;
                       
            createObjects();
           
            startPhysicsRender();
        }
       
        private function createObjects():void
        {
            var pivot:Circle = new Circle();
            pivot.radius = 10;
            pivot.position(stage.stageWidth * 0.5, stage.stageHeight * 0.5);
            pivot.type = "static";
            addBody(pivot);
           
            var plank:Box = new Box();
            plank.scale(20, 100);
            plank.position(pivot.x, pivot.y + 35);
            plank.type = "dynamic";
            addBody(plank);
           
            var tac:Joint = new Joint(Joint.REVOLUTE);
            tac.initialize(pivot.body, plank.body, pivot.body.GetWorldCenter());
           
            tac.enableMotor = true;
            tac.motorSpeed = 2;
            tac.maxMotorTorque = 50;
           
            addJoint(tac);
        }
       
    }
}

Gear Joint Example

package
{
    import Box2D.Dynamics.Joints.b2GearJoint;
    import Box2D.Dynamics.Joints.b2GearJointDef;
   
    import com.box2dwrapper.object.Circle;
    import com.box2dwrapper.object.Joint;
    import com.box2dwrapper.view.Box2DView;

    public class GearJointExample extends Box2DView
    {
        public function GearJointExample()
        {
            super();
            showDebug = true;
            allowDragging = true;
            initialize();
            startPhysicsRender();
        }
       
        private function initialize():void
        {
            var gear1:Circle = new Circle();
            gear1.radius = 40;
            gear1.density = 2;
            gear1.position(stage.stageWidth * 0.45, stage.stageHeight * 0.5);
            gear1.type = "dynamic";
            addBody(gear1);
           
            var gear2:Circle = new Circle();
            gear2.radius = 60;
            gear2.density = 3;
            gear2.position(stage.stageWidth * 0.65, stage.stageHeight * 0.5);
            gear2.type = "dynamic";
            addBody(gear2);
           
            var joint1:Joint = new Joint(Joint.REVOLUTE);
            joint1.initialize(world.GetGroundBody(), gear1.body, gear1.body.GetWorldCenter());
            addJoint(joint1);
           
            var joint2:Joint = new Joint(Joint.REVOLUTE);
            joint2.initialize(world.GetGroundBody(), gear2.body, gear2.body.GetWorldCenter());
            addJoint(joint2);
           
            var gearJoint:Joint = new Joint(Joint.GEAR);
            gearJoint.body1 = gear1.body;
            gearJoint.body2 = gear2.body;
            gearJoint.joint1 = joint1.joint;
            gearJoint.joint2 = joint2.joint;
            gearJoint.ratio = 1;
            addJoint(gearJoint);               
        }      
    }
}

Experiment, Lab, as3