Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Spine-TS] Group Container and Root Bone Position Problem #72

Open
shibekin69 opened this issue Aug 19, 2017 · 24 comments
Open

[Spine-TS] Group Container and Root Bone Position Problem #72

shibekin69 opened this issue Aug 19, 2017 · 24 comments

Comments

@shibekin69
Copy link

Hey guys,

Some things I noticed about the new Spine-TS:

When you put the Spine object inside a group, scaling a group does not affect the Spine object properly. In the old phaser-spine, you can scale the container group using Phaser, and the Spine object will scale accordingly. It doesn't happen here. It seems you need to scale the Spine object itself.

How the object is placed onto the stage is rather wonky and unpredictable. It doesn't seem to honor the Root bone's x and y coordinates nor Spine's 0,0 world coordinates. It seems to be somewhere on the top and left, maybe treating the Spine object as an image and laying it down like an image, where the 0,0 is the top left hand corner.

@shibekin69
Copy link
Author

Ok, I tried placing different sized animations in a group, and the 0,0 point is dependent on the size and is somewhere the top left of the entire animation body (is it treating it like an image?) . The centerX and centerY properties change. If the 0,0 position in spine equals the 0,0 world position of the Spine editor like in the old version, that would make things more predictable, but since it's always somewhere on the top left, this makes it unpredictable to work with.

@shibekin69
Copy link
Author

shibekin69 commented Aug 20, 2017

Based on my experiments, it seems that the origin/anchor position of the Spine animation is dependent on the width/height of it. So take the following for example, I have 2 animations, 1 that's full size, and the other shrunk to 20% (by importing a new Spine Data, altering the scale, and using image assets that's the same as the scale). I grabbed the Spine object's width and height, and positioned the root bone until it very closely matches the parent group's x and y points (where scaling the spine object will be very close to using the root bone's position as the anchor of the scaling.)

100% Size:
Spine Width (In Px, Phaser): 1830
Spine Height (In Px, Phaser): 1804
Approx. center where the root has to be in for scaling to work, using the root as the center:
x: -700
y: 1242

20% Size:
Spine Width (In Px, Phaser): 366
Spine Height (In Px, Phaser): 361
Approx. center where the root has to be in for scaling to work, using the root as the center:
x: -140
y: 248

I don't know why it's like this, but I'm trying to find some meaning into these numbers. Maybe someone can figure this out one?

@shibekin69
Copy link
Author

shibekin69 commented Aug 21, 2017

Ok, when I set the anchor of the Spine object to (0.5, 0.5), it helps. I need to move around the skeleton's x and y (not bone[0]'s x and y) for me to be able to adjust the spine object's position so it can scale properly. If I cancel out root's X and Y offset by moving it to the opposite direction, it should move it down to the 0,0 position in Spine and in Phaser.

I have something like this my code to try and center the root bone to 0,0:

spineGroup.spineObj.anchor.setTo(0.5, 0.5);
spineGroup.spineObj.x = 0;
spineGroup.spineObj.y = 0;
spineGroup.spineObj.centerX = 0;
spineGroup.spineObj.centerY = 0;

spineGroup.spineObj.skeleton.x = -1 * spineGroup.spineObj.skeleton.bones[0].x;
spineGroup.spineObj.skeleton.y = 1 * spineGroup.spineObj.skeleton.bones[0].y;

I usually have my root on the upper right quadrant in the editor. If I do this, it seems to move X properly, but the Y, it can't figure out. It's always above the root! In other words, the root is always below it, when it's supposed to be centered already.

See pic below:

image

EDIT 1: Regardless of where I move the spine object with the root bone in Spine Editor, I end up with the above, which is good in a way, but the Y is just not right...

@AleBles AleBles added this to To Do in Implement Spine-TS Aug 21, 2017
@AleBles AleBles added the v4 label Aug 21, 2017
@AleBles AleBles added this to the phaser-spine v4 milestone Aug 21, 2017
@shibekin69
Copy link
Author

shibekin69 commented Aug 21, 2017

Another observation between WebGL and Canvas. In WebGL, to get the same result, the Y needs to be negative. In the above example, if Y was set to 2000px, this needs to be -2000px in WebGL.

EDIT: If you move the spine object's root to 0,0 in the Spine Editor's space, WebGL positioning will be the same as Canvas.

@AleBles AleBles moved this from To Do to Progress in Implement Spine-TS Aug 22, 2017
@AleBles AleBles moved this from Progress to To Do in Implement Spine-TS Aug 24, 2017
@shibekin69
Copy link
Author

@AleBles - Do you see this problem on your end? This thing is making Spine-TS unusable and I can't find a fix for it :(

@AleBles
Copy link
Member

AleBles commented Aug 28, 2017

I'm actually working on it inbetween :p

@shibekin69
Copy link
Author

Yeah, I'm just seeing whether it's just me or it's really a problem others can see too.

@AleBles
Copy link
Member

AleBles commented Aug 29, 2017

Just to make sure we implement it correct: should the position you put down in Phaser always be the spot where the rootbone is located?

Then as a second question, how should we handle anchor's then?

In order for Phaser anchor's to work correctly you'd expect this lib to ignore the rootbone and just use the Phaser point as the top-left corner of the image.

Toughts @shibekin69 ?

Edit 1: This was not an issue in the old spine because the spine extended a Phaser.Group, therefor having no anchor, spine-ts extends Phaser.Sprite (which is better imho) but I feel like we should then also adhere to anchor (and therefor ignoring rootbone positions)

@shibekin69
Copy link
Author

shibekin69 commented Aug 29, 2017

Yes on the first question. I think that'd be most practical.

Hmm.. Is there a way to make it work both ways so that for 1.) those who want to use the root bone as the center of the spine object, and 2.) those who want to just use the top left of the image can use the plugin according to their preference?

Personally, I'd prefer to use the root bone as the center of the spine object with anchor 0.5, 0.5 so that it's predictable when I spawn it on screen and when I do transforms on it. Here's an idea, how about being able to set the anchor of the root when spawning a new spine object with 0.5, 0.5 as the default?

Something like this:

game.load.spine('spineboy', '/path/to/spineboy.json', {
  x: 100, // x position of root on the screen
  y: 100,  // y position of root on the screen
  anchorx: 0.5, //anchor x of root
  anchory: 0.5 //anchor y of root
})

Then just be able to change/tween the x, y, anchorx, and anchory any time after initialization.

The ability to change the anchor x and y of the root will let you change the way you scale the spine object. So for some games, like side scrollers (ex: contra), this might be set to where the feet's touching the ground (0.5, 1) and scaling it will make it grow upward and not clip the floor. Others who make maybe top down shooters, flying monsters, or other kinds of stuff, use 0.5, 0.5 or some other arbitrary number (like myself) to have an even scaling or some kind of scaling specific to their needs.

It's easier to use the root bone as the spawn point in phaser since it's very easy to also set it in the spine editor visually no? Doing invisible guess work with phaser was quite a pain.

@AleBles
Copy link
Member

AleBles commented Aug 29, 2017

We could go for a simple boolean or such where the bound position can be changed on the fly, maybe even generic plugin setting?

@shibekin69
Copy link
Author

Bound position?

So in the mode where the root position is not going to be treated as the center of the spine object, the position set in phaser will be the 0,0 origin shown in the spine editor? I think this is how the current phaser-spine worked no?

@AleBles
Copy link
Member

AleBles commented Aug 29, 2017

That's what I meant but after discussing with our artist am leaning more towards a solution where anchor and rootbone are the same thing.

So if you create a spine with your root bone in the death center if the animation, this will also be reflected towards the anchor (will be set to 0,5; 0,5). The moment you adjust the anchor we'll ignore the position of the rootbone and just anchor it according to regular sprite behaviour.

This means that the rootbone only dictates the default position of the anchor point and you're freely to adjust it anyway you like.

Example; a spine animation that is 200 wide and 400 heigh, with a rootbone positioned slightly above the bottom-middle will load up with an initial anchor of (0.5; 0.9) (ofcourse exactly calculated based on the spoine dimensions).

@shibekin69
Copy link
Author

shibekin69 commented Aug 29, 2017 via email

AleBles pushed a commit that referenced this issue Aug 30, 2017
…nchoring.

By default the anchor of the Spine is set to the rootbone location, this can be overwritten and also reset with resetAnchorToRootBonePosition().

Refs #72
@AleBles
Copy link
Member

AleBles commented Aug 30, 2017

So Canvas rendering should be good now. Moving on to WebGL ;x

@shibekin69
Copy link
Author

shibekin69 commented Aug 30, 2017

Ok, I'm testing out the canvas version. Moving the group container where it's in doesn't move the spine object. So if you do this:

spineContainerGroup.x = 200 <-- does not work (doesn't move spine object)
spineContainerGroup.children[0] = 50 <-- works

I tried to make x, y, centerX, and centerY properties start with 0 and it as it is. The positioning problems still there. Hmm. I'm trying to make the root bone align with my spineContainerGroup's 0,0. And then what I do is apply transformations to the group and sometimes to the spine object itself.

EDIT: I'm trying out the spine-ts-position build

EDIT 2: Ok, I think I'm figuring this out now. It kinda behaves like the old phaser-spine. I got rid of trying to set 0 to the spine object's [x, y, centerX, centerY], so I only have the code to cancel out the root bone's [x, y] to bring it to the origin:

skeleton.x = -1* skeleton.bones[0].x
skeleton.y = 1 * skeleton.bones[0].y

And I'm seeing the root bone does align at the very least to the top edge of the screen (0,0 point of something). Scaling the spine object even when its in a container is at least predictable (scales accordingly). However, adjusting the group container's [x,y] doesn't move the spine object.

@shibekin69
Copy link
Author

shibekin69 commented Aug 31, 2017

Btw, I deal with large spine animations, spine width and heights that's anywhere between 2000 x 2000 to 3000 x 3000. And they're on the upper right quadrant of the spine editor, and my root bone's about 1000+ x and y pixels from the editor's origin. So there might be some weird problems that only appear when offsets are exaggerated because of this?

@shibekin69 shibekin69 changed the title [Spine-TS] Some Quirks on Group Container and Root [Spine-TS] Group Container and Root Bone Position Problem Aug 31, 2017
@shibekin69
Copy link
Author

This is probably related to the group.x and group.y not working right now with the spine-ts-position WIP build, I'm using the Juicy screen shake plugin. It doesn't shake the Spine objects along with the other stuff on screen.

@shibekin69
Copy link
Author

shibekin69 commented Aug 31, 2017

I've been playing around with different spine objects, and there's a weird x offset if there's horizontal white space between x = 0 up to the edge of your spine's images. I've only tested this with the spine stuff on the upper right quadrant for now. This can be remedied by multiplying anchor.x by -1.

Please see pic:

image

@shibekin69
Copy link
Author

shibekin69 commented Aug 31, 2017

Here are my observations for the other quadrants. Just an FYI. The most important I guess might be the upper right one, since that's where the PSD to Spine export script places the output.

It seems applying a negative / opposite anchor value only to the axis or axes that has this weird offset fixes the positioning.

Btw, I'm still using:

skeleton.x = -1* skeleton.bones[0].x
skeleton.y = 1 * skeleton.bones[0].y

To cancel out the root's (x,y) position. This assumes the object is in the upper right quadrant.

image

If it helps you someway, I have something like this in my code:

if (sprite.type === 'spine') {
  if (sprite.children.length > 0) {
    if (sprite.children[0].constructor.name === 'Spine') {
      //console.log('Sprite.x: ' + sprite.x);
      //console.log('Sprite.y: ' + sprite.y);
      sprite.children[0].x = sprite.x;
      sprite.children[0].y = sprite.y;

      //TEMP: Anchor Corrector
      if (sprite.children[0].skeleton.bones[0].x > 0 && sprite.children[0].skeleton.bones[0].y > 0) {
        // Upper right quadrant
        // X correction
        sprite.children[0].anchor.x *= -1;

      } else if (sprite.children[0].skeleton.bones[0].x < 0 && sprite.children[0].skeleton.bones[0].y > 0) {
        // Upper left quadrant

      } else if (sprite.children[0].skeleton.bones[0].x < 0 && sprite.children[0].skeleton.bones[0].y < 0) {
        // Bottom left quadrant
        // Y correction
        sprite.children[0].anchor.y *= -1;

      } else if (sprite.children[0].skeleton.bones[0].x > 0 && sprite.children[0].skeleton.bones[0].y < 0) {
        // Bottom right quadrant
        // X and Y correction
        sprite.children[0].anchor.x *= -1;
        sprite.children[0].anchor.y *= -1;
      }

    }
  } else if (sprite.constructor.name === 'Spine') {
    sprite.x = sprite.x;
    sprite.y = sprite.y;

    //TEMP: Anchor Corrector
    if (sprite.skeleton.bones[0].x > 0 && sprite.skeleton.bones[0].y > 0) {
      // Upper right quadrant
      // X correction
      sprite.anchor.x *= -1;

    } else if (sprite.skeleton.bones[0].x < 0 && sprite.skeleton.bones[0].y > 0) {
      // Upper left quadrant

    } else if (sprite.skeleton.bones[0].x < 0 && sprite.skeleton.bones[0].y < 0) {
      // Bottom left quadrant
      // Y correction
      sprite.anchor.y *= -1;

    } else if (sprite.skeleton.bones[0].x > 0 && sprite.skeleton.bones[0].y < 0) {
      // Bottom right quadrant
      // X and Y correction
      sprite.anchor.x *= -1;
      sprite.anchor.y *= -1;
    }
  }
}

@AleBles
Copy link
Member

AleBles commented Aug 31, 2017

Pfff this is going in baby steps xD, Should be ok now for the Y axis, on to X ;x

@shibekin69
Copy link
Author

Proposed fix whilst keeping the adjustable anchor here:

6241a74#commitcomment-24040207

@ankush-badyal
Copy link

Hi,
Is this fixed? if yes then in which branch?

@shibekin69
Copy link
Author

No idea, I'm confused myself lol

@likeavenus
Copy link

I had a similar problem when I attached a hitbox to a brush bone and the Y value was mirrored. I think that spine can solve this problem, but I don't know how yet

// update method
const hitboxCoords = { x: leftArm.worldX, y: leftArm.worldY * -1 + this.game.canvas.height - 10 };
this.boy.physicsBody.position.copy(hitboxCoords);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Development

No branches or pull requests

4 participants