I have a CCLayer class imported onto a game layer
strangely all the the sprites have "artefacts" that seem to appear from nowhere since I have checked and re-exported all of the files
Is some setting or something else that could cause this to happen?
I'm new at this
but I have checked so far:
set to PixelFormat_RGBA8888
PVRImagesHavePremultipliedAlpha:YES
png's are clear from artefact (28bit with transparency)
Textures are made with texture packer with "pre-multiplied"
The Background is a CCLayer
The Mine is a CCLayer
both are added to the game layer (cclayer also) as "addChild"
backgroundManager = [[BackGround alloc] init];
[self addChild:backgroundManager z:0];
myShip = [[Ship alloc]init];
[self addChild:myShip z:5];
Yes it was the settings in texture packer
after a few changes in the settings they now seem to load fine.
with no artifacts
use pre multiple
trim not crop
and give a little more inner padding
hope it helps someone else (since it was driving me a little crazy)
Related
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.
In cocos2d 2.x we change the image of a CCSprite using CCTexture. But in cocos2d 3.x CCTextureCache seems to be deprecated as Xcode warns me : "undeclared identifier 'CCTextureCache'". Or may be am I miss something as I'm new to cocos.
So how can we change the image of a CCSprite in v3 ??
Thank you.
I think I know how to do.
We have to use a spriteSheet built with TexturePacker [note : may be it's wrong to speak about external resources like it on SO] for example (let's say we have 2 images : monster_01.png and monster_02.png).
We add the .plist and the .png into xCode
We put the spritesheet in cache
and then we can create a CCSprite with a frame using a item of the spritesheet.
This image can be changed.
Some code :
3) We put in cache
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"monsterSpriteSheet.plist"];
4) We create the sprite
CCSprite * mySprite = [CCSprite initWithSpriteFrame: [CCSpriteFrame frameWithImageNamed: #"monster_01.png"]];
5) To change image :
[mySprite setSpriteFrame:[CCSpriteFrame frameWithImageNamed: #"monster_02.png"]];
This works perfectly with cocos2d v3.
I spent 6 hours to have this process. Sometimes I feel stupid.
You can do it by using this
CCSpriteFrameCache and after that you can change you sprite by using function setSpriteFrame of ccsprite.
I'm working on a game and I want to create thumbnails of each level so I can use them in a menu. I do this with CCRenderTexture like this:
CCRenderTexture *renderer = [CCRenderTexture renderTextureWithWidth:bounds.size.width height:bounds.size.height];
ScreenShotLayer *scene = [[ScreenShotLayer alloc] init];
[renderer begin];
[scene visit];
[renderer end];
[renderer saveToFile:[NSString stringWithFormat:#"level%#.png", level.levelId] format: kCCImageFormatPNG];
This all works well and my image is saved, but it takes up a huge amount of memory and never releases it. Without saving this data my game takes 8 MB of RAM. When I save the image it takes over 430 MB.
If I leave everything the same and just comment out the saveToFile call I'm back to my 8 MB memory usage. I've debugged this with the leaks tool and it doesn't find any leaks.
Is this a framework issue? Is there a better way to handle this? Am I doing something silly?
My whole game is open source and you can get it at https://github.com/zgrossbart/bridges. This code happens in LevelMgr.mm.
Thanks for the help,
Zack
I found a solution to this problem on the Cocos2d forum and with a bit of poking around the code. You can read the forum post her:
http://www.cocos2d-iphone.org/forum/topic/48890
I still see CCRenderTexture leak a little memory. The Cocos2d team has tested this and says it's working in 2.1-beta. There's also a big performance improvement I could have made to my code.
I was using CCRenderTexture to create a thumbnail image of a Cocos2d scene. I did that by using CCRenderTexture to create a full size image and then using a special UIImage to resize and crop the image. It's much more efficient to create a CCRenderTexture of the size I want in the end and scale my Cocos2d scene to the size I want in the end.
I have several apps created with Cocos2D.
I am upgrading some of them to the new release 2.0 of Cocos2D. The method I am using is:
I create a new blank project from the standard template
I move all files to the new project
I generally keep the layer Helloworld as my initial Layer. I have noticed that Cocos2D creates an introLayer as the initial one and I have removed that and reverted the behavior to load Helloworld as before. Said that, I have noticed a few things:
The behavior inside Helloworld's init method is now different. I have noticed that the orientation is now reported incorrectly inside the init method. It will always report it as portrait even if the app is just landscape. What I have noticed also is that it is like the director is not fully initialized yet. This was confirmed if I try to use the director's view. This view will always come as not valid, if I try to use it inside Helloworld's init method.
To solve that, I have moved all code to Helloworld's onEnter method. Now, Helloworld and the director are full initialized and everything works.
This method worked for the first apps that I upgraded for Cocos2D 1.0 to 2.0, but something is wrong for the application I am converting now from Cocos2D 2.0beta to 2.0 final.
The problem I have now is that Helloworld is not triggering any touch and yes, I have this in place:
-(void) registerWithTouchDispatcher
{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
What can be preventing Helloworld from detecting touches in 2.0? How can I make the init method of Helloworld to behave like in 2.0 beta or 1.0?
NOTE: ccTouchBegan and registerWithTouchDispatcher are never called when Helloworld loads.
thanks.
The rotation issue is a known bug. The very first scene will be initialized in portrait mode, even if the app is set to be in landscape only. That's because the init happens before the orientation has been updated by the app delegate. Putting the code in onEnter fixes that, or simply loading an "intro" scene that then loads the actual first scene fixes that as well.
The touch issue is probably not a problem of cocos2d 2.0. Maybe it's as simple as not setting self.isTouchEnabled = YES. If the registerWithTouchDispatcher method isn't called, then isTouchEnabled is not set to YES or you're not doing this in a CCLayer class but maybe CCScene.
The solution for this question is to put [super onEnter] on the onEnter method.
-(void) onEnter {
[super onEnter];
self.isTouchEnabled = YES;
}
the lack of this line was creating all kind of problems on the application, like scheduler not working, weird behavior of ccMove, ccTransition not triggering onEnterTransitionDidFinish and all kind of problems.
I don't know if this is possible, but I would like to create one big texture atlas and use it on all classes of the application.
Can one CCSpriteBatchNode be used for multiple classes?
Suppose I create this on the main class
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"atlasGeral.plist"];
self.batchNodeGeneral = [CCSpriteBatchNode batchNodeWithFile:#"atlasGeral.png"];
[self addChild:self.batchNodeGeneral];
and I have another class creating CCLayers on the main class, that is initialized, before using CCSpriteBatchNode, like this:
-(id) init
{
if( (self=[super init])) {
self.bg = [CCSprite spriteWithFile: #"cCircularBG.png"];
[self addChild:self.bg];
self.dr = [CCSprite spriteWithFile: #"cCircularDR.png"];
[self addChild:self.dr];
}
return self; // self is a CCLayer
}
can this be optimized using the self.batchNodeGeneral from the main class? My idea is to replace these two sprites and others with something like [CCSprite spriteWithSpriteFrameName:...
thanks
I'm not entirely sure I follow, but I'm pretty sure the answer is yes.
CCSpriteBatchNode doesn't have anything to do with classes, it has to do with assets. The important restriction on the use of batch nodes is that every sprite in the batch needs to reference the same texture atlas. So it is perfectly fine to have one batch node for your entire application and have every gameplay class add its own sprites to that batch. This can turn into a practical issue if your texture atlas becomes larger than the maximum texture size on your target hardware (see iOS device specs for details), but if you still want to have global batches and lots of assets it's not too hard to create a batch pool indexed by texture ID, create one batch node per atlas, and whenever you create a new sprite add it to the appropriate batch.
Honestly, I feel like the whole batch node thing is a terrible kludge on Cocos2D's part that could be made almost completely transparent to developers while still retaining its efficiency, but maybe this opinion is not entirely fair since I haven't dug around in the rendering code to understand their motivations. I guess it would mess with expectations of how depth sorting works, etc., but still I don't understand why batching objects for render is made the programmer's responsibility, it should be done by the engine.
Edit to add possible solution:
-(id) initWithMainClass:(MainClass*)mc
{
if( (self=[super init])) {
self.bg = [CCSprite spriteWithSpriteFrameName: #"cCircularBG.png"];
[mc.batchNodeGeneral addChild:self.bg];
self.dr = [CCSprite spriteWithSpriteFrameName: #"cCircularDR.png"];
[mc.batchNodeGeneral addChild:self.dr];
}
return self; // self is a CCLayer
}
`
So when you initialize one of the other classes, you pass the main class instance as a parameter so you can access its fields. Or make the main/manager class a singleton or find another architecture suitable to your needs.