Get CGImageRef from CCSprite, CCTexture2D or even directly from CCSpriteFrameCache? - cocos2d-iphone

I have written some code that takes a UIImage.CGImageRef and puts it into a context so that I can analyze it. This all works great. BUT, I now wish to implement this process in a Cocos2D app.
All of my graphics for the app are done as sprite sheets using Texture Packer so I am looking for any way to get the CGImageRef that I require out of the sprite sheet.
My theory is that you can init a CCSprite with a CGImageRef so why can't I simply get it back out again?
Maybe I am missing something simple like does Cocos2D have a CGImageRef equivalent?

you can try smth like this
CCRenderTexture *renderer = [CCRenderTexture renderTextureWithWidth:size.width height:size.height];
[renderer begin];
CCSpriteBatchNode *spriteSheet = [m_sprite batchNode];
if (spriteSheet != nil)
[spriteSheet visit];
else
[m_sprite visit];
[renderer end];
NSData* uidata = [renderer getUIImageAsDataFromBuffer:kCCTexture2DPixelFormat_RGBA8888];
UIImage* uiimage = [UIImage imageWithData:uidata];
CGImageRef image = [uiimage CGImage];

You can get image data from OpenGL via glReadPixels. It needs some adjustments, but it would be wrong solution in performance aspect. OpenGL is designed as one-way conveyer (you pass data and don't read it back). Depending on your concrete task you may preload image data when loading textures from file.
As example we use alpha channel of textures for per-pixel touch test. So, when we load image we store its bitmask of alpha threshold in memory.

no
cctexture direct from [CCTextureCache sharedTextureCache] read from photo file
ccspriteframe direct from [CCSpriteFrameCache sharedSpriteFrameCache] read from ".plist" file

Related

Updating a CCTexture2D from a BatchNode

After I completed my testing, I have moved my images over to a spritesheet.
I loaded up the batchnode with the appropriate files and my images load just fine.
But I am running into an issue of swapping the textures out. When the images were individual files, there was no problem. Now it seems the CCTexture2d doesn’t like my sprite sheet.
I have the objects stored in a multidimensional array, so I can run through them quickly and update their image.
Here is what I did when it worked:
CCTexture2D* tex = [[CCTextureCache sharedTextureCache] addImage:#"alt-image.png"];
[((MyFunObject*)[[myFunObject2DArr objectAtIndex:j]objectAtIndex:i])->img setTexture: tex];
Here is what I am doing now:
CCTexture2D* tex = [[CCTextureCache sharedTextureCache] addImage:[CCSprite spriteWithSpriteFrameName:#"alt-image.png"]];
[((MyFunObject*)[[myFunObject2DArr objectAtIndex:j]objectAtIndex:i])->img setTexture: tex];
MyFunObject is a subclass of CCSprite and has an CCSprite img property that get set. I run through the array and find like objects and replace their image with a new image “alt-image.png”.
Seems simple, but outside of a sprite sheet this worked flawlessly.
Can someone tell me what I am doing wrong?
UPDATE:
HERE IS THE SOLUTION FOR ANYONE IN THE FUTURE WHO HAS THIS ISSUE
You can't change the sprites 'texture' when the texture in question is spritesheet. (Slapped my head on that one)
You can only change the rectangle that is viewed.
Here is how you do it:
[((MyFunObject*)[[myFunObject2DArr objectAtIndex:j]objectAtIndex:i])->img setTextureRect:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: #"alt-image.png" ].rect];
Notice I changed setTexture to setTextureRect, then I called the SpriteFrame's rectangle as an argument.
Enjoy.

Which APIs should we use to add spritesheets and sprites to a cocos2d game?

While creating a cocos2d iOS game, there are several options to add spritesheets - CCTextureCache::addImageAsync, CCSpriteFrameCache::addSpriteFramesWithFile, etc. - what is the difference between using these different ways to add a spritesheet?
Similarly, to load a sprite, we can call CCSprite::spriteWithSpriteFrameName or CCSprite::spriteWithFile or CCSpriteBatchNode::batchNodeWithTexture, etc. What is the difference between using these techniques?
Thanks
Anand
Load sprite frames, this also loads the textures:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"file.plist"];
Use sprite frames:
CCSprite* sprite = [CCSprite spriteWithSpriteFrameName:#"frame.png"];
Add the sprite to a batch node:
CCSpriteBatchNode* batchNode = [CCSpriteBatchNode batchNodeWithTexture:sprite.texture];
[batchNode addChild:sprite];
The batchNodeWithFile works too if you use the same image file of the sprite. If the sprite was initialized with a spriteframe, it'll be the texture atlas image (ie "file.png").
addImageAsync is only needed if you want to load your texture on another thread, usually to animate the loading screen. You'll still have to add the sprite frames afterwards.
CCSprite spriteWithFile creates a sprite from a single image file. Those can be batched too but it's better to use a texture atlas with sprite frames.

Cocos2d animations in main loop

Anyone that can give any hint of the smartest way to do a main loop animation? I don't want to use CCAnimation because I want to control the animations frame by frame.
Shall I store the sprite rect (relative to the sprite sheet) for each individual frame in an array, and then look up the suiting rect in each animation step? I tried to find out how this is done in CCAnimation, but I didn't succeed...
How to get the rect for each frame at initialization?
How to set the rect at each animation step?
Do I need to use CCSpriteBatchNode? I guess not, eh?
Cannot crealry understand, why you don't want to use CCAnimation, but anyway, to get answer for your questions you can check creation code of the CCSprite instance. Then, check creation of CCSpriteFrame instance. There you will find the answer for at least your first question.
Actually if you just want to manage animation frames differently from CCAnimate, you can just store array of CCSpriteFrames and show them as you want(in CCAnimate action these frames are just changed one by one in equal time intervals).
And if you do not want to show more than one frame of your animation, there is no difference will you use CCSpriteBatchNode or not. It saves a lot of processor time if you need to draw several parts of one texture, as it draws them in one draw call instead of send draw message to all of these sprites.
As you want animate sprite frame by frame I think using CCSpriteBatchNode would be a better option as it give you frame by frame access of animation.Making plist of sprites using any tool like "Zwoptex" will give an efficient way to animate using CCSpriteBatchNode.
Hope you know the animation using plist file with CCSpriteBatchNode.
I did the following with inspiration from Morions answer:
In the game tick function:
_animationFrames.legFrame = (_animationFrames.legFrame + 1) % _animationFrames.legFrames.count;
[_legs setDisplayFrame: [_animationFrames.legFrames objectAtIndex: _animationFrames.legFrame]];
And in the init function:
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode
batchNodeWithFile:#"Player.png"];
[self addChild:spriteSheet];
_animationFrames.legFrames = [[NSMutableArray array] retain];
for(int i = 0; i <= 15; ++i)
{
[_animationFrames.legFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"Player_legs-%d.png", i]]];
}
_legs = [CCSprite spriteWithSpriteFrameName:#"Player_legs-0.png"];
[_sprite addChild: spriteSheet];
[spriteSheet addChild:_legs z:1];

create a texture from a spritesheet cocos2d

Hey all
Basically all i want is to create CCTexture2D objects from a spritesheet. I can make individual sprites from
charSpriteCur = [CCSprite spriteWithTexture:charSheet.texture rect:CGRectMake(136, 0, 136, 223)];
but i want to get individual textures from a spritesheet so that i can use
[mySprite setTexture:tex];
to change the sprite as required. I dont need it to be an animated sprite i just want to be able to change its texture when i want using a spritesheet.
any ideas with this or what is the best approach?
thanks
g
I don't think this is possible. When I need to do this I instead remove the CCSprite node (which I have setup as a property in my class) and then make a new one. Here is an example:
[self removeChild:[self mySprite] cleanup:YES];
[self setMySprite:[CCSprite spriteWithSpriteFrameName:#"image.png"]];
[mySprite setAnchorPoint:ccp(0,1)];
[mySprite setPosition:ccp(623,872)];
[self addChild:mySprite z:5];

How to add animated background

i have a gif image and i want to put it in my iphone game background, the image is a moving scenery but when i put in my background its not moving ..How can i keep my background moving like the gif image?
FOr that you have to use the imageview and set its frame as background view.
Insert all your images used for creating GIF in Resource folder
Then use the following code
UIImageView *imgBackView=[[UIImageView alloc]initWithFrame:CGRectMake(0,0,320,480)];
NSArray *myImages = [NSArray arrayWithObjects:#"1.png",#"2.png",#3.png"#4.png", nil];
imgBackView.animationImages = myImages;
imgBackView.animationDuration = 0.5;// OR WHATEVER TIME YOU WANT
imgBackView.animationRepeatCount = 0; // 0 = loops forever
[imgBackView startAnimating];
[self.view addSubview:imgBackView];
[imgBackView release];
hAPPY iCODING...
As far as I know, animated gifs does not work in iPhone. However it is possible to have the same effect using animationImages property of UIImageView. Instead of setting single image, you can set array of UIImages as animationImages of the view. Then you can start the animation any time by calling startAnimating method.
Of course to have an array of images, you will have to extract the frames of the animated gif as different images and add them to your resources.