interactive
Flover Cow – A.K.A. Cover Flow Knockoff
I’ll do a tutorial on this later. For know, download the source and play with the example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | package { import de.polygonal.ds.DLinkedList; import de.polygonal.ds.DListNode; import gs.TweenMax; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.materials.ColorMaterial; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.view.BasicView; [SWF(width="900", height="480", backgroundColor="#ffffff", frameRate="60")] public class FloverCow extends BasicView { private static const SPACING:Number = 400; private static const NUMBER_OF_PLANES:int = 10; private static const TIME:Number = .5; private static const Z_FOCUS:Number = -500; private static const ROTATION_Y:Number = 45; private var planeList:DLinkedList = new DLinkedList(); public function FloverCow() { viewport.interactive = true; for(var i:int = 0; i < NUMBER_OF_PLANES; i++) { var randomColor:Number = Math.random() * 0xffffff; var colorMaterial:ColorMaterial = new ColorMaterial(randomColor); colorMaterial.interactive = true; var plane:Plane = new Plane(colorMaterial, 400, 400, 4, 4); plane.x = i * SPACING; plane.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, plane_objectClickHandler); planeList.append(plane); scene.addChild(plane); } flow(plane); startRendering(); } private function plane_objectClickHandler(event:InteractiveScene3DEvent):void { var plane:Plane = Plane(event.target); flow(plane); } private function flow(plane:Plane):void { var xPosition:Number = 0; TweenMax.to(plane, TIME, {x:xPosition, z:Z_FOCUS, rotationY:0}); var current:DListNode = planeList.nodeOf(plane).node; var walkLeft:DListNode = current.prev; while(walkLeft) { plane = Plane(walkLeft.data); xPosition -= SPACING; TweenMax.to(plane, TIME, {x:xPosition, z:0, rotationY:-ROTATION_Y}); walkLeft = walkLeft.prev; } xPosition = 0; var walkRight:DListNode = current.next; while(walkRight) { plane = Plane(walkRight.data); xPosition += SPACING; TweenMax.to(plane, TIME, {x:xPosition, z:0, rotationY:ROTATION_Y}); walkRight = walkRight.next; } } } } |
SpringCamera3D and Driving a Car
*update* – I updated the source download with Tim’s fix for FrustumClipping and BitmapMaterials. This should eliminate the memory leak pointed out in the comments. The fix is committed in google code if you use svn. I’ll create a .swc and .zip again sometime later this week (right now you can use the .swc included in the source download). *end update*
Well, looks like the forum launch went smoothly and now hopefully everyone knows about the upcoming training in Chicago, so it’s time for me to get back to making examples
Benoit Beauséjour created a nifty little new camera (which I just added to the trunk) that’s really useful for following things around. I decided to resurrect Carlos‘ old car demo and combine it with the new camera. All the credit goes to Carlos for the car stuff and to Benoit for the camera work. I just smashed everything together.
With these sorts of projects, you’ll spend a ton of time tweaking a the values to get everything to move “just right”. So when you start playing around with the SpringCamera3D, you’ll have to keep playing with all the settings until you get something that’s right for you.
Oh, and lastly, I updated the .swc and .zip on google code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | package { import flash.display.Bitmap; import flash.display.StageQuality; import flash.events.Event; import flash.events.KeyboardEvent; import flash.ui.Keyboard; import flash.utils.ByteArray; import org.papervision3d.cameras.SpringCamera3D; import org.papervision3d.core.clipping.FrustumClipping; import org.papervision3d.core.math.Number3D; import org.papervision3d.materials.BitmapMaterial; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.objects.parsers.DAE; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.view.BasicView; import org.papervision3d.view.layer.ViewportLayer; import org.papervision3d.view.layer.util.ViewportLayerSortMode; [SWF(width="640", height="480", backgroundColor="#ffffff", frameRate="60")] public class DrivingACar extends BasicView { [Embed(source="assets/Focus.dae", mimeType = "application/octet-stream")] private var carAsset:Class; [Embed(source="/assets/wheel.jpg")] private var wheelBitmapAsset:Class; [Embed(source="/assets/body.jpg")] private var bodyBitmapAsset:Class; [Embed(source="/assets/grassTexture.jpg")] private var grassTextureBitmapAsset:Class; private var car:DAE; private var springCamera:SpringCamera3D; private var focusMaterials:MaterialsList; private var topSpeed:Number = 0; private var topSteer:Number = 0; private var speed:Number = 0; private var steer:Number = 0; private var keyRight:Boolean = false; private var keyLeft:Boolean = false; private var keyForward:Boolean = false; private var keyReverse:Boolean = false; public function DrivingACar() { super(); addEventListener(Event.ENTER_FRAME, enterFrameHandler); stage.addEventListener( KeyboardEvent.KEY_DOWN, stage_keyDownHandler ); stage.addEventListener( KeyboardEvent.KEY_UP, stage_keyUpHandler ); setupScene(); stage.quality = StageQuality.MEDIUM; } private function setupScene():void { renderer.clipping = new FrustumClipping(FrustumClipping.BOTTOM | FrustumClipping.NEAR); springCamera = new SpringCamera3D(); springCamera.mass = 10; springCamera.damping = 10; springCamera.stiffness = 1; springCamera.lookOffset = new Number3D(0, 0, 10); springCamera.positionOffset = new Number3D(0, 5, -15); //Setup materials for the object var wheelBitmap:Bitmap = new wheelBitmapAsset() as Bitmap; var bodyBitmap:Bitmap = new bodyBitmapAsset() as Bitmap; var grassBitmap:Bitmap = new grassTextureBitmapAsset() as Bitmap; var bodyMaterial:BitmapMaterial = new BitmapMaterial(bodyBitmap.bitmapData); bodyMaterial.smooth = true; var wheelMaterial:BitmapMaterial = new BitmapMaterial(wheelBitmap.bitmapData); wheelMaterial.smooth = true; var grassMaterial:BitmapMaterial = new BitmapMaterial(grassBitmap.bitmapData); grassMaterial.precise = true; grassMaterial.tiled = true; grassMaterial.maxU = 2; grassMaterial.maxV = 2; grassMaterial.smooth = true; focusMaterials = new MaterialsList(); focusMaterials.addMaterial(bodyMaterial, "materialBody"); focusMaterials.addMaterial(wheelMaterial, "materialWheel"); // Load Collada var byteArray:ByteArray = new carAsset() as ByteArray; car = new DAE(true); car.load(byteArray, focusMaterials); car.scale = 10; springCamera.target = car; scene.addChild(car); var ground:Plane = new Plane( grassMaterial, 1000, 1000, 2, 2); ground.y = -20; scene.addChild( ground ); // Position the ground ground.rotationX = 90; viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT; var carViewportLayer:ViewportLayer = new ViewportLayer(viewport, car); carViewportLayer.addDisplayObject3D(car, true); carViewportLayer.layerIndex = 1; viewport.containerSprite.addLayer(carViewportLayer); } private function enterFrameHandler( event :Event ):void { // Check if car has been loaded if( car ) { // Calculate current steer and speed driveCar(); // Update car model updateCar(); } // Render the scene singleRender(); } private function updateCar():void { // Steer front wheels var steerFR :DisplayObject3D = car.getChildByName( "Steer_FR", true ); var steerFL :DisplayObject3D = car.getChildByName( "Steer_FL", true ); steerFR.rotationY = -steer; steerFL.rotationY = -steer; // Rotate wheels var wheelFR :DisplayObject3D = steerFR.getChildByName( "Wheel_FR", true ); var wheelFL :DisplayObject3D = steerFL.getChildByName( "Wheel_FL", true ); var wheelRR :DisplayObject3D = car.getChildByName( "Wheel_RR", true ); var wheelRL :DisplayObject3D = car.getChildByName( "Wheel_RL", true ); var roll :Number = speed * 2; wheelFR.roll( -roll ); wheelRR.roll( -roll ); wheelFL.roll( roll ); wheelRL.roll( roll ); // Steer car car.yaw( speed * steer / 500 ); // Move car car.moveForward( speed ); } private function driveCar():void { // Speed if( keyForward ) { topSpeed = 7; } else if( keyReverse ) { topSpeed = -2; } else { topSpeed = 0; } speed -= ( speed - topSpeed ) / 10; // Steer if( keyRight ) { if( topSteer < 45 ) { topSteer += 1.5; } } else if( keyLeft ) { if( topSteer > -45 ) { topSteer -= 1.5; } } else { topSteer -= topSteer / 24; } steer -= ( steer - topSteer ) / 2; } private function stage_keyDownHandler( event :KeyboardEvent ):void { switch( event.keyCode ) { case "W".charCodeAt(): case Keyboard.UP: keyForward = true; keyReverse = false; break; case "S".charCodeAt(): case Keyboard.DOWN: keyReverse = true; keyForward = false; break; case "A".charCodeAt(): case Keyboard.LEFT: keyLeft = true; keyRight = false; break; case "D".charCodeAt(): case Keyboard.RIGHT: keyRight = true; keyLeft = false; break; } } private function stage_keyUpHandler( event :KeyboardEvent ):void { switch( event.keyCode ) { case "W".charCodeAt(): case Keyboard.UP: keyForward = false; break; case "S".charCodeAt(): case Keyboard.DOWN: keyReverse = false; break; case "A".charCodeAt(): case Keyboard.LEFT: keyLeft = false; break; case "D".charCodeAt(): case Keyboard.RIGHT: keyRight = false; break; } } override protected function onRenderTick(event:Event=null):void { renderer.renderScene(scene, springCamera, viewport); } } } |
Dragging an object to rotate
The cool thing about this example is you can really just drop any DisplayObject3D in to rotate it around. It’s not super exciting, but I bet many of you will find it useful.
package { import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import org.papervision3d.core.math.Matrix3D; import org.papervision3d.core.math.Number3D; import org.papervision3d.lights.PointLight3D; import org.papervision3d.materials.shadematerials.FlatShadeMaterial; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.view.BasicView; [SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")] public class Trackball extends BasicView { private static const FORWARD:Number3D = new Number3D(0, 0, 1); private var sphere:Sphere; private var previousMousePoint:Point = new Point(); private var isMouseDown:Boolean = false; public function Trackball() { var light:PointLight3D = new PointLight3D(); var flatShadeMaterial:FlatShadeMaterial = new FlatShadeMaterial(light, 0xcc0000, 0x222222); sphere = new Sphere(flatShadeMaterial, 500, 32, 24); scene.addChild(sphere); startRendering(); stage.addEventListener(MouseEvent.MOUSE_DOWN, stage_mouseDownHandler); stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler); } private function stage_mouseDownHandler(event:MouseEvent):void { isMouseDown = true; } private function stage_mouseUpHandler(event:MouseEvent):void { isMouseDown = false; } override protected function onRenderTick(event:Event=null):void { var currentMousePoint:Point = new Point(viewport.containerSprite.mouseX, viewport.containerSprite.mouseY); if(isMouseDown) { var difference:Point = currentMousePoint.subtract(previousMousePoint); var vector:Number3D = new Number3D(difference.x, difference.y, 0); var rotationAxis:Number3D = Number3D.cross(vector, FORWARD); rotationAxis.normalize(); var distance:Number = Point.distance(currentMousePoint, previousMousePoint); var rotationMatrix:Matrix3D = Matrix3D.rotationMatrix(rotationAxis.x, -rotationAxis.y, rotationAxis.z, distance/250); sphere.transform.calculateMultiply3x3(rotationMatrix, sphere.transform); } previousMousePoint = currentMousePoint; super.onRenderTick(event); } } }
Rolling a Sphere with Keyboard and Box2DFlash Physics
You really didn’t think I was just going to leave yesterday’s example with just one ball rolling around, did you?
Remember to click the .swf to give it focus. The main rolling ball is randomized, so the .swf will look different each time you open it.
The source is a mess. I basically copied and pasted code from my other Box2DFlash examples. The only real new stuff here is using the “gravityOffset” to cancel out gravity and the m_linearVelocity to set the velocity within Box2DFlash.
package { import Box2D.Collision.Shapes.b2CircleDef; import Box2D.Collision.Shapes.b2PolygonDef; import Box2D.Collision.b2AABB; import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2BodyDef; import Box2D.Dynamics.b2World; import flash.events.Event; import flash.events.KeyboardEvent; import flash.ui.Keyboard; import org.papervision3d.core.math.Matrix3D; import org.papervision3d.core.math.Number3D; import org.papervision3d.lights.PointLight3D; import org.papervision3d.materials.shadematerials.FlatShadeMaterial; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.view.BasicView; [SWF(width="640", height="480", backgroundColor="#000000", frameRate="60")] public class RollingASphereWithTheKeyboardAndBox2D extends BasicView { private static const FORWARD:Number3D = new Number3D(0, 0, 1); private var WORLD_SCALE:Number = 30; private var WIDTH:Number = 640; private var HEIGHT:Number = 480; private var world:b2World; private var iterations:int = 10; private var timeStep:Number = 1.0/30.0; private var mainBody:b2Body; private var isDown:Boolean = false; private var isUp:Boolean = false; private var isLeft:Boolean = false; private var isRight:Boolean = false; public function RollingASphereWithTheKeyboardAndBox2D() { setupPapervision3D(); createWorld(); createFloor(); createCeiling(); createWalls(); createShapes(); startRendering(); stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler); stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler); } private function keyDownHandler(event:KeyboardEvent):void { switch(event.keyCode) { case Keyboard.DOWN: isDown = true; break; case Keyboard.UP: isUp = true; break; case Keyboard.LEFT: isLeft = true; break; case Keyboard.RIGHT: isRight = true; break; } } private function keyUpHandler(event:KeyboardEvent):void { switch(event.keyCode) { case Keyboard.DOWN: isDown = false; break; case Keyboard.UP: isUp = false; break; case Keyboard.LEFT: isLeft = false; break; case Keyboard.RIGHT: isRight = false; break; } } private function createWalls():void { var wallShapeDef:b2PolygonDef = new b2PolygonDef(); var wallBodyDef:b2BodyDef = new b2BodyDef(); var wall:b2Body; //Left and Right Shape Definition wallShapeDef.SetAsBox(100/WORLD_SCALE, (HEIGHT+40)/WORLD_SCALE/2); // Left wallBodyDef.position = new b2Vec2(-95 / WORLD_SCALE, HEIGHT/WORLD_SCALE/2); wall = world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); // Right wallBodyDef.position = new b2Vec2((WIDTH+95) / WORLD_SCALE, HEIGHT/WORLD_SCALE/2); wall = world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); } private function setupPapervision3D():void { camera.y = -300; camera.z = -300; } private function createWorld():void { var worldBounds:b2AABB = new b2AABB(); worldBounds.lowerBound = new b2Vec2( 0, 0 ); worldBounds.upperBound = new b2Vec2(WIDTH/WORLD_SCALE, HEIGHT/WORLD_SCALE); var gravity:b2Vec2 = new b2Vec2(0.0, 10.0); var sleep:Boolean = true; world = new b2World(worldBounds, gravity, sleep); } private function createFloor():void { // Create border of boxes var floorShapeDef:b2PolygonDef = new b2PolygonDef(); var floorBodyDef:b2BodyDef = new b2BodyDef(); var floor:b2Body; //bottom shape definition floorShapeDef.SetAsBox((WIDTH+40)/WORLD_SCALE/2, 100/WORLD_SCALE); // Bottom floorBodyDef.position = new b2Vec2(WIDTH/WORLD_SCALE/2, (HEIGHT+95)/WORLD_SCALE); floor = world.CreateBody(floorBodyDef); floor.CreateShape(floorShapeDef); floor.SetMassFromShapes(); } private function createCeiling():void { var ceilingShapeDef:b2PolygonDef = new b2PolygonDef(); var ceilingBodyDef:b2BodyDef = new b2BodyDef(); var ceiling:b2Body; //Top and bottom shape definition ceilingShapeDef.SetAsBox((WIDTH+40)/WORLD_SCALE/2, 100/WORLD_SCALE); // Top ceilingBodyDef.position = new b2Vec2(WIDTH/WORLD_SCALE/2, -95/WORLD_SCALE); ceiling = world.CreateBody(ceilingBodyDef); ceiling.CreateShape(ceilingShapeDef); } private function createShapes():void { var light:PointLight3D = new PointLight3D(); for (var i:Number = 0; i < 20; i++) { //radius for physics circle and sphere var radius:Number = Math.random() * 50 + 10; var bodyDef:b2BodyDef = new b2BodyDef(); //random position toward the top of the stage bodyDef.position = new b2Vec2(Math.random() * WIDTH / WORLD_SCALE, Math.random() * HEIGHT /WORLD_SCALE); var body:b2Body = world.CreateBody(bodyDef); var shapeDef:b2CircleDef = new b2CircleDef(); shapeDef.radius = radius/WORLD_SCALE; shapeDef.density = 1; shapeDef.friction = .7; shapeDef.restitution = .7; body.CreateShape(shapeDef); body.SetMassFromShapes(); var flatShadeMaterial:FlatShadeMaterial = new FlatShadeMaterial(light, Math.random() * 0xffffff, 0x111111); var sphere:Sphere = new Sphere(flatShadeMaterial, radius); scene.addChild(sphere); body.m_userData = sphere; mainBody = body; } } override protected function onRenderTick(event:Event=null):void { if(isDown) mainBody.m_linearVelocity.y += .2; if(isUp) mainBody.m_linearVelocity.y -= .2; if(isLeft) mainBody.m_linearVelocity.x -= .2; if(isRight) mainBody.m_linearVelocity.x += .2; //sets the position of any DisplayObject3D to the body position for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next) { var gravityOffset:b2Vec2 = world.m_gravity.Copy(); gravityOffset.Multiply(-bb.m_mass); bb.ApplyForce(gravityOffset, bb.GetWorldCenter() ); if (bb.m_userData is DisplayObject3D) { bb.m_userData.x = bb.GetPosition().x * WORLD_SCALE - WIDTH * .5; bb.m_userData.y = -bb.GetPosition().y * WORLD_SCALE + HEIGHT * .5; var distance:Number = Math.sqrt(bb.m_linearVelocity.x * bb.m_linearVelocity.x + bb.m_linearVelocity.y * bb.m_linearVelocity.y); var rotationAxis:Number3D = Number3D.cross(new Number3D(bb.m_linearVelocity.x, bb.m_linearVelocity.y, 0), FORWARD); rotationAxis.normalize(); var rotationMatrix:Matrix3D = Matrix3D.rotationMatrix(rotationAxis.x, -rotationAxis.y, rotationAxis.z, distance/30); bb.m_userData.transform.calculateMultiply3x3(rotationMatrix, bb.m_userData.transform); } } renderer.renderScene(scene, camera, viewport); world.Step(timeStep, iterations); } } }
Search
Recommended Books
Speaking at FITC Toronto
Recent Posts
- Moving to johnlindquist.com
- AsyncCommand with Robotlegs, Signals, Flight, MinimalComps
- Search Widget – Robotlegs, Signals, Flight, Minimal Comps, Yahoo Astra
- FDT Super Awesome March Deal
- FDT Theme Designer
- haXe Tutorial
- AS3 Signals Tutorial
- Preferred Video Tutorial Resolution?
- TweenMax – Tweening a timeline (Advanced Tweening)
- Robotlegs + Flight + Union Platform
- Back in the saddle
- Eclipse Theme Designer Preview
- RobotLegs Hello World Video Tutorial
- 10 Things Every Senior Flash Developer Should Know
- Efflex – 3D Effects for Flex
Recent Comments
- Ocatarinabelachichix on about
- Rajiv on faq
- Rajiv on 3ds max texture baking for Papervision3D
- Anupam Biswas on Maya Texture Baking
- Anupam Biswas on Maya Texture Baking
- Arindam Mojumder on requests
- Arindam Mojumder on requests
- Arindam Mojumder on Full Screen Cube
- Arindam Mojumder on faq
- Mimosa123321 on requests
Categories
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
| « May | ||||||
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 | |
Archives
Preferred Video Tutorial Resolution
- 1024x768 (53%, 85 Votes)
- 1280x1024 (15%, 24 Votes)
- 1920x1080 (15%, 24 Votes)
- 800x600 (13%, 20 Votes)
- 480x320 (4%, 6 Votes)
- 640x480 (0%, 2 Votes)
Total Voters: 160





