Gone Bowling

Just finished work on a simple little bowling game using the JiglibFlash physics engine and Papervision3D. It’s not a fully functional game as there are no frames or score keeping, but it was made as an example file for a tutorial so was deliberately kept simple. To play, first click on the little green rectangle to position the ball horizontally. Then, to roll, click the red square. The higher up on the square you click, the more forward power the ball will have. The angular power of the ball is determined by the horizontal location of your mouse click. Just play around, you’ll see what I’m talking about. And, just because it’s 3D, you can move the camera around using the arrow keys and your mousewheel.

[kml_flashembed fversion=”10.0.0″ movie=”http://blog.onebyonedesign.com/wp-content/uploads/2009/06/bowling.swf” targetclass=”flashmovie” publishmethod=”static” width=”550″ height=”500″]

Get Adobe Flash player

[/kml_flashembed]

For anyone interested on how to build something like that, I just submitted the full and rather lengthy tutorial to The TechLabs. Hopefully they’ll use it. If not, I’ll publish it myself. So, if interested, it’s coming out one way or another, just keep your eyes peeled.

On an unrelated note, in my Twisty Cubes post, I mentioned in a comment that once I used that code for myself, I’d go ahead and make it public (though it ain’t that complex and you’ll probably be pretty disappointed). Well, I went ahead and used it in an updated version of my portfolio, so true to my word, here is the source for anyone who wants to play around with it (just to make it abundantly clear, the script below produces the effect seen here):

package {
	
	import com.as3dmod.modifiers.Twist;
	import com.as3dmod.ModifierStack;
	import com.as3dmod.plugins.pv3d.LibraryPv3d;
	
	import flash.text.AntiAliasType;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filters.DropShadowFilter;
	
	import net.hires.debug.Stats;
	
	import gs.easing.Back;
	import gs.easing.Quad;
	import gs.TweenLite;
	
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.BitmapMaterial;
	import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
	import org.papervision3d.materials.shaders.PhongShader;
	import org.papervision3d.materials.shaders.ShadedMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.render.BasicRenderEngine;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.view.Viewport3D;
	import org.papervision3d.objects.primitives.Cube;
	
	/**
	 * Mmmmmm... Twisty Cubes...
	 * @author Devon O Wolfgang
	 */
	
	[SWF(width="500", height="400", frameRate="60", backgroundColor="#222222")] 
	public class Main extends Sprite {
		
		[Embed(source = "../assets/be_1.jpg")]
		private var Image1:Class;
		[Embed(source = "../assets/bf_1.jpg")]
		private var Image2:Class;
		[Embed(source = "../assets/hrr_1.jpg")]
		private var Image3:Class;
		[Embed(source = "../assets/zs_1.jpg")]
		private var Image4:Class;
		
		private var _view:Viewport3D;
		private var _cam:Camera3D;
		private var _light:PointLight3D;
		private var _scene:Scene3D;
		private var _engine:BasicRenderEngine;
		
		private var _cube:Cube;
		
		private var _twist:Twist;
		private var _stack:ModifierStack;
		
		public function Main():void {
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void {
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			
			init3d();
			initText();
			initScene();
			startRender();
			
			//addChild(new Stats());
		}
		
		private function init3d():void {
			_view = new Viewport3D(500, 400);
			_scene = new Scene3D();
			_engine = new BasicRenderEngine();
			_cam = new Camera3D();
			_cam.y = 400;
			_cam.z = -850;
			
			_view.filters = [ new DropShadowFilter(40, 90, 0x000000, .6, 24, 24) ];
			
			addChild(_view);
		}
		
		private function initText():void {
			var tf:TextField = new TextField();
			var fmt:TextFormat = new TextFormat("_sans", 12, 0xDDDDDD);
			tf.defaultTextFormat = fmt;
			tf.autoSize = TextFieldAutoSize.LEFT;
			tf.selectable = false;
			tf.mouseEnabled = false;
			tf.antiAliasType = AntiAliasType.ADVANCED;
			tf.text = "Click anywhere to rotate cube.";
			tf.x = int((250) - (tf.textWidth * .5));
			tf.y = int(400 - tf.height);
			addChild(tf);
		}
		
		private function initScene():void {
			_light = new PointLight3D();
			_light.y = 400;
			_light.x = 50;
			_light.z = -600;
			
			var flatMat:FlatShadeMaterial = new FlatShadeMaterial(_light, 0x666666);
			
			var img1:BitmapMaterial = new BitmapMaterial(new Image1().bitmapData);
			var img1Mat:ShadedMaterial = new ShadedMaterial(img1, new PhongShader(_light, 0xFFFFFF));	
			var img2:BitmapMaterial = new BitmapMaterial(new Image2().bitmapData);
			var img2Mat:ShadedMaterial = new ShadedMaterial(img2, new PhongShader(_light, 0xFFFFFF));
			var img3:BitmapMaterial = new BitmapMaterial(new Image3().bitmapData);
			var img3Mat:ShadedMaterial = new ShadedMaterial(img3, new PhongShader(_light, 0xFFFFFF));
			var img4:BitmapMaterial = new BitmapMaterial(new Image4().bitmapData);
			var img4Mat:ShadedMaterial = new ShadedMaterial(img4, new PhongShader(_light, 0xFFFFFF));
			
			
			var matList:MaterialsList = new MaterialsList( { top:flatMat, bottom:flatMat, left:img1Mat, right:img2Mat, front:img3Mat, back:img4Mat } );
			_cube = new Cube(matList, 500, 500, 500, 5, 5, 5);
			_cam.target = _cube;
			
			_stack = new ModifierStack(new LibraryPv3d(), _cube);
			
			_twist = new Twist(0);
			
			_stack.addModifier(_twist);
			
			_scene.addChild(_cube);
			
			stage.addEventListener(MouseEvent.CLICK, doTwist);
		}
		
		private function doTwist(event:MouseEvent):void {
			TweenLite.to(_twist, .25, { angle:.6, ease:Quad.easeOut, onComplete:untwist } );
			TweenLite.to(_cube, .5, { rotationY:_cube.rotationY + 90 } );
		}
		
		private function untwist():void {
			TweenLite.to(_twist, .3, { angle:0, ease:Back.easeOut } );
		}
		
		private function startRender():void {
			addEventListener(Event.ENTER_FRAME, render);
		}
		
		private function render(event:Event):void {
			var ratio:Number = ((stage.mouseY / 400) - .5 ) * 2;
			var targetPos:Number = ratio * 600;
			var ang:Number = ratio * 90;
			_cam.y += (targetPos - _cam.y) / 20;
			_light.y = _cam.y;
			
			var shadow:DropShadowFilter = _view.filters[0];
			shadow.angle += (ang - shadow.angle) / 20;
			_view.filters = [shadow];
			_stack.apply();
			_engine.renderScene(_scene, _cam, _view);
		}
	}
}

Of course you’ll have to get a hold of AS3DMod if you don’t already have it. Have fun…

Incidentally, you may have noticed I have, once again, changed blog themes and added some google ads. I know, I just can’t leave well enough alone. And the ads are looking like a temporary experiment. I was more interested in how they worked from a developer/API viewpoint than anything. Of course, I figured if I made a few shekels in the process, what the hell? So far I’ve earned a whopping 43 cents. Look out…

Date: