ZoEM
ZoEM

Reputation: 852

Stuck in logic trying to position something dynamic

I think I wrote some code with an end result in mind that wasn’t going to work. I hope I’m proven wrong in this case. I need some explaining before I can ask my question so bear with me.

I’ve got an animation of an svg element that looks like the Earth that revolves around the Sun. I’ve written my code so that it does revolve around it and eventually crashes dead center into the sun. With that comes other animation, like an explosion of some sort. So, I wanted to know which side of the sun gets impacted as the animation is interactive in that a click of the button decides when the collision course is to start, meaning all sides are possibilities.

var positionplanet = $("#Earth").position();
var positionsun = $("#Sun").position();
if((Math.round(positionplanet.left)) == (Math.round(positionsun.left)) && (Math.round(positionplanet.top)) == (Math.round(positionsun.top)))
{alert('booya')}

I thought that with the above code I could alert myself when the planet is positioned in the exact same coordinates as the sun was, and work from there. When the horizontal (left) coordinate is the same, as is the vertical coordinate (top).

My problem is the alert only works when the planet is the same size as the sun – of course, only then it would be placed just as far and high away as the sun is. If the planet is a few pixels smaller than the sun, it's also a few pixels further away.

What I need is the position of the sun, but then only a few % more or less, I don’t know. I’m stuck in that logic, as height and width can switch places when working with a rotating element! I want the planet to border the sun and then trigger the alert, not when it’s 100% positioned the same, otherwise that’s not going to work as the earth needs to be well smaller in my animation. Then when the animation I need help with that as my story kind of makes obvious. Any help would be much appreciated.

I thought I’d provide you with a FIDDLE for reference, but for some reason I can’t get the alert when the planet is positioned the same as the sun, while it does work for me on my local computer. Maybe it’ll help you anyway!

Upvotes: 0

Views: 55

Answers (3)

Odubuc
Odubuc

Reputation: 676

You could use a simple circle collision detection such as described on msdn website: https://msdn.microsoft.com/en-us/library/dn265052(v=vs.85).aspx

function circlesOverlap(circleA, circleB) { // Returns true if the SVG circles A and B overlap, false otherwise.
    var deltaX = circleA.cx.baseVal.value - circleB.cx.baseVal.value;
    var deltaY = circleA.cy.baseVal.value - circleB.cy.baseVal.value;
    var distance = Math.sqrt( (deltaX*deltaX) + (deltaY*deltaY) ); // The classic distance-between-two-points formula.
    var radiusA = circleA.r.baseVal.value; // The radius of circle A.
    var radiusB = circleB.r.baseVal.value; // The radius of circle B.

    if (circleA.id == circleB.id) // If true, circleA and circleB are the same circle.
      return false;

    return distance <= (radiusA + radiusB);
};

Using your fiddle, this is what it gives: https://jsfiddle.net/odubuc/qk3qrwbp/15/

Your animate function is now as simple as:

function animate () {
    var earth = document.getElementById("Earth"),
        sun = document.getElementById("Sun");

    planetrotation("Earth");  

    if( circlesOverlap(earth, sun) )
    {
        earth.setAttribute("fill-opacity", "0.0"); 
        sun.setAttribute("fill-opacity", "0.0");
    }
}

Upvotes: 2

Adjit
Adjit

Reputation: 10305

You should be able to use either position or offset according to jQuery docs -

The .position() method allows us to retrieve the current position of an element relative to the offset parent. Contrast this with .offset(), which retrieves the current position relative to the document. When positioning a new element near another one and within the same containing DOM element, .position() is the more useful.

So, what your issue is here, is that the position/offset will be different for elements of differing sizes. Even if they are on top of each other.

The reasoning, is because when you ask for the left positioning of the sun, since it's radius is bigger, thus a larger circle, it's left offset/position is less than what the earth would be.

So now, you just have a simple math problem to solve for concentric circles - aka finding the distance between the edge of the sun and the edge of the earth, then you would need to subtract/add to whichever offset you want to check against.

The way you find the distance between the two is by subtracting the radii. Now, I know that the r value does not refer to pixels, so I wasn't sure how to do that in your situation, but I think this should get you most of the way.

Upvotes: 0

Caleb O&#39;Leary
Caleb O&#39;Leary

Reputation: 763

Try using .offset() rather than .position() (check the console, with position, the values are never changing, with offset, they change)

var positionplanet = $("#Earth").offset();
var positionsun = $("#Sun").offset();

https://jsfiddle.net/zkuhpjwf/

As far as a good collision detection, you could write something saying if the planet's top offset is greater than the sun's top offset, but less than the sun's top offset + the sun's height and something similar for left offset/height. To trigger just when the planet touches the sun in any direction, you could throw in the planet's height and width to the equation. It would take some playing

if ( (positionplanet.left > positionsun.left && positionplanet.left < positionsun.left + SUNWIDTH) && (positionplanet.top > positionsun.top && positionplanet.top < positionsun.top + SUNHEIGHT) ) {
    //the planet is completely inside of the sun
} 

if ( (positionplanet.left > positionsun.left - PLANETWIDTH && positionplanet.left < positionsun.left + SUNWIDTH - PLANETWIDTH) && (positionplanet.top > positionsun.top - PLANETHEIGHT && positionplanet.top < positionsun.top + SUNHEIGHT - PLANETHEIGHT) ) {
    //the planet is touching the sun (will need some fiddling I'm sure..)
} 

Upvotes: 0

Related Questions