Objective-C and Box2D multiple sprite touch detection - objective-c

I have created an array of enemies and when I add an enemy I add the appropriate box2d code, however I have found that none of my enemies can be touched, I am not sure what is causing this but from what I can tell it never returns a fixture.
I have tried setting the user data but then I do not get multiple items.
This is how I add my sprite etc
for (int i = 0; i < EnemyType_MAX; i++)
{
CCArray* enemiesOfType = [enemies objectAtIndex:i];
int numEnemiesOfType = [enemiesOfType capacity];
for (int j = 0; j < numEnemiesOfType; j++)
{
EnemyEntity* enemy = [[EnemyEntity alloc]init:_gameScene enemyType:EnemyTypeBreadman];
[batch addChild:enemy z:0 tag:i];
[enemiesOfType addObject:enemy];
[allEnemies addObject:enemy];
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(self.position.x/PTM_RATIO, self.position.y/PTM_RATIO);
bodyDef.userData = self;
b2Body *body = _gameScene.world->CreateBody(&bodyDef);
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &circle;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);
}
}
I then use my touch handler to try and return what item has been touched
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"ccTouchesBegan %#", (_mouseJoint!= NULL) ? #"YES" : #"FALSE" );
if (_gameScene.mouseJoint != NULL) return;
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
float move = 0.0f, x1, y1, z1;
[_gameScene.camera centerX:&x1 centerY:&y1 centerZ:&z1];
b2Vec2 locationWorld = b2Vec2((location.x+x1)/PTM_RATIO, (location.y+y1)/PTM_RATIO);
NSLog(#"ccTouchesBegan %#",NSStringFromCGPoint(location));
b2AABB aabb;
aabb.lowerBound.Set(-1.0f+locationWorld.x, -1.0f+locationWorld.y);
aabb.upperBound.Set(1.0f+locationWorld.x, 1.0f+locationWorld.y);
b2Vec2 callPoint;
callPoint.Set (locationWorld.x,locationWorld.y);
QueryCallback callback(callPoint);
_gameScene.world->QueryAABB(&callback, aabb);
b2Body* nbody = NULL;
if (callback.m_fixture)
{
nbody= callback.m_fixture->GetBody();
}
if (nbody)
{
b2BodyDef bodyDef;
b2Body* groundBody = _gameScene.world->CreateBody(&bodyDef);
b2MouseJointDef md;
md.bodyA = groundBody;
md.bodyB = nbody;
md.target = locationWorld;
#ifdef TARGET_FLOAT32_IS_FIXED
md.maxForce = (nbody->GetMass() < 16.0)? (1000.0f * nbody->GetMass()) : f loat32(16000.0);
#else
md.maxForce = 1000.0f * nbody->GetMass();
#endif
_gameScene.mouseJoint = (b2MouseJoint *)_gameScene.world->CreateJoint(&md);
nbody->SetAwake(true);
}
}

In your init method, right after the if statement, is this in your code:
if(self = [super init]){
self.isTouchEnabled = YES;
EDIT------------------
Instead of using ccArray, you should use this:
CCSprite *_anArray[x];
When I deal with sprites I always put them in a sprite array, I declared it in the header. You also have to do the #property(nonatomic, retain) NSMutableArray *arrowArray; in the .h file and in the .m #synthesize arrowArray = _arrowArray;
Then I just added all my sprites into that array. Should work.

Related

SKPhysicsJoints are all fairly wobbly and elastic

So, I have an object composed of several physics bodies with 10 or so joints holding it together (pin and fixed). It works well but I am surprised at how wobbly the joints are. I'd imagine "fixed" to be just as fixed as if I merged them into one physics body, but it's substantially wobbly to the point that it is unusable. Also with pins, the points on each physics body seem to have quite some play apart from each other when force is applied to connecting objects. This is the case all the time, and both bodies involved are not restricted in motion in any way.
I would love to have the joints more rigid and less elastic. Has anyone been able to find a solution or reason for this? adding several more joints does not seem to make it any more rigid.
I faced a similar elasticity bug with a rope simulation and could finally come up with a workaround.
Here's my rope interface:
#import <SpriteKit/SpriteKit.h>
#interface ALRope : NSObject
#property(nonatomic, readonly) NSArray *ropeRings;
#property(nonatomic) int ringCount;
#property(nonatomic) CGFloat ringScale;
#property(nonatomic) CGFloat ringsDistance;
#property(nonatomic) CGFloat jointsFrictionTorque;
#property(nonatomic) CGFloat ringsZPosition;
#property(nonatomic) CGPoint startRingPosition;
#property(nonatomic) CGFloat ringFriction;
#property(nonatomic) CGFloat ringRestitution;
#property(nonatomic) CGFloat ringMass;
#property(nonatomic) BOOL shouldEnableJointsAngleLimits;
#property(nonatomic) CGFloat jointsLowerAngleLimit;
#property(nonatomic) CGFloat jointsUpperAngleLimit;
-(instancetype)initWithRingTexture:(SKTexture *)ringTexture;
-(void)buildRopeWithScene:(SKScene *)scene;
-(void)adjustRingPositions;
-(SKSpriteNode *)startRing;
-(SKSpriteNode *)lastRing;
#end
Rope Implementation:
#import "ALRope.h"
#implementation ALRope
{
SKTexture *_ringTexture;
NSMutableArray *_ropeRings;
}
static CGFloat const RINGS_DISTANCE_DEFAULT = 0;
static CGFloat const JOINTS_FRICTION_TORQUE_DEFAULT = 0;
static CGFloat const RING_SCALE_DEFAULT = 1;
static int const RING_COUNT_DEFAULT = 30;
static CGFloat const RINGS_Z_POSITION_DEFAULT = 1;
static BOOL const SHOULD_ENABLE_JOINTS_ANGLE_LIMITS_DEFAULT = NO;
static CGFloat const JOINT_LOWER_ANGLE_LIMIT_DEFAULT = -M_PI / 3;
static CGFloat const JOINT_UPPER_ANGLE_LIMIT_DEFAULT = M_PI / 3;
static CGFloat const RING_FRICTION_DEFAULT = 0;
static CGFloat const RING_RESTITUTION_DEFAULT = 0;
static CGFloat const RING_MASS_DEFAULT = -1;
-(instancetype)initWithRingTexture:(SKTexture *)ringTexture
{
if(self = [super init]) {
_ringTexture = ringTexture;
//apply defaults
_startRingPosition = CGPointMake(0, 0);
_ringsDistance = RINGS_DISTANCE_DEFAULT;
_jointsFrictionTorque = JOINTS_FRICTION_TORQUE_DEFAULT;
_ringScale = RING_SCALE_DEFAULT;
_ringCount = RING_COUNT_DEFAULT;
_ringsZPosition = RINGS_Z_POSITION_DEFAULT;
_shouldEnableJointsAngleLimits = SHOULD_ENABLE_JOINTS_ANGLE_LIMITS_DEFAULT;
_jointsLowerAngleLimit = JOINT_LOWER_ANGLE_LIMIT_DEFAULT;
_jointsUpperAngleLimit = JOINT_UPPER_ANGLE_LIMIT_DEFAULT;
_ringFriction = RING_FRICTION_DEFAULT;
_ringRestitution = RING_RESTITUTION_DEFAULT;
_ringMass = RING_MASS_DEFAULT;
}
return self;
}
-(void)buildRopeWithScene:(SKScene *)scene
{
_ropeRings = [NSMutableArray new];
SKSpriteNode *firstRing = [self addRopeRingWithPosition:_startRingPosition underScene:scene];
SKSpriteNode *lastRing = firstRing;
CGPoint position;
for (int i = 1; i < _ringCount; i++) {
position = CGPointMake(lastRing.position.x, lastRing.position.y - lastRing.size.height - _ringsDistance);
lastRing = [self addRopeRingWithPosition:position underScene:scene];
}
[self addJointsWithScene:scene];
}
-(SKSpriteNode *)addRopeRingWithPosition:(CGPoint)position underScene:(SKScene *)scene
{
SKSpriteNode *ring = [SKSpriteNode spriteNodeWithTexture:_ringTexture];
ring.xScale = ring.yScale = _ringScale;
ring.position = position;
ring.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ring.size.height / 2];
ring.physicsBody.allowsRotation = YES;
ring.physicsBody.friction = _ringFriction;
ring.physicsBody.restitution = _ringRestitution;
if(_ringMass > 0) {
ring.physicsBody.mass = _ringMass;
}
[scene addChild:ring];
[_ropeRings addObject:ring];
return ring;
}
-(void)addJointsWithScene:(SKScene *)scene
{
for (int i = 1; i < _ropeRings.count; i++) {
SKSpriteNode *nodeA = [_ropeRings objectAtIndex:i-1];
SKSpriteNode *nodeB = [_ropeRings objectAtIndex:i];
SKPhysicsJointPin *joint = [SKPhysicsJointPin jointWithBodyA:nodeA.physicsBody
bodyB:nodeB.physicsBody
anchor:CGPointMake(nodeA.position.x,
nodeA.position.y - (nodeA.size.height + _ringsDistance) / 2)];
joint.frictionTorque = _jointsFrictionTorque;
joint.shouldEnableLimits = _shouldEnableJointsAngleLimits;
if(_shouldEnableJointsAngleLimits) {
joint.lowerAngleLimit = _jointsLowerAngleLimit;
joint.upperAngleLimit = _jointsUpperAngleLimit;
}
[scene.physicsWorld addJoint:joint];
}
}
//workaround for elastic effect should be called from didSimulatePhysics
-(void)adjustRingPositions
{
//based on zRotations of all rings and the position of start ring adjust the rest of the rings positions starting from top to bottom
for (int i = 1; i < _ropeRings.count; i++) {
SKSpriteNode *nodeA = [_ropeRings objectAtIndex:i-1];
SKSpriteNode *nodeB = [_ropeRings objectAtIndex:i];
CGFloat thetaA = nodeA.zRotation - M_PI / 2,
thetaB = nodeB.zRotation + M_PI / 2,
jointRadius = (_ringsDistance + nodeA.size.height) / 2,
xJoint = jointRadius * cosf(thetaA) + nodeA.position.x,
yJoint = jointRadius * sinf(thetaA) + nodeA.position.y,
theta = thetaB - M_PI,
xB = jointRadius * cosf(theta) + xJoint,
yB = jointRadius * sinf(theta) + yJoint;
nodeB.position = CGPointMake(xB, yB);
}
}
-(SKSpriteNode *)startRing
{
return _ropeRings[0];
}
-(SKSpriteNode *)lastRing
{
return [_ropeRings lastObject];
}
#end
Scene code to showcase how to use the Rope:
#import "ALRopeDemoScene.h"
#import "ALRope.h"
#implementation ALRopeDemoScene
{
__weak SKSpriteNode *_branch;
CGPoint _touchLastPosition;
BOOL _branchIsMoving;
ALRope *_rope;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.2 green:0.5 blue:0.6 alpha:1.0];
[self buildScene];
}
return self;
}
-(void) buildScene {
SKSpriteNode *branch = [SKSpriteNode spriteNodeWithImageNamed:#"Branch"];
_branch = branch;
branch.position = CGPointMake(CGRectGetMaxX(self.frame) - branch.size.width / 2,
CGRectGetMidY(self.frame) + 200);
branch.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(2, 10)];
branch.physicsBody.dynamic = NO;
[self addChild:branch];
_rope = [[ALRope alloc] initWithRingTexture:[SKTexture textureWithImageNamed:#"rope_ring"]];
//configure rope params if needed
// _rope.ringCount = ...;//default is 30
// _rope.ringScale = ...;//default is 1
// _rope.ringsDistance = ...;//default is 0
// _rope.jointsFrictionTorque = ...;//default is 0
// _rope.ringsZPosition = ...;//default is 1
// _rope.ringFriction = ...;//default is 0
// _rope.ringRestitution = ...;//default is 0
// _rope.ringMass = ...;//ignored unless mass > 0; default -1
// _rope.shouldEnableJointsAngleLimits = ...;//default is NO
// _rope.jointsLowerAngleLimit = ...;//default is -M_PI/3
// _rope.jointsUpperAngleLimit = ...;//default is M_PI/3
_rope.startRingPosition = CGPointMake(branch.position.x - 100, branch.position.y);//default is (0, 0)
[_rope buildRopeWithScene:self];
//attach rope to branch
SKSpriteNode *startRing = [_rope startRing];
CGPoint jointAnchor = CGPointMake(startRing.position.x, startRing.position.y + startRing.size.height / 2);
SKPhysicsJointPin *joint = [SKPhysicsJointPin jointWithBodyA:branch.physicsBody bodyB:startRing.physicsBody anchor:jointAnchor];
[self.physicsWorld addJoint:joint];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(_branch.frame, location)) {
_branchIsMoving = YES;
_touchLastPosition = location;
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
_branchIsMoving = NO;
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if(_branchIsMoving) {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self],
branchCurrentPosition = _branch.position;
CGFloat dx = location.x - _touchLastPosition.x,
dy = location.y - _touchLastPosition.y;
_branch.position = CGPointMake(branchCurrentPosition.x + dx, branchCurrentPosition.y + dy);
_touchLastPosition = location;
}
}
-(void)didSimulatePhysics
{
//workaround for elastic effect
[_rope adjustRingPositions];
}
#end
Notice the [rope adjustRingPositions] call from [scene didSimulatePhysics]. That was the actual workaround for the elastic bug.
Complete demo code is here. I hope this helps!

-(void)didBeginContact is not being called. Thoughts?

#import "collisionTestMyScene.h"
const static int nodeBitMask = 0x1 << 0;
const static int node1BitMask = 0x1 << 1;;
#implementation collisionTestMyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.physicsWorld.contactDelegate = self;
w = 0;
}
return self;
}
-(void) didBeginContact:(SKPhysicsContact *)contact {
NSLog(#"Contact Begin");
if (contact.bodyA.categoryBitMask == nodeBitMask) {
NSLog(#"Node is Body A");
}
if (contact.bodyA.categoryBitMask == node1BitMask) {
NSLog(#"Node is Body B");
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
node = [SKSpriteNode spriteNodeWithImageNamed:#"block.jpg"];
node.position = location;
[node setScale:0.07];
node.physicsBody.contactTestBitMask = node1BitMask;
node.physicsBody.categoryBitMask = nodeBitMask;
node.physicsBody.collisionBitMask = nodeBitMask;
//node.physicsBody.collisionBitMask = 0;
node1 = [SKSpriteNode spriteNodeWithImageNamed:#"block2.jpg"];
node1.position = CGPointMake(200, 200);
node1.physicsBody.categoryBitMask = node1BitMask;
node1.physicsBody.contactTestBitMask = nodeBitMask;
node1.physicsBody.collisionBitMask = node1BitMask;
//node1.physicsBody.collisionBitMask = 0;
[node1 setScale:0.07];
[self addChild:node];
[self addChild:node1];
node.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(node.size.width, node.size.height)];
node1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(node1.size.width, node1.size.height)];
SKAction *moveUp = [SKAction moveToX:100 duration:3];
node1.physicsBody.affectedByGravity = NO;
node.physicsBody.affectedByGravity = NO;
[node1 runAction:moveUp];
w = 1;
}
}
It is never NSLogging anything. I have tried changing the bit masks, and more. The CGRectIntersects function would work, however it is not accurate enough. Also, the two nodes are in perfect box shapes. What could I be doing wrong? Thank you in advance!
The problem here are the bit masks. The two nodes are in different category, contact and collision groups (bit masks). Therefore they will not contact nor collide because the bitmasks are compared with AND and only if the result is non-zero will the contact/collision occur.
In short, put them in the same contact bit mask at the least, in order to receive didBeginContact messages.

multi touch error in cocos2d - index 1 beyond bounds

I am trying to get multi touch working so that I can move two sprites at the same time. I followed this tutorial http://www.saturngod.net/detecting-touch-events-in-cocos2d-iphone-ganbaru-games and this is the code I have in ccTouchesBegan:
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *touchArray = [touches allObjects];
// We're going to track the first two touches (i.e. first two fingers)
// Create "UITouch" objects representing each touch
UITouch *fingerOne = [touchArray objectAtIndex:0];
UITouch *fingerTwo = [touchArray objectAtIndex:1];
// Convert each UITouch object to a CGPoint, which has x/y coordinates we can actually use
CGPoint pointOne = [fingerOne locationInView:[fingerOne view]];
CGPoint pointTwo = [fingerTwo locationInView:[fingerTwo view]];
// The touch points are always in "portrait" coordinates
// You will need to convert them if in landscape (which we are)
pointOne = [[CCDirector sharedDirector] convertToGL:pointOne];
pointTwo = [[CCDirector sharedDirector] convertToGL:pointTwo];
if (CGRectContainsPoint(ball.boundingBox, pointOne))
{
//ball.position = ccp(location.x , location.y);
areWeTouchingABall = YES;
//printf("*** ccTouchesBegan (x:%f, y:%f)\n", location.x, location.y);
}
if(CGRectContainsPoint(sp.boundingBox, pointOne)){
areWeTouchingASquare = YES;
// printf("*** ccTouchesBegan (x:%f, y:%f)\n", location.x, location.y);
}
// Only run the following code if there is more than one touch
if ([touchArray count] > 1)
{
if ( CGRectContainsPoint(ball.boundingBox, pointTwo))
{
//ball.position = ccp(location.x , location.y);
areWeTouchingABall = YES;
//printf("*** ccTouchesBegan (x:%f, y:%f)\n", location.x, location.y);
}
if(CGRectContainsPoint(sp.boundingBox, pointTwo)){
areWeTouchingASquare = YES;
// printf("*** ccTouchesBegan (x:%f, y:%f)\n", location.x, location.y);
}
}
}
this is in touchesMoved:
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *touchArray = [touches allObjects];
// We're going to track the first two touches (i.e. first two fingers)
// Create "UITouch" objects representing each touch
UITouch *fingerOne = [touchArray objectAtIndex:0];
UITouch *fingerTwo = [touchArray objectAtIndex:1];
// Convert each UITouch object to a CGPoint, which has x/y coordinates we can actually use
CGPoint pointOne = [fingerOne locationInView:[fingerOne view]];
CGPoint pointTwo = [fingerTwo locationInView:[fingerTwo view]];
// The touch points are always in "portrait" coordinates
// You will need to convert them if in landscape (which we are)
pointOne = [[CCDirector sharedDirector] convertToGL:pointOne];
pointTwo = [[CCDirector sharedDirector] convertToGL:pointTwo];
if (areWeTouchingABall == YES) //
{
ball.position = ccp(pointOne.x , pointOne.y);
ball.zOrder = 1;
sp.zOrder = 0;
}
if (areWeTouchingASquare == YES) //
{
sp.position = ccp(pointOne.x , pointOne.y);
sp.zOrder = 1;
ball.zOrder = 0;
}
// Only run the following code if there is more than one touch
if ([touchArray count] > 1)
{
/*if (areWeTouchingABall == YES && CGRectContainsPoint(ball.boundingBox, pointOne)) //
{
ball.position = ccp(pointOne.x , pointOne.y);
ball.zOrder = 1;
sp.zOrder = 0;
}*/
if (areWeTouchingABall == YES && CGRectContainsPoint(ball.boundingBox, pointTwo)) //
{
ball.position = ccp(pointTwo.x , pointTwo.y);
ball.zOrder = 1;
sp.zOrder = 0;
}
/*if (areWeTouchingASquare == YES && CGRectContainsPoint(ball.boundingBox, pointOne)) //
{
sp.position = ccp(pointOne.x , pointOne.y);
sp.zOrder = 1;
ball.zOrder = 0;
}*/
if (areWeTouchingASquare == YES && CGRectContainsPoint(ball.boundingBox, pointTwo)) //
{
sp.position = ccp(pointTwo.x , pointTwo.y);
sp.zOrder = 1;
ball.zOrder = 0;
}
}
}
and this is in touchesEnded:
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
areWeTouchingABall = NO;
areWeTouchingASquare = NO;
//printf("*** ccTouchesEnded (x:%f, y:%f)\n", location.x, location.y);
}
Every time I touch anywhere with one finger, I get this error:
"Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'",
When I touch with two fingers, the error does not come up but multi touch does not work correctly ( I cannot drag a sprite with a finger each. The second sprite touched jumps straight to the other finger location so that both sprites are under one finger.)
I made sure to add the code:
[glView setMultipleTouchEnabled:YES];
to my AppDelegate.m file and I have touch enabled in my init method.
How can I fix this issue so that multi-touch works properly and the error is removed?
UITouch *fingerOne = [touchArray objectAtIndex:0];
UITouch *fingerTwo = [touchArray objectAtIndex:1];
There's no guarantee that you'll always receive two touches in a touch event. First test how many touches there are in touchArray using
UITouch *fingerOne = [touchArray objectAtIndex:0];
UITouch *fingerTwo = nil;
if (touchArray.count > 1)
{
fingerTwo = [touchArray objectAtIndex:1];
}
Even then this won't work logically because the second touch in the array may not always correspond to finger #2. I suggest to read up on tracking individual fingers here.

If Else satement working but not updating cocos2d

i have tested my code by changing the starting lives vaule, the problem is it doesn't remove them as the statement becomes valid, How do i fix this? I have tried placing it in my .m file but it doesn't seem to work properly anywhere, any ideas on where it would go? I would post the .m but it is about 500 lines so it is a bit big so i just pasted the relevant bit of it. also i am a 15 year old, and i am fairly new to cocos2d development
The Code
- (void) addMonster {
CCSprite * monster = [CCSprite spriteWithFile:#"startH.png"];
// Determine where to spawn the monster along the Y axis
CGSize winSize = [CCDirector sharedDirector].winSize;
int minY = monster.contentSize.height / 2;
int maxY = winSize.height - monster.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
monster.position = ccp(winSize.width + monster.contentSize.width/2, actualY);
[self addChild:monster];
// Determine speed of the monster}
if (Strategyscore < 10) {
int minDuration = 5.0;
int maxDuration = 10.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
eate the actions
CCMoveTo * actionMove = [CCMoveTo actionWithDuration:actualDuration
position:ccp(-monster.contentSize.width/2, actualY)];
CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
[_monsters removeObject:node];
Life--;
CCSprite *Life3 = [CCSprite spriteWithFile:#"heart.png"];
Life3.position = ccp(210,200);
CCSprite *Life2 = [CCSprite spriteWithFile:#"heart.png"];
Life2.position = ccp(220,200);
CCSprite *Life1 = [CCSprite spriteWithFile:#"heart.png"];
Life1.position = ccp(230,200);
[self addChild:Life3];
[self addChild:Life2];
[self addChild:Life1];
if(Life == 2) {
[self removeChild:Life3];
}
else if(Life == 1) {
[self removeChild:Life2];
[self removeChild:Life3];
}
else if(Life <= 0) {
[self removeChild:Life1];
[self removeChild:Life2];
[self removeChild:Life3];
// Cr [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[MainMenu scene]]];
}
}];
[monster runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
//collision stuff
monster.tag = 1;
[_monsters addObject:monster];
}
Also the .h file
int StrategyBullet;
int Strategyscore;
int high;
int Life;
CCLabelTTF *highlabel;
CCLabelTTF *StrategyBulletLabel;
CCLabelTTF *StrategyscoreLabel;
#interface Strategy: CCLayer
{
NSMutableArray * _monsters;
NSMutableArray * _projectiles;
int _monstersDestroyed;
}
+(CCScene *) scene;
#end
Every time you add a new monster, you add a new set of sprites Life1,Life2, and Life3, superimposed on the previous ones. You probably want to have a single set of life hearts.
in .h
CCSprite *Life1,*Life2,*Life3;
in .m, init method
Life3 = [CCSprite spriteWithFile:#"heart.png"];
Life3.position = ccp(210,200);
Life2 = [CCSprite spriteWithFile:#"heart.png"];
Life2.position = ccp(220,200);
Life1 = [CCSprite spriteWithFile:#"heart.png"];
Life1.position = ccp(230,200);
[self addChild:Life1];
[self addChild:Life2];
[self addChild:Life3];
and in your actionMoveDone call block, dont remove them, just make them not visible
CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
[_monsters removeObject:node];
Life--;
if(Life == 2) {
Life3.visible=NO;
}
else if(Life == 1) {
Life3.visible=NO;
Life2.visible=NO;
}
else if(Life <= 0) {
Life3.visible=NO;
Life2.visible=NO;
Life1.visible=NO;
}
}];
for starters. I just made this as 'like your coding style' as possible, but eventually you will find different patterns to do this as you game becomes more complex. Read about normal iOS code and naming conventions, it will help you and also make your code samples more palatable for the people trying to help you here.
Where are you montering the lives value ? In a tick method ?
if(Life == 2) {
[self removeChild:Life3];
}
else if(Life == 1) {
[self removeChild:Life2];
[self removeChild:Life3];
}
else if(Life <= 0) {
[self removeChild:Life1];
[self removeChild:Life2];
[self removeChild:Life3];
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[MainMenu scene]]];
}

CGRectContainsPoint problems

In my test game i have some sprites (Bubbles = NSMutableArray) wich are appear in random location at bottom of the screen.
I have addBubble and spawBubble methods:
- (void) addBubble {
CGSize winSize = [[CCDirector sharedDirector] winSize];
bubbles = [[NSMutableArray alloc] init];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"bubbleSpriteList.plist"];
CCSpriteBatchNode *bubbleSpriteList = [CCSpriteBatchNode batchNodeWithFile:#"bubbleSpriteList.png"];
[self addChild:bubbleSpriteList];
bigBubble = [CCSprite spriteWithSpriteFrameName:#"bubble"];
[self addChild:bigBubble];
[bubbles addObject:bigBubble];
for (CCSprite *bubble in bubbles) {
int minX = bubble.contentSize.width/2;
int maxX = winSize.width-bubble.contentSize.width/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;
bubble.position = ccp(actualX, 0);
int minSpeed = 15.0;
int maxSpeed = 20.0;
int rangeSpeed = maxSpeed - minSpeed;
int actualSpeed = (arc4random() % rangeSpeed) + minSpeed;
ccBezierConfig bubblePath;
bubblePath.controlPoint_1 = ccp(200, winSize.height/3);
bubblePath.controlPoint_2 = ccp(-200, winSize.height/1.5);
bubblePath.endPosition = ccp(0, winSize.height+bubble.contentSize.height/2);
id bezierMove = [CCBezierBy actionWithDuration:actualSpeed bezier:bubblePath];
[bubble runAction:bezierMove];
}}
-(void)spawBubble:(ccTime)dt {
[self addBubble];}
Then in my init method i added background and spawBubble method with random time interval
[self schedule:#selector(spawBubble:) interval:actualTime];
I'm trying to make every bubble from Bubbles blow, when it was touched, with this code
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
for (CCSprite *bubble in bubbles) {
CGRect bubbleRect = CGRectMake(bubble.position.x - (bubble.contentSize.width/2),
bubble.position.y - (bubble.contentSize.height/2),
bubble.contentSize.width,
bubble.contentSize.height);
if (CGRectContainsPoint(bubbleRect, touchLocation)) {
NSLog(#"%i", [bubbles count]);
[bubble setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"bubbleBlow"]];
id disappear = [CCFadeTo actionWithDuration:0.1 opacity:0];
[bubble runAction:disappear];
}
}
return TRUE;}
Every bubbles blowing perfectly if only one bubble in the screen, but if one bubble on the screen and another one was appeared, only last one is detects touches.
What am i doing wrong?
Hard to tell without seeing more code - but here's where I'd start:
Above this line:
for (CCSprite *bubble in bubbles) {
add:
NSLog(#"%i", [bubbles count]);
EDIT:
Based on the code you added:
Your problem is with this line:
bubbles = [[NSMutableArray alloc] init];
which is effectively wiping out your bubbles array every time you add a new bubble.
So, there will only ever be one bubble in the array - the last one.
Hence the problem you're running into.
I changed addBubble methods by removing bubbles = [[NSMutableArray alloc] init];, and adding it to init method...
Now everything works perfectly! )