I don't quite get what you guys mean by "offset (or anchorPoint) is needed on the frames" what does that mean? It sounds like it helps pack more images in a texture, but how, I'm not sure! How is it different than getting a sprite using a rect?
Atlas Sprite (cocos vs Zwortex, best of both worlds?)
(121 posts) (25 voices)-
Posted 2 years ago #
-
if you have one frame of animation where the character is shaped like this, with the plus being his ideal origin:
-+---
and another where he's like this:
---+-
then either you have to make every sprite on the sheet big enough to hold both sprites, wasting space, or you have to store an offset for the individual frame so it can draw correctly in either case.
Posted 2 years ago # -
that makes sense. thanks for the explanation... i get that the whole idea is to make it so you can basically decrease the amount of memory needed to display complex animations on screen. It almost seems like it'd be nice to be able to use something like Tiled to generate the keyframes for an animation using a tilesheet that's made out of all the common parts of a character. If that was done, then the characters could be huge on screen as well, but time would have to be spent building those animation frames from the tilesheet, I guess?? I saw that tiled mentions a tool that'll automatically generate a tilesheet from a large art png, but I don't know what it'd do with something like this... probably be too slow?
Posted 2 years ago # -
The other optimization atlas systems can make is reducing the number of draw calls by drawing many sprites from the same page in the same call. In most cases, graphics slowdowns comes from either too many draw calls or too much fill rate. From my experiences, with the iPhone it's usually the latter.
The cocos system is primarily designed to reduce draw calls. After 0.9, if riq manages all the changes planned, it should handle both optimized draw calls and optimized texture packing. It'll also be a lot easier to use, since you'll only have to deal with the drawing optimization complexity if you need the optimization.
Posted 2 years ago # -
One other thing I was thinking about today is how to properly handle anchor points on non-uniform atlas sprites. Because each frame is different, an anchor point doesn't really make sense. So I think there's potentially a few ways to do it:
- Anchor point in pixel space
Not a fan of this one, but it would allow you to change the anchor point and have it be consistent through many non-uniform frames.- Anchor point based on reference frame
I prefer this one. Basically, you init the sprite with a frame, and your anchor point is based on that frame's size.- Anchor point based on bounding box of all frames
This could work, but is not my preferred solution for a couple of reasons. First, you'd need to recompute it every time you add a frame or have some kind of end function, which is bleh. Second, it's not very predictable in use, in that often you're setting the anchor point to do things like put a characters feet on the floor. The total bounding box doesn't work well for that.Posted 2 years ago # -
We're also using a modified version of zwoptex in the way slipster outlined, so we're very much in favor of all the changes mentioned here. Thanks slipster for proposing this and detailing the advantages so thoroughly. (And of course thanks Robert for zwoptex/zwopple!)
Posted 2 years ago # -
@cloudmike / @slipster216: Are your mods to the Zwoptex code available somewhere ? I'd like to get a copy if possible! thanks!
hipjiveguy [at] gmail [dot] com
Posted 2 years ago # -
@slipster216: yes, I also prefer the anchor point based on reference frame
Posted 2 years ago # -
I've added a wiki page where we can start playing with the API:
http://www.cocos2d-iphone.org/wiki/doku.php/developers:sprite_refactoring
Posted 2 years ago # -
Should we comment in the wiki or do it here? I'll post my first round here:
Sprite * sprite1 = [Sprite spriteWithFile:@"spritesheet1.png" rect:CGRectMake(0,0,20,30) offset:ccp(-10,-15)];This seems fine for manual creation, but I think we should allow for plist integration so you can go:
// initialize the manager with a sprite sheet SpriteManager *mgr = [SpriteManager spriteManagerWithFile:@"spritesheet.png" data:@"spritesheet.plist"]; // initialize a sprite from the spritesheet Sprite* sp = [Sprite spriteFromManager:@"spritename"];Note that this would work regardless of if your going to parent your sprite to the manager for the performance benefit, and the spriteFromManager function would look up the texture coords and such based on the plist entry.
Ideally, it will search all the sprite sheets for this entry. The only thing that seems a little tricky is that the optimization requires all sprites of the manager be on the same sheet. Perhaps we throw an assert into the addChild function to test that the sprite comes from this manager.
In fact, thinking this through, perhaps we should do the following:
1. SpriteManager becomes a singleton that holds sprite sheets and coordinate information from a plist file but is not drawn, etc.. You simply add all of your sprite sheets and plist files to it:
[[SpriteManager sharedMgr] addSheet:@"sheet1.png" withCoords:"sheet1.plist"]; [[SpriteManager sharedMgr] addSheet:@"sheet2.png" withCoords:"sheet2.plist"];2. SpriteLayer is the optimized drawing object. When you add a sprite sheet it returns the sprite layer to you, or you can query for one from the manager.
// get it at creation time SpriteLayer* l = [[SpriteManager sharedMgr] addSheet:@"sheet1.png" withCoords:"sheet1.plist"]; //or by texture name SpriteLayer* l = [[SpriteManager sharedMgr] getSheetNamed:@"sheet1.png"];Finally, you initialize a sprite
Sprite* sp = [Sprite spriteFromManager:@"myframename"]; // sets anchor point based on myframename [sp setAnchorPoint:ccp(0.5,0)]; [sp setFrameFromManager:@"otherframe"]; // this should assert if otherframe is not on the same sheet as myframename and we're parented to a SpriteLayer [sp setAnchorPoint:ccp(0,0)]; // anchor point is set based on myframe stillNote that whatever frame you create the texture with becomes the reference frame for the anchor point.
The advantage of this setup is that you have to know nothing about SpriteLayers unless you want drawing optimization. You also don't have to know which sprite is on which sprite sheet. Often I re-pack my sprite sheets, and zwopple's system doesn't care which sheet they come from, so I don't have to refactor anything when I change the sheets around.
Now, if you opt in for the optimization because your scene needs it, you'll need to organize your sprite sheets accordingly and draw/parent based on sprite layers. But there's no need to have that complexity unless you need that optimization.
Posted 2 years ago # -
.plists are really easy to create in Cocoa MacOS and iPhoneOS. Many developers seem to be creating editors in Java and Flash, so maybe SpriteManager should support an XML format too?
Posted 2 years ago # -
yes, loading from a plist (or any other format) should be present on the API. I will ease the development a lot.
We can continue to discuss the API here, but also it's important to update the wiki with the proposed API.
Posted 2 years ago # -
I've updated the wiki.
I prefer to avoid the
SpriteManagersingleton (at least for now).eg:
SpriteManager *mgr = [SpriteManager spriteManagerWithFile:@"spritesheet.plist"]; Sprite *sprite = [mgr spriteByName:@"frame_0"]; // current API still works // getChildByTag should be renamed to childByTag Sprite *sprite = [mgr getChildByTag:0];If someone wants to query all the spritesheets, he could do it manually
eg:
for( SpriteManager *mgr in ArrayOfSpriteManagers) { Sprite *spr = [mgr spriteByName:@"frame_0"]; if( spr ) break; }Posted 2 years ago # -
Codemattic: A plist is xml, just a subset of it. The format will likely be the one output by zwopple's tool, which is written in AS3 currently. Since he's willing to submit the source, people can add whatever features they want to it; which is awesome.
riq: My only problem with this is that re-arranging your sprite sheets for optimal packing will require you to re-write a lot of code unless you think to design things in such a way ahead of time. Using the singleton pattern means the framework effectively pushes the user into that direction instead of requiring them to figure it out. Also, how does animation across multiple sheets work (in either case)?
Though, to be my own counter point, forcing them to understand the 1 manager == 1 sheet == one optimal draw call early might make the transition to optimized drawing easier. I suppose it's a trade-off between ease of use and ease of understanding optimization.
Currently we get tons of questions on how to use atlas sprites. I suspect that many of those people would be hitting frame rate with regular old sprites, and that these questions will be replaced with optimization questions by the smaller group of people who need the speed.
I also noticed this in the comments:
// It will also create the sprites (all the sprites that belong to the sprite sheet)
// It will set the correct Anchor Point to the sprites (each sprite might have a different anchor point)This, and the api seem to imply that it's going to create actual sprite objects and parent them to the manager. I don't think that's what we want; I think we want it to have helper functions to create sprites when you need them from the manager. I've updated the wiki with an example of this..
Another minor thing worth bring up is that the offset can be outside of the texture itself. I do this all the time in my current game, because it allows me to export every layer in a photoshop file to a full-screen sized set of png files, load them into the texture tool (which crops them and stores the offsets), and I can place them all in the center of the screen and everything appears exactly where it was. It really makes scene layout easy.
Posted 2 years ago # -
Love the way this is all heading...
My 2 main requests would be:
- the parenting feature (I presume you'd loose optimised drawing by parenting to something other than a sprite manager? But that would be worth it to achieve the behavior in cases that need it)
- animations across multiple sprite sheets, not necessarily a single animation (although that would be nice), but being able to say have walk, run, shoot animations on one sheet, and jump, punch etc ones on another without having to manually handle jumping between the 2 sheets/managers.
@slipster: I like the sound of how you use the offset for layout. So I take it when calculating the position of those objects in game (e.g. for collisions), you need to always take that offset into account?
Posted 2 years ago # -
PhilM:
Both of those should be possible in the new system. It shouldn't matter which frame is on which sheet in an animation, except in the case where you want optimal drawing. I suspect for games heavy on character animation, drawing optimizations aren't the main motivator for using sprite sheets; texture space is.
As for the offset layout trick, the game I'm working on doesn't have collision, so I haven't needed to worry about it. It really only makes sense in a scene where your going to play back animation; not one in which you'll be moving the sprites around with a physics engine. I suppose in that case you could normalize them by using the offset to calculate the real position and then setting the offset back to 0,0.
Posted 2 years ago # -
@slipster: The singleton, as you said, will put focus on the game and not optimizations. Which is correct (or at least is the right step).
Games with lots of animations/frames will benefit from it.But I have some concerns about the singleton. I can't really explain them know because my ideas not so clear... actually it's more like a feeling than ideas.
I'll continue to play with the API on the wiki and I'll post my ideas here.Posted 2 years ago # -
@slipster:
Yup, the game I'm working on has an insane number of animations, so texture memory seems to be the biggest bottle neck for us right now, and drawing optimizations were a bonus, but not essential, so thats great to hear!The reason I quite liked your offset idea, was so the artist(s) I work with could do more of the initial comp work, rather than me. But its not a major issue for us right now, and as we are using a physics engine, doesn't sound suitable after your comments. Could be useful for simple background layouts etc, although we've been looking into developing our own simple layout editor for the artists to use in the future.
Thanks for the extra info, and getting the ball rolling on this great feature improvement!
Edit: back on topic - are you planning to keep a manual way to add frames to a sprite, in addition to plists/xml? When doing initial tests, it might be overkill to require the user to use an extra tool to prep the spritesheet, although in the long run it certainly makes sense.
Posted 2 years ago # -
Oh yeah, you'll be able to add frames manually or use a sprite without a sprite sheet; ease of use is one of the major goals here. Also, if you haven't tried zwopple's layout tool it's really nice; just a few clicks and your done, plist and all.
Posted 2 years ago # -
Sweet.
I'll give zwopple a whirl while the new features being fleshed out. Thanks.Posted 2 years ago # -
By the time these features hit Cocos2d I should have an AIR application ready for the tool. It should help support more native integration for saving/loading and having multiple documents open at once.
Also unsure yet but I probably will be combining the files (texture and coordinates) into a single binary since they pretty much are always exported and loaded together. I'll write supporting code in Obj-C Cocoa to load and parse it back into NSData / NSDictionary respectively.
-Z
Posted 2 years ago # -
Your going to stuff the png into an nsdata? Why? I personally find having the plist useful, as I can look at the config without opening the tool. Same for the png. If they're bundled up, it's just a binary blob that only cocos and the tool can read. Plus, as a more open format, other people might be able to use it for other engines.
Posted 2 years ago # -
@slipster216 rather I will be stuffing the .png data into the .plist.. PLIST can support NSData objects and it only makes sense to pack the texture into it.. I'll make sure it's at the bottom of the file so it doesn't clog up scrolling while trying to view the coordinates data.
Posted 2 years ago # -
If the .png will be enbedded into the .plist:
+ easier to integrate (just 1 file)
- .png won't be compressed by XCode (not a big problem)
- it will be difficult to modify the .png (in some cases it's easier to modify the texture atlas file, than individual files)I would prefer that the .plist contains a "pointer" to the .png file.
In any case, an option on the editor that says "embed .png" could be addedPosted 2 years ago # -
I'm with riq on this, though as long as it's optional, whatever..
Posted 2 years ago # -
Hi!
I'm new here, but figured this is as good a time as any to start posting.
I've been using zwoptex together with a subclassed Animation and Animate action to get the offsets to work on a frame by frame basis and I'm very much looking forward to this new API.
Since we are changing the API, are there any thoughts on adding hooks to the animations? For instance a start, stop and step hook so one could know how far along the animation has progressed and when it stops. I know you can use actions for some of this stuff, but there is no way to check for animation steps (as far as I know) without subclassing it.
Otherwise I think the API looks good. Simple and effective.
It will be nice to have a clean solution to the offset problem, and at least for me it will probably remove the need to have multiple sheets for a single animation, since we can compress each frame quite a bit.On the PNG embedding in PLIST: I'd like to agree with slipster on this, it should be optional.
PS: cocos2d and zwoptex FTW :)
Posted 2 years ago # -
Yeah, I brought this up a while ago but we haven't gotten into the api much. The idea I had was mostly about wanting to tie an arbitrary callback to a given frame, for triggering sound effects and the like. So you could do something like so:
[myAnim addFrame:@"frame_01"]; [myAnim addEventWithTarget:self selector:@selector(myFunc) withObject:@"something"]; [myAnim addFrame:@"frame_02"]; [myAnim addFrame:@"frame_01"];This would cause the animation to call the selector with the string when frame_01 is displayed the first time. The only thing I don't like about this api is that it's not clear which frame it's being attached to (first or second), but I'd be ok with a convention here if no one has a better idea. I didn't want to pass in the frame reference name because you might be using it more than once, so you don't really want to attach it to the frame but rather put it into the sequence of frames.
Another way to do it would be to have a delegate class and call events on the delegate. So if self is a <ccAnimationDelegate>, you could do something like:
myAnim.delegate = self; [myAnim addFrame:@"frame_01"]; [myAnim addEvent:@"something"]; [myAnim addFrame:@"frame_02"]; [myAnim addFrame:@"frame_01"];and the OnAnimationEvent function would get called on your delegate (self). While somewhat more objective-c like, it isn't as flexible in that one class would have to act as the dispatch for the animation and switch on the event string to figure out what to do.
I'll put these options on the wiki so we can play with them and keep track of it. This would really be the final piece needed to complete the animation system imo.
Posted 2 years ago # -
Finally fixed my account on this forum so I could say that I really like the direction you guys are going with this.
Also, I've been developing my own AIR app to create atlases, so I'll make it use the same plist format that you guys are using. Once the source for Zwopple's app is up, I'll see if anything in mine can be added into that. I think it'll be sweet if we eventually end up with an AIR app that can export tile atlases AND font atlases, so we don't even need to use hiero(etc) anymore.
Oh, and I'll put my vote towards keeping the atlas data and the png file seperate. I like to be able to go in and tweak the png file afterward(sharpen, color correction, etc.)
Posted 2 years ago # -
@slipster216 I started out writing about how I thought delegates were a better idea, then I thought about it some more and now I'm not sure. Being able to sequentially insert the events is a good idea.
My main concern is to be able to dynamically load animations from an external file... and to a lesser extent the ability to reuse the same animation instance from multiple objects.
How would one then handle the adding of events, and especially events that might need to be sent to an object that is not known at compile time?
I suppose one can simply define animation files in a separate list like:
frame:punch_frame_01
event:playSound:foobar.wav
frame:punch_frame_02
frame:punch_frame_03
event:punchConnected:
frame:punch_frame_04
In this case the object that plays the animation will need to somehow subscribe to these events... But then we're back at the delegate and switch... Then again, the strings from the file can be made into selectors and the target for the selectors can be set by the Action rather then the animation...
I just feel that it's a bit wasteful to have to instance the animation every time you want to use it with different object. Is that silly?
Perhaps something as such:
[myAnim addFrame:@"frame_01"];
SEL selector = NSSelectorFromString([datarow objectForKey:@"selector"]);
id data = [datarow objectForKey:@"data"];[myAnim addEventWithSelector:selector withObject:data];
[myAnim addFrame:@"frame_02"];
[myAnim addFrame:@"frame_01"];.......
[Animate actionWithAnimation:myAnim eventTarget:self];This has the drawback that only one target can exist for all events in a single animation, but it might be worth it.
I'm gonna think about this more, as I play with the framework thoughts take shape... hehe
And I totally agree, with this the animation framework would be complete.
Posted 2 years ago #
Reply »
You must log in to post.