Is it possible in Cocos2d to create a move animation that would go on a specific path?
For example, how should I do if I need an object to move on an arc or full circle?
Regards!
Sure you can do this using :
ccBezierConfig bezier;
bezier.controlPoint_1 = ccp(320,0); // control point 1
bezier.controlPoint_2 =ccp(0,0); // control point 2
bezier.endPosition = ccp(endPoint.x,endPoint.y) ;
id bezierForward = [CCBezierTo actionWithDuration:3 bezier:bezier];
[ball runAction:bezierForward];
you can use ccBezier to move any node in curves :
Now Animation Part :
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"eggAnimation.plist"];
spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"eggAnimation.png"];
[gameBackgroundLayer addChild:spriteSheet];
eggAnimFrames = [NSMutableArray array];
for ( int i = 1; i <= 10; i++ )
{
[eggAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"%d.png", i]]];
}
rotateAnim = [CCAnimation animationWithFrames:eggAnimFrames delay:0.05f];
ball = [CCSprite spriteWithSpriteFrameName:#"1.png"];
ball.position=ccp(160,80);
rotateAction =[CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:rotateAnim restoreOriginalFrame:YES]];
[spriteSheet addChild:ball];
Reference Links : http://www.raywenderlich.com/1271/how-to-use-animations-and-sprite-sheets-in-cocos2d
http://www.math.ubc.ca/~cass/gfx/bezier.html
Related
I have some sprite-sheet that i have to animate forever , and i would like to add it as a CCLayer
to my scene .
Later on , i have to move this whole animation sprite on the screen.
So, for example, i have some animation of a dog walking, from sprite sheet, this one is running forever. than i want to be able to move this dog on screen while animating.
What is the best way to do this ? (or the right way)
This is how i animate the frames :
CCSprite *boom;
boom = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:#"%#_00000.png",file]];
boom.position=touch;
[self addChild:boom];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 0; i < 5; i++)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:
#"%#_0000%i.png",file,i]];
[animFrames addObject:frame];
}
CCAnimation* boxAnimation = [CCAnimation animationWithSpriteFrames:animFrames delay:0.075f];
CCAnimate * boxAction = [CCAnimate actionWithAnimation:boxAnimation];
CCAction *call=[CCCallBlock actionWithBlock:^{[self removeFromParentAndCleanup:YES];}];
CCAction * sequence=[CCSequence actions:boxAction,[CCHide action],call,nil];
[boom runAction:sequence];
return self;
How would you move this whole thing ?
There are a few ways to do this. If you are not preocupied with collision detection, then one way would be to :
CGPoint egressPosition = ccp(0,0); // figure this out in your app
float moveDuration = 1.5f ; // whatever time you compute for desired speed and distance
id move = [CCMoveTo actionWithDuration:moveDuration position:egressPosition];
id spawn = [CCSpawn actions:sequence,move,nil];
[boom runAction:spawn];
otherwise, using your code as is
[self schedule:#selector(moveBox:)]; // optional, you could do this in update method
[boom runAction:sequence];
-(void) moveBoom:(CCTime) dt {
CGPoint newPosition;
delta = ccp(dt*speedX,dt*speedY); // crude , just to get the idea
newPosition = ccpAdd(boom.position,delta);
// here you can figure out collisions at newPosition before the collision
// and do whatever seems appropriate
boom.position = newPosition;
}
Using iPad 2 simulator , after i have created a sprite sheet, its size was ±8000 pixels, i got warning that is bigger than the supported 4096 x 4096 .
The Animation is made of images in the size of half iPad screen, and each animation has 10 frames .
So , how can i create a sprite sheet to run the animation ? do i need 2 sprite sheets? and if yes , is there a way to run them in sequence ?
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:plist];
hotGirl= [CCSprite spriteWithSpriteFrameName:pngFirst];
hotGirl.position=ccp(winSize.width/2,winSize.height/1.335);
[self addChild:hotGirl];
NSMutableArray *animFrames = [NSMutableArray array];
for(int i = 1; i < num+1; i++)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"%#%i.png",file,i]];
[animFrames addObject:frame];
}
CCAnimation* Animation = [CCAnimation animationWithSpriteFrames:animFrames delay:0.1f];
CCAnimate * pAction = [CCAnimate actionWithAnimation:Animation];
id call=[CCCallFunc actionWithTarget:self selector:#selector(done:)];
id seq=[CCSequence actions:pAction,call, nil];
[hotGirl runAction:seq];
Thanks .
Its openGLES Texture memory limitation.
int maxTexSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
printf("Max = %d\n",maxTexSize);
You can't load image that is larger than GL_MAX_TEXTURE_SIZE. It depends on device.
So after taking a little break after being very frustrated for months on end with this issue, I am now back and attempting to solve my issue once and for all.
I’m not going to post code, because the code I have is messy and patchy and is from countless points of view.
My issue is this:
I have a sprite, and his information is stored in a class called player.m. I have a game level, and it is stored in GameLevelLayer.m
I have player.m store velocity, direction, and all the information about the character, and then I have the GameLevelLayer.m implement, move, use bounds to check collisions, etc.
I now want to make the character move using a spritesheet (I know how to do spritesheeting, I just don’t know how to do it while working with two different classes)
My question is, do I create the batchnodes and spritesheet information (CCBatchnodes, caches, etc) and all of the actions and everything in player.m, and then run them in GameLevelLayer.m? Or do I create all that in GameLevelLayer.m
I really need some help here because I’ve been stuck on this for months
EDIT:
Here is where I am, thanks to a suggestion from a community member.
This is my entire player.m (Long story short, I define everything about the player 'you might just want to pay attention to the init, because that seems to be the problem. The other stuff is my physics engine')
#import "Player.h"
#import "SimpleAudioEngine.h"
#import "GameLevelLayer.h"
#implementation Player
#synthesize velocity = _velocity;
#synthesize desiredPosition = _desiredPosition;
#synthesize onGround = _onGround;
#synthesize forwardMarch = _forwardMarch, mightAsWellJump = _mightAsWellJump, isGoingLeft = _isGoingLeft;
#synthesize WalkAction = _WalkAction;
#synthesize isMoving = _isMoving;
-(id)initWithTexture:(CCTexture2D *)texture{
if (self = [super init]) {
self.velocity = ccp(0.0, 0.0);
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: #"BankerSpriteSheet_default.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"BankerSpriteSheet_default.png"];
[self addChild:spriteSheet];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <=6; ++i) {
[walkAnimFrames addObject: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:#"banker%d.png", i]]];
CCAnimation *walkAnim = [CCAnimation animationWithFrames:walkAnimFrames delay:0.1f];
self = [super initWithSpriteFrameName:#"banker1.png"];
self.WalkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
//[_Banker runAction:_WalkAction];
[spriteSheet addChild:self];
[[CCAnimationCache sharedAnimationCache] addAnimation:walkAnim name:#"walkAnim"];
}
}
return self;
}
-(void)update:(ccTime)dt {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults synchronize];
CGPoint jumpForce = ccp(0.0, 310.0);
float jumpCutoff = 150.0;
if (self.mightAsWellJump && self.onGround) {
self.velocity = ccpAdd(self.velocity, jumpForce);
if (![defaults boolForKey:#"All Muted"]) {
if (![defaults boolForKey:#"SFX Muted"]) {
[[SimpleAudioEngine sharedEngine] playEffect:#"jump.wav"];
}
}
} else if (!self.mightAsWellJump && self.velocity.y > jumpCutoff) {
self.velocity = ccp(self.velocity.x, jumpCutoff);
}
CGPoint gravity = ccp(0.0, -450.0);
CGPoint gravityStep = ccpMult(gravity, dt);
CGPoint forwardMove = ccp(800.0, 0.0);
CGPoint forwardStep = ccpMult(forwardMove, dt);
self.velocity = ccp(self.velocity.x * 0.90, self.velocity.y); //2
if (self.forwardMarch) {
self.velocity = ccpAdd(self.velocity, forwardStep);
if (!self.isMoving) {
//[self runAction: _WalkAction];
//self.isMoving = YES;
}
} //3
CGPoint minMovement = ccp(0.0, -450.0);
CGPoint maxMovement = ccp(120.0, 250.0);
self.velocity = ccpClamp(self.velocity, minMovement, maxMovement);
self.velocity = ccpAdd(self.velocity, gravityStep);
CGPoint stepVelocity = ccpMult(self.velocity, dt);
if (!self.isGoingLeft) {
self.desiredPosition = ccpAdd(self.position, stepVelocity);
}else{
self.desiredPosition = ccp(self.position.x-stepVelocity.x, self.position.y+stepVelocity.y);
}
}
-(CGRect)collisionBoundingBox {
CGRect collisionBox = CGRectInset(self.boundingBox, 3, 0);
//CGRect collisionBox = self.boundingBox;
//collisionBox = CGRectOffset(collisionBox, 0, -2);
CGPoint diff = ccpSub(self.desiredPosition, self.position);
CGRect returnBoundingBox = CGRectOffset(collisionBox, diff.x, diff.y);
return returnBoundingBox;
}
#end
So now the issue is, how do i get the player to appear in the game like a normal sprite, and then how do I run the animations when the player begins to move forward
Your game architecture is very good! Keep player properties on player and use GameLayer only to send player actions is the best approach.
If your Player Class extends from CCSprite, put everithing related to player in your Player Class: Run animations on it, load the cache on player constructor (use the CCSprite initWithTexture:rect:rotated: or a custom autorelease constructor, like a +(id)player ).
Then, in your GameLevelLayer you will need a CCSpriteBatchNode to add your player to it. You can use this batch node to add other objects that use same spritesheet.
EDIT:
Reviewing your code, your initWithTexture is wrong. The correct is to call [super initWithTexture:]:
-(id)initWithTexture:(CCTexture2D *)texture{
if (self = [super initWithTexture:texture]) {
Then, in your GameLevelLayer, create your player and add it to a CCSpriteBatchNode:
// *** In GameLevelLayer.m ***
// Create player
Player *player = [Player spriteWithFile:#"player.png"];
// Create batch node
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithTexture:player.texture];
// Add batch node as child
[self addChild:batchNode];
// Add player as batch node's child
[batchNode addChild:player];
// Set player position
player.position = ccp(100,100);
Your GameLevelLayer needs to do only this to create your Player. And when it detects user input, call methods like "jump", "moveRight", "moveLeft" in your player. Also detect collisions and send actions to player like "die", "getSpecialItem".
// *** In GameLevelLayer.m ***
[player jump];
[player die];
So, your player needs to handle these methods and performs its own logic to do the actions:
// *** In Player.m ***
- (void)moveRight
{
self.position = ccpAdd(self.position, ccp(10,0));
}
I created a CCAnimation as seen below. I tried lowering the delay to something below .05f and the animation now fails to complete! Its only 8 frames. I don't know if I am doing something wrong. At first I thought it was a memory leak and I was losing the action, so I assigned it to a strong property to test that, and still did it. I'm not sure how the delay could cause my animation to fail to finish. I am running in the simulator at 60 frames per sec.
Using Kobold 2.0.4
Can anyone help?
else if([model currentState] == PROCESSING_FIRST_ACTION)
{
CCDirector* director = [CCDirector sharedDirector]; // process model
//Get the top left corner of the screen
int screen_height = director.screenSizeAsPoint.y;
int screen_width = director.screenSizeAsPoint.x;
id attacker = [model attacker];
id attackChoice = [attacker getRegisteredAttack];
CCAction* attack = [model.resourceManager animation: #"simple-attack-frame"];
CCSprite * attackSprite = [model.resourceManager sprite: #"simple-attack-frame-01"];
attackSprite.position = ccp(screen_width - rxa(80), screen_height - rya(80));
attackSprite.tag = 5;
self.action = attack;
CCNode * check = [self getChildByTag:5];
if(check == nil)
{
[self addChild: attackSprite];
[attackSprite runAction:attack];
}
}
resource manager:
-(id)animation: (NSString*)_resource
{
NSMutableArray *frames = [NSMutableArray array];
for(int i = 1; i <= 8; ++i)
{
[frames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"%#-0%d", _resource, i]]];
}
CCAnimation *animation = [CCAnimation animationWithSpriteFrames: frames delay:1/60];
CCAction * action = [CCAnimate actionWithAnimation: animation];
return action;
}
In your line
CCAnimation *animation = [CCAnimation animationWithSpriteFrames: frames delay:1/60];
you're setting the delay to 1/60, but as 1 and 60 are both integers, 1/60 is 0. Try using 1.0f/60.0f and you'll get a floating point divide.
After digging around on the web I found a solution. I'm not the one who submitted this solution but I can attest that it fixed my problems:
https://github.com/cocos2d/cocos2d-iphone/commit/60f9cc98783b9a6a5635db4f468f83e0511c74c8
I am newer to cocos2d and preparing my demo game. I am moving a sprite from right to left using just a single image like a bird image moving from left to right. But I want to animate that sprite through various images so that it may look like a flying bird. I don't know how to accomplish that.
Here is my code:
CCSprite *target = [CCSprite spriteWithFile:#"Target.png" rect:CGRectMake(0, 0, 27, 40)]
id actionMove = [CCMoveTo actionWithDuration:actualDuration position:ccp(-target.contentSize.width/2, actualY)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)];
[target runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
For Animating particular sprite You would require sprite-sheet to be there in your Resource. You can create the Sprite-sheet from eitherTexture Packer OR Zwoptex Tools which I normally use.
Next you can implement the Below Code
CCSpriteBatchNode *sheet = [CCSpriteBatchNode batchNodeWithFile:#"drawing1-i3.png"]; // Png File Name
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"drawing1-i3.plist"]; // Plist File Name
[self addChild:sheet];
//Generating the Animation
NSMutableArray *arr_anim =[NSMutableArray array];
for(int i=1; i<30; i++) // i< number of frames in the plist File Name
{
NSString *str_fileNm = [NSString stringWithFormat:#"drawing1%d.png",i];
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:str_fileNm];
[arr_anim addObject:frame];
}
CCSprite *startAnim = [CCSprite spriteWithSpriteFrameName:#"drawing11.png"];
[startAnim setPosition:ccp(150,150)];
[self addChild:startAnim];
//Starting the Animation
CCAnimation *animation = [CCAnimation animationWithFrames:arr_anim delay:0.15f];
// id action =[CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:animation restoreOriginalFrame:YES]];
id action =[CCAnimate actionWithAnimation:animation restoreOriginalFrame:NO];
[startAnim runAction:action];
I think it would help you for creating the Animations.
Use the CCAnimation class.
In particular, use methods like animationWithFrames: and supply your images as an array.