In our last tutorial, we covered making a sprite appear on the screen. In this tutorial, we will be moving a sprite across the screen by using a technique called “animation”. In animation, a succession of new positions are combined to give the illusion of movement. Think “Steamboat Willie”, the famous Walt Disney cartoon. It was created with thousands of drawings all strung together and played in quick succession. Similarly, we will set a new position for our sprite in every frame. This new position will be right next to the last, and when the app is opened, these frames containing the new positions will be played in quick succession. Unlike cartoons, however, this animation will only consist of the movement of a single static object.
To begin the coding process for animating our sprite, we must first have a sprite. We already did that in the last tutorial, so let’s simply work with that code. If you don’t already have it, go to the last tutorial and copy and paste the code into Xcode.
The things that we will need to add to our program in order to accomplish animation include a line that will call a method every frame, and the method that is called every frame.
#import "HelloWorldScene.h" CCSprite *icon; @implementation HelloWorld +(id) scene {
CCScene *scene = [CCScene node]; HelloWorld *layer = [HelloWorld node]; [scene addChild: layer]; return scene; } -(id) init {
if( (self=[super init] )) {
icon = [CCSprite spriteWithFile:@"Icon.png"]; icon.position = ccp(300,200); [self addChild:icon]; [self schedule:@selector(DoEveryFrame:)];
} return self; } - (void) dealloc {
[super dealloc]; } -(void) DoEveryFrame: (ccTime)dt{
icon.position = ccp(icon.position.x + 150*dt, icon.position.y);
}
@end |
[self schedule:@selector(DoEveryFrame:)];
This line will run the “schedule” method of the “self” object. When calling a method that is in the same class as the method you are working on, you use “self” instead of the name of your object to refer to the class. In this case, our class is CCLayer. The “schedule” method runs the method that is passed into it every frame. The method that we are passing into it is “DoEveryFrame.”
-(void) DoEveryFrame: (ccTime)dt{
icon.position = ccp(icon.position.x + 150*dt, icon.position.y);
}
This is the method “DoEveryFrame.” It requires that that the paramater “ccTime” be passed into it. The variable “dt” will be set equal to “ccTime” so that we can use it in our method code. ccTime will give us the difference in time from when the DoEveryFrame method was last called. The only line of code in our method is going to be the one that sets a new position for our sprite. It basically sets the position equal to the point with an x-coordinate that is the current x-coordinate plus 150 pixels times the difference in time since the last frame (usually fractions of a second), and a y-coordinate that is the same as the current y-coordinate. The net effect is that our sprite will appear to slide right on our screen. The reason we use the difference in time is to make sure that the sprite moves 150 pixels a second no matter what the frame rate is.
If we run the program now, the cocos2d icon will appear on the screen and then slide to the right. It keeps on going even after it goes off the screen. The next thing we’re going to to is prevent it from going off screen by resetting its position to the left side of the screen once it’s reached the right side of the screen. We can do this with a simple if-else statement that essentially says “if the x-coordinate is greater than this value, then change the x-coordinate to this.”
#import "HelloWorldScene.h" CCSprite *icon; @implementation HelloWorld +(id) scene {
CCScene *scene = [CCScene node]; HelloWorld *layer = [HelloWorld node]; [scene addChild: layer]; return scene; } -(id) init {
if( (self=[super init] )) {
icon = [CCSprite spriteWithFile:@"Icon.png"]; icon.position = ccp(300,200); [self addChild:icon]; [self schedule:@selector(DoEveryFrame:)]; } return self; } - (void) dealloc {
[super dealloc]; } -(void) DoEveryFrame: (ccTime)dt{
icon.position = ccp(icon.position.x + 150*dt, icon.position.y); if (icon.position.x > 480+30) {
icon.position = ccp(-30, icon.position.y);
}
} @end |
if (icon.position.x > 480+30) {
icon.position = ccp(-30, icon.position.y);
}
This is the if-else statement. In plain English, it says “If the x-coordinate of the icon sprite is greater than 480 + 30, then set its x-coordinate to -30 and leave the y-coordinate the same as it currently is.” The reason we chose 480 + 30 as the x-coordinate at which the position is reset is because the width of the screen is 480 pixels, and half the width of our sprite is 30 pixels. That way, the icon re-appears on the left side of the screen at the same time it disappears off the right side of the screen.
Upon running the above code, your sprite will move across the screen, re-appearing on the left side of the screen as it goes off the right side. I encourage you to mess around with the positions in the DoEveryFrame method. See if you can get the sprite to scroll vertically or even diagonally!


Seven Considerations for PHP Hosting
Intersteller Space Travel: is it Possible?
Smart Ways to Choose a Gadget
There’s an App for That: How to Find the Best Apps
Finding the Right Hosting Environment for Your Photographs
Using the techniques and code explained above, you could create a simple app that displays a scrolling message =)
Hey!
Great tutorial! I tried it out but I encountered a problem though. The movement was jerky. any suggestions on how to fix the movement?
Hi Chris,
Thanks :)
Hmmm….. I’ve never heard of anyone having that problem before. Setting the new position of the sprite using the time since the last frame is what usually fixes that, but since you are using the code I provided (you are, right?), that shouldn’t be a problem. Soooo… the only thing I can think of is that you have the Debug configuration on. To check this, open up Xcode and under “Active Configuration” check “Release” and make sure that “Debug” isn’t checked.
hey :)
I changed the active configuration to release but it’s still the same… the movement is still jerky
this is my code (I modified it a little to get it to work with my images)
-(void)animateClouds:(ccTime)dt{
Clouds1Image.position = ccp(Clouds1Image.position.x+75*dt, Clouds1Image.position.y);
if(Clouds1Image.position.x> 480+1150){
Clouds1Image.position = ccp(-480, Clouds1Image.position.y);
}
Clouds2Image.position = ccp(Clouds2Image.position.x+75*dt, Clouds2Image.position.y);
if(Clouds2Image.position.x> 480+1150){
Clouds2Image.position = ccp(-480, Clouds2Image.position.y);
}
}
Bummer.
I take it your clouds image is 2300 pixels wide? Hmm…
I can think of two more things it could be. When your app is running, what is the FPS? (it is displayed in the bottom left corner of the simulator screen by default). A low FPS would cause jerky-ness. It is usually the result of slow hardware, a low FPS setting somewhere, or many resource-intensive programs running at once. Many developers have apps that are terribly jerky in the simulator but run fine on the actual iDevice.
Open up the AppDelegate.m file in your Cocos2D project. Find the line that starts with “[director setAnimationInterval ". Make sure that it is "[director setAnimationInterval:1.0/60];”. It’s possible that that got changed somewhere down the line, which would result in jerky movement (low FPS). In fact, I can recreate your jerky-ness by setting that line to “[director setAnimationInterval:5.0/60];”. If it is at the correct setting, you might try fiddling around with that line anyways.
It is rather difficult to track down the cause of your problem, and I’m sure it’s painfully annoying. Hopefully this will fix it, but if not, then you might want to try asking around on the official Cocos2D iPhone forums: http://www.cocos2d-iphone.org/forum/
the cloud is 500×437.
the FPS started at 8.6 and went up to 10 and there it stayed.
yes, it says “[director setAnimationInterval:1.0/60];”
I’ve been asking around in that forum but noone seem to be able to help me. some suggest that I should instead use a run action instead of the way you mentioned in your tutorial.
Hmm…
Ah, so your problem is that your FPS is low. This is most likely a hardware/software related issue (as opposed to a problem in your code). It is also posible that your large, moving sprites are causing some lag (unlikely). Are you able to move a small sprite across the screen?
A run action would work, but you shouldn’t start changing your coding habits because of a problem like this. You SHOULD be able to move sprites across the screen using the method described above.
I am out of ideas about the cause of your problem, but I wish you the best of luck fixing it! Please come back and drop a comment about your solution if you figure things out :)
I’m sitting on MAC mini.
I tried with another image, 40×38 but the movement was jerky also, not much but a little. the FPS were 12.
I’ll let you know if I find a solution :)
thanks!
I’m not sure if you subscribed to this thread, but I’ve found a solution. Test it on an actual device; the simulator is unreliable.
You can thank Delo for bringing me back here ;)
Similar problem here, created cocos2d test app that have only one small ball sprite which is moved across the screen and movement motion is jerky. I’m using mini-mac as well. Was browsing internet last two days hoping that maybe im missing some trivial basic to normalize sprite movement with FPS for animation graphics, but could not find anything so it sounds like problem is not in software but in device.
In my case simulator runs with 60 FPS, but still motion is not smooth.
Btw, during animation FPS keeps almost constant (60FPS +- 0.5) and yes, tried to run Release build as well.
I, and many other developers, have come to the conclusion that the iPhone simulator is awful and unreliable. That is probably your problem. Test it on an iPod, iPhone, or iPad by signing up as a developer or jailbreaking and following a tutorial on how to do so.
Also, ensure that you are using the latest version of Cocos2D and either Xcode 3 or 4. Additionally, read through the discussion I had with Chris and try everything we mentioned.
Just tried to run my simple app on iPhone and sprite movements were normalized and smooth.
I’m glad to hear that you resolved the problem! It’s a shame that the testing process has to be so tedious.