Replacing one long CCMoveTo to multiple CCMoveTo with update Cocos2D - cocos2d-iphone

Currently, I have a game where an object determines a point to go to. It then calculates a path to that point and constructs one long CCMoveTo animation to get to that point. With this method, the animation seems very smooth and continuous.
I am now trying to break this one long CCMoveTo to multiple CCMoveTo leveraging the update method that gets called periodically. I want to do this because at each node of the path that the objects passes through, there might be a distraction and I want my object to be able to act on that. So this is what I am doing:
- (void) update: (ccTime) dt
{
if(![self isWalking]){
CGPoint nextNode = [_path objectAtIndex:(_currentPathIndex%[_path count])];
_currentPathIndex++;
NSMutableArray *actions = [[NSMutableArray alloc] init];
[actions addObject:[CCCallBlockO actionWithBlock:^void(id obj) {
[(Monkey *) obj setIsWalking:NO];
} object:self]];
[self moveTo: nextNode withCallbacks: actions];
}
}
Note: that I set isWalking to NO as a callback when the object has completely reached the destination node. This will let it calculate the next node to go to and construct that animation. Without this, the object would try to runAction in the middle of an ongoing CCMoveTo action. The problem with this method is that the movement does not seem smooth and continuous anymore. There seems to be a lag at the end of each CCMoveTo animation
Anybody has any clue on how to fix this?

That's a side effect of cocos2d's CCAction system respectively the CCScheduler.
There will always be a 1-frame delay because when an action stops, it won't do any work in the current frame: it made the last position update in the previous frame, and in the current frame it does no longer exist as a running action.
If you now run another move action in a scheduled method, that action won't begin updating until the next frame because it will schedule itself to receive updates. And updates that are scheduled while cocos2d's CCScheduler performs updates will not be run until the next frame, due to the fact that you can't modify an array during enumeration.
My advise is always to avoid using CCMove* actions for gameplay purposes, and instead manually update position of game objects. It's easy enough to do, and if you need a code example, look inside the CCMoveTo class.
A workaround would be to extend the distance of the CCMoveTo and replace the action shortly before it completes. Though that'll be a hack and may actually be harder to implement correctly than manual position updates.
PS: That's an issue I have addressed in the action model of KoboldTouch. It implements its own action system, with more lightweight and reusable actions.

Related

cocos2D: Adding delay after rendering a scene

I am trying to launch a physics object after loading a game scene, something similar to https://www.makegameswith.us/tutorials/getting-started-with-spritebuilder/creating-two-levels/
The code I have is something like this
- (void)didLoadFromCCB {
// tell this scene to accept touches
self.userInteractionEnabled = TRUE;
[self launchObject];
}
- (void) launchObject {
CCNode* object = [CCBReader load:#"Object"];
// Apply force to it
}
The problem is if I add a sleep method in didLoadFromCCB before launching the object or the first line in the launchObject, the game scene itself is loading only after that many seconds (say after clicking play) and immediately launches, but I want the game scene to load and after n seconds the physics object is launched.
I can easily solve this problem by using
- (void)update:(CCTime)delta
by setting some conditions for launch, but the question is, is that the right approach. I don't want to complicate update method to hold multiple if/else stuff and use it beyond what it's intended for, especially if there is another best way to do it.
I tried different solutions posted in this forum but didn't help my case.

Particles in cocos2d-x flicker when setPosition is changed

I'm using a particles, slightly modified CCParticleFlower with positionVar to be in form of vertical line, from top to bottom. In CCNode update I constantly change the position of the particles from left to right across the whole screen, when it reaches the right side I set x to 0 and start scrolling to the right.
The problem is when I reset the X value to 0, all particles blinks, they disappear for about one frame and appear in the next frame, it causes a nasty flickering effect.
It does not happen when I increment X values by small numbers but when the particle position is reset to its beginning position it flickers, on win32, android and ios. I’m using most recent 1.1 version (master branch)
I recently had something of a similar problem where the particles would jump around whenever their parent changed direction. I'm not sure if it's exactly the same problem, but here's the thread I found that helped with my problem:
http://www.cocos2d-iphone.org/forum/topic/17167
The relevant post:
I just encountered the same problem and it took me a while to get to the bottom of it, >here's the low down: do not use
[self schedule:#selector(NextFrame:)];
Instead, use
[self scheduleUpdate];
and rename NextFrame: to update:
Using a custom selector schedules your update at the very end of the CCScheduler queue, in other words, it will cause your NextFrame: method to be called AFTER the particle system's update: method, because the particle system schedules its own update method with a priority of 1.
This is not good because the position of the quads for the particles are updated using the current position of the emitter, and then the emitter is moved in your NextFrame: method, which causes all the particles to be moved again because the position of the emitter is really the position of the CCNode that draws the particles.
By using scheduleUpdate, you really schedule your update: method with a priority of 0, which means it will be called before the particle system's update: method and all will be well.
So basically, add an update method to your class and call scheduleUpdate instead of manually scheduling it.

How To Retrieve Actions From Sprite In cocos2d

I have a CCSprite that I'm using in a scene and have created multiple CCAnimation actions to apply to it all using a single CCSpriteFrameCache sharedSpriteFrameCache. While everything is working and I'm able to switch between animations, I feel like I'm doing poorly and would like to simplify my code by retrieving the running action(s) on the CCSprite to stop them individually before running the next action on it.
To help create some context, lets assume the following situation:
We have a CCSprite called mySprite
We have 3 separate CCAnimation actions defined for walking to the right, walking to the left, and sitting looking forward called: actionAnimWalkRight, actionAnimWalkLeft, and actionAnimSitForward respectively.
We want to have the sprite walk to the right when someone touches the screen right of mySprite, walk left when someone touches the screen left of mySprite and sit when someone touches mySprite.
The approach I'm using to accomplish this is as follows:
Place CCSprite as a child in the scene.
Tell the sprite to run an action using: [self runAction:actionWalkRight];
When I want to change the action after someone touches, I have a method called stopAllAnimationActions which I call before I apply a new action that stops any animation action no matter what's running. Basically lists ALL the CCAnimation/CCActions I have defined and stops each one individually since I don't want to use stopAllActions. as follows: [self stopAction:actionWalkRight]; [self stopAction:actionWalkLeft]; [self stopAction:actionSitForward];
Then I apply the new animation after the above method fires using: [self runAction:actionWalkLeft];
While this works, it just seems like a poor design to stop items that I know aren't running just because I don't know exactly what is running. So just looking for advice and the best recommended practice to do something like this within very complex situations so tracking every possible situation is difficult. Any feedback would be appreciated.
When creating the actions set the tag of that action with a constant:
actionWalkRight.tag= kCurrentAction;
[self runAction:actionWalkRight];
Then, retrieve the running action by that tag and stop it.
[self stopActionByTag:kCurrentAction];
I recommend you simplify your process and take advantage of the native Cocos features, including stopAllActions. Don't re-use actions, always create them from scratch as it has been well discussed among Cocos developers that re-using actions can be buggy.
Cocos is well optimized and features like stopAllActions are not performance hogs. It would probably be faster than your approach, actually.

Cocos2D - Particles follow the emitter instead of staying at the position they were released

In cocos2D I currently have a very simple particle emitter initialized like this:
turnEmitter = [[CCParticleFlower alloc] init];
turnEmitter.texture = [[CCTextureCache sharedTextureCache] addImage:#"Pocket.png"];
[self addChild:turnEmitter z:1];
turnEmitter.scale = 0.7f;
turnEmitter.positionType = kCCPositionTypeFree;
It is simply added directly to the gameplay layer.
This emitter follows a sprite around the screen in this way (happens in the update method):
turnEmitter.position = turnEmblem.position;
Now the problem is that the tail of particles left behind the emitter moves with the emitter, instead of released particles simply staying in the position they were released, which gives a really weird and stupid looking effect.
What I want to do is have the particles not follow the emitter at all after they have been spawned, unfortunately I have been unable to find any way of doing so.
As you can see from the code above I have already searched around, and found people which suggests changing the positionType property of the emitter, although I have tried all the possibilities and it does not solve the problem.
Does anyone have any ideas as to what this might be?
You may want to try changing the "emitterMode" as well to "kCCPositionTypeFree". I had a similar issue where i had the emitter as a child of a CCNode. The CCNode was being rotated, but the particles and emitter wasn't. In the same way it looked stupid because the illusion of rotation was ruined. I need to set the following on my emitter:
emitter.emitterMode = kCCPositionTypeRelative;
emitter.positionType = kCCPositionTypeRelative;

Handlings Game Loops in cocos2d

How does one handle multiple elements of a game at once?
In a scroller which the background/tilemap moves every gameloop how is the user input handled at the same time?
The map needs to be moved in the game loop and collision needs to be checked for the player object and parts of the map which it shouldnt hit, and there also needs to be code which takes the user input, moves the player on the map and checks for collisions too?
Should these be threaded or how are these done in cocos2d?
Are there any built in methods?
Register a step method with a specified interval.
[self schedule:#selector(step:) interval:1.0/60.0];
// Main loop of the application
-(void) step:(ccTime)delta
{
// do your step actions here
}
Try and avoid registering multiple step methods. You can do everything you need in one step method. You don't need to use threading.
It is prefer to register the update method
[self scheduleUpdate];
Then override the update method as you like
-(void) update:(ccTime)delta
{
//All steps happen here
}
this will be called in every frame of your game more accurately by the cocos2d than schedule a new one.
(Cocos2dx version: this->scheduleUdate(), void update(float delta);)