Creating animated sprites for cocos2d from a single image file without a .plist file - objective-c

I am starting to learn cocos2d and I have the following issue:
I cannot seem to find a way to create sprite frames from a single png sprite file and animate them. I have found a million tutorials about using separate image files or a plist file with the png but I can't find how to do it WITHOUT one (with a regular loop that selects rectangular areas. Any help?

For a sprite sheet to work in cocos2D you need both the .plist file and the .png file.
You need a CCSpriteFrameCache object which will be in sharedSpriteFrameCache and global, meaning the Sprite frame cache is not only for the method but will exist in the memory until you remove it. Then you have to make a CCBatchNode object which will contain the sprite sheet file reference.
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"EntryJump.plist"];
CCSpriteBatchNode *entrySpriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"PotkaEntry.pvr.ccz"];
I am using .pvr.ccz format, you may use .png file if you want.
What I am trying to say here is that it is necessary to load the .plist file on the Sprite frame cache for cocos2D where everything is defined and loaded globally, then cocos2D will use the CCSpriteBatchNode object (the sprite sheet) where the individual images of the sprite are explained in the .plist file.

Related

Transferring Touch points between classes [Objective-C]

I'm working on an alternate version of a program I already wrote, it's mostly for the sake of understanding a little more.
In x-Code (Objective-C), I have a ViewController that calls out a UIView (GraphicsView) that draws a line from the center to the touch point. This sub-view is smaller than the larger ViewController.
The view controller has a label that outputs the coordinates of the touched point.
So far I was able to get everything working, so that if you touch inside the sub-view you get the line AND the coordinates updated and if you touch outside the sub-view you only get the coordinates updated. I did this using delegates which was a little complicated.
I've been reading some books and I learned about using the extern feature and global variables (which are supposed to be bad practice) and I wanted to try the same app but using global variables.
I declared my externCGPoint in the ViewController.h and imported it on the GraphicsView.m file and in the method touches began I put the definition of myGlobalPoint = touchedpoint; followed by an NSLog that displays the coordinates. So far it works. (However it does not update the coordinates)
However whenever I touch outside the sub-view, into the main view the app crashes with a EXC_BAD_ACCESS message. From what I understand the main View cannot access the global variable if it's declared in another class ?
I've read many there stack overflows about this and I;ve tried it in the methods suggested but I keep getting this error.

How to set initial zoom on UIWebView in xcode

I'm wondering how to set an initial zoom on a PDF document loaded in a UIWebView in XCode. It is a table, and I want the web view to load zoomed in on a specific column (or part of a column which I can then scroll up and down). I've been reading and some people have pointed to this method - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script but I don't know exactly how this works.
And while we're on the subject of PDFs, is there any way to scrape the PDF and turn it into usable strings?
Edit: For reading a pdf, PDFBox is one possible solution. You have to import JAR files into your Xcode project. Here is a tutorial: http://www.oreillynet.com/pub/a/mac/2005/01/07/ipod_reader.html
UIWebView *webV = [[UIWebView alloc] init];
webV.scrollView.zoomScale = 4.0;

How to use CCSpriteBatchNode properly?

I add my sprite frames to CCSpriteFrameCache. Then I create a CCSpriteBatchNode with my desired image file.
This is what I don't quite understand:
When I make a CCSprite, if I want to take advantage of the CCSpriteBatchNode, I need to initialize the CCSprite with [CCSprite spriteWithBatchNode: rect:]? But if that's the case, I don't see how am I taking advantage of CCSpriteFrameCache to get the frames, since now I would be manually making the rect.
So I guess I use [CCSprite spriteWithSpriteFrameName:] and then I add this sprite to the batch node. But I am still unsure.
You should use:
CCSprite *sp = [CCSprite spriteWithSpriteFrameName:#"monster.png"];
The .plist that you specified in the SpriteFrameCache will take care of the frames for you.
Then you create the sprite and add to the batch.
If you create the batchnode with a file called "myArt.png", you CAN ONLY add a sprite to it that is contained inside "myArt.png".
Hope it helps!
According to what I've learned of cocos2d. SpriteFrameCache and SpriteBatchNode have the same result but are used differently and can notice a slight performance difference if your game is very big...
CCSpriteFrameCache loads your frames according to when they are called by their named according to the plist file it was given. The atlas associated with the plist has to be added to the project as well or else the frames will be called but nothing will be found to be drawn. The Plist is like the address of where the image is located inside the image atlas.
The good part of CCSpriteFrameCache is that the code is neater, and smaller than CCSpriteBatchNode method, at the cost that for every call of that frame, it goes to that specific atlas and draws it.
CCSpriteBatchNode, on the other hand, loads the atlas and loads it in one draw call. This is efficient because it reduces the amount of times the draw has to be done per need in the game. The only difficulty here is that you need to do math for the rectangles of each sprite in the atlas. This is because lets say your atlas is of 2 actions of a character, the atlas image file has a size of 1024x1024, and each sprite has a size of 128x128. so you would do the math to get each rectangle for the whole jump action for example.(This is where .plist come in handy to avoid doing such math)
The code gets complicated as you can see but it will only do one call, making it performance-wise your best call.
Another way to use CCSpriteBatchNode is to have different static sprites and you would just do one draw call for those multiple static images or sprites.
If you need example code just ask, I would be more than happy to provide it.
Update: Adding Link for SpriteBatchNode and an Example of my own.
SpriteBatchNode:
Example using SpriteBatchNode with Ray Wenderlich
I believe in this guy, and I have learned alot of Cocos2d from his tutorials. I would suggest you to read other of his tutorials.
In a nutshell, CCSpriteBatchNode is the exact same process we did below with the CCSpriteFrameCache the ONLY difference and its that you add the Sprite Child Node to the CCSpriteBatchNode and not the Layer, BUT you do Add the CCSpriteBatchNode to the Layer.
This is the hard concept that new comers to Cocos2d get entangled at.
SpriteFrameCache:
The SpriteFrameCache I couldn't find a good example so here is one simple one.
//By doing this your sprites are now in the cache ready to be used
//by their names declared in the .plist file.
-(void) loadingSprites:(NSString*) plistName {
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:plistName];
}
-(id)initGameLayer {
//CCSprite accepts CCSpriteFrame and your img is now ready to be displayed.
//However is still not drawn yet.
CCSprite * mySprite = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:framename];
//set a position if desired
//20 pixels to the right and 0 pixels to the top.
mySprite.position = CGPointMake(20,0);
//Now the Image has been drawn, making 1 draw call.
[self addChild:mySprite];
}
It is noteworthy to point out that CCSpriteBatchNode makes just 1 drawcall, HOWEVER all the sprites being added to the batchnode have to be part of the same SpriteAtlas.
And using SpriteFrameCache only its easier and simpler, but for every child added to the layer it means +1 draw call is being done.(This is the downside, performance)
So if you add 10 Sprites to the layer with SpriteFrameCache you will have 10 drawcalls.
However if you implement the SpriteBatchNode and add those 10 Sprites in the CCSpriteBatchNode instead and just add that CCSpriteBatchNode to the layer, you will have the same 10 sprites added but only ONE draw call will be done. Hence the Performance difference(for the best) will be significant in larger games.
Hope it helps, Cheers!

CCSpriteFrameCache optimization

[[CCSpriteFrameCache sharedSpriteFrameCache]addSpriteFramesWithFile:];
That will add sprite frames through a .plist file. I would like to ask: if I tried, for whatever reason, to load the same .plist file again, is CCSpriteFrameCache smart enough as to ignore it? Or will it reload it all again, consuming more processing/memory?
It will re-use the already loaded texture, but reload the sprite frames in the plist. It will create new sprite frames and throw out the existing ones.
If you plan to modify a texture atlas and reload it, you'll have to make sure to remove the texture from the texture cache as well, so that it gets reloaded as well.
If you're just lazy and call this method over and over again, it shouldn't be an issue if you do this between scenes but I wouldn't do that during gameplay, since each sprite frame is deallocated and a new one allocated, and a lot of other code runs behind the scenes to load the sprite frames.

Help loading a texture in a variable in Objective-C

I have a "ball" sprite that changes it's texture when a certain scenario occurs. I change it's texture like this:
[ball setTexture:[[CCTextureCache sharedTextureCache] addImage:#"red.png"]];
This does work; it changes the ball sprite to use the red.png image. How would I handle this if I have about 20 balls that need to switch to using this sprite? Would I run through each ball and "addImage"?
If I could, I would like to load the texture once, save it in a variable (called like "redTexture"), and then be able to assign it to any of the ball objects.
Any advice on how to approach this would be a huge help, thank you!
If you were to put that statement inside, say, a for loop, you'd be adding the red.png image to the shared texture cache over and over again, which I doubt is what you want.
Let's back up and re-write things a bit, starting by adding the red.png image to the shared texture cache, on a line by itself:
[[CCTextureCache sharedTextureCache] addImage:#"red.png"];
You'd subsequently get the same texture again simply by calling [CCTextureCache sharedTextureCache]. Until you add another image to the shared texture cache, that is.
CCTextureCache is a singleton, and its docs don't suggest there's a way to make a copy of the shared texture cache (which would be ideal for preserving your redTexture). That being the case, just create a variable and point it at [CCTextureCache sharedTextureCache]; just be careful not to add any other images to it before you're done with it:
CCTextureCache *redTexture = [CCTextureCache sharedTextureCache];
Now let's assume you already have an array (or mutable array) called ballArray, that contains 20 ball objects. You could loop through them like this:
for (YourBallObject *ball in ballArray)
{
[ball setTexture:redTexture];
}
Or even better, you could do this:
[ballArray makeObjectsPerformSelector:#selector(setTexture:) withObject:redTexture];
Good luck in your endeavors.