|
package ; |
|
|
|
import flash.display.Sprite; |
|
import flash.events.Event; |
|
import flash.Lib; |
|
import haxe.Timer; |
|
import openfl.events.KeyboardEvent; |
|
import openfl.events.MouseEvent; |
|
import openfl.text.TextField; |
|
import openfl.text.TextFormat; |
|
import openfl.ui.Keyboard; |
|
|
|
/** |
|
* ... |
|
* @author Kenton Hamaluik |
|
*/ |
|
|
|
class Main extends Sprite |
|
{ |
|
var inited:Bool; |
|
var drawContainer:Sprite = new Sprite(); |
|
|
|
var v100Text:TextField; |
|
var v500Text:TextField; |
|
var v1000Text:TextField; |
|
var v10000Text:TextField; |
|
|
|
var boxA:AABB; |
|
var boxB:AABB; |
|
|
|
var lastTime:Float = 0; |
|
|
|
/* ENTRY POINT */ |
|
|
|
function resize(e) |
|
{ |
|
if (!inited) init(); |
|
// else (resize or orientation change) |
|
} |
|
|
|
var spr:Sprite = new Sprite(); |
|
|
|
function init() |
|
{ |
|
if (inited) return; |
|
inited = true; |
|
|
|
this.addChild(drawContainer); |
|
|
|
// initialize the boxes |
|
boxA = new AABB(new Vector(stage.stageWidth / 2, 0), new Vector(10, 10), new Vector(0, 100), new Vector(0, 1000)); |
|
boxB = new AABB(new Vector(stage.stageWidth / 2, 450), new Vector(stage.stageWidth / 2 - 50, 25), new Vector(0, 0)); |
|
|
|
// draw text to let things reset |
|
v100Text = new TextField(); |
|
v100Text.defaultTextFormat = new TextFormat(null, 12, 0xffffff); |
|
v100Text.embedFonts = false; |
|
v100Text.text = "Reset, v = 100"; |
|
v100Text.x = 10; |
|
v100Text.y = 10; |
|
v100Text.mouseEnabled = false; |
|
v100Text.width = v100Text.textWidth + 5; |
|
v100Text.height = v100Text.textHeight + 5; |
|
v100Text.background = true; |
|
v100Text.backgroundColor = 0x555555; |
|
drawContainer.addChild(v100Text); |
|
|
|
v500Text = new TextField(); |
|
v500Text.defaultTextFormat = new TextFormat(null, 12, 0xffffff); |
|
v500Text.embedFonts = false; |
|
v500Text.text = "Reset, v = 500"; |
|
v500Text.x = 10; |
|
v500Text.y = 20 + v500Text.textHeight; |
|
v500Text.mouseEnabled = false; |
|
v500Text.width = v500Text.textWidth + 5; |
|
v500Text.height = v500Text.textHeight + 5; |
|
v500Text.background = true; |
|
v500Text.backgroundColor = 0x555555; |
|
drawContainer.addChild(v500Text); |
|
|
|
v1000Text = new TextField(); |
|
v1000Text.defaultTextFormat = new TextFormat(null, 12, 0xffffff); |
|
v1000Text.embedFonts = false; |
|
v1000Text.text = "Reset, v = 1000"; |
|
v1000Text.x = 10; |
|
v1000Text.y = 30 + v100Text.textHeight + v500Text.textHeight; |
|
v1000Text.mouseEnabled = false; |
|
v1000Text.width = v1000Text.textWidth + 5; |
|
v1000Text.height = v1000Text.textHeight + 5; |
|
v1000Text.background = true; |
|
v1000Text.backgroundColor = 0x555555; |
|
drawContainer.addChild(v1000Text); |
|
|
|
v10000Text = new TextField(); |
|
v10000Text.defaultTextFormat = new TextFormat(null, 12, 0xffffff); |
|
v10000Text.embedFonts = false; |
|
v10000Text.text = "Reset, v = 10000"; |
|
v10000Text.x = 10; |
|
v10000Text.y = 40 + v100Text.textHeight + v500Text.textHeight + v1000Text.textHeight; |
|
v10000Text.mouseEnabled = false; |
|
v10000Text.width = v10000Text.textWidth + 5; |
|
v10000Text.height = v10000Text.textHeight + 5; |
|
v10000Text.background = true; |
|
v10000Text.backgroundColor = 0x555555; |
|
drawContainer.addChild(v10000Text); |
|
|
|
// add event listeners and begin! |
|
stage.addEventListener(Event.ENTER_FRAME, onFrame); |
|
stage.addEventListener(MouseEvent.CLICK, onClick); |
|
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed); |
|
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyReleased); |
|
lastTime = Timer.stamp(); |
|
} |
|
|
|
private inline function ptInTextField(p:Vector, textField:TextField):Bool |
|
{ |
|
return (p.x >= textField.x && p.x <= textField.x + textField.width && p.y >= textField.y && p.y <= textField.y + textField.height); |
|
} |
|
|
|
private var rightDown:Bool = false; |
|
private var leftDown:Bool = false; |
|
function onKeyPressed(event:KeyboardEvent):Void |
|
{ |
|
if (event.keyCode == Keyboard.W) |
|
{ |
|
boxA.velocity.y = -400; |
|
boxA.center.y -= 1; |
|
} |
|
else if (event.keyCode == Keyboard.A) |
|
{ |
|
leftDown = true; |
|
} |
|
else if (event.keyCode == Keyboard.D) |
|
{ |
|
rightDown = true; |
|
} |
|
} |
|
function onKeyReleased(event:KeyboardEvent):Void |
|
{ |
|
if (event.keyCode == Keyboard.A) |
|
{ |
|
leftDown = false; |
|
} |
|
else if (event.keyCode == Keyboard.D) |
|
{ |
|
rightDown = false; |
|
} |
|
} |
|
|
|
function onClick(event:MouseEvent):Void |
|
{ |
|
if (ptInTextField(new Vector(event.stageX, event.stageY), v100Text)) |
|
{ |
|
boxA.center = new Vector(stage.stageWidth / 2, 0); |
|
boxA.velocity = new Vector(0, 100); |
|
boxB.center = new Vector(stage.stageWidth / 2, 450); |
|
boxB.velocity = new Vector(0, 0); |
|
} |
|
else if (ptInTextField(new Vector(event.stageX, event.stageY), v500Text)) |
|
{ |
|
boxA.center = new Vector(stage.stageWidth / 2, 0); |
|
boxA.velocity = new Vector(0, 500); |
|
boxB.center = new Vector(stage.stageWidth / 2, 450); |
|
boxB.velocity = new Vector(0, 0); |
|
} |
|
else if (ptInTextField(new Vector(event.stageX, event.stageY), v1000Text)) |
|
{ |
|
boxA.center = new Vector(stage.stageWidth / 2, 0); |
|
boxA.velocity = new Vector(0, 1000); |
|
boxB.center = new Vector(stage.stageWidth / 2, 450); |
|
boxB.velocity = new Vector(0, 0); |
|
} |
|
else if (ptInTextField(new Vector(event.stageX, event.stageY), v10000Text)) |
|
{ |
|
boxA.center = new Vector(stage.stageWidth / 2, 0); |
|
boxA.velocity = new Vector(0, 10000); |
|
boxB.center = new Vector(stage.stageWidth / 2, 450); |
|
boxB.velocity = new Vector(0, 0); |
|
} |
|
} |
|
|
|
function onFrame(event:Event):Void |
|
{ |
|
var t:Float = Timer.stamp(); |
|
var dt:Float = t - lastTime; |
|
lastTime = t; |
|
|
|
// deal with side-to-side motion |
|
var moveV:Float = 100; |
|
if (rightDown && !leftDown) |
|
boxA.velocity.x = moveV; |
|
else if (!rightDown && leftDown) |
|
boxA.velocity.x = -moveV; |
|
else |
|
boxA.velocity.x = 0; |
|
|
|
// deal with acceleration |
|
boxA.velocity += boxA.acceleration * dt; |
|
boxB.velocity += boxB.acceleration * dt; |
|
|
|
// construct the relative velocity ray |
|
var rvRayColour:Int = 0xff0000; |
|
var rvRay:Vector = (boxA.velocity - boxB.velocity) * dt; |
|
|
|
// see if there is already a collision |
|
var boxAColour:Int = 0xff0000; |
|
var rvRayIntersection:Vector = null; |
|
var md:AABB = boxB.minkowskiDifference(boxA); |
|
var penetrationVector:Vector = null; |
|
var doMove:Bool = true; |
|
if (md.min.x <= 0 && |
|
md.max.x >= 0 && |
|
md.min.y <= 0 && |
|
md.max.y >= 0) |
|
{ |
|
// collision is occurring! |
|
boxAColour = 0x00ff00; |
|
|
|
// find the penetration depth |
|
penetrationVector = md.closestPointOnBoundsToPoint(Vector.zero); |
|
|
|
// offset the box to make sure it's not penetrating |
|
boxA.center += penetrationVector; |
|
|
|
// zero out the box's velocity in the direction of the penetration |
|
if (!penetrationVector.isZero()) |
|
{ |
|
// zero the velocity in the normal direction |
|
var tangent:Vector = penetrationVector.normalized.tangent; |
|
boxA.velocity = Vector.dotProduct(boxA.velocity, tangent) * tangent; |
|
boxB.velocity = Vector.dotProduct(boxB.velocity, tangent) * tangent; |
|
} |
|
} |
|
else |
|
{ |
|
// see if there WILL be a collision |
|
var intersectFraction:Float = md.getRayIntersectionFraction(Vector.zero, rvRay); |
|
if (intersectFraction < Math.POSITIVE_INFINITY) |
|
{ |
|
// yup, there WILL be a collision this frame |
|
rvRayColour = 0x00ff00; |
|
rvRayIntersection = rvRay * intersectFraction; |
|
|
|
// move the boxes appropriately |
|
boxA.center += boxA.velocity * dt * intersectFraction; |
|
boxB.center += boxB.velocity * dt * intersectFraction; |
|
doMove = false; |
|
|
|
// zero out the normal of the collision |
|
var nrvRay:Vector = rvRay.normalized; |
|
var tangent:Vector = new Vector( -nrvRay.y, nrvRay.x); |
|
boxA.velocity = Vector.dotProduct(boxA.velocity, tangent) * tangent; |
|
boxB.velocity = Vector.dotProduct(boxB.velocity, tangent) * tangent; |
|
} |
|
} |
|
|
|
if (doMove) |
|
{ |
|
boxA.center += boxA.velocity * dt; |
|
boxB.center += boxB.velocity * dt; |
|
} |
|
|
|
// clear the graphics |
|
drawContainer.graphics.clear(); |
|
|
|
// draw the origin point |
|
drawContainer.graphics.beginFill(0xffffff); |
|
drawContainer.graphics.drawCircle(stage.stageWidth / 2, stage.stageHeight / 2, 2); |
|
drawContainer.graphics.endFill(); |
|
|
|
// draw the md box (moved to the fake origin) |
|
var origin:Vector = new Vector(stage.stageWidth / 2, stage.stageHeight / 2); |
|
md.center += origin; |
|
md.draw(drawContainer, 0x0000ff); |
|
|
|
// draw the intersection point |
|
if (rvRayIntersection != null) |
|
{ |
|
drawContainer.graphics.beginFill(0xff00ff); |
|
rvRayIntersection += origin; |
|
drawContainer.graphics.drawCircle(rvRayIntersection.x, rvRayIntersection.y, 2); |
|
drawContainer.graphics.endFill(); |
|
} |
|
|
|
// draw the actual boxes |
|
boxB.draw(drawContainer); |
|
boxA.draw(drawContainer, boxAColour); |
|
|
|
// draw the relative velocity ray |
|
rvRay.draw(drawContainer, origin, rvRayColour); |
|
} |
|
|
|
/* SETUP */ |
|
|
|
public function new() |
|
{ |
|
super(); |
|
addEventListener(Event.ADDED_TO_STAGE, added); |
|
} |
|
|
|
function added(e) |
|
{ |
|
removeEventListener(Event.ADDED_TO_STAGE, added); |
|
stage.addEventListener(Event.RESIZE, resize); |
|
#if ios |
|
haxe.Timer.delay(init, 100); // iOS 6 |
|
#else |
|
init(); |
|
#end |
|
} |
|
|
|
public static function main() |
|
{ |
|
// static entry point |
|
Lib.current.stage.align = flash.display.StageAlign.TOP_LEFT; |
|
Lib.current.stage.scaleMode = flash.display.StageScaleMode.NO_SCALE; |
|
Lib.current.addChild(new Main()); |
|
} |
|
} |