I have 100 movieclips of different sizes to randomly make a grid out of, how would I optimize this?
our client开发者_如何转开发 has tasked us(well, me alone..) to dynamicly generate grids with different size boxes. The grid should not have defined edges, but each movieclip should have a certain defined border. I'm pretty new to AS3 still, but can handle pretty much everything besides this sort of giant math problem.
Here's a simple layout of what I'm looking for on a much smaller scale: http://i.stack.imgur.com/Pnikm.png
Have any of you guys been able to effectively do this?
I can almost emulate this, but sometimes my boxes will overlap, and that's a dealbreaker. If I start hitTesting it works up until I try it with 55+ movieclips, then I fear that the script could freeze.
here's the code that works, but may freeze at times. How can I optimize this so that stack overflow errors can't happen?
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.utils.getDefinitionByName;
public class box_builder extends MovieClip
{
private var _path:MovieClip;
private var mc_holder:Sprite;
private var box_ar:Array;
private var box_spacing:int = 5;
private var mc_ar:Array = new Array();
private var placed_box_ar:Array = new Array();
private var p_step:int = 0;
public function box_builder()
{
_path = this;
mc_holder = new Sprite();
_path.addChild(mc_holder);
getBoxArray();
startBoxDistribution();
}
private function getBoxArray()
{
box_ar = new Array("box_1","box_2","box_3","box_4","box_3","box_3","box_1","box_2","box_4","box_1","box_1","box_2","box_3","box_4","box_3","box_3","box_1","box_2","box_4","box_1","box_1","box_2","box_3","box_4","box_3","box_3","box_1","box_2","box_4","box_1",
"box_1","box_2","box_3","box_4","box_3","box_3","box_1","box_2","box_4","box_1","box_1","box_2","box_3","box_4","box_3","box_3","box_1","box_2","box_4","box_1","box_1","box_2","box_3","box_4","box_3","box_3","box_1","box_2","box_4","box_1");
}
private function startBoxDistribution():void
{
var i = 0;
var len = box_ar.length;
createBoxes();
}
private function createBoxes():void
{
var len = box_ar.length;
for (var i=0; i<len; i++)
{
var tMC:Class = getDefinitionByName(box_ar[i]) as Class;
var newMc:MovieClip = new tMC() as MovieClip;
mc_ar.push(newMc);
mc_holder.addChild(newMc);
}
executeQueue();
}
private function executeQueue():void
{
if (p_step < box_ar.length)
{
var mc = mc_ar[p_step];
p_step++;
try{ findPlacement(mc); }
catch(e:Error){ trace("ERROR!",e) };
}
else centerAll();
}
private function findPlacement(mc:MovieClip,prev_seed:int = 0):void
{
var mc_len:int = mc_ar.length;
var rN:int = randomNumber(0,mc_len - 2);
if (prev_seed == 0)
{
rN = rN;
}
else if (prev_seed == mc_len-1)
{
rN = 0;
}
else
{
rN = prev_seed + 1;
}
trace(rN,mc);
var seed = mc_ar[rN];
var d = randomNumber(1,8);
if (d == 1)
{
mc.x = seed.x - seed.width - box_spacing;
mc.y = seed.y - seed.height - box_spacing;
}
else if (d==2)
{
mc.x = seed.x + seed.width / 2 - mc.width / 2;
mc.y = seed.y - seed.height - box_spacing;
}
else if (d==3)
{
mc.x = seed.x + seed.width + box_spacing;
mc.y = seed.y - seed.height - box_spacing;
}
else if (d==4)
{
mc.x = seed.x + seed.width + box_spacing;
mc.y = seed.y + seed.height / 2 - mc.width / 2;
}
else if (d==5)
{
mc.x = seed.x + seed.width + box_spacing;
mc.y = seed.y + seed.height + box_spacing;
}
else if (d==6)
{
mc.x = seed.x + seed.width / 2 - mc.width / 2;
mc.y = seed.y + seed.height + box_spacing;
}
else if (d==7)
{
mc.x = seed.x - mc.width - box_spacing;
mc.y = seed.y - mc.height - box_spacing;
}
else if (d==8)
{
mc.x = seed.x - mc.width - box_spacing;
mc.y = seed.y + seed.height / 2 - mc.width / 2;
}
var isGood:int = 0;
for (var c=0; c<placed_box_ar.length; c++)
{
if (mc.hitTestObject(placed_box_ar[c]) && mc != placed_box_ar[c])
{
trace("overlap, retrying");
findPlacement(mc,rN);//Retry placing this box.
}
else
{
isGood++;
}
}
if (isGood == placed_box_ar.length)
{
placed_box_ar.push(mc);
executeQueue();//Moves to next box to be placed.
}
}
private function centerAll():void
{
_path.addChild(mc_holder);
mc_holder.x = _path.stage.stageWidth / 2;
mc_holder.y = _path.stage.stageHeight / 2;
}
private function randomNumber(low:Number=0, high:Number=1):Number
{
return Math.floor(Math.random() * (1+high-low)) + low;
}
}
}
This answer might be a little bit out of the ordinary, but I'll leave it here anyway, for the sake of other people who may happen to come by.
There are no doubt plenty of ways that you could dynamically generate and randomly arrange a group of bounding boxes (look up bin packing algorithms) but there may be an incredibly low-tech way to do this and achieve the same effect, assuming the intent is to simulate randomness or dynamism in a UI.
Simply create 20 or so prefab arrangements and pick one of them at random. Unless the interface absolutely depends on randomization or the illustration of randomization, or the incoming data are truly unpredictable, the perceived result to the end user should be no different than actually programmatically creating the layout at runtime.
First of all: I agree with alemay's answer.
If you cannot go for a set of layouts or just don't want to, you should have a look at Force-based algorithms. To be honest, you'll need some math, but the results are often suprisingly good!
You could determine the biggest or most important Sprite as the main node, which is centered and fixed. Now connect every other Sprite with a spring to it (there comes the math). After a few iterations (the sprites are pulled to their main node) it will look similar to your sketch.
You can also group elements by connecting them with another spring.
精彩评论