Jump to content

How to calculate absolute world x/y without using world xy property?


ForgeableSum
 Share

Recommended Posts

I have strong suspicions that the world x/y property on Phaser.Sprite (which I think replaced the old toGlobal method) is buggy and would like to figure out a way to manually calculate the absolute position of a sprite. Suppose I have a sprite child of a sprite child of a sprite child of the world.

spriteA ([0,0], rotation: 0) > spriteB ([0,0], rotation: 0) > spriteC ([0,0], rotation: 0) > world.

We all know if the sprites have no rotations, you can easily calculate the absolute positions by adding the parent positions, e.g. the absolute world position of spriteA would be:

var xValue = spriteA.x + spriteB.x + spriteC.x;

var yValue = spriteA.y + spriteB.y + spriteC.y; 

But what about when the child sprites have rotations and offsets. e.g.:

spriteA ([15,34], rotation: 2.3) > spriteB ([30,0], rotation: 0) > spriteC ([1400,1000], rotation: .6) > world.

How then will you calculate absolute world positions? Because simply adding the x/y won't work as it doesn't take rotation into account. I suspect using Phaser.Point.rotate will be involved but I'm not sure exactly how to solve this and I ran out of patience testing different parameters.  Someone please help me figure this out! 

 

 

Link to comment
Share on other sites

Not sure if this is what you're looking for, but let's say we have these: 

parent {x: 100, y:100, rotation: Math.PI*0.5}

child {x: 50, y: 50, rotation: 0}

so you want to get the global cords of the child right?,

var childDisFromParent = Math.sqrt(child.x*child.x + child.y*child.y)

var childRotFromParent = Math.atan2(child.y, child.x)

var childActualPos = {

 x: Math.cos(childRotFromParent + Parent.rotation) * childDisFromParent + parent.x,

 y: Math.sin(childRotFromParent + Parent.rotation) * childDisFromParent + parent.y

}

I'm quite sure there's probably a lot better way of doing this, but this thing is first that I had in mind

Link to comment
Share on other sites

Here's my implementation. Unfortunately, it doesn't work ... bullets are beginning somewhere near the sprites though. Bug guess what? Where the bullets start are affected by the camera position once again! 

function getAbsolutePosition(sprite) {

    var child = sprite;
    var spriteParent = child.parent;

    var absPosition;

    while (spriteParent.name != '_stage_root') {

        var childDisFromParent = Math.sqrt(child.x * child.x + child.y * child.y)

        var childRotFromParent = Math.atan2(child.y, child.x)
        var absX = Math.cos(childRotFromParent + spriteParent.rotation) * childDisFromParent + spriteParent.x;
        var absY = Math.sin(childRotFromParent + spriteParent.rotation) * childDisFromParent + spriteParent.y;

        if (absPosition == undefined) {
            absPosition = {

                x: absX,
                y: absY

            }

        } else {

            absPosition.x += absX,
            absPosition.y += absY

        }
        child = spriteParent;
        spriteParent = spriteParent.parent; 

    }
    
    return absPosition; 

}

 

P.S. Just changed parent to spriteParent because parent is a global variable used by the window. 

Link to comment
Share on other sites

It's truly bizarre. I have a mini map which shows where all the bullets are starting from and going on the map. When I move the camera away from the sprites, the start x/y position of the bullets changes drastically as if they are relative to the camera. It's the same exact thing that was happening when I was using .world. 

And yes, I have checked - all my sprites are using .5 as an anchor. 

Link to comment
Share on other sites

Oh! got it, camera position changes Phaser.World position, if you move camera to x: 20, y:10, then Phaser.World position will be x:-20, y-10, and in that while loop you're also considering in the Phaser.World which probably is the cause of this issue. So use while(spriteParent.name !=  "__world" ) { //code here } instead

Link to comment
Share on other sites

function getAbsolutePosition(sprite) {

    var child = sprite;
    var spriteParent = child.parent;

    var absPosition;

    while (spriteParent.name != '__world') {

        var childDisFromParent = Math.sqrt(child.x * child.x + child.y * child.y)

        var childRotFromParent = Math.atan2(child.y, child.x)
        var absX = Math.cos(childRotFromParent + spriteParent.rotation) * childDisFromParent;
        var absY = Math.sin(childRotFromParent + spriteParent.rotation) * childDisFromParent;

        if (absPosition == undefined) {
            absPosition = {

                x: absX,
                y: absY

            }

        } else {

            absPosition.x += absX,
            absPosition.y += absY

        }
        child = spriteParent;
        spriteParent = spriteParent.parent; 

    }
    
    return absPosition; 

}

Try this, I have a suspicion that this should work

Edited by TickleMeElmo
Link to comment
Share on other sites

7 minutes ago, TickleMeElmo said:

function getAbsolutePosition(sprite) {

    var child = sprite;
    var spriteParent = child.parent;

    var absPosition;

    while (spriteParent.name != '_stage_root') {

        var childDisFromParent = Math.sqrt(child.x * child.x + child.y * child.y)

        var childRotFromParent = Math.atan2(child.y, child.x)
        var absX = Math.cos(childRotFromParent + spriteParent.rotation) * childDisFromParent + spriteParent.x;
        var absY = Math.sin(childRotFromParent + spriteParent.rotation) * childDisFromParent + spriteParent.x;

        if (absPosition == undefined) {
            absPosition = {

                x: absX,
                y: absY

            }

        } else {

            absPosition.x += spriteParent.x,
            absPosition.y += spriteParent.y

        }
        child = spriteParent;
        spriteParent = spriteParent.parent; 

    }
    
    return absPosition; 

}

Try this, I have a suspicion that this should work(in case you only have on parent of that sprite rotated)

Hmm, now the bullets are starting from the very top left of the map, so it seems to be the opposite problem (before bullets were starting at bottom right). The bullets should be starting near the center of the map as that's where the test sprites are. 

 

Btw, I very much appreciate the help and will send you a free copy of my game once it's finished. I never imagined I would be spending 2 days trying to get the absolute position of a child sprite. That's one of those things you assume the framework will handle. 

 

P.S. Why does Phaser take the camera location into account on the world property? How does the camera have anything to do with the absolute position of a sprite in the world. Is that intentional? 

Link to comment
Share on other sites

8 minutes ago, TickleMeElmo said:

oh yeah, sorry, I just edited the code try again now, (getting a bit late so I'm starting to produce not the brightest codes, night coding isn't for everyone you know)

Just tried it now. The results mirror the results using .world x/y on the muzzle flash (lowest child in hierarchy). The only difference is the results are no longer skewed by camera movement, which is a good thing. However, they bullet start x/y doesn't rotate perfectly along with the muzzle flash.  Of course, everything is where it's supposed to be if nothing is rotated. But pretty much every child/parent is rotated in my case. 

Link to comment
Share on other sites

Top of tree to bottom (all objects are anchored by .5): 

world

group ("game objects" [0,0], rotation = 0)

sprite ("unit", [345,600],rotation = .785)

sprite ("gun", [-7,0],rotation = 2.486)

sprite ("muzzleFlash", [32,-23],rotation = 1.5)

 

The bullet is in a separate group which is the child of the world. So when I fire the bullet, I'm trying to get it to start exactly where the muzzle flash sprite is. I should note that the muzzle flash moves to arbitrary coordinates based on which gun is firing (these are double and triple guns), like so:

        msprite.x = unit.guns[gunIndex].multi[currentMulti][0];
        msprite.y = unit.guns[gunIndex].multi[currentMulti][1];

        unit.guns[gunIndex].currentMulti++
 

So the first time the gun fires, it will be at:

            [32, -23],
And the second time:

            [32, 22]


Then currentMulti is reset to zero and it goes back to [32, -23].

It's just dawned on my that may be where the miscalculation is, because those arbitrary movements assume 0 rotations. But how can I calculate the x/y, taking all the world transforms into account?

 

 

 

 

 

 

 

Link to comment
Share on other sites

Here are some example results: 

unit position:  {x: 4361.8046108200615, y: 4299.997671575902, type: 25}

unit rotation: -0.014180800172453928

gun position {x: 50, y: 15, type: 25}

gun rotation: 2.440526462913298

muzzle flash position: {x: 20, y: 0, type: 25}

muzzle flash rotation: 0

 

gun bullet start (results): {x: 4396.729190524387, y: 4327.1878029138115, type: 25}

 

 

Link to comment
Share on other sites

btw, here are some more test results (everything is in the same order):

game2.js:1864 P…r.Point {x: 4356.86049998745, y: 4300, type: 25} -0.012042771838760834 P…r.Point {x: 50, y: 15, type: 25} 2.3884880298189324 P…r.Point {x: 20, y: 0, type: 25} 0 P…r.Point {x: 4392.446129251321, y: 4328.0749300625785, type: 25}

game2.js:1864 P…r.Point {x: 4356.86049998745, y: 4300, type: 25} -0.012042771838760834 P…r.Point {x: 50, y: -15, type: 25} 2.1412993755593033 P…r.Point {x: 20, y: 0, type: 25} 0 P…r.Point {x: 4395.875127157528, y: 4301.23155181026, type: 25}

game2.js:1864 P…r.Point {x: 3592.809754647056, y: 3687.190245352944, type: 25} -0.7853981633974483 P…r.Point {x: -7, y: 0, type: 25} 2.917026544114841 P…r.Point {x: 32, y: 22, type: 25} 0 P…r.Point {x: 3551.764466450548, y: 3677.8182631932104, type: 25}

game2.js:1864 P…r.Point {x: 5165.6067975568885, y: 4285.995071426674, type: 25} 0.12767083478338517 P…r.Point {x: 50, y: 15, type: 25} 2.9450681640327123 P…r.Point {x: 20, y: 0, type: 25} 0 P…r.Point {x: 5193.674967799077, y: 4311.144440777133, type: 25}

game2.js:1864 P…r.Point {x: 5165.6067975568885, y: 4285.995071426674, type: 25} 0.12767083478338517 P…r.Point {x: 50, y: -15, type: 25} 2.910269127507492 P…r.Point {x: 20, y: 0, type: 25} 0 P…r.Point {x: 5197.642442777036, y: 4282.0686882863665, type: 25}
 

Link to comment
Share on other sites

I had this wacky solution a while back which worked perfectly about 95% of the time. Unfortunately, it was affected by camera movement. about 5% of the time, if you moved the camera, it would offset everything incorrectly. msprite is muzzleflash sprite, startPosition is bullet start x/y:

    var position = msprite.toGlobal(msprite);
                position.x = game.camera.x + position.x;
                position.y = game.camera.y + position.y;
                unit.guns.startPosition = position;  

But with that, the bullet always started right on top of the muzzle flash sprites, as intended. 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...