Cocos2d v2 + Chipmunk : Fails when adding shapes to a CCLayer - objective-c

I'm very experienced with Cocos2d and Box2d, and wanted to try Chipmunk instead. Everything works fine as long as I add sprites to the helloworldlayer, but if I add another layer and attempt to add a sprite to that new layer it crashes.
It fails with an EXC_BAD_ACCESS in the cpSpaceStep function call in the update on the main layer.
-(void) update:(ccTime) delta
{
// Should use a fixed size step based on the animation interval.
int steps = 2;
CGFloat dt = [[CCDirector sharedDirector] animationInterval]/(CGFloat)steps;
for(int i=0; i<steps; i++){
HERE -> cpSpaceStep(space_, dt);
}
}
EDIT:
The problem seems to be regarding sprite batch nodes and not CCLayers.

Chipmunk doesn't actually interact directly with Cocos2D, it's just a physics engine. So if it's crashing in cpSpaceStep() with an EXC_BAD_ACCESS it's almost certainly because you gave Chipmunk a dangling pointer somewhere or have another memory bug that's corrupting data that Chipmunk is using.
If you compile it as debug, where does it crash exactly? Are you using any callbacks at all and are sure it's not happening in one of those?

Related

SKSpriteNode pools in iOS 8 seem to be allocated to overlapping memory

I might be missing something. But my current app on the appstore works in iOS 7, but in iOS 8 completely fails because it won't create a preallocated pool of sprites. They appear to be written to the same address unless the sprites have specifically different properties.
In iOS 7 the following code produces a set with 4 unique objects. In iOS 8, the same code produces a set with only 1 object:
NSMutableSet *aSet = [NSMutableSet set];
SKColor *sameColor = [SKColor redColor];
CGSize sameSize = CGSizeMake(10, 10);
for (int i = 0; i < 4; i++) {
//allocate a brand new sprite
SKSpriteNode *thisSprite1 = [[SKSpriteNode alloc] initWithColor:sameColor size:sameSize];
[aSet addObject:thisSprite1];
}
NSLog(#"aSet Count: %i", aSet.count);
iOS8 Result:
2014-09-09 15:06:43.065 MSM[383:27490] aSet Count: 1
Am I going crazy? Amazingly, pretty much my entire app is based on this code concept repeated over and over again. If I do the same thing, but use something like NSObject, then the problem goes away, so it appears to be a new change to SKSprite. I know I can work around it with some crazy stuff, but is a huge pain, since I shouldn't have to do that, and I was hoping to avoid another version submission.
Thanks to Josh for the direction on how to solve this new bump in the road.
I subclassed SKSpriteNode, overriding -isEqual and -hash, to both be what my best guess at the NSObject implementation is. Then just did a Find/Replace All in Project for "SKSpriteNode" for my subclass name, and all is back to it was in the iOS 7 build:
-(BOOL)isEqual:(id)object{
return self == object;
}
- (NSUInteger)hash
{
return (NSUInteger)self;
}

Reuse Same Sprite Cocos2d 3.0

I am wanting to use the same sprite multiple times in Cocos2d 3.0
at the moment when i do this i get the following error
"reason: 'child already added to another node. It can't be added again'"
i have looked at other responses to similar questions here on stacker overflow and they state that spriteBatchNode is required. However this has depreciated in version 3.0.
Make local instances of the sprites *( i have used nodes here as i get an error when trying to add them to the array (Incompatible pointer types assigning to 'CCSprite *' from 'CCNode '))
CCNode *_sprite1;
CCNode *_sprite2;
CCNode *_sprite3;
CCNode *_sprite4;
I currently Have an array where sprites(CCNodes)are added
_array1 = #[_sprite1,_sprite2,_sprite3,_sprite4];
_array2 = #[_sprite1,_sprite2,_sprite3,_sprite4];
I would then make a call to spawn the sprites
-(void)spawnSprites1
{
int randomNumber = [self generateRandomNumberBetweenMin:0 Max:_array1.count-1];
CCSprite *sprite = [_array1 objectAtIndex:randomNumber];
sprite.position = ccp(_size.width +100 , _size.height *0.26);
sprite.zOrder = DrawingOrderPlayer;
[_physicsNode addChild:sprite];
CCLOG(#"content size = %f",_size.height);
}
-(void)spawnSprites2
{
int randomNumber = [self generateRandomNumberBetweenMin:0 Max:_array2.count-1];
CCSprite *sprite = [_array2 objectAtIndex:randomNumber];
sprite.position = ccp(_size.width +100 , _size.height *0.26);
sprite.zOrder = DrawingOrderPlayer;
[_physicsNode addChild:sprite];
CCLOG(#"content size = %f",_size.height);
}
if the same sprite is drawn from either i receive the above crash log.
Does anybody know how to resolve this issue in Cocos2d v3.0
Thanks
Each new sprite needs to be a new CCSprite instance. Since cocos2d doesn't implement NSCopying yet, the easiest way is to initialize new sprites using one template instance's texture, like so:
CCSprite* newSprite = [CCSprite spriteWithTexture:templateSprite.texture];
Then assign any property from the templateSprite to newSprite if the copy should have the same value(s).
Problem resolved, rather the pulling sprites out of an array randomly, it was just as easy to randomly pull them using a switch statement.

OpenGL with Cocoa: No matching function call when trying to call CGLLockContext([[self openGLContext] CGLContextObj]);

I am learning OpenGL. To get an OpenGL context setup I was following the GlEssentials example from Apple. The GlContext is there locked in the draw method as follows:
- (void) drawView
{
[[self openGLContext] makeCurrentContext];
// We draw on a secondary thread through the display link
// When resizing the view, -reshape is called automatically on the main
// thread. Add a mutex around to avoid the threads accessing the context
// simultaneously when resizing
CGLLockContext([[self openGLContext] CGLContextObj]);
[m_renderer render];
CGLFlushDrawable([[self openGLContext] CGLContextObj]);
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
When I tried to call CGLLockContext with exactly the same arguments as above in my view class I the following error:
No matching function for call to 'CGLLockContext
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/OpenGL.framework/Headers/OpenGL.h:111:17: Candidate function not viable: cannot convert argument of incomplete type 'void *' to 'CGLContextObj' (aka '_CGLContextObject *')
Quickly inserting a typecast fixed the issue:
CGLLockContext((CGLContextObj)[[self openGLContext] CGLContextObj]);
Question is why? In Apples example it works fine without this typecast.
Two thoughts:
1) Are you doing this inside a C++ or ObjC++ file? That whole “candidate function” thing sounds like C++ to me, but I don’t really know C++.
2) Are your compiler flags (especially warnings and errors) the same in your project files as they are in Apple’s sample project. (I took a quick look at Xcode 5’s compiler settings and nothing jumped out at me.)

Creating autoreleased object inside GLKViewController run loop causes malloc error

I'm currently using GLKit to do some OpenGL drawing. I created a normal UIViewController and then added a GLKViewController subclass inside a container to do my drawing. While everything runs fine initially, if I let my program run for a period of time (perhaps 15-30 minutes), eventually it crashes and gives me the following error.
malloc: *** mmap(size=2097152) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
So I turned on the malloc_error_break breakpoint, and the stack trace points to the following code.
-(NSArray*)meshes:(NSArray *)meshes sortedFromFrontToBack:(BOOL)sortedFromFrontToBack
{
NSMutableArray *sortedMeshes = meshes.mutableCopy;
[sortedMeshes sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
DSNode *mesh1 = obj1;
DSNode *mesh2 = obj2;
GLKVector3 depth1 = isnan(mesh1.boundingSphere.radius) ? mesh1.transformationState.position : mesh1.boundingSphere.center;
GLKVector3 depth2 = isnan(mesh2.boundingSphere.radius) ? mesh2.transformationState.position : mesh2.boundingSphere.center;
GLKMatrix4 mesh1ToCameraSpace = [mesh1 nodeToOtherNodeTransform:self];
GLKMatrix4 mesh2ToCameraSpace = [mesh2 nodeToOtherNodeTransform:self];
GLKVector3 depth1InCameraSpace = GLKMatrix4MultiplyVector3WithTranslation(mesh1ToCameraSpace, depth1);
GLKVector3 depth2InCameraSpace = GLKMatrix4MultiplyVector3WithTranslation(mesh2ToCameraSpace, depth2);
NSNumber *n1 = [NSNumber numberWithFloat:depth1InCameraSpace.z];
NSNumber *n2 = [NSNumber numberWithFloat:depth2InCameraSpace.z]; /* Breakpoint triggered here */
if(sortedFromFrontToBack)
{
return [n2 compare:n1];
}
return [n1 compare:n2];
}];
return sortedMeshes;
}
As I commented, the [NSNumber numberWithFloat:] call throws the malloc error. This method gets called once each frame from my GLKViewController's drawInRect method. Essentially, I have a class which keeps track of my cameras and the meshes which are going to be drawn by OpenGL, and it sorts them in camera space from either front to back for opaque meshes or back to front for transparent before drawing them.
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(self.clearColor.r, self.clearColor.g, self.clearColor.b, self.clearColor.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DSDirector *director = [DSDirector sharedDirector];
for(DSMesh *mesh in director.opaqueMeshes)
{
[mesh draw];
}
/* The director class keeps track of my scene's cameras and meshes and calls the above method to return the scene's transparent meshes properly sorted */
for(DSMesh *mesh in director.transparentMeshes)
{
[mesh draw];
}
}
From what I've read, the autorelease pool should drain at the end of each run loop, so I wouldn't think that creating a bunch of autoreleased objects every frame is an issue, they should all get flushed each frame. I've profiled my program and checked for any leaks and can't find any, and I'm using ARC as well, which should minimize the risk. When I profile it, the live bytes total never budges, although the overall bytes rises quite quickly, and no leaks are found. In addition, didReceiveMemoryWarning never fires. I'm stumped.
Something smells wrong about the NSNumber creation being the cause of your malloc error. Testing with Instruments might help find the real culprit.
However, you're doing two things you don't need to, so there's some chance that eliminating them might help with your problem.
First, you don't need to wrap floats in an NSNumber to compare them. The basic comparison and mathematical operators work just fine, and don't require extra time or memory for object creation:
if (depth1InCameraSpace.z < depth2InCameraSpace.z)
return NSOrderedAscending;
else if (depth1InCameraSpace.z > depth2InCameraSpace.z)
return NSOrderedDescending;
else
return NSOrderedSame;
Second, the Tile-Based Deferred Rendering strategy implemented by the GPU hardware on iOS devices does its own hidden surface removal optimizations -- sorting opaque geometry front to back is redundant, so all it does is waste CPU time. (There's a decent explanation of this is in the OpenGL ES Hardware Platform Guide for iOS.) You should still sort translucent geometry back to front (and draw it after opaque geometry) for proper blending, though.
So, I think I've figured out what was going on. At some prior point I'd enabled NSZombies and then forgot about it, and so all of my objects that I expected to be deallocated were actually still hanging around. When profiling in Instruments, zombies must not be counted as live, which is why I couldn't figure out why I was seemingly running out of memory when the number of live bytes wasn't climbing. However, when I upgraded to XCode 5, the new memory gauge showed that I was quickly racking up memory, and then when I dropped into Instruments, Leaks was covered up by a warning that said that it would not work properly since NSZombies were enabled. So, I disabled zombies, and now my memory usage is staying constant, just like I expected it to.

copy a sprite pointer to keep him const?

i have this function :
-(void)blink:(CCSprite *)sprite
{
CCSprite *blinker=[sprite copy]; // i have add that to prevent sprite from change.
it gets a sprite and do animation on it, but sprite is keep changing all time cause its a pointer, so my function keep get a different sprites -WHICH I DONT WANT.
i was trying to copy it to another ccsprite, but its crashes.
whats wrong here ?
is that because i havnt release it ?
thanks alot
Can you post the code where call the blink method?
Maybe you can try this:
-(void) blink:(CCSprite*)sprite {
[sprite retain];
// Do some stuff with the sprite here
[sprite release];
}
However, functions should be called with thread-safe parameters so they don't get deallocated during the functions execution.