OimoPhysics is a 3D physics engine. It supports rigid bodies and has some out of the box collision detectors such as sphere/box and box/shape. There are two built-in shapes ready to be used: box and sphere.
Sample
/* Copyright (c) 2012 EL-EMENT saharan * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation * files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, * modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to * whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.element.oimo.physics.test { import com.element.oimo.physics.collision.shape.BoxShape; import com.element.oimo.physics.collision.shape.Shape; import com.element.oimo.physics.collision.shape.ShapeConfig; import com.element.oimo.physics.collision.shape.SphereShape; import com.element.oimo.physics.dynamics.RigidBody; import com.element.oimo.physics.dynamics.World; import com.element.oimo.math.Mat33; import com.element.oimo.math.Quat; import com.element.oimo.math.Vec3; import com.element.oimo.physics.OimoPhysics; import com.element.oimo.physics.util.DebugDraw; import flash.display.Sprite; import flash.display.Stage3D; import flash.events.Event; import flash.events.KeyboardEvent; import flash.text.TextField; import flash.text.TextFormat; import flash.ui.Keyboard; import net.hires.debug.Stats; /** * 動作テスト * @author saharan */ [SWF(width = "640", height = "480", frameRate = "60")] public class BoxTest extends Sprite { private var s3d:Stage3D; private var world:World; private var renderer:DebugDraw; private var rigid:RigidBody; private var count:uint; private var tf:TextField; private var fps:Number; private var l:Boolean; private var r:Boolean; private var u:Boolean; private var d:Boolean; private var ctr:RigidBody; public function BoxTest() { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); var debug:Stats = new Stats(); debug.x = 570; addChild(debug); tf = new TextField(); tf.selectable = false; tf.defaultTextFormat = new TextFormat("_monospace", 12, 0xffffff); tf.x = 0; tf.y = 0; tf.width = 400; tf.height = 400; addChild(tf); trace(OimoPhysics.DESCRIPTION); initWorld(); fps = 0; s3d = stage.stage3Ds[0]; s3d.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreated); s3d.requestContext3D(); stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void { var code:uint = e.keyCode; if (code == Keyboard.W) { u = true; } if (code == Keyboard.S) { d = true; } if (code == Keyboard.A) { l = true; } if (code == Keyboard.D) { r = true; } if (code == Keyboard.SPACE) { initWorld(); } }); stage.addEventListener(KeyboardEvent.KEY_UP, function(e:KeyboardEvent):void { var code:uint = e.keyCode; if (code == Keyboard.W) { u = false; } if (code == Keyboard.S) { d = false; } if (code == Keyboard.A) { l = false; } if (code == Keyboard.D) { r = false; } }); addEventListener(Event.ENTER_FRAME, frame); } private function initWorld():void { world = new World(); if (!renderer) renderer = new DebugDraw(640, 480); renderer.setWorld(world); var rb:RigidBody; var s:Shape; var c:ShapeConfig = new ShapeConfig(); c.restitution = 0; rb = new RigidBody(); c.position.init(0, -0.5, 0); c.rotation.init(); s = new BoxShape(32, 1, 32, c); rb.addShape(s); rb.setupMass(RigidBody.BODY_STATIC); world.addRigidBody(rb); c.rotation.init(); var width:uint = 6; var height:uint = 6; var depth:uint = 6; var bw:Number = 0.7; var bh:Number = 0.7; var bd:Number = 0.7; for (var i:int = 0; i < width; i++) { for (var j:int = 0; j < height; j++) { for (var k:int = 0; k < depth; k++) { rb = new RigidBody(); c.position.init( (i - (width - 1) * 0.5) * bw, j * (bh * 1.1) + bh * 0.5 + 0.05, (k - (depth - 1) * 0.5) * bd ); s = new BoxShape(bw, bh, bd, c); rb.addShape(s); rb.setupMass(RigidBody.BODY_DYNAMIC); world.addRigidBody(rb); } } } c.friction = 2; c.position.init(0, 1, 8); c.density = 10; c.rotation.init(); s = new SphereShape(1, c); ctr = new RigidBody(); ctr.addShape(s); ctr.setupMass(RigidBody.BODY_DYNAMIC); world.addRigidBody(ctr); } private function onContext3DCreated(e:Event = null):void { renderer.setContext3D(s3d.context3D); renderer.camera(0, 2, 4); } private function frame(e:Event = null):void { count++; var ang:Number = (320 - mouseX) * 0.01 + Math.PI * 0.5; renderer.camera( ctr.position.x + Math.cos(ang) * 8, ctr.position.y + (240 - mouseY) * 0.1, ctr.position.z + Math.sin(ang) * 8, ctr.position.x, ctr.position.y, ctr.position.z ); if (l) { ctr.linearVelocity.x -= Math.cos(ang - Math.PI * 0.5) * 0.8; ctr.linearVelocity.z -= Math.sin(ang - Math.PI * 0.5) * 0.8; } if (r) { ctr.linearVelocity.x -= Math.cos(ang + Math.PI * 0.5) * 0.8; ctr.linearVelocity.z -= Math.sin(ang + Math.PI * 0.5) * 0.8; } if (u) { ctr.linearVelocity.x -= Math.cos(ang) * 0.8; ctr.linearVelocity.z -= Math.sin(ang) * 0.8; } if (d) { ctr.linearVelocity.x += Math.cos(ang) * 0.8; ctr.linearVelocity.z += Math.sin(ang) * 0.8; } world.step(); fps += (1000 / world.performance.totalTime - fps) * 0.5; if (fps > 1000 || fps != fps) { fps = 1000; } tf.text = "Rigid Body Count: " + world.numRigidBodies + "\n" + "Shape Count: " + world.numShapes + "\n" + "Contacts Count: " + world.numContacts + "\n\n" + "Broad Phase Time: " + world.performance.broadPhaseTime + "ms\n" + "Narrow Phase Time: " + world.performance.narrowPhaseTime + "ms\n" + "Constraints Time: " + world.performance.constraintsTime + "ms\n" + "Update Time: " + world.performance.updateTime + "ms\n" + "Total Time: " + world.performance.totalTime + "ms\n" + "Physics FPS: " + fps.toFixed(2) + "\n" ; renderer.render(); var len:uint = world.numRigidBodies; var rbs:Vector. = world.rigidBodies; for (var i:int = 0; i < len; i++) { var r:RigidBody = rbs[i]; if (r.position.y < -12) { r.position.init(Math.random() * 8 - 4, Math.random() * 4 + 8, Math.random() * 8 - 4); r.linearVelocity.x *= 0.8; r.linearVelocity.z *= 0.8; } } } } }