curveTo() massive fps drop

15 posts

Flag Post

One of the enemies in my game enters the screen and stretches back, then flings itself forward. It’s kind of like a self slingshot. When I implemented this, I used curveTo to draw the parabola. However, when there are many of these enemies on the screen, there is a HUGE fps drop. How can I make this code more efficient to keep the fps up?


package  
{
	import flash.display.Bitmap;
	import flash.events.Event;
	import org.flintparticles.twoD.renderers.DisplayObjectRenderer;
	
	/**
	 * Slow moving unit that, upon reaching the platform, flings itself across
	 * extremely rapidly. It is the second enemy encountered in the game.
	 */
	public class Bola extends EnemyShape 
	{
		private var controlSpeed:Number;
		private var control:Number;
		
		/**
		 * Constructs a new bola.
		 */
                public function Bola()
		{
			moveSpeed = 30;
			
			controlSpeed = 0;
			control = 0;
			
			this.graphics.lineStyle(3, 0xFFCC00);
			this.graphics.moveTo(-16, 0);
			this.graphics.curveTo(8, 0, 16, 0);
		}
		
		public override function Update(elapsedTime:Number):void
		{
			if (controlSpeed > 0 && moveSpeed > 0 && moveSpeed < 500) 
			{
				moveSpeed -= 5;
			}
			
			if (control > 120) 
			{
				controlSpeed = -1024;
			}
			else if (control < -32)
			{
				moveSpeed = 600;
			}
			
			control += controlSpeed * elapsedTime;
			
			this.graphics.clear();
			this.graphics.lineStyle(3, 0xFFCC00);
			this.graphics.moveTo(-16, 0);
			this.graphics.curveTo(8, control, 16, 0);
			
			super.Update(elapsedTime);
		}
		
		public function BeginFling():void
		{
			controlSpeed = 180;
		}
	}
}

Edit: Sorry, I know a lot of these functions are abstract, but BeginFling is called when the enemy moves far enough into the map, and the unit is moved using the current moveSpeed in the superclass.

 
Flag Post

curveTo isn’t the issue; clearing and redrawing all the time is what causes the fps drop.
Instead of redrawing the shape at its new position, simply draw it once on the constructor and then update its x and y values.

 
Flag Post

Well unless there’s a way to update the curve control point then I don’t see how I could do that, that’s the reason I have to redraw

 
Flag Post

Oh, my bad, got it all wrong.
THe only think I can think of is to cache (with bitmapdata) all the possible graphics for the curve and update the bitmap from there.

 
Flag Post

So… basically an animation? Is it possible to use tweening to do this faster? I’m not too familiar with tweening yet.

 
Flag Post

I mean something like the following:
At the beginning of the game create a BitmapData big enough to hold the graphics for all the possible curve values, then simply run the Update method for every value that you will use during the game and draw it to the bitmapdata. Once the actual level starts, you’ll simply pass a reference to that bd (or clone it, depending on what suits you better) to the instance of Bola, which will use it to display the current curve animation via copyPixels instead of the heavy clear/draw thing.

Pseudocode:

// before the level
bd=new bitmapdata
while(coveringAllCurveValues){
   bola.drawNextCurve()
   bd.draw(bola,nextAvailableSpace())
}
// Bola
function Update(...){
   //   control and speed logic...
    ...
   data.copyPixels(curvesData,currentControlRect...)
}
 
Flag Post

This is all good, but I seem to have this problem even when I have a display object based on png images. The fps only drops when I have many of the units on the screen. Is this because there are too many displayobjects on the screen? If so is there a more efficient drawing method I can use for drawing many objects?

 
Flag Post
is there a more efficient drawing method I can use for drawing many objects?

Hard to tell with that little information. Rendering is heavy, yes, but there are a ton of things that can also cause bad performance. Run some tests to see what’ causing it. You can use tools like Scout to make it easier to find the issue. You can also post the relevant parts of your frame/timer handler so we can give you hints about what could be causing the performance issues.

is there a more efficient drawing method I can use for drawing many objects?

Yes; the answer is the same: blitting.
Basically, instead of having a ton of display objects, you would have a single bitmap, then at every rendering step you’d clear it and redraw its contents using the copyPixels method.

 
Flag Post

Well, I haven’t been able to figure out what’s causing the fps drop. I can’t run tests because I’m using FlashDevelop and I think you need Builder to use Scout. Here is the update function for my World class which updates units and manages collision. I use CDK Collision Detection kit because I need pixel perfect collision.


public function Update(elapsedTime:Number):void
		{
			currentTime += elapsedTime;
			
			if (worldState == STATE_MAIN)
			{
				if (!bossRound) 
				{
					// spawn any units if its time
					if (spawnQueue != null)
					{
						// if there are spawns left then spawn
						if (spawnQueue.length > 0)
						{
							ProcessSpawnQueue(currentTime);
						} 
						// otherwise check if the round is over (all units have gone)
						else if (localPlayer.Hero.Active && 
							collisionGroup.numChildren <= 1)
						{
							// and end the round
							Game(parent).dispatchEvent(new StateEvent(
								StateEvent.ON_ENDROUND));
						}
					}
				}
				else
				{
					
				}
				
				// get the collisions
				var collisions:Array = collisionGroup.checkCollisions();
				
				// process the collisions
				for (var i:uint = 0, j:uint = collisions.length; i < j; i++)
				{
					var collision:Object = collisions[i];
					var obj1:Unit = collision.object1;
					var obj2:Unit = collision.object2;
                    
					if (obj1 is PlayerWidget) obj1.Kill();
					else if (obj2 is PlayerWidget) obj2.Kill();
				}
				
				// update the collision group
				for each(var unit:Unit in unitList)
				{
					if (unit.Active) unit.Update(elapsedTime);
					
					var radius:Number = unit.width / 2;
					
					for each(var rect:Rectangle in rectList) 
					{
						// check if unit has entered rectangle
						if (!CircleRectangleCollide(new Point(unit.PrevX,
							unit.PrevY), radius, rect) &&
							CircleRectangleCollide(new Point(unit.x, unit.y),
							radius, rect))
						{
							dispatchEvent(new RectEvent(RectEvent.ON_ENTER,
								rect, unit));
						}
						// check if unit has left rectangle threshold
						else if (RectangleContainsCircle(new Point(unit.PrevX,
							unit.PrevY), radius, rect) &&
							!RectangleContainsCircle(new Point(unit.x, unit.y),
							radius, rect))
						{
							dispatchEvent(new RectEvent(
								RectEvent.ON_LEAVETHRESHOLD, rect, unit));
						}
						// check if unit has completely left rectangle
						else if (CircleRectangleCollide(new Point(unit.PrevX,
							unit.PrevY), radius, rect) &&
							!CircleRectangleCollide(new Point(unit.x, unit.y),
							radius, rect))
						{
							dispatchEvent(new RectEvent(RectEvent.ON_LEAVE,
								rect, unit));
						}
					}
				}
			}
		}

 
Flag Post

Is your collision detection particularly strenuous?

 
Flag Post

I’m curious about that too. If you disable collisions (for instance by replacing

				// get the collisions
				var collisions:Array = collisionGroup.checkCollisions();

with

				// get the collisions
				// var collisions:Array = collisionGroup.checkCollisions();
				var collisions:Array = new Array();

or something else along those lines that will compile) does it still lag?

 
Flag Post

You can use Scout with anything; it profiles all Flash movies running. There are alternatives, like FD’s built-in profiler and TheMiner, although they won’t give you as much data as Scout does.
That said, you can always run your own tests using getTimer()


+1 to collisions. Besides the one mentioned by Ace, you may want to check the whole rects and circles part.
Also, depending on how many units and rects you have, storing the values of its properties (PrevX, PrevY) may earn you a couple ms.

And again, depending on how many times that unit/rect loop iterates, you may want to replace the function calls for the function logic itself (kind of what Ace already suggested). It may look uglier, but it’s a sacrifice you must make when dealing with performance issues.

Another thing: instead of creating new Points all the time, you should create a constant one before running the conditionals.

 
Flag Post

Well, disabling collision seems to have pretty much eliminated the fps drops, but I’m not sure if I want to lose the pixel perfect collision…

 
Flag Post

Post the relevant collisions code.
The point isn’t to remove it, but to improve it.

 
Flag Post
Well, the pixel perfect collision is the CDK Collision Detection Kit, I mean it's not my code but here it is:



/*

Licensed under the MIT License

Copyright (c) 2008 Corey O'Neil
www.coreyoneil.com

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.coreyoneil.collision
{
import flash.display.DisplayObject;
import flash.display.BitmapData;
import flash.text.TextField;
import flash.errors.EOFError;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.geom.Matrix;
import flash.geom.ColorTransform;
import flash.utils.ByteArray;
import flash.utils.getQualifiedClassName;

public class CDK
{
protected var objectArray :Array;
protected var objectCheckArray :Array;
protected var objectCollisionArray :Array;
private var colorExclusionArray :Array;

private var bmd1 :BitmapData;
private var bmd2 :BitmapData;
private var bmdResample :BitmapData;

private var pixels1 :ByteArray;
private var pixels2 :ByteArray;

private var rect1 :Rectangle;
private var rect2 :Rectangle;

private var transMatrix1 :Matrix;
private var transMatrix2 :Matrix;

private var colorTransform1 :ColorTransform;
private var colorTransform2 :ColorTransform;

private var item1Registration :Point;
private var item2Registration :Point;

private var _alphaThreshold :Number;
private var _returnAngle :Boolean;
private var _returnAngleType :String;

private var _numChildren :uint;

public function CDK():void
{
if(getQualifiedClassName(this) == "com.coreyoneil.collision::CDK")
{
throw new Error('CDK is an abstract class and is not meant for instantiation - use CollisionGroup or CollisionList');
}

init();
}

private function init():void
{
objectCheckArray = [];
objectCollisionArray = [];
objectArray = [];
colorExclusionArray = [];

_alphaThreshold = 0;
_returnAngle = true;
_returnAngleType = "RADIANS";
}

public function addItem(obj):void
{
if(obj is DisplayObject)
{
objectArray.push(obj);
}
else
{
throw new Error("Cannot add item: " + obj + " - item must be a Display Object.");
}
}

public function removeItem(obj):void
{
var loc:int = objectArray.indexOf(obj);
if(loc > -1)
{
objectArray.splice(loc, 1);
}
else
{
throw new Error(obj + " could not be removed - object not found in item list.");
}
}

public function excludeColor(theColor:uint, alphaRange:uint = 255, redRange:uint = 20, greenRange:uint = 20, blueRange:uint = 20):void
{
var numColors:int = colorExclusionArray.length;
for(var i:uint = 0; i < numColors; i++)
{
if(colorExclusionArray[i].color == theColor)
{
throw new Error("Color could not be added - color already in the exclusion list [" + theColor + "]");
break;
}
}

var aPlus:uint, aMinus:uint, rPlus:uint, rMinus:uint, gPlus:uint, gMinus:uint, bPlus:uint, bMinus:uint;

aPlus = (theColor >> 24 & 0xFF) + alphaRange;
aMinus = aPlus - (alphaRange << 1);
rPlus = (theColor >> 16 & 0xFF) + redRange;
rMinus = rPlus - (redRange << 1);
gPlus = (theColor >> 8 & 0xFF) + greenRange;
gMinus = gPlus - (greenRange << 1);
bPlus = (theColor & 0xFF) + blueRange;
bMinus = bPlus - (blueRange << 1);

var colorExclusion:Object = {color:theColor, aPlus:aPlus, aMinus:aMinus, rPlus:rPlus, rMinus:rMinus, gPlus:gPlus, gMinus:gMinus, bPlus:bPlus, bMinus:bMinus};
colorExclusionArray.push(colorExclusion);
}

public function removeExcludeColor(theColor:uint):void
{
var found:Boolean = false, numColors:int = colorExclusionArray.length;
for(var i:uint = 0; i < numColors; i++)
{
if(colorExclusionArray[i].color == theColor)
{
colorExclusionArray.splice(i, 1);
found = true;
break;
}
}

if(!found)
{
throw new Error("Color could not be removed - color not found in exclusion list [" + theColor + "]");
}
}

protected function clearArrays():void
{
objectCheckArray = [];
objectCollisionArray = [];
}

protected function findCollisions(item1, item2):void
{
var item1_isText:Boolean = false, item2_isText:Boolean = false;
var item1xDiff:Number, item1yDiff:Number;

if(item1 is TextField)
{
item1_isText = (item1.antiAliasType == "advanced") ? true : false;
item1.antiAliasType = (item1.antiAliasType == "advanced") ? "normal" : item1.antiAliasType;
}

if(item2 is TextField)
{
item2_isText = (item2.antiAliasType == "advanced") ? true : false;
item2.antiAliasType = (item2.antiAliasType == "advanced") ? "normal" : item2.antiAliasType;
}

colorTransform1 = item1.transform.colorTransform;
colorTransform2 = item2.transform.colorTransform;

item1Registration = new Point();
item2Registration = new Point();

item1Registration = item1.localToGlobal(item1Registration);
item2Registration = item2.localToGlobal(item2Registration);

bmd1 = new BitmapData(item1.width, item1.height, true, 0x00FFFFFF);
bmd2 = new BitmapData(item1.width, item1.height, true, 0x00FFFFFF);

transMatrix1 = item1.transform.matrix;

var currentObj = item1;
while(currentObj.parent != null)
{
transMatrix1.concat(currentObj.parent.transform.matrix);
currentObj = currentObj.parent;
}

rect1 = item1.getBounds(currentObj);
if(item1 != currentObj)
{
rect1.x += currentObj.x;
rect1.y += currentObj.y;
}

transMatrix1.tx = item1xDiff = (item1Registration.x - rect1.left);
transMatrix1.ty = item1yDiff = (item1Registration.y - rect1.top);

transMatrix2 = item2.transform.matrix;

currentObj = item2;
while(currentObj.parent != null)
{
transMatrix2.concat(currentObj.parent.transform.matrix);
currentObj = currentObj.parent;
}

transMatrix2.tx = (item2Registration.x - rect1.left);
transMatrix2.ty = (item2Registration.y - rect1.top);

bmd1.draw(item1, transMatrix1, colorTransform1, null, null, true);
bmd2.draw(item2, transMatrix2, colorTransform2, null, null, true);

pixels1 = bmd1.getPixels(new Rectangle(0, 0, bmd1.width, bmd1.height));
pixels2 = bmd2.getPixels(new Rectangle(0, 0, bmd1.width, bmd1.height));

var k:uint = 0, value1:uint = 0, value2:uint = 0, collisionPoint:Number = -1, overlap:Boolean = false, overlapping:Array = [];
var locY:Number, locX:Number, locStage:Point, hasColors:int = colorExclusionArray.length;

pixels1.position = 0;
pixels2.position = 0;

var pixelLength:int = pixels1.length;
while(k < pixelLength)
{
k = pixels1.position;

try
{
value1 = pixels1.readUnsignedInt();
value2 = pixels2.readUnsignedInt();
}
catch(e:EOFError)
{
break;
}

var alpha1:uint = value1 >> 24 & 0xFF, alpha2:uint = value2 >> 24 & 0xFF;

if(alpha1 > _alphaThreshold && alpha2 > _alphaThreshold)
{
var colorFlag:Boolean = false;
if(hasColors)
{
var red1:uint = value1 >> 16 & 0xFF, red2:uint = value2 >> 16 & 0xFF, green1:uint = value1 >> 8 & 0xFF, green2:uint = value2 >> 8 & 0xFF, blue1:uint = value1 & 0xFF, blue2:uint = value2 & 0xFF;

var colorObj:Object, aPlus:uint, aMinus:uint, rPlus:uint, rMinus:uint, gPlus:uint, gMinus:uint, bPlus:uint, bMinus:uint, item1Flags:uint, item2Flags:uint;

for(var n:uint = 0; n < hasColors; n++)
{
colorObj = Object(colorExclusionArray[n]);

item1Flags = 0;
item2Flags = 0;
if((blue1 >= colorObj.bMinus) && (blue1 <=>
{
item1Flags++;
}
if((blue2 >= colorObj.bMinus) && (blue2 <=>
{
item2Flags++;
}
if((green1 >= colorObj.gMinus) && (green1 <=>
{
item1Flags++;
}
if((green2 >= colorObj.gMinus) && (green2 <=>
{
item2Flags++;
}
if((red1 >= colorObj.rMinus) && (red1 <=>
{
item1Flags++;
}
if((red2 >= colorObj.rMinus) && (red2 <=>
{
item2Flags++;
}
if((alpha1 >= colorObj.aMinus) && (alpha1 <=>
{
item1Flags++;
}
if((alpha2 >= colorObj.aMinus) && (alpha2 <=>
{
item2Flags++;
}

if((item1Flags == 4) || (item2Flags == 4)) colorFlag = true;
}
}

if(!colorFlag)
{
overlap = true;

collisionPoint = k >> 2;

locY = collisionPoint / bmd1.width, locX = collisionPoint % bmd1.width;

locY -= item1yDiff;
locX -= item1xDiff;

locStage = item1.localToGlobal(new Point(locX, locY));
overlapping.push(locStage);
}
}
}

if(overlap)
{
var angle:Number = _returnAngle ? findAngle(item1, item2) : 0;
var recordedCollision:Object = {object1:item1, object2:item2, angle:angle, overlapping:overlapping}
objectCollisionArray.push(recordedCollision);
}

if(item1_isText) item1.antiAliasType = "advanced";

if(item2_isText) item2.antiAliasType = "advanced";

item1_isText = item2_isText = false;
}

private function findAngle(item1:DisplayObject, item2:DisplayObject):Number
{
var center:Point = new Point((item1.width >> 1), (item1.height >> 1));
var pixels:ByteArray = pixels2;
transMatrix2.tx += center.x;
transMatrix2.ty += center.y;
bmdResample = new BitmapData(item1.width << 1, item1.height << 1, true, 0x00FFFFFF);
bmdResample.draw(item2, transMatrix2, colorTransform2, null, null, true);
pixels = bmdResample.getPixels(new Rectangle(0, 0, bmdResample.width, bmdResample.height));

center.x = bmdResample.width >> 1;
center.y = bmdResample.height >> 1;

var columnHeight:uint = Math.round(bmdResample.height);
var rowWidth:uint = Math.round(bmdResample.width);

var pixel:uint, thisAlpha:uint, lastAlpha:int, edgeArray:Array = [], hasColors:int = colorExclusionArray.length;

for(var j:uint = 0; j < columnHeight; j++)
{
var k:uint = (j * rowWidth) << 2;
pixels.position = k;
lastAlpha = -1;
var upperLimit:int = ((j + 1) * rowWidth) << 2;
while(k < upperLimit)
{
k = pixels.position;

try
{
pixel = pixels.readUnsignedInt();
}
catch(e:EOFError)
{
break;
}


thisAlpha = pixel >> 24 & 0xFF;

if(lastAlpha == -1)
{
lastAlpha = thisAlpha;
}
else
{
if(thisAlpha > _alphaThreshold)
{
var colorFlag:Boolean = false;
if(hasColors)
{
var red1:uint = pixel >> 16 & 0xFF, green1:uint = pixel >> 8 & 0xFF, blue1:uint = pixel & 0xFF;

var colorObj:Object, a:uint, r:uint, g:uint, b:uint, item1Flags:uint;

for(var n:uint = 0; n < hasColors; n++)
{
colorObj = Object(colorExclusionArray[n]);

item1Flags = 0;
if((blue1 >= colorObj.bMinus) && (blue1 <=>
{
item1Flags++;
}
if((green1 >= colorObj.gMinus) && (green1 <=>
{
item1Flags++;
}
if((red1 >= colorObj.rMinus) && (red1 <=>
{
item1Flags++;
}
if((thisAlpha >= colorObj.aMinus) && (thisAlpha <=>
{
item1Flags++;
}
if(item1Flags == 4)
{
colorFlag = true;
}
}
}

if(!colorFlag) edgeArray.push(k >> 2);
}
}
}
}

var edgePoint:int, numEdges:int = edgeArray.length;
var slopeYAvg:Number = 0, slopeXAvg:Number = 0
for(j = 0; j < numEdges; j++)
{
edgePoint = int(edgeArray[j]);

slopeYAvg += center.y - (edgePoint / rowWidth);
slopeXAvg += (edgePoint % rowWidth) - center.x;
}

var average:Number = -Math.atan2(slopeYAvg, slopeXAvg);

average = _returnAngleType == "RADIANS" ? average : average * 57.2957795;

return average;
}

public function dispose():void
{
objectArray = [];
}

public function set alphaThreshold(theAlpha:Number):void
{
if((theAlpha <=>= 0))
{
_alphaThreshold = theAlpha * 255;
}
else
{
throw new Error("alphaThreshold expects a value from 0 to 1");
}
}

public function get alphaThreshold():Number
{
return _alphaThreshold;
}

public function get returnAngle():Boolean
{
return _returnAngle;
}

public function set returnAngle(value:Boolean):void
{
_returnAngle = value;
}

public function set returnAngleType(returnType:String):void
{
returnType = returnType.toUpperCase();

switch (returnType)
{
case "DEGREES" :
case "DEGREE" :
case "DEG" :
case "DEGS" :
_returnAngleType = "DEGREES";
break;
case "RADIANS" :
case "RADIAN" :
case "RAD" :
case "RADS" :
_returnAngleType = "RADIANS";
break;
default :
throw new Error("returnAngleType expects 'DEGREES' or 'RADIANS'");
break;
}
}

public function get returnAngleType():String
{
return _returnAngleType;
}

public function getChildAt(index:uint):Object
{
return objectArray[index];
}

public function get numChildren():uint
{
return objectArray.length;
}
}
}







/*

Licensed under the MIT License

Copyright (c) 2008 Corey O'Neil
www.coreyoneil.com

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.coreyoneil.collision
{
import flash.display.DisplayObject;

public class CollisionGroup extends CDK
{
public function CollisionGroup(... objs):void
{
for(var i:uint = 0; i < objs.length; i++)
{
addItem(objs[i]);
}
}

public function checkCollisions():Array
{
clearArrays();

var NUM_OBJS:uint = objectArray.length, item1:DisplayObject, item2:DisplayObject;
for(var i:uint = 0; i < NUM_OBJS - 1; i++)
{
item1 = DisplayObject(objectArray[i]);

for(var j:uint = i + 1; j < NUM_OBJS; j++)
{
item2 = DisplayObject(objectArray[j]);

if(item1.hitTestObject(item2))
{
if((item2.width * item2.height) > (item1.width * item1.height))
{
objectCheckArray.push([item1,item2])
}
else
{
objectCheckArray.push([item2,item1]);
}
}
}
}

NUM_OBJS = objectCheckArray.length;
for(i = 0; i < NUM_OBJS; i++)
{
findCollisions(DisplayObject(objectCheckArray[i][0]), DisplayObject(objectCheckArray[i][1]));
}

return objectCollisionArray;
}
}
}