0
votes

I'm creating a screen saver which requires a movie clip to be loaded to the stage at a random position based on the size of the screen, then fade out (which I have all of the animation within a movie clip as tweens)

I've hit a road block and can't figure out how to prevent the movie clips from overlapsing on top of each other. If anything, I'd like for them to appear at another random spot that does not cause the overlapse.

here is all of the code for my project:

 stop();

import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
var greystoneLogos:Array = new Array  ;
var countTimeArray:Array = new Array  ;
var previousLogos:Array = new Array  ;
var xpoint:int;
var ypoint:int;


function getNewSymbols()
{
    previousLogos = new Array  ;
    greystoneLogos = new Array  ;
    var i:int;
    for (i=0; i < 3; i++)
    {
        greystoneLogos[i] = new GreystoneLogo1();
        greystoneLogos[i].width = 100;
        greystoneLogos[i].height = 60;
        addSymbolToStage(greystoneLogos[i],i*2000);

    }
}

getNewSymbols();



function addSymbolToStage(currentLogo:MovieClip,waitTime:int)
{


    var i3:int;
    var i4:int;
var logoBoundaries:Array = new Array()
var XandY:Array = new Array()
    for (i3=0; i3 < greystoneLogos.length; i3++)
    {
        if (greystoneLogos[i3] !== currentLogo)
        {

            xpoint = randomRange(this.stage.stageWidth - (currentLogo.width * 4.8));
            ypoint = randomRange(this.stage.stageHeight - (currentLogo.height * 6.9));
            logoBoundaries = getOffDimensions(currentLogo)

                for (i4=0; i4 < logoBoundaries.length; i4++)
    {
        XandY = logoBoundaries[i4].split(":")

        while ((xpoint <= (Number(XandY[0]) + Number(currentLogo.width * 4.8)) &&  xpoint >= (Number(XandY[0]) - Number(currentLogo.width * 4.8))) && (ypoint <= (Number(XandY[1]) + Number(currentLogo.height * 6.9)) &&  ypoint >= (Number(XandY[1]) - Number(currentLogo.height * 6.9)))){

        xpoint = randomRange(this.stage.stageWidth - (currentLogo.width * 4.8));
        trace(XandY[0] + " And " + (Number(currentLogo.width * 4.8)))
        trace(xpoint + " And " + (Number(XandY[0]) + Number(currentLogo.width * 4.8)))
        ypoint = randomRange(this.stage.stageHeight - (currentLogo.height * 6.9));
        }
    }




        }
        else
        {
            continue;
        }

    }

    previousLogos.push(currentLogo);
    currentLogo.x = xpoint;
    currentLogo.y = ypoint;
    stage.addChild(currentLogo);
    currentLogo.gotoAndStop(1);
    var countTime:Timer = new Timer(waitTime,1);
    countTime.addEventListener(TimerEvent.TIMER, function(){

       currentLogo.gotoAndPlay(1);
       currentLogo.addFrameScript ( currentLogo.totalFrames - 1 , function(){
        currentLogo.stop()
     stage.removeChild(currentLogo)
     if(stage.numChildren <= 1){

    getNewSymbols(); 

     }

       }) ;

       });
    countTime.start();
}

function getOffDimensions(currentLogo:MovieClip){
    var i3:int;
    var tempArr:Array = new Array()
    for (i3=0; i3 < greystoneLogos.length; i3++)
    {
        if (greystoneLogos[i3] !== currentLogo){
        tempArr[i3]=greystoneLogos[i3].x +":"+ greystoneLogos[i3].y
        }
    }
    return tempArr
}

function randomRange(max:Number, min:Number = 0):Number
{
    return Math.random() * (max - min) + min;
}

There are also may be a handful of unused variables from multiple things I've been trying out.

The code that I posted, will make the movie clip appear at a random spot based on the last movie clip that came up. So let's say we have 3 movie clips (the user will be able to change how many of the clips get displayed) 1 appears at 0,0 the other at 400,400 and the last one appears at 10,10 because I have no way of saving the previous values to compare in the while loop.

I hope this clarifies it a tad more

EDIT:

Based on a function shown below, I've added this:

for (i3=0; i3 < greystoneLogos.length; i3++)
    {
        if (greystoneLogos[i3] !== currentLogo && greystoneLogos[i3] != null)
        {

            while(currentLogo.hitTestObject(greystoneLogos[i3]) == true){  

            xpoint = randomRange(this.stage.stageWidth - (currentLogo.width));
            ypoint = randomRange(this.stage.stageHeight - (currentLogo.height));
            i3 = 0
             }
        }else{
            continue;
        }

    }

Which results in a rather bad loop as well as the logo's still overlap above each other

2

2 Answers

0
votes

The quickest way I can think to solve this is to do a hit test (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#hitTestObject()) on the new MovieClip and if it returns true, run the placement code again

0
votes

Ok, here's the implementation of this quickest way. You can track your present displayObject by the .numChildren property. You don't even need an array of your logos or things. Let's say you have a function that adds new movieClip to your screen. It knows how many clips you can have (MovieClipDummy is just my testing class - it draws a circle with a specified radius. It should be replaced by your objects).

private function addAnotherMovieClip(): void {
    if (_currentDummmiesCount < _dummmiesCount) {
        var newDummy: MovieClipDummy = new MovieClipDummy(90);
        addChild(newDummy);
        //If we get a stackoverflow error (see below)
        //we just remove our object from the screen as it will most likely just won't fit
        if (checkForEmptySpace(newDummy) != "") {
            removeChild(newDummy);
            return;
        }
    } else {
        //Do nothing or do something
    }
}

It calls another function, checkForEmptySpace, which tries to place your movieclip so it won't overlap with other objects. Here it is:

private function checkForEmptySpace(newClip: Sprite): String {
    //you should store your screen width somewhere.
    //you can also call stage.stageWidth instead, but first make sure that you
    //always have a link to the stage or it will throw an error
    newClip.x = Math.random() * _screenWidth;
    newClip.y = Math.random() * _screenHeight;
    //===========================
    //Important part - we try to check all the present children of our container
    //numChildren is a property of the DisplayObjectContainer
    for (var i: int; i < numChildren; i++) {
        //We need a try here because we will get a StackOverflow error if there's no empty space left
        try {
            //We need to check if our current display object, received with getChildAt()
            //is not the same as the one we've just added to the screen
            //And if our new object intersects with ANY other object on the stage - we
            //call THIS function once again.
            //We do recursion because we can easily catch an error and remove this object from
            //the screen
            if (newClip != getChildAt(i) && newClip.hitTestObject(getChildAt(i))) {
                //If our recursive function returns an error - we should pass it further
                if (checkForEmptySpace(newClip) != "") {
                    return "error";
                }
            }
            //The only error that can go here is stackoverflow error. So when we get one
            //we return this error string
        } catch (error: Error) {
            trace(error);
            return "error";
        }
    }
    //We only return this empty string if we don't have stackoverflow error
    //so there's possibly no space left for another movieclip
    return "";
}

You can do it without recursion, but you will have to check for empty space with another logic.

And, you can do it more "professionally" by using Minkowski addition. You should consider storing an array of "boundary" points of your movieclips (let's say every movieclip is a rectangle) and when you add a new object to the screen, you calculate this Minkowsky addition. It will have some "free" spots on your screen which represent any possible coordinates of your new movieclip. It's pretty interesting to implement something like that because the accuracy will be phenomenal. But if you don't have time - just use that recursive placement function