Thanks for taking the time to read and reply to my post. I know you're superbusy!
I'm usually very direct when talking about these things, so, please don't take it personally if it sounds like I'm "attacking" you. 🙂
I hope you can better appreciate the issues at hand. Claiming things are "poorly written" when you don't understand them or don't agree with them is not constructive and is not useful for gaining leverage to get what you want. I am not easily offended and not offended now, I just want to make it clear we can have a nice discussion without this criticism nonsense.
Criticism nonsense? I actually suggested you how to improve the API with a list of points and reasons. That's called constructive criticism...
When I said "poorly written" I wasn't talking about the spine-c API or its internal design, but I was referring to the ObjC interface, which is, in fact, "poorly written". I'm not saying this to offend you (why would I do that?), but to quickly make you understand that this API, compared to other free/commercial APIs out there (cocos2d, Chipmunk, ObjectAL, ... and some of those have a C core and just a ObjC wrapper, like Spine) is of a lower quality.
It "screams" C/C++, and that's my main complain.
I'm a seasoned C++ programmer as well, and I love it, but not in a ObjC context. And you learned this as well, when you refactored it to avoid having to rename all the files .mm just to make it compile.
I'm not really concerned about the integration with Cocos2D, I'm more worried about the ObjC correctness and proper use of the language's fantastic features (properties, delegation, protocols...) that you're very skeptical on implementing.
Of course, I'm not so naive to ask you to add features that only I would need. That's not the point. If you think that a delegation pattern to inform when an animation ends is not needed by anyone, then I won't complain (but I just read another post where someone was asking a similar thing and you decided to implement the "isComplete" flag to the C structure).
The spine-c object graph contains lists, references to other objects in the graph, etc. This can't be wrapped this easily, converting lists to NSMutableArray, wrapping structs in ObjC classes, etc because then the rest of the spine-c code could not interpret the data. Attempting to keep two parallel object graphs in sync would be nasty. What you would end up doing is rewriting the entire runtime, duplicating all the spine-c data structures and logic in ObjC.
No, you don't need to go that way of course. I'm not asking that! 🙂
But for example, if I want to retrieve the current animation time, or duration, or name... or any other field in that structure (and other structures you're using), I should be able to access them through properties. Even if they're just readonly properties.
This is extremely important in an API because tomorrow you might change the AnimationState struct in the Spine-C for some good reason, and my code won't compile anymore. I'll have to go through all my sources where I do _skeleton->state->animation->duration and fix it. On the other hand, if you have a property called animationDuration I'll be safe because you will just change the getter for that property and everything will work. (You can create dynamic properties where you provide the getter/setter methods).
Etabubu wrote:- Both class and instance methods need to follow Apple guidelines in regard to naming conventions
Please be more specific with your proposed changes and I will consider them.
Sure. This is a good doc to start with: https://developer.apple.com/library/mac ... lines.html
In this specific case:
1) All the "create:" methods should be called "skeletonWithFile: ...". The word "create" is discouraged by Apple because creates confusion about the ownership. Factory methods are usually named "<ObjectReturned>With<Param>".
So:
+ (id)skeletonWithFile:(NSString *) atlas:(Atlas *)atlas;
+ (id)skeletonWithFile:(NSString *) atlas:(Atlas *)atlas scale:(float)scale;
+ (id)skeletonWithFile:(NSString *) atlasFile:(NSString *)atlasFile;
+ (id)skeletonWithFile:(NSString *) atlasFile:(NSString *)atlasFile scale:(float)scale;
+ (id)skeletonWithData:(SkeletonData *)skeletonData;
+ (id)skeletonWithData:(SkeletonData *)skeletonData stateData:(AnimationStateData*)stateData;
2) Init methods should return "id" and should follow the same naming conventions:
- (id)initWithData:(SkeletonData *)skeletonData;
- (id)initWithData:(SkeletonData *)skeletonData stateData:(AnimationStateData*)stateData;
3) Only property setters should start with "set", so... suggestions on how to rename all your "set" methods:
"setMix..."
- (void)mixAnimation:(NSString *)firstAnimation withAnimation:(NSString *)secondAnimation duration:(float)duration;
"setAnimation..."
- (void)startAnimation:(NSString *)animationName loop:(BOOL)loop;
And so on...
4) In getters, never use the prefix "get". So...
"getAttachmentForSlotName..."
- (Attachment *)attachmentForSlotName:(NSString*)slotName attachmentName:(NSString*)attachmentName;
AnimationState does not have an explicit method to stop animating. setAnimation(null) can be used. I will add a clearAnimation method though, as it is generally less nice to overload a method parameter to use null as a special case.
Actually, if I use the ObjC setAnimation: method and I pass NULL, it crashes.
Beside that, as I said above, this shouldn't be called "setAnimation" because it's not a setter. Just to be clear, I'm ONLY talking about ObjectiveC conventions and I'm not suggesting to rename spine-c functions!
A "startAnimation/stopAnimation" or "startAnimation/clearAnimation" pair of methods would be much appreciated. That's also what you usually find in ObjC APIs. You'll never find a method that expects "nil" to perform a different or opposite action. But I'm well aware that it's common practice in C/C++.
About the delegation pattern: keep in mind that you can implement it in the ObjC runtime without having to touch the C code. To be clear: I don't want you to implement a notification system in spine-c, but only in the ObjC wrapper. It's possible, I've done it yesterday, without touching your class. But it would be much cleaner if it was implemented by you in CCSkeleton.
Final words: the current state of the CCSkeleton class makes it relatively useless. Yes, it helps a lot to render the animations in Cocos2D (and I know this is its main purpose), but it lacks a clean ObjC interface to access all the internal data and to perform non-rendering related tasks (such as playing with bones and slots).
IMHO, if you just wanted to create a Cocos2D renderer for Spine, you could remove all the "find...", "set..." and "get..." methods because people can just use the spine-c API to do all that stuff.
It looks like you're in the middle between a simple Cocos2D renderer and a full blown ObjC wrapper. (I'd like to have the latter 🙂 ).
I'll stop here, otherwise this post becomes way too long and then it looks like I want to teach you stuff. 🙂
These are just suggestions from one of your customers. You can then do whatever you want with them.
Hopefully this post won't sound like "criticism nonsense" and will give you some tip on how to improve the ObjC API.
No hard feelings! Spine is a fantastic tool and it was really needed in the 2D games scene. That's why we bought it 🙂
Thx,
Marco