Cocos2d v3.0 - Using Physics Editor with animations - ios

I am trying to use Physics Editor to create custom physics for my sprites, which are animated. I am following the guide from https://www.codeandweb.com/blog/2014/04/09/using-physicseditor-with-cocos2d-v3, but it doesn't show what to do with animations.
Below is the code where I have my animations:
//adding the png with all the sprites(run)
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"run-hd.plist"];
CCSpriteBatchNode *runSheet = [CCSpriteBatchNode batchNodeWithFile:#"run-hd.png"];
[self addChild:runSheet];
//The sprite animation(run)
NSMutableArray *runAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 4; ++i)
{
[runAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"Run%d-HDN.png", i]]];
}
CCAnimation *runAnim = [CCAnimation animationWithSpriteFrames:runAnimFrames delay:0.1f]; //Speed in which the frames will go at
//Adding png to sprite
_character = [CCSprite spriteWithImageNamed:#"Run1-HDN.png"];
_character.position = ccp(100,80);
//Repeating the sprite animation
CCActionAnimate *runAnimationAction = [CCActionAnimate actionWithAnimation:runAnim];
CCActionRepeatForever *runRepeatingAnimation = [CCActionRepeatForever actionWithAction:runAnimationAction];
//Animation continuously repeating
[_character runAction:runRepeatingAnimation];
//Adding the Sprite to the Scene
_character.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, _character.contentSize} cornerRadius:0];
_character.physicsBody.collisionGroup = #"playerGroup";
_character.physicsBody.collisionType = #"playerCollision";
_character.scale = 2;
[_physicsWorld addChild:_character];
I created the .plist with the custom physics body in Physics Editor, is there a way to add it to my code? Or is there another way to get this done?
Thanks!

I figured it out. Just in case anyone needed to know, here is what I did. First I needed to add the GCCShapeCache classes found here https://github.com/CodeAndWeb/PhysicsEditor-Cocos2D-V3/tree/master/PhysicsEditor-Cocos2D-V3/Classes to my project. Then I added
#import "GCCShapeCache.h"
to my HelloWorldScene.m class and added the .plist file created in Physics Editor into my project. I then added
[[GCCShapeCache sharedShapeCache] addShapesWithFile:#"run.plist"];
[[GCCShapeCache sharedShapeCache] setBodyWithName:#"Run1-HDN" onNode:_character];
and my custom shape was added to my project.

Related

Check if SKShapeNode which is a Line contains Point

I'm programming a little Game. For this I need some Walls. Therefor I have used:
Wall[w] = [[SKShapeNode alloc] init];
Wall[w].path = WallPos[w];
Wall[w].lineWidth = 4;
Wall[w].strokeColor = [UIColor whiteColor];
Wall[w].zPosition = 3;
[self addChild: Wall[w]];
Wall is an Array of SKShapeNodes and is set in #interface, so I can use it in every method. WallPos contains CGMutablePathRefs.
In TouchesBegan and TouchesMoved I'm calling a method which should check if you have touched one of the walls.
I have also some SKShapeNodes which are Rectangles, and to check if they are touched, I have used
if ([SomeShape containsPoint: Position] {
//Do some stuff
}
But with a line it's not working. Sometimes I'm touching on the line and nothing happens. Then I've seen this: Detecting Touch on SKShapeNode that is a Line and I have tried to do it on that way:
for (int i = 0; i < NrWalls; i++) {
if (CGRectContainsPoint(Wall[i].frame, Position)) {
[self GameOver];
}
}
But now every Point I touch sets a "Game Over" to me!!
Has anyone an Idea, how could I check if the line is touched?
Thanks for your help!
DXXL
Not sure why you want to use SKShapeNodes for walls and rectangles. To answer your question, you can attach a physics body to your shape node and use the contact methods to check for possible contacts. However, assigning a physics body to a shape node could be a tricky undertaking due to the anchor points and getting a desired alignment.
Seeing that you are really only drawing rectangles for your walls, I suggest you use a SKSpriteNode with a physics body instead. Something like this:
SKSpriteNode *myNode = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(5, 100)];
myNode.position = CGPointMake(100, 100);
myNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:myNode.size];
myNode.physicsBody.dynamic = NO;
myNode.physicsBody.categoryBitMask = CategoryWall;
[self addObject:myNode];
If you need, you can read up on SKPhysicsBody here.

Using Sprite Kit to draw multiples of the same sprite as a background

So what I am trying to do is use a holder (the SKSpriteNode *sprite) and load from a set of three sprites:
coral
water
base.
What I intend to do is based on previously created NSMutableArrays, draw that particular texture at positions across the iPad screen so that, for instance:
at position 1,6: water
at position 5,18: coral.
The problem that is happening is that it is only drawing one texture and no others. Is there any fix for this? Should I go about this a different way?
// Load the sprites
SKSpriteNode *sprite;
TerrainType ter;
for (int i = 0; i < numberOfRows; i++)
{
innerArray = [terrainArray objectAtIndex:i];
for (int j = 0; j < rowLength; j++)
{
ter = [[innerArray objectAtIndex:j] intValue];
sprite = [[SKSpriteNode alloc] init];
switch (ter)
{
case base1:
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"MidBase"];
break;
case base2:
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"MidBase"];
break;
case coral:
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"Coral"];
break;
default:
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"PureWater"];
break;
}
sprite.position = CGPointMake(rowLength + width30, numberOfRows + height30);
[self addChild:sprite];
}
}
It looks like you are loading all the Sprites in the same position:
sprite.position = CGPointMake(rowLength + width30, numberOfRows + height30);
You are creating an identical CGPointMake for all of them (not sure what width30 and height30 are but they don't seem to change/increase anywhere in your code). If the Sprites are also of the same size they will be overlaid one up on the other. And you end up seeing only the last one loaded.
I assume you want to make this position be related to the two for loops indexes j and i in some way.

Crash when restarting a scene

So, here is my scene problem: I start from a Menu Scene, then go into the InGame Scene, and when the character is dead, I go to the Menu Scene again, all this using:
[[CCDirector sharedDirector] replaceScene:[MainMenu scene]];
and
[[CCDirector sharedDirector] replaceScene:[InGame scene]];
After losing the game, and trying to go back to the game, my SpriteSheet crashes with the error :
'CCSprite is not using the same texture id'
Here is how I init the animation :
- (void) initSprite:(NSString *)plist andTexture:(NSString *)texture_ {
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:plist];
spriteSheet = [CCSpriteBatchNode batchNodeWithFile:texture_];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for (int i=1; i<=12; i++) {
[walkAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"%d.png",i]]];
}
CCAnimation *walkAnim = [CCAnimation animationWithSpriteFrames:walkAnimFrames delay:0.05f];
texture = [CCSprite spriteWithSpriteFrameName:#"1.png"];
walkAction = [CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:walkAnim]];
[texture runAction:walkAction];
texture.position = position;
texture.tag = HeroType;
[spriteSheet addChild:texture];
[self addChild:spriteSheet];
}
The crash occurs when I add the texture to the spriteSheet:
[spriteSheet addChild:texture];
I believe the problem comes from the deallocation of the texture..
I don't use ARC.
You probably have a "1.png" in the cache that corresponds to another animation that was created before quit-restart sequence. Maybe you want to purge the sprite frame cache (and possibly a whole lot of other things) prior to restarting.
I completely avoid "1.png" through 'NNNN.png' since in all likelihood all your animations will have them. Instead i use things like :
walk_classKey_upNNNN.png {up,down,left,right,idle,jump ... and any other map stance i need)
fight_classKey_strikeNNNN.png {strike,hurt,dead ... for example)
classKey is {fighter,rogue, ... etc ... whichever unique soldier type I have)
and i name my plists/textures the same
walk_fighter_up-hd.plist (using texture packer, the plist embeds the texture name).
fight_rogue_cheapShot-hd.plist (cheapShot is one of my rogue's skill in my current game).

""CCSprite is not using the same texture id"" workaround?

I am animating a whole body through SpriteSheets with CCSpriteBatchNode and CCSpriteFrameCache. Now user can add his own pic to that body which when i try to addChild to Spritesheet crashes with error "CCSprite is not using the same texture id"
Now i know the face CCSprite was not in that cache/texture(it was created through texturepacker) and the crash was normal but i wanted to know if there was a workaround to this as i have to add a face to that body through user interaction and animate that body. And by far using spritesheets is the best option for animation. anyone??
In this case what you can do is You take picture of user , then you make texture from user's image .
Then Add that texture to the CCTextureCache . Now you have texture of user image. Now you can use that texture in animation.
Make Texture from Sprite(You can make sprite from user image)
CCSprite *spr = nil;//your sprite
CCRenderTexture* renderTexture = [CCRenderTexture renderTextureWithWidth:spr.contentSize.width height:spr.contentSize.height];
spr.anchorPoint = ccp(0, 0);
spr.position = ccp(0, 0);
[renderTexture addChild:spr];
[renderTexture begin];
[spr draw]; // or [spr visit];
[renderTexture end];
CCTexture2D *result = renderTexture.sprite.texture;
Add that Texture in to Texture Cache.
[[CCTextureCache sharedTextureCache] addTexture]
When you create a CCSpriteBatchNode it is linked to a single texture. This is the point of a CCSpriteBatchNode: to draw different sprites that use the same texture to reduce OpenGL draw calls and increase efficiency.
The easiest workaround (if you have not reached a performance-critical point) would be to use a regular CCLayer instead of a CCSpriteBatchNode.
If you still want to add different CCSprites (say, the body, the limbs and the head of your character) to the same CCSpriteBatchNode, the you need to build a single sprite sheet (or texture pack) which contains all the body parts that you need to add to the CCSpriteBatchNode. This single sprite sheet will be the only one that the CCSpriteBatchNode will use. You won't be able to add CCSprites that are not using this sprite sheet.
You can not Manually add CCSprite to SpriteSheets. Because When you create animated Sprite using texturepacker then i hope that you know it also created with .plist file and it loas image from it with its size.
When you add manually CCSprite then it is nor found from SpriteFramesWithFile. may be you got error.
another way for add animated CCSprite without use of texturepacker
CCSprite *dog = [CCSprite spriteWithFile:#"dog1.gif"];
dog.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:dog z:2];
NSMutableArray *animFrames = [NSMutableArray array];
for( int i=1;i<=5;i++)
{
NSString* file = [NSString stringWithFormat:#"dog%d.gif", i];
CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:file];
CGSize texSize = texture.contentSize;
CGRect texRect = CGRectMake(0, 0, texSize.width, texSize.height);
CCSpriteFrame* frame = [CCSpriteFrame frameWithTexture:texture rect:texRect];
[animFrames addObject:frame];
}
CCAnimation * animation = [CCAnimation animationWithSpriteFrames:animFrames];
animation.delayPerUnit = 0.07f;
animation.restoreOriginalFrame = YES;
CCAnimate *animAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:animation]];
[dog runAction:animAction];
Above code is just describe that how can you add animated CCSprite without use of texturepacker
Here you can also change array of Images so you may be add manually image also.

Can We change the players images dynamically in cocos2d game?

I want to select the player image from gallery or I can take picture from cam and I need to animate those images while player movement. I am new to cocos2d, can any body help me ?
To change player animations, you need to run a CCAnimate action on it.
// Add sprite frames to sprite frame cache (if you are using a spritesheet)
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"NinjaPreto.plist"];
// Create animation
CCAnimation* animation = [CCAnimation animation];
// Create sprite frames
CCSpriteFrame *spriteFrame1 = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"animation1.png"];
CCSpriteFrame *spriteFrame2 = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"animation2.png"];
CCSpriteFrame *spriteFrame3 = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"animation3.png"];
// Add sprite frames to animation
[animation addSpriteFrame:spriteFrame1];
[animation addSpriteFrame:spriteFrame2];
[animation addSpriteFrame:spriteFrame3];
animation.delayPerUnit = 0.1;
animation.restoreOriginalFrame = NO;
// Run action
[player runAction:[CCRepeatForever actionWithAction:animation]];
So, if you want to change the player image, just create a new animation action with the new images that you want.
PS.: If you just want to change player image, without animation, use:
[player setTexture:[[CCTextureCache sharedTextureCache] addImage:#"image.png"]];
In COCOS2D-X you can do this by following way
CCTexture2D *tex = CCTextureCache::sharedTextureCache()->addImage("xyz.png");
sprit_name->setTexture(tex);
iF YOU WANT TO CHANGE THE SPRITE SIZE THEN ALSO WRITE THIS LINE
sprit_name->setTextureRect(CCRectMake(0,0, tex->getContentSize().width, tex->getContentSize().height));

Resources