Sprite Positioning and TexturePacker's "Trim" Function

Hi,

I’m nearing the end of development of my game, and have run into a strange problem positioning sprites in Corona.

Here’s the TexturePacker-generated Sprite Sheet, which has “Shape Outlines” enabled and uses “Trim” to remove white space and make the sprite sheet smaller:

[lua]local SheetInfo = {}

SheetInfo.sheet =

{

    frames = {

    

        {

            – BabyMushroom1_01@2x

            x=428,

            y=323,

            width=20,

            height=9,

            sourceX = 44,

            sourceY = 78,

            sourceWidth = 100,

            sourceHeight = 100

        },    

    – Frames 2 - 18 omitted to save space

    sheetContentWidth = 512,

    sheetContentHeight = 512

}

SheetInfo.frameIndex =

{

    [“BabyMushroom1_01@2x”] = 1,

    [“BabyMushroom1_03@2x”] = 2,

    [“BabyMushroom1_05@2x”] = 3,

    [“BabyMushroom1_07@2x”] = 4,

    [“BabyMushroom1_09@2x”] = 5,

    [“BabyMushroom1_11@2x”] = 6,

    [“BabyMushroom1_13@2x”] = 7,

    [“BabyMushroom1_15@2x”] = 8,

    [“BabyMushroom2_01@2x”] = 9,

    [“BabyMushroom2_03@2x”] = 10,

    [“BabyMushroom2_05@2x”] = 11,

    [“BabyMushroom2_07@2x”] = 12,

    [“BabyMushroom2_09@2x”] = 13,

    [“BabyMushroom2_11@2x”] = 14,

    [“BabyMushroom2_13@2x”] = 15,

    [“BabyMushroom2_15@2x”] = 16,

    [“BabyMushroom2_17@2x”] = 17,

    [“BabyMushroom2_19@2x”] = 18,

}

function SheetInfo:getSheet()

    return self.sheet;

end

function SheetInfo:getFrameIndex(name)

    return self.frameIndex[name];

end

return SheetInfo[/lua]

Here’s my code:

[lua]display.setStatusBar(display.HiddenStatusBar)

local testSpriteSheetInfo = require(“sprites.Baby_Mushrooms-Anim”)

local testSpriteSheet = graphics.newImageSheet(“sprites/Baby_Mushrooms-Anim.png”, testSpriteSheetInfo:getSheet())

local sequenceData = {

    {

        name=“test”,

        frames={1},

        loopCount=1

    },

}

local testSprite = display.newSprite(testSpriteSheet, sequenceData)

testSprite:setSequence(“test”)

testSprite:setReferencePoint(display.TopLeftReferencePoint)

testSprite.x = 0; testSprite.y = 0[/lua]

And here’s the output:

[sharedmedia=core:attachments:1368]

As you can see, the sprite is visually not at 0,0, but is a little to the right, and obviously a bit lower than it should be. I’m using build 1262, but have tried it in 2100 with V1 compatibility mode, and also 1202; all versions of Corona show it like this. Anyone have any ideas? We’re sprinting toward a deadline, and this is really slowing me down.

Thanks a lot!

  • David

Have you tried to position it on display.screenOriginX and display.screenOriginY

@primoz.cerar: Thanks for the reply! I printed out both display.screenOriginX and display.screenOriginY, and both said “-0”. I also tried positioning the sprite at display.screenOriginX and Y, and it looked exactly the same. I guess that indicates that there’s no added or cropped area to the screen that’s causing this.

For what it’s worth, this only seems to happen with sprite objects. For example, this code:

[lua]local testObj = display.newImageRect(“images/items/ExtHouse_Boot.png”, 77, 125)

testObj:setReferencePoint(display.TopLeftReferencePoint)

testObj.x = 0; testObj.y =0[/lua]

Produces this output:

[sharedmedia=core:attachments:1369]

Perfectly positioned in the top-left corner.

Is it possible that the sprite sheet isn’t trimmed as you expect?

Try putting an image in the sheet that doesn’t have to be trimmed and see where it ends up.

@primoz.cerar: Thanks for the idea. I trimmed the first frame in Pixelmator and remade the sprite sheet. Here’s the TexturePacker output for that frame:

[lua]frames = {

    

        {

            – BabyMushroom1_01@2x

            x=428,

            y=323,

            width=20,

            height=9,

        },[/lua]

And here’s the Corona output:

[sharedmedia=core:attachments:1370]

Worked great. I’m really at a loss here. It must have something to do with either how TexturePacker trims the sprite, or how Corona positions trimmed sprites. The original TexturePacker-trimmed frame code:

  1. {
  2.             – BabyMushroom1_01@2x
  3.             x=428,
  4.             y=323,
  5.             width=20,
  6.             height=9,
  7.  
  8.             sourceX = 44,
  9.             sourceY = 78,
  10.             sourceWidth = 100,
  11.             sourceHeight = 100
  12.         },  

Sorry but I can’t help you with that as I’m not familiar with texture packer but you can see that corona positions the image correctly I don’t know how the images are trimmed and if corona knows how to handle that.

@primoz.cerar: That’s alright, thank you for the suggestions!

Anyone else?

Hi @davidcondolora,

Have you specifically read the “Trimming Notes” section in the documentation? This should help clarify what’s going on, under the hood:

http://docs.coronalabs.com/guide/media/imageSheets/index.html#trimming

Hope this helps,

Brent

@Brent Sorrentino: I had read that doc, but thanks for referring me to it again. This time, this phrase stood out to me as the key:

Notice how in both frames, the sourceWidth and sourceHeight parameters match the size of the original, untrimmed frames. This imaginary “canvas” is what you must consider when positioning a trimmed image on the screen. Effectively, the image will be positioned in respect to the center point of the untrimmed frame size.

This makes sense to me, and before I reset the reference point it does indeed behave such that when I position the trimmed sprite, it uses the center point of the untrimmed sprite. What confuses me is how it behaves when I set the reference point to TopLeftReferencePoint. It neither positions it according to the untrimmed size or the trimmed size, but somewhere in between.

For example, this code:

[lua]display.setStatusBar(display.HiddenStatusBar)

local testSpriteSheetInfo = require(“sprites.Baby_Mushrooms-Anim”)

local testSpriteSheet = graphics.newImageSheet(“sprites/Baby_Mushrooms-Anim.png”, testSpriteSheetInfo:getSheet())

local sequenceData = {

    {

        name=“test_1”,

        frames={1},

        loopCount=1

    },

    {

        name=“test_2”,

        frames={8},

        loopCount=1

    },

}

local testSprite_1 = display.newSprite(testSpriteSheet, sequenceData)

local testSprite_2 = display.newSprite(testSpriteSheet, sequenceData)

testSprite_1:setSequence(“test_1”); testSprite_2:setSequence(“test_2”)

testSprite_1:setReferencePoint(display.TopLeftReferencePoint)

testSprite_2:setReferencePoint(display.TopLeftReferencePoint)

testSprite_1.x = 0; testSprite_1.y = 0

testSprite_2.x = 0; testSprite_2.y = 0

testSprite_1.alpha = .5; testSprite_2.alpha = .5[/lua]

Produces this output: 

The large mushroom is the same size as the untrimmed small mushroom that you can (hopefully) see through it. The small one is not positioned at 0,0 from a visual perspective, and if I let it play its animation sequence and arrive at the final untrimmed frame, it looks like this:

 

The grown small mushroom is neither centered around the untrimmed frame’s center point, nor is it TopLeft, as I would expect having given it a reference point of TopLeft.

I have a workaround (leave the reference point in the center, and adjust my coordinates by half the untrimmed frame’s width and height), but I still don’t know why this is happening, and would like to figure it out.

Thanks a lot!

  • David

Hi David,

If I recall from last time I was testing this, if you’re using trimmed frames with the trim information from TexturePacker or otherwise, you must position using the center reference/anchor point… you can’t use non-center in this case if you want to achieve perfect positioning. It sounds like you’ve figured out a method though. :slight_smile:

Brent

@Brent Sorrentino: Thanks! I’ll be using Center from now on. I was trying to use TopLeft to make it easier to match the layout of the scene in Sketch (vector graphics app), which gives me coordinates based on TopLeft, but using Center I can just add half of the width and height to the coordinate and it will match perfectly. A bit of a workaround, but not bad.

Thanks again!

  • David

Have you tried to position it on display.screenOriginX and display.screenOriginY

@primoz.cerar: Thanks for the reply! I printed out both display.screenOriginX and display.screenOriginY, and both said “-0”. I also tried positioning the sprite at display.screenOriginX and Y, and it looked exactly the same. I guess that indicates that there’s no added or cropped area to the screen that’s causing this.

For what it’s worth, this only seems to happen with sprite objects. For example, this code:

[lua]local testObj = display.newImageRect(“images/items/ExtHouse_Boot.png”, 77, 125)

testObj:setReferencePoint(display.TopLeftReferencePoint)

testObj.x = 0; testObj.y =0[/lua]

Produces this output:

[sharedmedia=core:attachments:1369]

Perfectly positioned in the top-left corner.

Is it possible that the sprite sheet isn’t trimmed as you expect?

Try putting an image in the sheet that doesn’t have to be trimmed and see where it ends up.

@primoz.cerar: Thanks for the idea. I trimmed the first frame in Pixelmator and remade the sprite sheet. Here’s the TexturePacker output for that frame:

[lua]frames = {

    

        {

            – BabyMushroom1_01@2x

            x=428,

            y=323,

            width=20,

            height=9,

        },[/lua]

And here’s the Corona output:

[sharedmedia=core:attachments:1370]

Worked great. I’m really at a loss here. It must have something to do with either how TexturePacker trims the sprite, or how Corona positions trimmed sprites. The original TexturePacker-trimmed frame code:

  1. {
  2.             – BabyMushroom1_01@2x
  3.             x=428,
  4.             y=323,
  5.             width=20,
  6.             height=9,
  7.  
  8.             sourceX = 44,
  9.             sourceY = 78,
  10.             sourceWidth = 100,
  11.             sourceHeight = 100
  12.         },  

Sorry but I can’t help you with that as I’m not familiar with texture packer but you can see that corona positions the image correctly I don’t know how the images are trimmed and if corona knows how to handle that.

@primoz.cerar: That’s alright, thank you for the suggestions!

Anyone else?

Hi @davidcondolora,

Have you specifically read the “Trimming Notes” section in the documentation? This should help clarify what’s going on, under the hood:

http://docs.coronalabs.com/guide/media/imageSheets/index.html#trimming

Hope this helps,

Brent

@Brent Sorrentino: I had read that doc, but thanks for referring me to it again. This time, this phrase stood out to me as the key:

Notice how in both frames, the sourceWidth and sourceHeight parameters match the size of the original, untrimmed frames. This imaginary “canvas” is what you must consider when positioning a trimmed image on the screen. Effectively, the image will be positioned in respect to the center point of the untrimmed frame size.

This makes sense to me, and before I reset the reference point it does indeed behave such that when I position the trimmed sprite, it uses the center point of the untrimmed sprite. What confuses me is how it behaves when I set the reference point to TopLeftReferencePoint. It neither positions it according to the untrimmed size or the trimmed size, but somewhere in between.

For example, this code:

[lua]display.setStatusBar(display.HiddenStatusBar)

local testSpriteSheetInfo = require(“sprites.Baby_Mushrooms-Anim”)

local testSpriteSheet = graphics.newImageSheet(“sprites/Baby_Mushrooms-Anim.png”, testSpriteSheetInfo:getSheet())

local sequenceData = {

    {

        name=“test_1”,

        frames={1},

        loopCount=1

    },

    {

        name=“test_2”,

        frames={8},

        loopCount=1

    },

}

local testSprite_1 = display.newSprite(testSpriteSheet, sequenceData)

local testSprite_2 = display.newSprite(testSpriteSheet, sequenceData)

testSprite_1:setSequence(“test_1”); testSprite_2:setSequence(“test_2”)

testSprite_1:setReferencePoint(display.TopLeftReferencePoint)

testSprite_2:setReferencePoint(display.TopLeftReferencePoint)

testSprite_1.x = 0; testSprite_1.y = 0

testSprite_2.x = 0; testSprite_2.y = 0

testSprite_1.alpha = .5; testSprite_2.alpha = .5[/lua]

Produces this output: 

The large mushroom is the same size as the untrimmed small mushroom that you can (hopefully) see through it. The small one is not positioned at 0,0 from a visual perspective, and if I let it play its animation sequence and arrive at the final untrimmed frame, it looks like this:

 

The grown small mushroom is neither centered around the untrimmed frame’s center point, nor is it TopLeft, as I would expect having given it a reference point of TopLeft.

I have a workaround (leave the reference point in the center, and adjust my coordinates by half the untrimmed frame’s width and height), but I still don’t know why this is happening, and would like to figure it out.

Thanks a lot!

  • David

Hi David,

If I recall from last time I was testing this, if you’re using trimmed frames with the trim information from TexturePacker or otherwise, you must position using the center reference/anchor point… you can’t use non-center in this case if you want to achieve perfect positioning. It sounds like you’ve figured out a method though. :slight_smile:

Brent