简体   繁体   中英

JavaScript object positioning collision logic

@Pointy:

As I said below, the size variable adjusts the size by a percentage. So this number could have, for example, a value of 1, or 1.5, or 2, etc. The default circle diameter is 100 pixels, and the actual diameter of the circle displayed is size*100 . When checking for collision I use size*120 because I want to leave some extra room.

To my understanding, the CSS left and top properties positions the object in terms of its left and top bounds, respectively. Thus if I want to check collision on the right side of the object, I'd have to take the left boundary and add the diameter of the circle (which is given by size*100 ). When checking the collision on the left side, I take the left bound and subtract size*(1.2-1)*100 , because I do not need to account for the diameter of the circle as I am starting from the left bound. The same thing applies to the y-axis.

I hope this was understandable, thanks for helping me out.

Original Post:

I have two circles on my screen, a pink one and a purple one. The positions of these circles (x,y) are randomly determined. Initially, only the purple circle is on the page. One second later, the pink circle will appear. I want to check if these two circles will overlap, and if so, reposition the pink circle.

My code:

   if(document.getElementById("purple").style.left+(size*120) > x 
      && document.getElementById("purple").style.left-(size*20) < x)
   {
        if(x + 200 <= rightBound) {
            x = x+200;
        }
        else {
            x = x-200;
        }
    }
    else if(document.getElementById("purple").style.top+(size*120) > y
            && document.getElementById("purple").style.top-(size*20) < y)
    {
        if(y+200 <= bottomBound) {
            y = y+200;
        }
        else {
            y = y-200;
        }
    }
    document.getElementById("pink").style.left = x+"px";
    document.getElementById("pink").style.top = y+"px";

The size variable modifies the circle size by a percentage. The default circle size is 100 pixels, but in my code I specify 120 pixels to leave a bit of extra room.

The rightBound and bottomBound variables dictate the bounds in which the circle must be randomly positioned. My code checks if moving the circle 200 pixels to the right, or 200 pixels down would still position the circle within the bounds. If so, then this is done, otherwise the circle is moved 200 pixels to the left instead.

By the way, in case it is not clear x and y are the randomly generated values for the position of the pink circle.

With this code, however, I have still experienced instances where the pink and purple circle will overlap. I'm wondering what the problem is with my logic, as in my explanation and thinking I feel that everything should be working fine.

Why not just keep trying new pink circles until you get one that's right? Random numbers are cheap, after all: http://jsfiddle.net/HVX7d/

while(distance(purple, pink) < 120) {    
  pink = {
    x: int_rand(100, 500),
    y: int_rand(100, 500)
  };  
}

Just use a loop to keep generating new positions for pink until you're sure there are no collisions, using Pythagorean to calculate how far apart the circles are.

Original Answer (incorrectly assumed 100 was a radius): The issue is that you're specifying 120 in your boundary logic but only moving the circle by 200 when you detect it. That means there's a scenario where the circles originally don't overlap, but when you move them by only 200 you've created an overlap that didn't previously exist.

Change your instances of 200 to 240 and you shouldn't see any more issues.

For example: you have purple at 200, 200 and pink at 310, 200. That's enough to trigger your boundary logic because 310 - 200 is only 110, so you choose to move pink. Let's say you move it up because it's near the bottom boundary, so now it's at 110, 200 and you've created overlap.

I think this should do what you need:

function reposition_check(x, y, rightBound, bottomBound, size, elem) {
    var c1_size = 120 * size;
    var c2_size = 120 * size;

    var c1_x = parseInt(elem.style.left.replace("px", "")) + (c1_size / 2); //center the purple x coordinate
    var c1_y = parseInt(elem.style.top.replace("px", "")) + (c1_size / 2); //center the purple y coordinate

    var c2_x = x + (c2_size / 2); //center the pink x coordinate
    var c2_y = y + (c2_size / 2); //center the pink y coordinate

    var d_x = c1_x - c2_x; //distance on the x plane
    var d_y = c1_y - c2_y; //distance on the y plane

    if (Math.sqrt((d_x * d_x) + (d_y * d_y)) < (c1_size / 2) + (c2_size / 2)) { //Pythagorean theorum to determine if overlapping
        console.log("is overlapping");
        if (Math.abs(d_x) < (c1_size / 2) + (c2_size / 2)) { //if true, the overlap is on the x plane
            //if(x + (c2_size) + 200 <= rightBound && d_x > 0) {
            if(d_x > 0) {
                x = (x + 200 <= rightBound) ? x + 200 : (x - 200 - d_x);
            }else{
                x = (x + 200 <= rightBound) ? x - d_x + 200 : (x - 200);
            }
            return {x: x, y: y};
        }

        if (Math.abs(d_y) < (c1_size / 2) + (c2_size / 2)) { //if true, the overlap is on the y plane
            if(d_y > 0) {
                y = (y + 200 <= bottomBound) ? y + 200 : (y - 200 - d_y);
            }else{
                y = (y + 200 <= bottomBound) ? y - d_y + 200 : (y - 200);
            }
            return {x: x, y: y};
        }

    }
    return {x: x, y: y};
}

//Here's how you would use it:

var purple = document.getElementById("purple");
var values = reposition_check(111, 1, 1000, 800, 1, purple); //x, y, rightBound, bottomBound, size, element

document.getElementById("pink").style.left = values.x + "px";
document.getElementById("pink").style.top = values.y + "px";

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM