package { import flash.display.DisplayObject; import flash.display.MovieClip; import flash.utils.Timer; import flash.events.TimerEvent; import flash.events.KeyboardEvent; import flash.geom.Transform; public class Man extends MovieClip { private var deltaX:Number = 0; private var deltaY:Number = 0; private var previousFrameContact:DisplayObject = null; private var accelerateGround:Number = 2; private var accelerateAir:Number = 0.2; private var brake:Number = 0.7; private var maxSpeed:Number = 4.5; private var gravity:Number = 0.4; private var jump:Number = -6.5; private var bounce:Number = -0.2; private var bounceSupplement:Number = -0.2; private var keys:Object = new Object(); public function Man():void { var timer:Timer = new Timer(1000 / 60, 0); timer.addEventListener(TimerEvent.TIMER, Process); timer.start(); stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown); stage.addEventListener(KeyboardEvent.KEY_UP, KeyUp); } private function KeyDown(event:KeyboardEvent):void { keys[event.keyCode] = true; switch (event.keyCode) { } } private function KeyUp(event:KeyboardEvent):void { keys[event.keyCode] = false; } private function Collide(t:Number, testObject:DisplayObject):DisplayObject { var foundOne:DisplayObject = null; var oldX:Number = x; var oldY:Number = y; x = x + deltaX * t; y = y + deltaY * t; for (var idx:int = 0; idx != parent.numChildren; idx++) { var obj:Object = parent.getChildAt(idx); if (obj != this && obj is DisplayObject) { var displayObject:DisplayObject = obj as DisplayObject; if (testObject == null || displayObject == testObject) { if (hitTestObject(displayObject)) { foundOne = displayObject; break; } } } } x = oldX; y = oldY; return foundOne; } private function Process(event:TimerEvent):void { var restingContact:DisplayObject = null; var steps:int = 4; // number of iterations to time slice interval // due to hit the same object we hit the previous frame? if (previousFrameContact != null) { restingContact = Collide(Math.pow(0.5, steps - 1), previousFrameContact); if (restingContact == previousFrameContact) { // in resting contact with object from previous frame // therefore, sliding over another object var preserveDeltaY:Number = deltaY; deltaY = 0; // nullify movement in direction of collision // will clear? if (Collide(Math.pow(0.5, steps - 1), previousFrameContact)) { deltaY = preserveDeltaY; // set back Y var preserveDeltaX:Number = deltaX; deltaX = 0; // nullify movement in direction of collision // will clear? if (Collide(Math.pow(0.5, steps - 1), previousFrameContact)) { deltaX = preserveDeltaX; // set back Y } else { deltaY *= brake; // friction } } else { deltaX *= brake; // friction } } } // range of time slice starts 0 -> 1 var tMin:Number = 0; // first time object is known to be airbourne var tMax:Number = 1; // last time object is known to collide (once collision is detected) // record of the first object we hit var newContact:DisplayObject; var t:Number = tMax; for (var count:int = 0; count != steps; count++) { newContact = Collide(t, null); if (newContact == null) { tMin = t; } else { restingContact = null; // considered a new contact tMax = t; } if (tMin == tMax) { break; } t = (tMin + tMax) / 2; } // actually progress object without bringing it into contact with other object x = x + deltaX * tMin; y = y + deltaY * tMin; // if new contact, apply bounce if (newContact != null && previousFrameContact == null) { deltaY = deltaY * bounce - bounceSupplement;// } // always apply gravity deltaY += gravity; // can jump if in slide contact if (keys[32] && restingContact != null) { // space, for jump deltaY = jump; } // can move if in slide contact, also influence movement airbourne if (keys[37]) { // left if (restingContact != null) { deltaX -= accelerateGround; } else { deltaX -= accelerateAir; } if (deltaX < -maxSpeed) { deltaX = -maxSpeed; } } if (keys[39]) { // right if (restingContact != null) { deltaX += accelerateGround; } else { deltaX += accelerateAir; } if (deltaX > maxSpeed) { deltaX = maxSpeed; } } // record contact for next frame // either newest contact or resting contact // or nothing. if (newContact != null) { previousFrameContact = newContact; } else { previousFrameContact = restingContact; } } } }