Game Development Community

Getting started with TexturePacker

by RJAG Entertainment · in Torque 2D Beginner · 02/23/2013 (6:07 am) · 37 replies

I am quite tired as I write this, so perhaps I am simply missing something obvious, but I figured it would be best if I post this before I go to sleep, in hope of an answer by the time I begin work again. I have spent all day and night attempting my best to understand how to use TorqueScript and its basic functions.

Have I missed documentation or simple understanding of T2D MIT's implementation of TexturePacker and Animation?
I went through the youtube videos and browsed the documentation and various toys, in attempt to figure out how to animate my character correctly. From the youtube tutorials, I have edited them and my understanding of everything to get my sprite animated. It animates perfectly, but...


PROBLEM: It doesn't animate at the correct offsets and changes in Height/Width. Obviously, since nowhere in my code does it ask for the offsets.

The character warps, due to the fact each frame is a different Width/Height (see below), but the sprite is ALWAYS stretched to (10.8 20) (the size of the first frame scaled correctly).

I can't tell if the offset (TexturePacker trimming) works or not, as I currently get too much warping of the image Size to tell.



I have literally just made a new "./ToyAssets/1/assets/animations/PoisonCloudWobble.asset.taml" by copy/pasting the file and changing the name from "PoisonCloudWobble" to "PoisonCloudWobble22". The animation is 24 frames.

//~~~~~~~ "./ToyAssets/1/assets/animations/PoisonCloudWobble22.asset.taml"
<AnimationAsset
    AssetName="PoisonCloudWobble22"
    Image="@asset=ToyAssets:Human_Walk_SE.asset"
    animationFrames="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24"
    animationTime="2"
    animationCycle="1"
	RandomStart="1"
     />


//~~~~~~~ "./ToyAssets/1/assets/images/Human_Walk_SE.asset.png"

//~~~~~~~ "./ToyAssets/1/assets/images/Human_Walk_SE.asset.taml"
<ImageAsset
    AssetName="Human_Walk_SE.asset"
    ImageFile="@assetFile=Human_Walk_SE.asset.png">	
	<ImageAsset.Cells>
		<Cell Offset="216 202" Width="108" Height="200"/>
		<Cell Offset="326 202" Width="100" Height="200"/>
		<Cell Offset="186 2" Width="90" Height="198"/>
		<Cell Offset="278 2" Width="88" Height="198"/>
		<Cell Offset="2 2" Width="84" Height="196"/>
		<Cell Offset="180 404" Width="88" Height="202"/>
		<Cell Offset="2 810" Width="94" Height="206"/>
		<Cell Offset="98 812" Width="98" Height="206"/>
		<Cell Offset="370 610" Width="102" Height="204"/>
		<Cell Offset="178 608" Width="104" Height="202"/>
		<Cell Offset="376 406" Width="104" Height="202"/>
		<Cell Offset="270 404" Width="104" Height="202"/>
		<Cell Offset="198 814" Width="102" Height="206"/>
		<Cell Offset="302 816" Width="100" Height="206"/>
		<Cell Offset="404 816" Width="96" Height="206"/>
		<Cell Offset="88 604" Width="88" Height="204"/>
		<Cell Offset="284 608" Width="84" Height="204"/>
		<Cell Offset="428 202" Width="80" Height="202"/>
		<Cell Offset="2 602" Width="84" Height="202"/>
		<Cell Offset="2 400" Width="86" Height="200"/>
		<Cell Offset="90 402" Width="88" Height="200"/>
		<Cell Offset="88 2" Width="96" Height="196"/>
		<Cell Offset="2 200" Width="104" Height="198"/>
		<Cell Offset="368 2" Width="104" Height="198"/>
		<Cell Offset="108 202" Width="106" Height="198"/>
		
	</ImageAsset.Cells>
</ImageAsset>


//~~~~~~~ "main.cs"
//Same as youtube tutorial, with the exception of "10.8 20" replacing %size
//Create a SPRITE
   %position = "0 0";
   %sprite = buildIsoSprite(%position, "10.8 20");








Obviously my logic should be %size as a variable of some sort. But before I go into thinking of how I should approach this, my tired eyes wonder if there already is a simple way to do this that I am just missing.

TexturePacker .taml doesn't look anything like the Toy's animation or image .taml files, given the offset and changing width.

It is also a bit confusing that it says "ImageAsset" instead of "AnimationAsset" in the created TexturePacker output .taml files.


I assume "TexturePacker" support means an extremely easy way to start up TexturePacker, output to Torque2D MIT format, and then just type a few lines of code and WALLAH! Animated sprite from a trimmed spritesheet! This is why I figure I'm missing something obvious.

Are there any examples or Toys I am missing?
Thank you very much! :)
Page «Previous 1 2
#1
02/23/2013 (6:45 am)
Texture Packer's output is an ImageAsset. An animation asset just tells the system which image asset and which frames to use; the ImageAsset contains the image file and frame definitions.

This sounds like a bug. The engine is doing exactly what I would expect it to do - stretching the texture to fit the sprite - when in this instance it most certainly should not. It should blit the cell into the center of a padded image frame before proceeding to display that frame on the sprite object. Perhaps you've found some special edge case....
#2
02/24/2013 (7:32 pm)
I took a few minutes to briefly look for the TexturePacker code in the engine. I couldn't find it with a quick search or browse in a few classes.

Would you happen to know what files the code is in? If not, I'm sure I'll find it when I get more time to actually work on it.

Hopefully I can fix the problem and/or improve TexturePacker support and then push it to the potential update on github. I am no professional, but I have worked several times with implementing TexturePacker into other engines including my own creation, so I should be able to fix it without messing things up, hehe. It's probably not much of a bug anyway.

I am willing to fix it myself if I have to, to get a quick fix. Just to note though, it'll probably take me quite a bit longer than anyone else. Reading other's code is a nightmare for amateurs. This MIT (or at least available source) is always the way to go though. I dropped a lot of engines because I couldn't have the source: a requirement to fix the engine's bugs or add in a nice feature. I feel so fortunate to have come looking at T2D right when it comes out at MIT. I remember when I first took a look at it- it was one of the first attempts I had at making games, and I loved it. I only dropped it due to two big things, which are now no longer a problem. Not sure if I'll stay, because I have to figure out if it's worth ditching my custom engine for- but I think it probably is.

I also really, really, REALLY like the idea of bettering the engine by releasing modules or adding to the open source engine. Of course, I'm sure someone will beat me to adding in real-time multiplayer, but if not, I'll eventually have it implemented in with my tile based module!

Exciting, for several reasons. Not just for personal game development, but for the opportunity to contribute. If I were a professional programmer, I'd be contributing a hell of a lot "just because" or perhaps "out of spite" for the trolls over at Unity (barf). I am actually a bit disappointed I won't be able to contribute as much as I wish I could.
#3
02/24/2013 (8:02 pm)
I believe Richard is suggesting that the bug (if it really is a bug) is within T2D, and the Sprite class, not TexturePacker.

T2D looks to be stretching/shrinking your source texture cell into your destination render area (sprite size). Since your cells are all different sizes, it is skewing the texture cell on the different frames.

I'm not sure if a Sprite is really designed to handle an animation set of different sized cells. It would have to resize itself on each frame, which would affect its Box2D properties, etc.

At best, it could support a max cell width/height, and any cell under that should get rendered into the center of the destination with no stretch.


#4
02/24/2013 (8:42 pm)
To start, I figured I would figure out what was going on first. I edited the .taml to set Width/Height to be a constant 108,200 on every frame.

This stopped the warping. Unfortunately, this was also the offset for each individual frame within the spritesheet.

So instead of having an offset for X/Y, it seems the code uses Height/Width as the offset. The actual Height/Width being the entity's %size.

Meaning it takes every frame, and makes sure ONLY that frame is drawn- (correct logic) but does so by stretching or shrinking each individual frame to fit the sprite entity, if it is smaller than the largest frame.

I think. I tried setting the Width/Height constant to the SMALLEST frame integers and the character stops warping, but has the larger frames cut off. If I set the Width/Height constant to the LARGEST frame integers then the smaller frames show other frames due to it showing more of the spritesheet.

So obviously the Width/Height in the TexturePacker output are correct.

That's when I noticed the TexturePacker's output is missing the offset values when using trimming.

Normally, TexturePacker outputs the following information into a .xml


FrameNumber
X of frame within spritesheet (top left point of RECT)
Y of frame within spritesheet (top left point of RECT)
Width of frame within spritesheet (bottom right point of RECT)
Height of frame within spritesheet (bottom right point of RECT)

Offset of X (how much to offset the image based on trimming)
Offset of Y (^see above)


This would mean that the bug isn't in T2D, but in the TexturePacker output file.


//"Exporter.xml"
//LINE 32
<supportsTrimming>true</supportsTrimming>


Should be
<supportsTrimming>false</supportsTrimming>

Torque2D MIT does NOT support trimming with TexturePacker.
Turning it off should solve the problem.

**Feature Request needs to be added to make it compatible with Trimming (Offset X & Offset Y)

Correct me if I'm wrong. I had to rush this due to the fact I wasn't suppose to be working on this :P




ALSO TO NOTE:
The TexturePacker output file results in
////ImageFile="@assetFile=#Human_Walk_SE.asset.png">
This crashes T2D with an error because the "#" should not exist.

////ImageFile="@assetFile=Human_Walk_SE.asset.png">
...........................................^delete
#5
02/24/2013 (8:46 pm)
I will try to upload the new /tools/TexturePacker/T2DMIT/ "exporter.xml" and "template.asset.taml" to github when I have more time.

All I did was set

1)<supportsTrimming> false (exporter.xml)
2) delete the # (template.asset.taml)


Unless I'm mistaken, this corrects the problem because the problem doesn't exist within T2D, it exists in the TexturePacker custom output file. T2D wasn't suppose to support TRIMMING.

Unfortunate that the problem was that T2D doesn't support trimming :(
Adds so much extra overhead for me, but it's certainly not a reason to abandon the engine, and nothing that can't be added later. From what I saw in the source code though, the amount of work it would take to add in TRIMMING is a bit more than I thought since it requires adding in offsets for the rendered image but not offsetting the entity itself.

At least that explains why I couldn't find it in the source code, LOL
#6
02/25/2013 (1:59 am)
I can confirm this was exactly the problem. Solved. I tried to sync with Github but had some trouble, so I just made it an open issue. Extremely simple fixes.

Unfortunately, even after getting everything right, it seems as though my animations are not working as smoothly as they should. There is a small "jerk" in T2D that I do not find in other engines or render methods.

While I'm not really sure what is causing this, I am beginning to realize I am still probably better off going back to work on my own implementation of an 2D tile based isometric engine with SDL. I am beginning to see quite a bit of trouble with T2D ('trouble' as in, what I'd normally have to go through in any other engines or my own creation, making T2D less appealing) and since most of my code is logic for tiles, I have my doubts this engine would benefit me :(

Maybe it's just me, and the fact I already spent quite a big headache fixing animation and texture flickering in SDL, and before that having some big problems with it in XNA (hence why I switched to SDL. That and some awful performance with XNA and the fact the large amount of formal programming I learned after quitting XNA was mostly C++). I'm just burned out trying to fix basic rendering, and it tears at any excitement I have with T2D just to see I'll have to dig deep again to fix it. After so much trouble with flickering and jitters with SDL- and solving all of it to make it render perfectly, I am just ready to move on with development. As they say, if it (SDL) aint broke, don't fix it (switch to T2D).

Not that T2D isn't awesome, but that editing source code or adding features to code written by someone else is extremely alien to me. It takes me 10x-100x longer to mess with T2D's engine than anything I'd have made myself since T2D is foreign code. Since I am already a very slow programmer, this is just really rough for me. Then you have learning an entirely new scripting language... bleh. Especially when SDL seems to be just as simple (if not more simple) and/because I already have a lot of the tile logic and animation with TexturePacker implemented.

I am beginning to realize there really aren't any shortcuts to game development. Which makes me ponder why even have game engines in the first place except to create extremely simple sidescrollers or puzzle games. This and seeing some awkward animation in my fixed tests just bummed me out a lot.
#7
02/25/2013 (2:02 am)
In the end, I believe you're talking about a single type within the engine, namely "Sprite" and yes, it takes the frame region from an ImageAsset and renders that to the "size" you specify. This would apply to other types like the CompositeSprite.

Both these types (and others) inherit from SpriteProxyBase which performs the actual work which is trivial BTW.

You are obviously free to change how this works, add an option etc.

There are probably other ways to specify how to constantly size frames but one method that comes to mind might be to specify a scaling vector for frames on a sprite. This would probably work by being able to state the pixels size that relates to the size you specify. Any frames smaller than that would therefore appear smaller, larger ones larger etc.

As to how to render those frames which are larger/smaller than the sprites size then I guess you could just use centering or expose a couple of alignment arguments i.e left/center/right and top/center/bottom.

Because most of the things that render use the same base type, it could be added there and exposed in places like SpriteBase and SpriteBatchItem.

... and yes, that "#" was supposed to be removed when that particular character was removed from the ImageAsset, sorry about that. In the end, the TexturePacker file you see there took about 30 minutes of my time when I tested it. Everything you see there was just a preliminary test so thanks for catching those problems.

#8
02/25/2013 (2:06 am)
Thank you for the reply.

I've thought of a few ways to do quick fixes, and I got excited for a second with the idea of actually adding in a new feature to T2D.

But I'm just burned out being stuck at such low level for so long. It's been months just working with SDL to get animation, rendering, and a (rather intelligent) tile based world working perfectly. I really just want to move on and actually have something to show for all the headaches and tired eyes, lol.
#9
02/25/2013 (2:08 am)
Well as busy as I am, tell me how I could possibly help and if it's possible for me to find the time, I'll help.
#10
02/25/2013 (2:18 am)
Alright, well that is very kind of you to offer your help when you really don't have the time to. Since I've already given T2D a good portion of my week, I see no reason why to abandon it entirely before seeing what it can do.

For now, it's really not a big deal at all to not have trimming. It's not a problem to use photoshop to automate crop a few hundred images (trim them myself before packing). Later on, when the images become thousands it becomes a bigger problem but that's way later in the future. This definitely isn't a high priority feature to support TexturePacker's trimming.

The animation being a bit glitchy is probably not that big of a deal either. I'm sure if I dig deeper I can fix it, probably my own fault or some small option I'm missing. Who knows, I might have just been so tired I forgot a frame. Not a big deal either. Nothing that will stop me from prototyping anyway.

I think I'll spend some time trying to make a "Isometric Tile Map" module. It'll help me test all I know and let me see what T2D is like. I admit it's probably quite a bit easier to implement animation and movement in T2D than it would be otherwise, which is very tempting. I also am a bit giddy about the idea of using the GUI to alter said tilemap and see it happen in realtime. Being able to hit "reload toy" is so much more awesome than having to build/run (F9) every time I want to play around.
#11
02/25/2013 (2:29 am)
Glad you're sticking with it, I know how it feels to be so burned on a project.

T2D is pretty solid in many areas however it's probably still in its infancy for certain features but being open-sourced helps us improve that situation and collaborating to come up with features that could suit a lot of folks is something I'm personally passionate about.

So to be clear, what you want is a method to import differently sized images but have some way to render all those frames uniformly independent of a sprites absolute size?

I think it'd be nice to have it somehow mathematically linked to the sprites size.

This is analogous to how you'd set backgrounds on your OS desktop where you have scale-to-fit (which is what most sprite-based things in T2D do now but can distort the images if they're are not drawn for that size) but you seem to want other modes (or just a specific mode) like center-fit etc where the sprites size is analogous to the desktop resolution.


#12
02/25/2013 (7:47 am)
CompositeSprite has built in support for laying out iso tiles. You can also look at my TMX map repo on GitHub for something a bit more integrated.

It supports iso and orth TMX maps. My support is designed to then drop rendered movable/animated sprite objects into the right scene layer to render on the map.

#13
02/25/2013 (3:16 pm)
I render my 2D sprites from 3D models, and for convenience all of my images are always in the power of 2 (typically 512x512) and have tons of transparency around them. I severely doubt others would handle it the same way though. The idea is still universal though, as Trimming a very powerful and I'd imagine very popular feature in TexturePacker. I would discourage implementing it for my own needs, but would encourage supporting trimming in general.

To be clear, what I want is a method to use a TRIMMED spritesheet. It's nearly identical to using a normal spritesheet, except for a small offset value in TexturePacker's xml/taml output.

Usually the solution to trimming is a simple offset by only a few pixels. Ideally though, you'd want to take the largest Offset value in the .taml and subtract it from the current offset value. Due to the large amount of transparency around my images, the offsets are usually something like 200x300, which then means the sprite at screen position (0,0) would render at (-200,-300). The difference between the smallest and largest is only about 1-6 pixels though. So a simple (LargestOffset - Offset) equation would give a more accurate offset value, which can THEN be used to actually offset the frame. This way when the sprite is rendered at (0,0) it is a lot closer to being positioned at (0,0). I'm sure theres a more ideal way to make trimmed sprites render EXACTLY at the right position (by having some sort of anchor point users could choose from or brainy algorithm).

Realistically though, the offset doesn't need any fancy math. Most engines that support trimming expect the developer to compensate for the offset by changing the sprite's screen coordinates.


TexturePacker gives an offset X/Y value for trimming enabled formats. The value is based on how much transparency it trimmed, relative to the object. Most implementations of the feature simply add in an offset to the image based on the value.

Here is an example of how I render in SDL, compensating with trimming. GetCurrentFrame OX and OY are the offset values.

//X/Y = Sprite's position
//X1/Y1 = Rendered Frame Position
//X2/Y2/W/H = Rendered Frame Rectangle within SpriteSheet

------------------------------------
xmlparser.LoadXMLdocument(XMLfile, MaxFrames);

X1 = X + xmlparser.GetCurrentFrameOX(Anim_Control.CurrentFrame);
//Ideally (GetLargestOX - xmlparser.GetCurrentFrameOX);
Y1 = Y + xmlparser.GetCurrentFrameOY(Anim_Control.CurrentFrame);
//Ideally (GetLargestOY - xmlparser.GetCurrentFrameOY);
X2 = xmlparser.GetCurrentFrameX(Anim_Control.CurrentFrame);
Y2 = xmlparser.GetCurrentFrameY(Anim_Control.CurrentFrame);
W = xmlparser.GetCurrentFrameW(Anim_Control.CurrentFrame);
H = xmlparser.GetCurrentFrameH(Anim_Control.CurrentFrame);
OnDraw(/*surfaces*/ X1, Y1, /*ImageRectangle x2 y2 W H*/);
------------------------------------------
#14
02/25/2013 (3:44 pm)
I don't understand why you are not fixing up your images correctly in the first place? Why are you only rendering a portion of your cells? That whole sprite sheet is still getting loaded onto the graphics card, taking up resources.

Figure out what a common H/W is for every cell of your animation. Setup those cells in a graphics package, and align each animation cell so that they line up when flipped through. That could mean that some of your smaller source cells get centered into your final cell area, with a transparent layer filling in the void.

That way, when the animation renders out each frame to your sprite size, it will be uniform (no interframe movement).

Melv's suggestion is a way to support cells with different sizes, and still render properly (basically compute where a cell should render within a sprite if the cell size doesn't match from the previous).

This trimming you are talking about sounds like something you wouldn't want to put out in a shipped game. It just sounds like it calculates what the offset should be within a source cell to pull from, which means a lot of wasted texture space.




#15
02/25/2013 (10:09 pm)
http://www.codeandweb.com/texturepacker/features

Go down to "Trimming / Cropper" feature.

Perhaps I was not clear as to the benefits of trimming.

The trimming I am talking about is standard practice, especially in mobile development where you want to trim as much possible for performance. If trimming and offsetting were not popular, it would not be supported by popular engines such as Cocos2D, among others. There would be no reason to buy TexturePacker (what is by far the best most powerful image packing tool) as there are plenty of free software that simply lines images up like a flipbook.

The primary reason I need support for a trimming function is BECAUSE I am lining up my sprites perfectly in the first place. The first place being the very first step in the long process of creating the image to rendering it. There is a very important reason my renders are mostly transparency.

I try to do everything in the most efficient way possible, saving myself what would be hundreds of hours of tedious work over a long span of time. I don't feel comfortable giving away exactly why I need to do so, but efficiency and performance are two very large parts. I read early on while learning programming, the benefits of laziness. The beauty of developing a system that creates systems. Automation.


And things like figuring out a common H/W for every cell is a lot more work and time consumption than writing code ONCE to automate the whole process where I never have to do a single calculation ever again.
#16
02/26/2013 (1:21 am)
I fixed the exporter this morning and pushed it into the dev branch here.

I had a look at TexturePacker this morning and read the documentation and tried adding the "{{sprite.absoluteOffset.x}}" and "{{sprite.absoluteOffset.y}}" to the template so I could look at what could be done in the future:
<ImageAsset
    AssetName="{{texture.trimmedName}}"
    ImageFile="@assetFile={{texture.fullName}}">	
	<ImageAsset.Cells>
		{% for sprite in allSprites %}<Cell Offset="{{sprite.frameRect.x}} {{sprite.frameRect.y}}" Width="{{sprite.frameRect.width}}" Height="{{sprite.frameRect.height}}" TrimOffset="{{sprite.absoluteOffset.x}} {{sprite.absoluteOffset.y}}"/>
		{% endfor %}
	</ImageAsset.Cells>
</ImageAsset>
After wasting 30 minutes wondering why I was getting no output from those I discovered that this has been a bug since at least December 2012.

I don't have any more time right now to investigate this, perhaps you do.
#17
02/27/2013 (4:02 am)
I didn't think too hard on what is actually happening, but for my sprites at least, this works.

Instead of "sprite.absoluteoffset.x", "sprite.sourceRect.x" or even the "sprite.cornerOffset.x" (which is always the same as my "sprite.sourceRect.x")

No matter what I do, with any of MY sprites, oX and oY (the two values that the XML format outputs- the values that I use in my own engine) are always equal to sourceRect or cornerOffset. Of course, my transparency is always a power of 2, 512x512. But it works for me perfectly.

I assume that since sprite.sourceRect.x = oX, and .y = oY, that it would work to offset the image, since those values work in my engine.
Of course, ideally we'd still want to take the largest oX and subtract it from the current oX to get the ACTUAL offset. (a mostly transparent 512x512 image of mine has an offset of 198-206, but the actual offset is only 0-8 pixels, not 200ish. But the largest oX in the spritesheet is 206, then is much simpler (206 - CurrentFrame.oX = 0 to 8) actual pixels needing to be offset to keep the image still.)


<ImageAsset  
        AssetName="{{texture.trimmedName}}"  
        ImageFile="@assetFile={{texture.fullName}}">   
        <ImageAsset.Cells>  
            {% for sprite in allSprites %}<Cell 

Offset="{{sprite.frameRect.x}} {{sprite.frameRect.y}}" 

Width="{{sprite.frameRect.width}}" 

Height="{{sprite.frameRect.height}}" 
TrimOffset="{{sprite.sourceRect.x}} {{sprite.sourceRect.y}}"/>  
            {% endfor %}  
        </ImageAsset.Cells>  
    </ImageAsset>
#18
02/27/2013 (5:00 am)
Quote:.sourceRect.x - The x coordinate of the trimmed sprite inside the original sprite. int
Quote:.sourceRect.y - The y coordinate of the trimmed sprite inside the original sprite. int
I don't see how that helps knowing the position from the sourceRect. Isn't that the original pre-packed image? T2D doesn't see that so how does it help?

The solution has to work generically for everyone.
#19
02/27/2013 (9:01 am)
Wouldn't you need to know the original cell x/y/h/w? If trim is shrinking the source cell to as small a rect as possible, you need to know how much was trimmed on both sides to reconstruct that source cell at runtime.

Or, does trim remove the same space on both sides? Which would mean you'd only need to know that h/w trim size to recenter at runtime.
#20
02/27/2013 (9:26 am)
Not sure if that was directed to me or not. :)

My point above was that the "original" art references are irrelevant as that art is not loaded into T2D. All it gets is the image that TexturePacker spits out. The "sourceRect.x" and "sourceRect.y" don't help at all.

Texture packer calculates the offset due to trim, it's called "sprite.absoluteOffset.x" and "sprite.absoluteOffset.y" but there seems to be a bug and it's not outputting it.

T2D only needs the offset of the new frame relative to the old one, no matter how it's calculated, no matter what is said here, that's all it needs. :)

With that information, it's possible to write a type that could utilize that info.
Page «Previous 1 2