I am creating a sprite like this in my init method (mySprite is declared in the .h):
mySprite = [CCSprite spriteWithFile:#"Image1.png"];
[mySprite setPosition:ccp(100, 300)];
[self addChild:mySprite z:1 tag:1];
Then in my other method, I try to animate it like so but it doesn't seem to animate at all, I also know that the method that this is in is getting called because I NSLogged it. Anyway here is how I try to animate mySprite:
CCSequence *moveSequence = [CCSequence actions:[CCMoveTo actionWithDuration:5 position:ccp(120, 400)],[CCMoveTo actionWithDuration:4 position:ccp(100, 300)], nil];
[mySprite runAction:[CCRepeatForever actionWithAction:moveSequence]];
Any ideas why this might be happening?
Thanks!
At first glance this part of the code seems right, so perhaps you would need to show more of your overall program so that we can examine what happens between your init function and your other method being called.
A couple things out of the blue:
make sure to call retain on your sprite so that it does not get removed summarily until you are done with it
what is "self" exactly here, is it a cocos layer? Is the layer added to the scene properly (ie, are you seeing the sprite being displayed, even if it does not move)?
I would also look to see if anything in the scene graph might happen between the "init" call and that second method of yours, in which you execute the animation code. Is there a StopAllActions somewhere? A removeFromParent or removeAllChildren, perhaps?
Cheers
Related
I am working with SpriteBuilder and Cocos2d to build a simple game, and I want to display an error message inside an if statement.
My problem is trying to initialize the CCNode I created in SpriteBuilder to show up on-screen.
I tried creating a CCNode layer and just creating all the objects via SpriteBuilder, but wasn't exactly sure how I was supposed to get that to show up on-screen as what I tried did not work correctly. I tried just using [self addChild:errorLayer] in the if statement and it crashed my app with the error message Argument must be non-nil, so I set up a breakpoint and errorLayer is nil, but I'm not sure how to make it non-nil.
I also tried creating a CCNode programmatically, but when the if-statement was run it didn't display anything on-screen. Here is the code I tried:
CCNode *errorLayer = [[CCNode alloc] init];
[errorLayer setContentSize:CGSizeMake(50, 100)];
[errorLayer setColor:[CCColor redColor]];
[self addChild:errorLayer];
Could anyone give me some tips on getting this to work? Thanks.
MainScene, which is the scene that the above code is called in, is initialized in AppController like this
- (CCScene*) startScene
{
return [CCBReader loadAsScene:#"MainScene"];
}
How can I enable shadow effect on *.pod object?
I set up camera and light but my object didn't have shadow.
Can somebody explain how to resolve this?
In order to enable shadows in cocos3d, you must first set
_viewController.viewShouldUseStencilBuffer = NO;
to
_viewController.viewShouldUseStencilBuffer = YES;
in the application delegate.
Next, you must add shadow volumes to the objects of a scene manually.
You can do this by adding this method call to the initialization method of your cc3scene subclass:
[self addShadowVolumesForLight:yourLight];
in order to add shadow volumes to every object in the scene for a specific light, or:
[self addShadowVolumes];
to do the same for all lights in the scene.
alternatively you can do the same for specific objects in the scene, if you want to limit shadowing.
e.g.
[someObject addShadowVolumesForLight:yourLight];
[someObject addShadowVolumes];
So in my project, I call an instance method called "-(void)fire" in the class "Survival.m":
-(void)fire {
NSLog(#"Firing");
CCSprite *sprite = [CCSprite spriteWithFile:#"bullet.png"];
sprite.position = player.position;
NSLog(#"%#",NSStringFromCGPoint(player.position));
[self addChild:sprite z:100];
}
When I do this, the sprite doesn't show on the screen.
The method is being called from another layer but since it logs "Firing" every time I tap the button, it's not the problem.
I am using a TMXTiledMap as well if that could cause any problems.
Please help, thanks!
EDIT---------
I can create sprites in the other layer, HUDLayer but not in the Survival layer which contains the player and the tiled map. If I create a sprite in the "init" method, it works correctly but If i do it in the method "fire" it doesn't work. The method "fire" is being called from the HUDLayer but I still now the method is being called since I see in the log that it says "Firing"
Could it be that:
1. The sprite is being created out of sight?
2. The sprite is not being created?
3. The sprite is not added to the correct parent?
Any suggestions?
to add a sprite in cocos2d do something like this
CCNode *parent = [self getChildByTag:kTagParentNode];
[parent addChild:sprite];
if that doesnt fix it, make sure the point where you are adding it is on the screen and try changing the z value to see if that helps
EDIT
add this under where you import files
enum {
kTagParentNode = 1,
};
Thanks Everybody, Solved it in some mysterious way. Thanks for the help anyway. I think I declared the layer in a wrong way.
Have a nice day!
I am using some static instance of a GameScene subclass of CCScene. Calling from GameScene
[[CCDirector sharedDirector] replaceScene:[MainMenuScene scene]];
doesn't trigger the dealloc method of the GameScene.
The method is called once I load again the scene (and a new GameScene is created):
+(id) sceneWithId:(int)sceneId
{
CCScene* scene = [CCScene node];
GameScene* gameScene = [[self alloc] initWithId:sceneId];
[scene addChild:gameScene z:0 tag:GameSceneLayerTagGame];
return scene;
}
-(id) initWithId:(int)sceneId
{
CCLOG(#"scene With id");
if ((self = [super init]))
{
instanceOfGameScene = self;
//ONLY NOW the previous object becomes unreferenced and the memory management system is allowed to deallocate it
I wanted to understand if there is a way of forcing the dealloc method to be called every time I replace a (static) scene and not only when the memory gets "freed".
Or, if I should instead, write some cleanups methods that stops ongoing processes that I don't want to effect the MainMenuScene (e.g. I have put a stop background music method call in the dealloc method of GameScene but as also the background music is in a static class -and is not added to GameScene as child- then it keeps playing once back in the MainMenuScene).
My quick fix proposal hence is to do something like this:
[self stopAllStuffInOtherStaticClassesThatAreRelatedOnlyToGameScene];
[[CCDirector sharedDirector] replaceScene:[MainMenuScene scene]];
Is this a good approach?
EDIT: when is sensible to add this code in the dealloc method?
[self removeAllChildrenWithCleanup:TRUE];
I smell bad practice. Never, ever keep a static instance of a node around. Especially not outside the scene hierarchy. It just breaks cocos2d's way of handling memory management.
If you need to preserve state, save this state to a separate class but by all means let the scene go when you change scenes. Then restore the state when the scene inits again.
You can not force the dealloc method. Wanting to do so is a sign of code smell. You can however override the -(void) cleanup method to run de-initialization code before dealloc and after the node has been removed as child.
EDIT: when is sensible to add this code in the dealloc method?
[self removeAllChildrenWithCleanup:TRUE];
Never. Ever.
Again, if you find you need to do this, there's a terrible bug somewhere. Cocos2D will have removed the child nodes by this time. In fact, it does so during the cleanup method, one way to cause cocos2d not to remove a node's children is when you override cleanup and not call [super cleanup].
Or perhaps when you keep it as a static instance, so it'll never actually call the cleanup method. And even worse would then continue to run scheduled updates and actions.
You trouble is that you don't release your game scene. Create it as
GameScene* gameScene = [[[self alloc] initWithId:sceneId] autorelease];
and it will be deallocated right.
Anyway, I don't see any need to create game scene as a child of other scene, but maybe i don't know something about your project.
And I cannot understand, what do you mean under "static CCScene"
Using 'Instruments' under Developer Tools, I was able to make some progress on this matter:
When the scene is created it should follow a few simple rules to keep the memory low:
Allocate the sprites from smallest to largest
Make sure to call [self unscheduleAllSelectors]; at the right times
Override the -(void)dealloc method with the following code if you want to see significant memory improvements in your case, as this will hit every time the CCScene is loaded:
// Clean up memory allocations from sprites
[[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
[[CCDirector sharedDirector] purgeCachedData];
[[CCSpriteFrameCache sharedSpriteFrameCache] removeSpriteFrames];
[CCSpriteFrameCache purgeSharedSpriteFrameCache];
I am looking into converting my OpenGL rendering code to take advantage of a few features of GLKit (namely the asynchronous texture loading and the automation provided by GLKView/Controller). However, it appears that the classes are designed mainly to accommodate people rendering using an animation loop, whereas I'm working with on-demand rendering. Additionally, some of the rendering is to a texture rather than the GLKView's framebuffer, so should I be looking to just subclass the GLKView and add additional FBOs?
Is there a recommended approach for this type of setup? I would expect something along the lines of:
Set the view controller's preferredFramesPerSecond to 0, or just
pause the frame updates?
Ignore the glkViewControllerUpdate or glkView:drawInRect: methods
and just draw what I need, when I need it.
Use the view's setNeedsDisplay as with a normal UIView in order
to display the frame (do I need to call bindDrawable given that I
will be rendering to a texture as well?).
Perhaps it's not worth the effort if this is not what the new API is designed for? I wish the documentation was a little more thorough than it is. Perhaps more samples will be provided when the API has 'matured' a little...
Thanks
The approach I ended up using was to not bother with the GLKViewController, but just use GLKView directly under a UIViewController subclass.
Clearly, the GLKViewController is intended for use by people who need a consistent rendering loop for apps such as games. Without it, drawing to the GLKView is as simple as calling [glkView setNeedsDisplay]. Be sure to set enableSetNeedsDisplay to YES in order to enable this behaviour.
If you did still want to make use of a GLKViewController, you can disable the animation rendering loop in viewWillAppear like so:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated]; // setPaused automatically set to NO in super's implementation
[self setPaused:YES];
}
Also, set resumeOnDidBecomeActive to NO to prevent the view controller from resuming again automatically.
Using a plain UIViewController with a GLKView is perfectly acceptable however, and I have seen it recommended by an Apple engineer as an appropriate way to perform on-demand drawing.
I've just converted my code from using an EAGLContext manager I rolled myself to using the GLKit classes.
You suggest you might "..ignore the.. glkView:drawInRect: methods and just draw what [you] need, when I need it". This seems like a sensible option performance-wise; I assume (though haven't tried) if you simply don't specify a GLKViewDelegate or provide a subclassed GLKView with its drawInRect: defined then no animation loop rendering will occur. Have you attempted this?
The alternative would be to simply create some #property (assign, nonatomic) BOOL shouldUpdate; in your MyController : GLKViewController <GLKViewDelegate> class which will only update if there is something to do:
[self setDelegate:self]; // in init or awakeFromNib or other..
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
if ([self shouldUpdate]) { ...
I'm sure you get the idea, it's hardly complicated.
One thing worth mentioning: the official API docs state that viewDidLoad should be used in your GLKViewController for initial GL setup. I had issues with this; for some reason my glCreateShader calls always returned zero. This may have been due to my setting the EAGLContext post-initialisation; I couldn't pass it as an init parameter since I created the controller in Storyboard. However, there was nothing logically wrong with the code, so I offer this friendly warning in case you encounter similar issues. My solution is simply to have the following in my drawInRect:
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
if ([self initialGLSetupDone] == NO) {
[self beforeFirstRender];
[self setInitialGLSetupDone:YES];
}
// .. rest of render code goes here.
}
Obviously it's not ideal to have an IF in there unnecessarily, but it was an easy solution.
Let me know how it goes if you try updating to use GLKit.
After you have created GLKView, add this line:
glkView.enableSetNeedsDisplay = TRUE;
(Because of this, no one will redraw the view automatically)
When you want redraw, insert this line:
[glkView setNeedsDisplay];
... then drawInRect routine will be called only once.
Hope it helps.