/trunk/demos/OneWayPlatforms/Main.hx
http://nape.googlecode.com/ · Haxe · 252 lines · 132 code · 52 blank · 68 comment · 22 complexity · 7367b58e5da6a061de40bca1043a2578 MD5 · raw file
- /*
- * Stage size 800x600
- * fps 60
- *
- * Necessitates that there 'is' a sound Bang in the library.
- */
-
- package;
-
- //urgh far too many imports!
- import nape.Space;
- import nape.PhysObj;
- import nape.Tools;
- import nape.Geom;
- import nape.PhysAux;
- import nape.Dynamics;
- import nape.Constraint;
-
- import flash.Lib;
- import flash.text.TextField;
- import flash.events.Event;
- import flash.events.MouseEvent;
- import flash.display.StageQuality;
-
- import flash.display.Bitmap;
- import flash.display.BitmapData;
- import flash.display.Sprite;
-
- import flash.filters.ColorMatrixFilter;
- import flash.geom.Point;
- import flash.geom.Rectangle;
-
- import flash.media.Sound;
- import flash.media.SoundTransform;
-
- //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- class Main {
- static var space:Space;
-
- //cbType values for objects.
- static var OBJECT :Int = CbType.get();
- static var PLATFORM:Int = CbType.get();
- static var IN_BIN :Int = CbType.get();
- static var OUT_BIN :Int = CbType.get();
-
- static var fps:TextField;
-
- //shiz for the fade-out of removed objects.
- static var bit:BitmapData;
- static var conv:ColorMatrixFilter;
- static var graph:Sprite;
-
- static function main() {
- //set up bitmap for fade outs (could be done differently, but i like bitmaps :P)
- bit = new BitmapData(800, 600, true, 0);
- graph = new Sprite();
- Lib.current.addChild(new Bitmap(bit));
- conv = new ColorMatrixFilter([1,0,0,0,0, 0,1,0,0,0, 0,0,1,0,0, 0,0,0,0.85,0]);
-
- fps = new TextField();
- Lib.current.addChild(fps);
-
- //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- space = new UniformSleepSpace(0,0,800,600,15, new Vec2(0,250));
-
- var b:Body;
- //create platforms
- b = Tools.createBox(200, 300, 250, 10, 0, 0, 0, true, Material.Wood);
- b.cbType = PLATFORM; space.addObject(b);
- Lib.current.addChild(b.graphic);
- b = Tools.createBox(600, 300, 250, 10, 0, 0, 0, true, Material.Wood);
- b.cbType = PLATFORM; space.addObject(b);
- Lib.current.addChild(b.graphic);
-
- b = Tools.createBox(400, 100, 300, 25, 0, 0, 0, true, Material.Wood);
- b.cbType = PLATFORM; space.addObject(b);
- Lib.current.addChild(b.graphic);
-
- b = Tools.createBox(400, 500, 500, 50, 0, 0, 0, true, Material.Wood);
- b.cbType = PLATFORM; space.addObject(b);
- Lib.current.addChild(b.graphic);
-
- //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- //create sensor bins.
- // note the values for group layer, and sensor layer.
- // 0 collision => can never collide
- // 1 sensor => acts in layer 1.
-
- b = Tools.createBox(300, 400, 150, 30, 0, 0, 0, true, Material.Tire, 0, 1);
- b.cbType = IN_BIN; space.addObject(b);
- Lib.current.addChild(b.graphic); b.graphic.alpha = 0.5;
-
- b = Tools.createBox(500, 400, 150, 30, 0, 0, 0, true, Material.Rubber, 0, 1);
- b.cbType = OUT_BIN; space.addObject(b);
- Lib.current.addChild(b.graphic); b.graphic.alpha = 0.5;
-
- //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- //----assign callbacks to the type pairs
- //one-way platforms
- space.addCbPreBegin (OBJECT, PLATFORM, cbOneWay);
-
- //sounds
- //use post-solve to get a sound for every single impact
- // rather than 'begin' wherein in the case of a box hitting the ground
- // and then rotating down to have a second impact without it seperating not
- // generating a second sound. impactImpulse only takes into account
- // new contacts, so there's no issues of generating sounds when objects
- // are simply in a stack etc.
- //can easily use 'begin' anyways for effeciency reasons perhaps.
- // the overall result isn't so different.
- space.addCbPostSolve(OBJECT, PLATFORM);
- space.addCbPostSolve(OBJECT, OBJECT);
-
- //removal of objects for bins.
- space.addCbSenseBegin(IN_BIN, OBJECT);
- space.addCbSenseEnd (OUT_BIN, OBJECT);
-
- //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- //set graphical quality to medium
- Lib.current.stage.quality = StageQuality.MEDIUM;
-
- //set up events
- Lib.current.stage.addEventListener(Event.ENTER_FRAME, enterFrame);
- Lib.current.stage.addEventListener(MouseEvent.MOUSE_DOWN, mdown);
-
- //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- //create a list of Bang's up to flash limit of concurrent sounds
- bangs = new Array<Bang>();
- for (i in 0...32)
- bangs.push(new Bang());
- }
-
- static function mdown(ev) {
- for(i in 0...10) {
- var b:PhysObj;
- var mx = ev.stageX +Math.random() * 50 - 25;
- var my = ev.stageY +Math.random() * 50 - 25;
-
- var vy = (my > 300) ? -400 : 0;
- var m = (my > 300) ? Material.Steel : Material.Tire;
-
- // note collision and sensor layers
- // collision = 0xffffffff => collides with everything
- // sensor = 1 => senses in the first layer, matching with that of the bins.
- b = Tools.createBox(mx, my, 14,14, 0, vy, 0, false, m, 0xffffffff, 1);
- b.cbType = OBJECT; space.addObject(b);
- Lib.current.addChild(b.graphic);
- }
- }
-
- //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- static function cbOneWay(arb:Arbiter):Int {
- //grab first contact in arbiter.
- var con = arb.contacts.front();
- //if contact normal points wrong way, let object move through platform
- // here i abuse the fact that platforms are all static, and therefore
- // the contact normal MUST be pointing away from the platform.
- // without knowledge of this inner working of the engine, you could
- // still simply do it as below with the bins and compare cbTypes to know
- // which object is which, to know which direction normal will be pointing
- return if (con.ny < 0) Callback.ACCEPT else Callback.IGNORE;
- }
-
- //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- //in the following, i've not abused the fact that both bins
- //are static: I 'could' have abused this, and therefore assumed that
- //p2 will always be the object to be removed.
- static inline function cbBin(cb:Callback,type:Int) {
- var p1 = cb.obj_arb.p1; var p2 = cb.obj_arb.p2;
- var rem = if (p1.cbType == type) p2 else p1;
- //rem = p2; is equivalent should you abuse the fact that the bins are static.
- // again, this depends however on internal knowledge of the engine workings.
-
- space.removeObject(rem);
- if (Lib.current.contains(rem.graphic)) Lib.current.removeChild(rem.graphic);
- bit.draw(rem.graphic,rem.graphic.transform.matrix);
- }
-
- //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- //sound shiz.
- static var bangs:Array<Bang>;
- static var cbang = 0;
- static var soundt:SoundTransform = new SoundTransform();
- static var psound = 0; static var pvol = 0.0;
-
- static function enterFrame(ev) {
- //step 1/60th of a second through time in space.
- //not bothered with variable time step here clearly.
- space.step(1 / 60, 6, 8);
-
- //apply filter to bitmap.
- bit.applyFilter(bit, new Rectangle(0, 0, 800, 600), new Point(0, 0), conv);
-
- //max volume, pan accumulator, impact count.
- var vol = 0.;
- var pan = 0.;
- var cnt = 0;
-
- //iterate the non-immediate callbacks.
- while(!space.callbacks.empty()) {
- var cb = space.callbacks.pop();
- if (cb.type == Callback.SENSE_BEGIN) cbBin(cb,IN_BIN);
- else if (cb.type == Callback.SENSE_END) cbBin(cb, OUT_BIN);
-
- else if (cb.type == Callback.POST_SOLVE) {
- var oarb = cb.obj_arb;
- //iterate associated arbiters.
- var ite = oarb.arbiters.begin();
- while (ite != oarb.arbiters.end()) {
- var arb = ite.elem();
-
- //use first contact position as an aprox. to impact position for sound
- //not neccessary to be perfect for sound panning.
- var impact = arb.impactImpulse();
-
- pan += -1 + 2 * arb.contacts.front().px / 800;
- var cvol = Math.sqrt(impact.px * impact.px + impact.py * impact.py) * 2e-6;
- if (cvol > vol) vol = cvol;
- cnt++;
-
- ite = ite.next;
- }
- }
- }
-
- //sound is only played if it's volume is not tiny.
- // and either it is significantly louder than previously played sound
- // or sufficient time has passed since the previous sound was played (5 frames)
- //this helps de-clutter the sound and makes it not just sound horrible.
- if (vol > 0.01 && (space.stamp - psound > 5 || vol>pvol+0.15)) {
- psound = space.stamp;
- pvol = vol;
-
- soundt.volume = vol;
- soundt.pan = pan / cnt;
- bangs[cbang++].play(150, 0, soundt);
- }
- cbang %= 32;
- }
- }
-
- //dummy Bang class to link against the Bang sound in library swf.
- class Bang extends Sound { public function new() { super(); } }