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);)
Related
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.
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.
I'm working on a two player iOS game that is similar to checkers. I'm using cocos2d to create this game.
I want a think time of .5 seconds between when the player's move renders and when the computer's move renders to simulate think time.
The flow of the game is controlled using NSNotification events and looks like this...
Player (computer or human) submits a move -> The board adds the new sprite -> The game controller updates the current player and asks them to submit a move.
I've tried adding usleep(500000) at the end of the board update or the beginning of the game update. What ends up happening is the sprites added in the board update, for the human player, don't show up until after the computer player has submitted his move. So the game waits 500 milliseconds and then updates with both moves.
Is there a way to force the CCLayer to update its child sprites before the usleep, or is there just a better way of adding this think time?
Thanks
if you schedule for receiving an update in your controller, you could slip time in the update:(ccTime)dt function.
in your .h
float _slipTime;
in your .m
// with other declaratives
static float THINK_TIME=.5f;
// last line before the stall
_slipTime=0.f;
[self schedule:#selector(pauseForThink:)];
-(void) pauseForThink:(ccTime) dt {
_slipTime+=dt;
if(_slipTime>THINK_TIME) {
[self unschedule:#selector(pauseForThink:)];
// trigger here whatever you wanted to accomplish after
// the think pause.
}
}
ok, this is simple, but will prevent the main loop from being blocked (this is what happens with your sleep). When running at 60 FPS, the pauseForThink method will be called about 30 times, and cocos will have 30 draw cycles during the pause.
I move an instance of CCSprite in my Cocos2D-based iPhone game like this:
[mySprite runAction:[CCMoveBy actionWithDuration:1.0
position:ccp(10, 10)]];
How can I get a callback everytime the sprite moves?
I'd like to do something like this:
[self registerForCallbacksFrom:mySprite
selector:#selector(spriteMovedOneStep)];
So spriteMovedOneStep would be called everytime mySprite moves. Would be nice to specify the frequency of the callback too so minimize CPU usage.
One possible solution is to subclass CCMoveBy and call your callback from it's update method. You also can setup frequency and everything you want with this approach.
If I get your question right you would like to have a method called at times when the Sprite is moving, correct ?
How about scheduling an update method that performs what you want if a SpriteIsMoving BOOL is set to YES, I'm not sure on what your trying to achieve but this is my take on it.
I'm developing a shoot'em up with qt creator and my problem is the link with the keyPressEvent function of my scene:
void Scene::keyPressEvent(QKeyEvent *event){
liste_event << event->key();
if (liste_event.contains(Qt::Key_Left)) {
vaisseau->MoveX(-1);
}
if (liste_event.contains(Qt::Key_Right)) {
vaisseau->MoveX(1);
}
}
It compiles, but my sprite (vasisseau) moves very slowly. How can I improve the code so it moves faster?
Well, the problem is that you are leaving the animation of the game to the keyPressEvent, which is not triggered as often as you would like.
To solve this problem I suggest you use the traditional approach, which involves having an function to draw() the scene (and it's objects). The idea is that this function is called every X miliseconds, and the drawing will work independently of a key being pressed or not.
So in this case, inside keyPressEvent you would just store the key that was pressed, and in Scene::draw() you will implement the logic that will call MoveX() with the appropriate parameter, based on the stored key.