SpriteGrabber class -SpriteSheets in 2 lines

@delta

I am trying to fully understand what you exactly mean. Why not, for example, just register the frames as individual clips of 1 frame and also make a table “iClip” that gives a clip name for a specific integer (the index number of the table).
[lua]framsheet=grabber.grabSheet(“myFrames”)
sprite=frameSheet.grabSprite("",true, { clip1={1,1,1000,1}, … clip5={5,1,1000,1} } )
iClip={“clip1”, “clip2” … “clip5”}[/lua]

Then, inside your game logic functions, you just produce
[lua]r=math.random(1,5) [/lua]
and call:
[lua]sprite:playClip(iClip[r])[/lua]

There are many other ways to implement this.
But, is that what you exactly want? [import]uid: 7356 topic_id: 3197 reply_id: 10129[/import]

Yes, I probably overcooked the example a bit there. I just need a way to turn an integer value into a text version, be it an X coordinate or whatever. To that end, would an integer converted to a string, as in my last message, be usable as the image file name ?
(I’m not able to get on Corona right now to test this) [import]uid: 7396 topic_id: 3197 reply_id: 10133[/import]

Ok…

From the Lua manual: http://www.lua.org/manual/5.1/manual.html
“Lua provides automatic conversion between string and number values at run time. Any arithmetic operation applied to a string tries to convert this string to a number, following the usual conversion rules. Conversely, whenever a number is used where a string is expected, the number is converted to a string, in a reasonable format.”

So, the following, for example, runs like a charm:
[lua] umaSheet=grabber.grabSheet(“uma”)
uma=umaSheet:grabSprite("",true,{[1]={1,8,1000,0}})
uma:playClip(1)[/lua]

Also, have in mind that:

  1. You can always concatenate a dump string with a number to force a type conversion (but do this only when you don’t have any alternatives, because it is slow in a loop) e.g. “”…(1) outputs “1”

  2. You can converse a number to a string with tostring(number) e.g. tostring(1) outputs “1” [import]uid: 7356 topic_id: 3197 reply_id: 10144[/import]

That sounds promising. I’ve used a similar system in other dev programs but often had to concatenate the output, which I really wanted to avoid. I really need to get this coded in Corona to see it in action but it sounds like it should do what I’m after.

Thanks for the input, and SpriteGrabber of course, [import]uid: 7396 topic_id: 3197 reply_id: 10146[/import]

[ref: http://developer.anscamobile.com/forum/2010/11/11/sprite-sheet-returning-incorrect-physics-body-dimensions]

hey magenda,

this is great!

the trouble i’m having is my physics addBody thinks the square sprites are all the same size from what I can tell. I’m not sure how i need to get this info or whether it’s a corona bug because it’s not coming from a single image. they all come back as 60x60. I am using texture packer to pack differently shaped sprites

this may be because somewhere in my spritesheet i have one “crate.png” that is 60x60. i also have a “crateA.png” that is 90x90 and a "createB.png’ that is 53x30. The rest of my sprites aren’t called “crate…”

thanks for any advice

I think it’s a corona bug not a spritegrabber bug

regards
j

[import]uid: 6645 topic_id: 3197 reply_id: 10735[/import]

@jmp909

It doesn’t sound like a bug. Could you please post the code you use to make a sprite and add it as physics object?

(I follow the other topic too, so feel free to answer wherever you want) [import]uid: 7356 topic_id: 3197 reply_id: 10755[/import]

it’s just the normal code

eg

[lua]local spriteSet = sprite.newSpriteSet(mySpriteSheet,1,1)[/lua]

i’ll try and make a simple example.

it’s noted as a bug by someone else as well
https://developer.anscamobile.com/issues/3491

by the way could we have a SpriteGrabber flag that says just grab a single sprite please? (this would stop it checking for any sprites with the same name prefix). I made this amend myself but it would be better to be an official release :wink:

thanks
j [import]uid: 6645 topic_id: 3197 reply_id: 10769[/import]

@jmp909

You can extract a single framed sprite (even if the frame is part of an animation sequence) like this:
[lua]mySheet=grabber.grabSheet(“uma”)
hero=mySheet:grabSprite(“03”,true,{openlegs={1,1,1,1} })[/lua]
Regarding the “bug”, you have right, it is indeed an SDK bug. The second frame determines the dimensions of all frames. But it only last for 1 cycle.

PROBLEM:
[lua]grabber=require(“SpriteGrabber”)
mySheet=grabber.grabSheet(“uma”)
horse=mySheet:grabSprite(“03.png”,false,{openlegs={1,1,1,0} })
print(“On creation :”…horse.stageWidth…" * "…horse.stageHeight)
timer.performWithDelay(1, function() print("After 1ms: “…horse.stageWidth…” * "…horse.stageHeight) end,5)[/lua]

I am working on a workaround, which should work but it doesn’t!
This makes me believe that what we see is not what really happens. Still investigating…

WANNABE WORKAROUND:
[lua]function debugSprite(sprite,clip)
sprite:show() --the object enters the stage only here
sprite:playClip(clip)
–add physics here
print(“On creation :”…sprite.stageWidth…" * "…sprite.stageHeight) --but this returns false dimensions again !!!
timer.performWithDelay(1, function() print("After 1ms: “…sprite.stageWidth…” * "…sprite.stageHeight) end,5)
end
grabber=require(“SpriteGrabber”)
mySheet=grabber.grabSheet(“uma”)
horse=mySheet:grabSprite(“03.png”,false,{openlegs={1,1,1,0} }) --object is still invisible here, but it performs the first “animation” cycle.
timer.performWithDelay(10, debugSprite(horse,“openlegs”),1) --object gets visible after the first cycle[/lua]

EDIT: I have edited a mistake in my code, but the workaround still doesn’t seem to catch the actual problem. It is just like print() works differently inside a timer and as an individual statement. Weird! [import]uid: 7356 topic_id: 3197 reply_id: 10777[/import]

what we could do is parse the lua file and override the physics shape with the relevant height and width. this works when i use a custom radius/polygon for a sprite, so i just need to make a function to get the data from the spritesheet.lua file

you could actually add this to your SpriteGrabber class presumably.

then attach eg a sgRect table dynamically to returnSprite

[lua]returnSprite.sgRect = self:getSpriteGrabberRectangle(returnSprite)
return returnSprite[/lua]

[lua]mySheet=grabber.grabSheet(“whatever”)
mySprite = mySheet:grabSprite(…)

– for rectangles
physic.addBody(mySprite, { shape = mySprite.sgRect })

– otherwise for eg circles we can pass our own shape
– or calculate the circle radius from the sgRect
– ie:
– shape = myUtils.getRadius(mySprite.sgRect)[/lua]

(see the end of http://developer.anscamobile.com/reference/index/physicsaddbody for their squareShape example)

[import]uid: 6645 topic_id: 3197 reply_id: 10778[/import]

I’ve embedded jmp909’s suggestion into SpriteGrabber. You can download it again from Code Section.
WHAT IS NEW: Having a single-framed sprite, you can call sprite:getShape() to get what physics:addBody() is waiting as a “shape”, to override the sprites dimensions.

WHY USE sprite:getShape() ?
Because there is bug in SDK regarding sprites’ dimensions, which falsifies the resulting dimensions of a physics enabled sprite. With this method, you override the SDK returned dimensions and get the actual ones from the spritesheet.lua file, which you then give to physics.addBody() to apropriatelly make the physics object.

REQUIREMENT: The sprite has to be single-framed for the getShape() function to be created. Otherwise, it has no real meaning to get the “shape” of a multi-framed animation series (in which the individual frames can be of different sizes).

CAVEATS:

  1. When scaling the sprite the shape doesn’t get in sync.
  2. There is an offset of some pixels which I suspect is affected by this other bug. Probably, the the reference point of the sprite is always that of the second frame in the spritesheet, and because of this the shape is not placed precisely (sometimes it gets significantly shifted). Not sure yet…

EXAMPLE:

[lua]grabber=require(“SpriteGrabber”)
mySheet=grabber.grabSheet(“uma”)
horse=mySheet:grabSprite(“05”,true)

physics = require “physics”
physics.start()
physics.setGravity(0,0)
physics.setDrawMode( “hybrid” ) --so you can see the shape outline
physics.addBody( horse, { density = 1.0, friction = 0.3, bounce = 0.2, shape=horse:getShape() } ) [/lua]

[import]uid: 7356 topic_id: 3197 reply_id: 10791[/import]

great, this worked for me…

im my Actor class
[lua] sprite = mySheet:grabSprite(img,true)
sprite.parsedShape = sprite:getShape()[/lua]

in my main class
[lua]obj = BallActor.new(x,y,spritedef.src)

– get my sprite definitions (from elsewhere in this class)
local bodydef = spritedef.bodydef

– if i’m not explicitly specifying what the shape is already
if(bodydef.shape == nil and bodydef.radius==nil) then

– get the shape from the new SpiteGrabber class
local spriteShape = obj.sprite.parsedShape

bodydef.shape = spriteShape

end
physics.addBody(obj.sprite,bodydef)[/lua]

thanks again
j. [import]uid: 6645 topic_id: 3197 reply_id: 10795[/import]

Hi,
I am using TexturePacker along with SpriteGrabber, what the guide didn’t tell me was that this line:

local hero=mainSprites:grabSprite(“hero”,true,{ breath={1,8,1000,0}, jump={9,8,700,1}})

assumes the texturepacker spritesheet is in order, which is not always the case, you might have to reorder the data sprite sheet
[import]uid: 11334 topic_id: 3197 reply_id: 12842[/import]

@newbie101

I actually had in mind to write this to the guide but then I saw that if you leave TexturePacker / Zwoptex with the default settings both of them have the data alphabetically ordered and there is no real reason to order them otherwise. Am I wrong to this? What setting caused the different order in TP for you?
[import]uid: 7356 topic_id: 3197 reply_id: 12862[/import]

I did basic settings, I think the order is random, I tried generating other sprites and sometimes the order would be correct so I talked to the creator of TexturePacker, and he said the new texturepacker 2.1.0 will have an option to order the spritedata based on the file name, e.q: “Basic” + SortBy “Name” + “Order Ascending” so I guess 2.0 is not actually ordered? or it is naturally ordered (the order of file being processed)
[import]uid: 11334 topic_id: 3197 reply_id: 12885[/import]

I currently have TexturePacker version 2.00 rc3 installed and it works fine without any settings for ordering (same for Zwoptex). I am going to install the new version and report back the results. [import]uid: 7356 topic_id: 3197 reply_id: 12891[/import]

Hi,

I updated TexturePacker which should now work perfectly with SpriteGrabber. Please report back any problems you find.

You can now create textures up to 2048x2048 in basic layout mode for free. It also supports creation of non power of 2 textures in PNG format. So if you have an animation with 10 23x43 sprites it’ll set them up in 230x43.

You can order the sprites by name, size and others.

There are several other features but I think these are the major ones for corona.

Cheers
Andreas

[import]uid: 9611 topic_id: 3197 reply_id: 13239[/import]

Some SpriteGrabber news…

There is a SpriteGrabber v1.2 currently released in code section, which supports “on the fly blurriness elimination” (aka: always get crisp sprites, even if you have odd image dimension for width/height), after an idea of Amigoni. I still haven’t documented this and 2 other features already implemented in v1.2, so I apologize for this…

I am also thinking of releasing a v1.3 update that implements a super duper (yeah!) core feature, but I would like some feedback about whether you find it a good or …messy idea.

The new feature, which actually I already have implemented and I am currently beta-testing it in my own game, is called “Adaptive Layout”. In its essence it incarnates the “Desired Scenario” as I have described it here (with extra improvements, optional HD versions, any number of versions and full automation), which allows Universal-ready builds for games with spritesheets.

In a nutshell, Adaptive Layout is an alternative to Ansca’s “Dynamic Content Scaling”, and requires/supports “relative positioning” of sprites, which IMHO is the only real solution to get trully Universal-ready builds.
Adaptive Layout:

  1. Detects the device resolution the game is running on.

  2. Dynamically loads a provided spritesheet version (normal, HD, etc) which best fits the device, even if you have provided only 1-2 versions but there are dozens of possible device resolutions that don’t exactly fit your provided assets. It then makes corrective scaling to get sprites appearing the same on eye to any device resolution.

In other words, you make a High Definition version for your spritesheets, autoscale them down with a tool like TexturePacker to get a “normal” version and with them you are ready to go for any current/future iDevices and the dozens of Android devices, without caring about the involved resolutions.

  1. It requires “relative positioning” of sprites, which may seem an extra step but to my opinion is a best practice if you trully want to be to be Universal-ready, not only for 2-3 devices but for any current and future ones, regardless their width/height ratio (which makes Ansca’s “Dynamic Content Scaling” prune to blank stripes that break real “universability” on many devices, like iPad and Galaxy).

  2. It supports quick and easy relative positioning: instead of writing mysprite.x=240 (yuck!) you write mysprite.x=px(50) …meaning x=50% of the device width resolution. It doesn’t get easier/healthier !

I am also thinking of releasing this feature as an optional one, that when deactivated will provide automatic support for Scenario 3 (which is explained here and in the next 3-4 posts) that is based on Ansca’s Dynamic Content Scaling. Again it will be provided as a fully automated solution with the appropriate handling to be ready to work for spritesheets.

***

Now, help me on this: are you ready to invest on relative positioning (on sprites creation) to get perfect universability once and forever, or do you find “Adaptive Layout” as something messy and outside of SpriteGrabber scope? I am trying to understand whether Adaptive Layout would make SriteGrabber an awesome module or it would totally mess things up regarding the already hard to understand “Proper Scaling” thing in our beloved Corona SDK.

Feedback is much appreciated…

Regards
[import]uid: 7356 topic_id: 3197 reply_id: 14581[/import]

Does this introduce additional requirements from my side (TexturePacker)? Or is all you need already available for that?
[import]uid: 9611 topic_id: 3197 reply_id: 14586[/import]

@Andreas

Adaptive Layout already works nicely with TexturePacker, which is a lifesaver with its “Auto SD” feature!

Thanks for the high quality support you provide to the Corona community. [import]uid: 7356 topic_id: 3197 reply_id: 14595[/import]

Let me put my 2 cents in,

I think it’s a good feature, but you are solving a problem that corona should be solving.

Corona might in the future have an automated solution for publishing to more devices with less configuration for each, I am not sure how your solution would work into that. However, if you get every corona user to use your library, which is easy if it’s noob friendly, I can see you having the upper hand.

My suggestion: Release 2 versions? Basic and Advanced, there are developers who specifically target certain devices. There are also developers who want to cover as many devices as possible, having 2 options will enable them to pick and choose. Should corona solve what you are solving in Advanced, people can still use SpriteGrabber basic as it is currently being used.
Also, I might be wrong in this but isn’t positioning in corona already relative? I use object.x = constants in my current game, I use the simulator’s view as=> ipad, iphone, etc the position still works fine, am I missing something? Is px(coordinate) a function from SpriteGrabber?
EDIT: added my suggestion. [import]uid: 11334 topic_id: 3197 reply_id: 14606[/import]