with this code monsters don't appear, only hero shows
for (int j = 0; j <= _discrH; j++)
{
for (int i = 0; i <= _discrW; i++)
{
CCSprite * sprite = [CCSprite spriteWithImageNamed:#"monster.png"] ;
sprite.position = ccp([self getCanvasXFromGameI : i],[self getCanvasYFromGameJ : j]);
[_sprites addObject:sprite ];
[self addChild:sprite];
}
}
_hero = [CCSprite spriteWithImageNamed:#"case1.png"];
_hero.position = ccp(0,0);
[self addChild:_hero];
But with this (non-sense) code, the monsters and the hero show, and I don't understand why...
for (int j = 0; j <= _discrH; j++)
{
for (int i = 0; i <= _discrW; i++)
{
CCSprite * sprite = [CCSprite spriteWithImageNamed:#"monster.png"] ;
sprite.position = ccp([self getCanvasXFromGameI : i],[self getCanvasYFromGameJ : j]);
[_sprites addObject:sprite ];
[self addChild:sprite];
}
_hero = [CCSprite spriteWithImageNamed:#"case1.png"];
_hero.position = ccp(0,0);
[self addChild:_hero];
}
Any ideas what I'm doing wrong ?
Related
I have two SKSpriteNode first Hero
+(id)hero
{
NSMutableArray *walkFrames = [NSMutableArray array];
SKTextureAtlas *heroAnimatedAtlas = [SKTextureAtlas atlasNamed:#"HeroImages"];
int numImages = (int)heroAnimatedAtlas.textureNames.count;
for (int i=1; i <= numImages; i++) {
NSString *textureName = [NSString stringWithFormat:#"hero%d", i];
SKTexture *temp = [heroAnimatedAtlas textureNamed:textureName];
[walkFrames addObject:temp];
}
Hero *hero = [Hero spriteNodeWithTexture:walkFrames[0]];
hero.heroWalkingFrames = walkFrames;
hero.name =#"Hero";
hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:hero.size];
hero.physicsBody.categoryBitMask = heroCategory;
hero.physicsBody.categoryBitMask = obstacleCategory | groundCategory | homeCategory | ~goodiesCategory;
return hero;
}
and second is Coin
SKSpriteNode *coin = [SKSpriteNode spriteNodeWithImageNamed:#"coin"];
coin.size = CGSizeMake(10,10);
coin.position = CGPointMake(100,100);
coin.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:coin.size];
coin.physicsBody.contactTestBitMask = coinCategory;
coin.physicsBody.dynamic=NO;
coin.name = #"coin";
[self.world addChild:coin];
And I am able to get collision detection by
if([contact.bodyA.node.name isEqual: #"coin"] || [contact.bodyB.node.name isEqual: #"coin"])
{
//[self LevelComplete];
SKNode* coinNode ;
if ([contact.bodyA.node.name isEqual: #"coin"]) {
coinNode=contact.bodyA.node;
}
else{
coinNode=contact.bodyB.node;
}
[coinNode removeFromParent];
NSLog(#"Coin touched");
}
Now my problem is every time hero jump and touch the coin it will go down to ground instead to continue jump and reach the height that it should, I know I am missing something here but don't know what it is, So anyone can please show me the right direction to correct this effect .
Create an extra "nilCategory" and set the collisionBitMask of your coin..
coin.physicsBody.collisionBitMask = nilCategory;
I'm trying to create 10 balloons in my app. I create a random CGPoint to set my node's position and check, in case that already exist a node at this point I try again.
I don't know why, the balloons keep being placed over another balloon.
Any ideia of what I am doing wrong?
Here is my code:
-(void)gerarBaloes:(int)quantidade
{
balloons = [NSMutableArray new];
u_int32_t maxHorizontal = 900;
u_int32_t minHorizontal = 100;
u_int32_t maxVertical = 650;
u_int32_t minVertical = 100;
for (int i=1; i<= quantidade; i++) {
CGPoint posicao = CGPointMake(arc4random_uniform(maxHorizontal - minHorizontal + 1) + minHorizontal, arc4random_uniform(maxVertical - minVertical + 1) + minVertical);
while (![self validPosition:posicao]) {
posicao = CGPointMake(arc4random_uniform(maxHorizontal - minHorizontal + 1) + minHorizontal, arc4random_uniform(maxVertical - minVertical + 1) + minVertical);
}
balao* nBalao = [[balao alloc]initWithPosition:posicao];
SKLabelNode* numero = [[SKLabelNode alloc]initWithFontNamed:#"Arial Rounded MT Bold"];
numero.text = [NSString stringWithFormat:#"%d",i];
numero.zPosition = 1;
nBalao.body.zPosition = 0;
[nBalao addChild:numero];
nBalao.body.name = #"balloon";
[balloons addObject:nBalao];
[self addChild:nBalao];
}
}
And this is my validation method:
-(BOOL)validPosition:(CGPoint)position
{
NSArray* nodes = [self nodesAtPoint:position];
NSLog(#"total de nodes %d",nodes.count);
if (nodes.count > 0) {
for (SKNode* n in nodes) {
if ([n isKindOfClass:[balao class]]) {
return NO;
}
}
return YES;
}else{
return YES;
}
}
Balao.m class:
#implementation balao
-(id)initWithPosition:(CGPoint)pos
{
if (self = [super init]) {
self.position = pos;
int n = arc4random_uniform(4);
_balloonAtlas = [SKTextureAtlas atlasNamed:[NSString stringWithFormat:#"balloon%d",n]];
_explosionFrames = [NSMutableArray array];
int numImages = _balloonAtlas.textureNames.count;
for (int i=1; i<= numImages; i++){
NSString *textureName = [NSString stringWithFormat:#"balloon_%d",i];
SKTexture *temp = [_balloonAtlas textureNamed:textureName];
[_explosionFrames addObject:temp];
}
SKTexture *textInicial = [_explosionFrames[0] copy];
[_explosionFrames removeObjectAtIndex:0];
self.body = [SKSpriteNode spriteNodeWithTexture:textInicial];
[self addChild:_body];
}
return self;
}
- (void)explodeBalloon
{
SKAction* explosao = [SKAction animateWithTextures:_explosionFrames timePerFrame:0.02f resize:NO restore:YES];
[self.body runAction:explosao completion:^(void){
[self removeFromParent];
}];
[self runAction:[SKAction playSoundFileNamed:#"popSound.mp3" waitForCompletion:NO]];
}
This is how the balloons appears:
Edit:
I tried the suggested method, with CGRectCointainsPoint, but it didn't work too. :/
Checking for nodes at a given point is not enough to prevent overlap. You need to check whether the point falls inside the frame of another balloon. You can modify the function like this
-(BOOL)validPosition:(CGPoint)position
{
NSArray* nodes = [self children];
if (nodes.count > 0) {
for (SKNode* n in nodes) {
if ([n isKindOfClass:[balao class]]) {
if (CGRectContainsPoint([n getBalloonFrame], position)) // Changed line
{
return NO
}
}
}
return YES;
}
return YES;
}
CGRectContainsPoint checks whether a given rectangle contains a point.
Inside balao class define the following function. Also note the changed line in the above code.
-(void)getBalloonFrame
{
return CGRectOffset(self.body.frame, self.frame.origin.x, self.frame.origin.y)
}
I have a boat with attached physics body. This boat is static physics body. Boat moving with CCAnimateMoveTo from left to right. When I tap on screen my character fall down. I detect collisions well. But I want that after collision my character just fall on boat and keep moving with it. Character is dynamic body. Link to sample video: Sample video
Here I create a boat:
- (void)createBoat
{
currentBoat = [CCSprite spriteWithImageNamed:#"Boat.png"];
currentBoat.position = ccp(0 - currentBoat.boundingBox.size.width, winSize.height * 0.2);
// currentBoat.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){0, 0, currentBoat.contentSize.width, currentBoat.contentSize.height * 0.5} cornerRadius:0];
CGPoint shape[6];
shape[0] = ccp(0, 30);
shape[1] = ccp(64, 10);
shape[2] = ccp(128, 30);
shape[3] = ccp(128, 0);
shape[4] = ccp(0, 0);
shape[5] = ccp(0, 30);
currentBoat.physicsBody = [CCPhysicsBody bodyWithPolylineFromPoints:shape count:6 cornerRadius:0 looped:NO];
currentBoat.physicsBody.type = CCPhysicsBodyTypeStatic;
currentBoat.physicsBody.collisionGroup = #"BoatGroup";
currentBoat.physicsBody.collisionType = #"BoatCollision";
[physicsWorld addChild:currentBoat z:PHYSICS_Z+3];
id actionMoveBoat = [[CCActionMoveTo alloc] initWithDuration:5.0f position:ccp(winSize.width + currentBoat.boundingBox.size.width, currentBoat.position.y)];
id actionMethod = [CCActionCallFunc actionWithTarget:self selector:#selector(createBoat)];
[currentBoat runAction:[CCActionSequence actions:actionMoveBoat, [[CCActionRemove alloc] init], actionMethod, nil]];
}
Character creation:
- (void)createCharacter
{
if (needCharacter)
{
CCSprite *newCharacter = [CCSprite spriteWithImageNamed:#"Character.png"];
newCharacter.opacity = 0;
newCharacter.position = ccp(winSize.width * 0.5, winSize.height * 0.76);
newCharacter.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, newCharacter.contentSize} cornerRadius:0];
newCharacter.physicsBody.affectedByGravity = NO;
newCharacter.physicsBody.allowsRotation = YES;
newCharacter.physicsBody.collisionGroup = #"playerGroup";
newCharacter.physicsBody.collisionType = #"playerCollision";
[physicsWorld addChild:newCharacter z:PHYSICS_Z+4];
id actionFadeIn = [[CCActionFadeIn alloc] initWithDuration:0.5];
[newCharacter runAction:actionFadeIn];
[allCharacters addObject:newCharacter];
needCharacter = false;
touchDone = false;
}
}
Then detection touch and collision:
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CCNode *lastCharacter = [allCharacters lastObject];
if (!touchDone)
{
[lastCharacter.physicsBody applyImpulse:ccp(0, 300)];
lastCharacter.physicsBody.type = CCPhysicsBodyTypeDynamic;
lastCharacter.physicsBody.affectedByGravity = YES;
touchDone = true;
}
}
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair playerCollision:(CCNode *)currentCharacterC BoatCollision:(CCNode *)currentBoatC {
currentCharacterC.physicsBody.collisionType = #"tmpCollision";
CCLOG(#"score++");
if ([allCharacters containsObject:currentCharacterC])
{
score++;
[scores setString:[NSString stringWithFormat:#"%d", score]];
[allCharacters removeAllObjects];
if (lives != 0)
{
needCharacter = true;
[self createCharacter];
}
}
CCLOG(#"allCharacters = %#", allCharacters);
return YES;
}
well I too faced the same problem, tried increasing the friction/surface velocity etc, it didn't really work well.
Finally had to resolve it my own way, whenever player lands on any body, you keep a pointer to that body as say _bodyUnderFeet of the player object.
Now, in the update loop add the velocity of the _bodyUnderFeet to the players calculated velocity. See the use of zeroVel_x
Sample code is here:
void Player::update(float dt)
{
float zeroVel_x = 0;
if(_bodyUnderFeet != NULL)
{
zeroVel_x = _bodyUnderFeet->v.x;
}
cpBody *bd = getCPBody();
assert(bd);
//log("Body angle %f", bd->a);
//check forward backward or at rest
float accel = _accelGround;
if(_onGroundBoost < UP_BOOST)
{
accel = _accelAir;
}
if(_touchPressedB)
{
if(!isFlippedX())
{
setFlippedX(true);
}
//cpBodySetVel(bd, cpv(cpBodyGetVel(bd).x - accel*0.25, 0));
cpVect bdv = cpBodyGetVel(bd);
bdv.x = bdv.x - zeroVel_x;
if(bdv.x > 0) bdv.x = 0;
if(bdv.x > -_maxVelocity.x)
cpBodySetVel(bd, cpv(zeroVel_x + bdv.x - accel*0.25, bdv.y));
}
else if(_touchPressedF)
{
if(isFlippedX())
{
setFlippedX(false);
}
//cpBodySetVel(bd, cpv(cpBodyGetVel(bd).x + accel*0.25, 0));
cpVect bdv = cpBodyGetVel(bd);
bdv.x = bdv.x - zeroVel_x;
if(bdv.x < 0) bdv.x = 0;
if(bdv.x < _maxVelocity.x)
cpBodySetVel(bd, cpv(zeroVel_x+bdv.x + accel*0.25, bdv.y));
}
else
{
cpFloat bd_x = cpBodyGetVel(bd).x;
bd_x = bd_x - zeroVel_x;
if(bd_x>0)
{
if(bd_x > accel*0.25)
{
cpBodySetVel(bd, cpv(zeroVel_x+bd_x - accel*0.25, cpBodyGetVel(bd).y));
}
else
{
cpBodySetVel(bd, cpv(zeroVel_x+0, cpBodyGetVel(bd).y));
}
}
else if(bd_x < 0)
{
if(bd_x < accel*0.25)
{
cpBodySetVel(bd, cpv(zeroVel_x+bd_x + accel*0.25, cpBodyGetVel(bd).y));
}
else
{
cpBodySetVel(bd, cpv(zeroVel_x+0, cpBodyGetVel(bd).y));
}
}
}
//check jump
if(_touchPressedJ)
{
if(_onGroundBoost)
{
cpVect bdv = cpBodyGetVel(bd);
if(bdv.y < 0) bdv.y = 0;
if((bdv.y + _accelUp) < _maxVelocity.y)
{
cpBodySetVel(bd, cpv(bdv.x, bdv.y + _accelUp));
--_onGroundBoost;
}
else
{
cpBodySetVel(bd, cpv(bdv.x, _maxVelocity.y));
_onGroundBoost = 0;
}
}
}
//check shots
if(_touchPressedS)
{
if(!_bulletFired)
{
}
}
//check home
if(_touchPressedH)
{
}
boundRotation(bd);
}
I think,
you can increase the friction between man and boat after he fall down. and reduce the elasticity . then the boat can 'take' the man go together...
just a trick.
I add one sprite per body and run animation, but when I try to remove this sprite after reloading scene(calling afterLoadProcessing once again) - removes the only first with animation. I'm new to iOS & Cococs2D programming, please help me with advice.
Here is my code:
-(void)afterLoadProcessing:(b2dJson*)json
{
[super afterLoadProcessing:json];
[self removeChild:enemysprite cleanup:YES];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"player_enemy.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"player_enemy.png"];
[self addChild:spriteSheet];
NSMutableArray *enemyGusenitsaAnimFrames = [NSMutableArray array];
for (int i = 31; i <=36; ++i) {
[enemyGusenitsaAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"%d.png",i]]];
}
CCAnimation *gusenitsaMovAnim = [CCAnimation animationWithSpriteFrames:enemyGusenitsaAnimFrames delay:0.1f];
_enemyGusenitsaMovement = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:gusenitsaMovAnim]];
_enemyGusenitsaMovement.tag = 109;
std::vector<b2Body*> enemySprites;
json->getBodiesByName("enemy", enemySprites);
for (int i = 0; i < enemySprites.size(); i++) {
b2Body *bod = enemySprites[i];
enemysprite = [[CCSprite alloc] init];
[enemysprite stopAllActions];
enemysprite.scale = 0.04;
[self addChild:enemysprite z:50];
bod->SetUserData(enemysprite);
[[enemysprite runAction:[_enemyGusenitsaMovement copy]] autorelease];
}
}
Instead of use [self removeChild:enemysprite cleanup:YES];, you can remove all children
[self removeAllChildrenWithCleanup:YES];
Or loop all bodies and remove it :
for (int i = 0; i < enemySprites.size(); i++) {
b2Body *bod = enemySprites[i];
CCSprite *sprite = (CCSprite *)bod->GetUserData();
[self removeChild:sprite];
}
I have a ball sprite that falls from the top and a boy underneath it. When the ball hits the boy's head I want it to follow a parabolic path. I tried using CCJumpTo as follows but I cannot get it to work. I'm calling the action inside the update loop. Am I not allowed to do that? Cant I call CCJumpTo inside the update loop?
- (void) jump
{
if(!method_called)
{
method_called=TRUE;
CCActionInterval *jump1 = [CCJumpTo actionWithDuration:3 position:CGPointMake(400, 400) height:150 jumps:1];
[_ball runAction:jump1];
NSLog(#"something");
}
else
{
NSLog(#"do nothing");
}
}
- (void)update:(ccTime)dt
{
time ++;
if ( dpad.leftJoystick.velocity.x > 0 && x < 2000 ) {
x = x + 10;
} else if ( dpad.leftJoystick.velocity.x < 0 && x > 0 ) {
x = x - 10;
}
if (x > 10 && x < 2000)
_boy.position = ccp(x, 100);
_ball.position = ccp(ball_x, ball_y);
ball_y = _ball.position.y - (speed * rebound);
_boy.anchorPoint = ccp(0, 0);
CGRect boyBox = CGRectMake(_boy.position.x, _boy.position.y, [_boy boundingBox].size.width, [_boy boundingBox].size.height);
_ball.anchorPoint = ccp(0, 0);
CGRect ballBox = CGRectMake(_ball.position.x, _ball.position.y, [_ball boundingBox].size.width, [_ball boundingBox].size.height);
if (CGRectIntersectsRect(boyBox, ballBox) && flag == 0)
{
rebound = -rebound;
flag = 1;
topFlag = 0;
[_ball stopAllActions];
[self jump];
}
if (_ball.position.y > 700 && topFlag == 0)
{
rebound = -rebound;
flag = 0;
topFlag = 1;
}
}
Thanks in advance.
EDIT:
Here's my init method
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if( (self=[super init]) ) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
self.ball = [CCSprite spriteWithFile:#"ball.png"
rect:CGRectMake(0, 0, 50, 50)];
self.ball.position = ccp(275, 999);
[self addChild:self.ball];
x = 0;
ball_y = 650;
ball_x = 300;
rebound = 1;
flag = 0;
topFlag = 0;
speed = 5;
time = 0;
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
#"boy.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"boy.png"];
//spriteSheet.scaleX = 0.5;
//spriteSheet.scaleY = 0.5;
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 8; ++i) {
[walkAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"boy%d.png", i]]];
CCAnimation *walkAnim = [CCAnimation animationWithFrames:walkAnimFrames delay:.1f];
self.boy = [CCSprite spriteWithSpriteFrameName:#"boy1.png"];
_boy.position = ccp(100000, 100000);
self.walkAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:walkAnim]];
[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO];
[_boy runAction:_walkAction];
_boy.flipX = YES;
[spriteSheet addChild:_boy];
dpad = [[MyJoystick alloc] init];
[self addChild:dpad z:10];
[self schedule:#selector(update:)];
}
[self addChild:spriteSheet];
}
return self;
}
Keep your action code inside a method and call it from update method using a boolean variable so that it would be called once only. Something like this:
take a boolean variable method_called in .h file:
-(void)update:(ccTime)dt
{
_boy.anchorPoint = ccp(0, 0);
CGRect boyBox = CGRectMake(_boy.position.x, _boy.position.y, [_boy boundingBox].size.width, [_boy boundingBox].size.height);
_ball.anchorPoint = ccp(0, 0);
CGRect ballBox = CGRectMake(_ball.position.x, _ball.position.y, [_ball boundingBox].size.width, [_ball boundingBox].size.height);
if (CGRectIntersectsRect(boyBox, ballBox) && flag == 0)
{
flag = 1; topFlag = 0;
[self callJumpAction];
}
}
-(void)callJumpAction
{
if(!method_called)
{
method_called=true;
CCActionInterval *jump1 = [CCJumpTo actionWithDuration:3 position:CGPointMake(400, 400) height:150 jumps:1];
[_ball runAction:jump1];
}
else
{
NSLog(#"do nothing");
}
}
Hope this will help.