Search code examples
flashactionscript-3collision-detectioncollisionhittest

collision testing with multiple objects on stage


I'm trying to create a sort of tree diagram such that, if you click on one of the circles, its child circles spread outward with some degree of randomness from the original circle, connected by lines. I have this working, but now what I want to do is make sure that none of the circles collide with each other and none of the lines criss cross. You can see the screenshot for what is currently happening. My code is below. How do I change this code so that it checks for collisions and avoids them? I've read up on flash's hitTestObject command, but that only works in the context one object to another. I want to test for one object contacting any display object.

import com.greensock.TweenMax;

var sw = stage.stageWidth;
var sh = stage.stageHeight;
var cr = 3; //circle radius
var moveRange = 25;
var circleColor = 0xcccccc;
var numCircles = 4;
var lineCanvas:Sprite = new Sprite();
addChild(lineCanvas);
var lineColor = 0xe9e9e9;
var lineWeight = 1;

function init(){
    firstCircle();
}

function firstCircle(){
    var xPos = randomRange(cr, sw-cr);
    var yPos = randomRange(cr, sh-cr);
    var newCircle:Shape = new Shape();
    newCircle.graphics.beginFill(circleColor);
    newCircle.graphics.drawCircle(0,0,cr);
    newCircle.graphics.endFill();

    var circleClip:MovieClip = new MovieClip();
    circleClip.childCircles = 2;
    circleClip.x = xPos;
    circleClip.y = yPos;
    circleClip.addChild(newCircle);

    addChild(circleClip);
    circleClip.addEventListener(MouseEvent.CLICK,clickCircle);
}

function clickCircle(e:MouseEvent):void {
    var thisCircle = e.target;
    for (var i=0; i<thisCircle.childCircles;i++){
        drawCircle(thisCircle);
    }
}

function drawCircle(parentCircle){
    var xPos = parentCircle.x;
    var yPos = parentCircle.y
    //var xPos = randomRange(cr, sw-cr);
    //var yPos = randomRange(cr, sh-cr);
    var newCircle:Shape = new Shape();
    newCircle.graphics.beginFill(circleColor);
    newCircle.graphics.drawCircle(0,0,cr);
    newCircle.graphics.endFill();

    var circleClip:MovieClip = new MovieClip();
    circleClip.childCircles = 2;
    circleClip.x = xPos;
    circleClip.y = yPos;
    circleClip.addChild(newCircle);
    addChild(circleClip);
    circleClip.addEventListener(MouseEvent.CLICK,clickCircle);
    moveCircle(circleClip,xPos,yPos);
}

function drawLine(childCircle,parentX,parentY){
        lineCanvas.graphics.lineStyle(lineWeight,lineColor);
        lineCanvas.graphics.moveTo(parentX,parentY);
        lineCanvas.graphics.lineTo(childCircle.x,childCircle.y);

//Want to check if either the line or the circle is contacting anything here. If it is, I want to kill the tween to the circle (thus also stopping the drawing of the line).

}

function moveCircle(childCircle,parentX,parentY){
    var curX = childCircle.x;
    var curY = childCircle.y;
    var moveX = randomRange(curX-moveRange,curX+moveRange);
    var moveY = randomRange(curY-moveRange-cr,curY+moveRange+cr);
    TweenMax.to(childCircle,.5, { x: moveX, y: moveY, onUpdate:drawLine, onUpdateParams:[childCircle,parentX,parentY]});
}

function randomRange(minNum:Number, maxNum:Number):Number {  
    return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);  
}

init();

Solution

  • There's 2 ways you could do this:

    1. Re-factor your code to use an Actionscript Physics Library (i.e. Box2D or whichever you prefer). Then, consider your "circles" and "lines" as physical objects that will collide with each other, probably having the same effect as what you're trying to do here. The PRO to this is that the library comes with an assortment of extended classes to handle physical interaction. The CON is the overhead in implementation.
    2. The manual/custom way to do this is to add an eventlistener for ENTER_FRAME, on the stage OR the initial circle, that will loop through it's children, and call the hitTestObject method on each "child" circle, compared with every other "child" circle. The lines are within the children circles, so should be fine.

    I notice you're not actually adding the childCircles to the initial circle, and instead adding them to the stage. You might want to push these circles into an Array to reference later for this "collisionDetection" method.