/**
* Copyright omgnoseat ( http://wonderfl.net/user/omgnoseat )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/bO6Y
*/
package
{
import flash.display.MovieClip;
[SWF(frameRate=60, width=800, height=600)]
public class CollisionMain extends MovieClip
{
var test:CollisionTest;
public function CollisionMain()
{
init();
}
private function init():void
{
test = new CollisionTest();
addChild(test);
var mousecoord:MouseCoord = new MouseCoord();
addChild(mousecoord);
}
}
}
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Rectangle;
import net.hires.debug.Stats;
/**
* ...
* @author Martino Wullems
*/
class CollisionTest extends MovieClip
{
public static var shape:Shape; //for drawing debug stuff on
public static var holder:Sprite;
var world:TestWorld;
public function CollisionTest()
{
holder = new Sprite();
addChild(holder);
shape = new Shape();
addChild(shape);
addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
SetupWorld();
//addChild(new Stats());
}
private function SetupWorld():void
{
world = new TestWorld();
addChild(world);
addObjects(1);
}
private function addObjects(amount:int):void
{
for (var i:int = 0; i < amount; ++i) {
var square:Square = new Square(14);
//square.x = Math.random() * stage.stageWidth;
//square.y = Math.random() * stage.stageHeight;
square.x = 5;
square.y = 230;
square.vx = (Math.random() * 2) + 1;
square.vy = (Math.random() * 2) + 1;
square.hitBounds = new Rectangle(5, 230, 14, 14);
world.addObject(square);
}
}
}
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
/**
* ...
* @author Martino Wullems
*/
class TestWorld extends MovieClip
{
public var objects:Array;
public var collisionMethod:String;
var quadtree:QuadTree;
public function TestWorld()
{
collisionMethod = CollisionMethod.QUADTREE;
addEventListener(Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
initWorld();
}
private function initWorld():void
{
objects = new Array();
quadtree = new QuadTree(stage.stageWidth, stage.stageHeight);
addChild(quadtree);
quadtreeDebugDraw();
addEventListener(Event.ENTER_FRAME, loopWorld);
}
private function quadtreeDebugDraw():void
{
}
private function loopWorld(e:Event):void
{
for (var i:int = 0; i < objects.length; i++) {
objects[i].isHit = false;
//MoveObject(objects[i]);
//CheckCollision(i);// doesn't work here for some reason [case 1]
}
switch(collisionMethod) {
case "REGULAR":
CheckCollision(0); //[case 2]
break;
case "QUADTREE":
CheckQuadTreeCollision();
break;
}
}
private function CheckQuadTreeCollision():void
{
for (var i:int = 0; i < objects.length; i++) {
var object:* = objects[i];
if(object.currentNode != null){
//object.nodeDraw();
}
//check collision for every object in the objects node
//for (var j:int = 0; j < object.currentNode.objects.length; j ++) {
//}
}
}
private function CheckCollision(i:int):void
{
//test collision
for (var i:int = 0; i < objects.length; i++){ //only use in case 2
var elementA:CollisionObject;
var elementB:CollisionObject;
elementA = objects[i];
for (var j:int = i + 1; j < objects.length; j++) {
if (j <= i){
continue; //j resets each I loop and therefor sets collision to false while it could be true [fixed with i + 1]
}
elementB = objects[ j ]// as ObjSprite;
if (elementA.hitTestObject(elementB)) {
elementA.isHit = elementB.isHit = true;
/////////////////
// CHECK X Y //
////////////////
/* if (elementA.x + elementA.width < elementB.x) {
} else if (elementA.x > elementB.x + elementB.width) {
// elementA.isHit = elementB.isHit = false;
} else if (elementA.y + elementA.height < elementB.y) {
// elementA.isHit = elementB.isHit = false;
} else if (elementA.y > elementB.y + elementB.height) {
// elementA.isHit = elementB.isHit = false;
} else {
elementA.isHit = elementB.isHit = true;
*/
}
}
} //[case 2]
}
private function MoveObject(object:CollisionObject):void
{
object.x += object.vx;
object.y += object.vy;
////////////////////
//check boundaries//
////////////////////
if (object.x > stage.stageWidth)
{
object.vx *= -1;
}else if (object.x < 0)
{
object.vx *= -1;
}else if (object.y > stage.stageHeight)
{
object.vy *= -1;
}else if (object.y < 0)
{
object.vy *= -1;
}
//object.isHit = false;// where do we check when it isn't colliding?
}
public function addObject(object:CollisionObject):void
{
objects.push(object);
addChild(object);
switch(collisionMethod) {
case "REGULAR":
//nothing special
break;
case "QUADTREE":
quadtree.addItem(object);
break;
}
}
}
import flash.display.Sprite;
import flash.events.Event;
/**
* ...
* @author Martino Wullems
*/
class QuadTree extends Sprite
{
public var Width:int;
public var Height:int;
public var topNode:Node;
public static var TopNode:Node;
public function QuadTree(WIDTH:int, HEIGHT:int)
{
Width = WIDTH;
Height = HEIGHT;
topNode = new Node(0, 0, WIDTH, HEIGHT, 5, NodeLabel.TOP); //make top node, generates 4 child nodes for each layer
topNode.Label = NodeLabel.TOP;
addChild(topNode);
TopNode = topNode;
}
public function addItem(item:*):void {
//topnode is entire screen!
topNode.addItem(item);
}
}
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
/**
* ...
* @author Martino Wullems
*
* contains 4 child nodes till final layer is reached.
* checks objects in furthest node agains each other
*/
class Node extends Sprite
{
public var Width:int;
public var Height:int;
public var Layer:int;
public var rootNode:Node;
public var parentNode:Node;
public var childNodes:Array;
public var objects:Array;
public var Label:String;
public var bounds:Rectangle;
public var nw:Node;
public var ne:Node;
public var sw:Node;
public var se:Node;
public function Node(X:int, Y:int, WIDTH:int, HEIGHT:int, LAYER:int, LABEL:String = null) //subspace
{
x = X;
y = Y;
Width = WIDTH;
Height = HEIGHT;
Layer = LAYER;
if (LABEL != null) { Label = LABEL };
objects = new Array();
bounds = new Rectangle(0, 0, Width, Height);
childNodes = new Array();
if (Layer > 1) {
generateChildNodes();
}
CollisionTest.shape = new Shape();
CollisionTest.shape.graphics.lineStyle(Layer, 0x000000, 0.1);
CollisionTest.shape.graphics.drawRect(X, Y, WIDTH,
HEIGHT);
CollisionTest.holder.addChild(CollisionTest.shape);
addEventListener(MouseEvent.CLICK, getNode);
}
private function getNode(e:MouseEvent):void
{
trace("[layer " + this.Layer + "] : " + this.Label + "x: " + this.x);
e.target.generateChildNodes();
trace("-----");
}
private function generateChildNodes():void
{
//trace("generating child nodes");
//trace("[layer " + this.Layer + "[" + this.Label + "]");
for (var i:int = 1; i < 5; i++) { //4 child nodes
var childNode:Node// = new Node(this.Width / 2, this.Height / 2, this.Layer - 1);
switch(i) {
case 1: //top left
nw = new Node(this.x, this.y, this.Width / 2, this.Height / 2, this.Layer - 1, NodeLabel.NW);
//node is placed in current node, so 0 isn't stage 0 - but parent 0;
nw.Label = NodeLabel.NW;
childNodes.push(nw);
addChild(nw);
break;
case 2: //top right
ne = new Node(this.x + (this.Width / 2), this.y, this.Width / 2, this.Height / 2,
this.Layer - 1, NodeLabel.NE);
ne.Label = NodeLabel.NE;
childNodes.push(ne);
addChild(ne);
break;
case 3: //down left
sw = new Node(this.x , this.y + (this.Height / 2 ), this.Width / 2,
this.Height / 2, this.Layer - 1, NodeLabel.SW);
//childNode.x = this.x;
//childNode.y = this.y + (this.Height / 2 )
sw.Label = NodeLabel.SW;
childNodes.push(sw);
addChild(sw);
break;
case 4:
se = new Node(this.x + (this.Width / 2), this.y + (this.Height / 2 ), this.Width / 2,
this.Height / 2, this.Layer - 1, NodeLabel.SE);
//childNode.x = this.x + (this.Width / 2);
//childNode.y = this.y + (this.Height / 2)
se.Label = NodeLabel.SE;
childNodes.push(se);
addChild(se);
break;
}
//childNodes.push(childNode);
//addChild(childNode);
//trace("creating node: [layer " + childNodes[childNodes.length].Layer + "][" + childNodes[childNodes.length].Label + "]");
}
}
public function addItem(item:*):void {
/*
* child nodes are counted x and y at zero again, not taking in account the location of the parent node !
* [layer 4][NE] node.x: 275
[layer 4][NE] node.y: 0
[layer 3][NW] node.x: 0 --> parent node is 275, so child should be at least 275 aswell !
*
*
* */
var foundNode:Node;
/*if(childNodes.length > 0 && this.Layer > 0){ //check if this isn't the bottom node
trace("##########################################");
trace("[layer " + this.Layer + "[" + this.Label + "]");
trace("########################################## \n");
for (var i:int = 0; i < childNodes.length; i++) {
//!go throgh each node to check if the item is in there!
//check in which part of the node the item is [contains rectangle function]
if (item.x >= childNodes[i].x && //left
item.x + item.width <= childNodes[i].x + (childNodes[i].x + childNodes[i].Width) && //right
item.y >= childNodes[i].y && //up
item.y + item.height <= childNodes[i].y + (childNodes[i].y + childNodes[i].Height) //down
){
if (item.currentNode == null) {
item.currentNode == this;
}
if (item.currentNode.Layer > childNodes[i].Layer && item.currentNode.Layer > 0) { //get best depth
//adds one layer deeper
//childNodes[i].objects.push(item);
addToNode(childNodes[i], item);
}
}else {
//this is best depth
trace("best depth is current node");
objects.push(item);
item.currentNode = this;
}
}
}*/
//////////////////////////////////
/////// NE, SE, SW, NW ///////////
//////////////////////////////////
//itemx - nodex seems to be lifted up 200px...
//last node always picks nw
if(this.Layer > 1){ //check if this isn't the bottom layer
/////////
// NE //
////////
trace("###############################");
trace("item.x: " + item.x);
trace("item.y: " + item.y);
if (item.x >= ne.x && //left
item.x + item.width <= ne.x + (ne.x + ne.Width) && //right
item.y >= ne.y && //up
item.y + item.height <= ne.y + (ne.y + ne.Height) //down
) {
addToNode(ne, item)
/////////
// NW //
////////
}else if (item.x >= nw.x && //left
item.x + item.width <= nw.x + (nw.x + nw.Width) && //right
item.y >= nw.y && //up
item.y + item.height <= (nw.y + (nw.y + nw.Height)) //down
) {
addToNode(nw, item)
/////////
// SW //
////////
}else if (item.x >= sw.x && //left
item.x + item.width <= sw.x + (sw.x + sw.Width) && //right
item.y >= sw.y && //up
item.y + item.height <= sw.y + (sw.y + sw.Height) //down
) {
addToNode(sw, item)
/////////
// SE //
////////
}else if (item.x >= se.x && //left
item.x + item.width <= se.x + (se.x + se.Width) && //right
item.y >= se.y && //up
item.y + item.height <= se.y + (se.y + se.Height) //down
) {
addToNode(se, item)
}
//doesn't fit in childnode, put in current node
else {
trace("doesn't fit anywhere");
addToNode(this, item);
this.addEventListener(MouseEvent.CLICK, clickNode);
}
////////////////////////////////////
///// C O N T A I N S R E C T /////
////////////////////////////////////
/*if (nw.bounds.containsRect(item.hitBounds)) {
addToNode(nw, item)
}else
if (ne.bounds.containsRect(item.hitBounds)) {
addToNode(ne, item)
}else
if (sw.bounds.containsRect(item.hitBounds)) {
addToNode(sw, item)
}else
if (se.bounds.containsRect(item.hitBounds)) {
addToNode(se, item)
}
else {
trace("doesn't fit anywhere");
item.currentNode = this;
objects.push(item); */
}
trace("item currentnode [layer " + item.currentNode.Layer + "][" + item.currentNode.Label + "]");
}
private function clickNode(e:MouseEvent):void
{
trace("node clicked: [" + this.Layer + "][ " + this.Label + "]");
}
private function addToNode(node:Node, item:*):void
{
trace("adding in layer: " + node.Layer + " [" + node.Label + "]");
trace("[layer " + node.Layer + "][" + node.Label + "] node.x: " + node.x +
" - " + (node.x + node.Width));
trace("[layer " + node.Layer + "][" + node.Label + "] node.y: " + node.y +
" - " + (node.y + node.Height));
objects.push(item);
item.currentNode = node;
item.nodeDraw();
node.addItem(item); //DO THIS LAST OR IT WILL BUG THE FUCK UP
}
public function itemMoved(item:*):void {
trace("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
trace("!!! R E C A L C U L A T E !!!!");
trace("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! \n\n");
QuadTree.TopNode.addItem(item);
}
}
/**
* ...
* @author Martino Wullems
*/
class CollisionMethod
{
public static const REGULAR:String = "REGULAR";
public static const QUADTREE:String = "QUADTREE";
}
/**
* ...
* @author Martino Wullems
*/
class NodeLabel
{
public static const TOP:String = "TOP";
public static const NW:String = "NW";
public static const NE:String = "NE";
public static const SW:String = "SW";
public static const SE:String = "SE";
}
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
/**
* ...
* @author Martino Wullems
*/
class CollisionObject extends Sprite
{
public var size:int;
public var vx:int = 0;
public var vy:int = 0;
public var graphic:Sprite;
public var hitGraphic:Sprite;
public var currentNode:Node;
public var hitBounds:Rectangle;
var sleeping:Boolean = false;
private var _isHit:Boolean;
public function CollisionObject()
{
addEventListener(MouseEvent.MOUSE_DOWN, grab);
addEventListener(MouseEvent.MOUSE_UP, letGo);
}
private function grab(e:MouseEvent):void
{
//trace("currentnode: [layer " + currentNode.Layer + "]");
startDrag();
vx = 0;
vy = 0;
}
private function letGo(e:MouseEvent):void
{
stopDrag();
currentNode.itemMoved(this);
}
public function Collision():void{
}
public function nodeDraw():void {
trace("drawwing node layer[ " + currentNode.Layer + "][" + currentNode.Label + "]");
CollisionTest.shape.graphics.clear();
CollisionTest.shape.graphics.lineStyle(0, 0x00FF00, .5);
//CollisionTest.shape.graphics.drawRect(currentNode.x, currentNode.y, currentNode.width,
//currentNode.bounds.height);
CollisionTest.shape.graphics.moveTo(currentNode.x, currentNode.y);
CollisionTest.shape.graphics.lineTo(currentNode.x + currentNode.Width, currentNode.y);
CollisionTest.shape.graphics.lineTo(currentNode.x + currentNode.Width, currentNode.y + currentNode.Height);
CollisionTest.shape.graphics.lineTo(currentNode.x, currentNode.y + currentNode.Height);
CollisionTest.shape.graphics.lineTo(currentNode.x, currentNode.y);
}
//////////////////////
// setter and getter//
//////////////////////
public function set isHit(value:Boolean):void {
_isHit = value;
graphic.visible = _isHit;
hitGraphic.visible = !_isHit;
}
public function get isHit():Boolean {
return _isHit;
}
}
import flash.display.Sprite;
import flash.geom.Rectangle;
/**
* ...
* @author Martino Wullems
*/
class Square extends CollisionObject
{
public function Square(Size:int)
{
size = Size;
drawSquare();
}
private function drawSquare():void
{
graphic = new Sprite();
graphic.graphics.beginFill(0xFF0000);
graphic.graphics.drawRect(0, 0, size, size);
graphic.graphics.endFill();
addChild(graphic);
hitGraphic = new Sprite();
hitGraphic.graphics.beginFill(0x0066FF);
hitGraphic.graphics.drawRect(0, 0, size, size);
hitGraphic.graphics.endFill();
addChild(hitGraphic);
//hitGraphic.visible = false;
hitBounds = new Rectangle(0, 0, size, size);
}
override public function Collision():void {
trace("I collided with a friend");
}
public function debugDraw():void {
if (isHit) {
graphic.visible = false;
hitGraphic.visible = true;
}else {
graphic.visible = true;
hitGraphic.visible = false;
}
}
}
/* M O U S E C O O R D */
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* ...
* @author Martino Wullems
*/
class MouseCoord extends MovieClip
{
public var coordtext:TextField;
public function MouseCoord()
{
addEventListener(Event.ADDED_TO_STAGE, onStage);
this.mouseEnabled = false;
this.mouseChildren = false;
}
private function onStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onStage);
coordtext = new TextField();
coordtext.defaultTextFormat = new TextFormat("Arial", 15, null, true);
addChild(coordtext);
stage.addEventListener(MouseEvent.MOUSE_MOVE, movemouse);
}
private function movemouse(e:MouseEvent):void
{
//this.x = stage.mouseX;
//this.y = stage.mouseY;
coordtext.htmlText = "X: " + stage.mouseX + "\nY: " + stage.mouseY;
}
}