Using the method below, how can one refer to specific sprites when checking to see if they intersect?
- (void)update:(ccTime)dt {
for (CCSprite *sprite in movableSprites) {
if (CGRectIntersectsRect(sprite.boundingBox, sprite.boundingBox)) {
break;
}
}
}
It appears that all sprites are available in the moveableSprites object, but I don't know how to check if specific sprites are colliding... I don't know how to refer to them. If there is an easier way to perform collision detection I'm interested.
It appears your code above will always return TRUE because you are checking if the boundingbox of sprite collides with sprite, and since they are the same it always will.
if (CGRectIntersectsRect(sprite.boundingBox, sprite.boundingBox)) {//
break;
}
Should be comparing to a different sprite not the same sprite.
if (CGRectIntersectsRect(sprite.boundingBox, otherSprite.boundingBox)) {//
break;
}
If that does not answer your question maybe you are looking to avoid enumerating through the array? If that is the case try using tags. Someting like below.
CCSprite *aSprite = [CCSprite spriteWithFile:#"hurdle1.png"];
[self addChild:aSprite tag:2];
Now [self getChildByTag:2] can take the place of sprite
and you can just add boundingBox to check collisions, as below.
if (CGRectIntersectsRect([self getChildByTag:2].boundingBox, checkSprite.boundingBox)) {//
break;
}
Related
Im making a brick breaker type game and need to know if all the bricks have been broken in order to transition to the win screen.
The way I've been thinking of solving this is to create a BOOL method that is ran each time a brick is removed to calculate how many bricks are left. If there are no bricks left... move to the win scene.
Im struggling with the logic on how to do this.
So far I have:
-(BOOL)isGameWon{
for (SKNode* node in self.children){
if ([node.name isEqual:brickCategoryName]){
//some logic
}
}
return YES;
}
didBeginContactMethod:
if (notTheBall.categoryBitMask == brickCategory) {
[self runAction:_smashSound];
[notTheBall.node removeFromParent];
if ([self isGameWon]) {
NSLog(#"YOU WIN!");
}
}
I have an Array of CCSprites that being displayed all at once.
Every sprite has a movement path, a movement path is a random point on screen.
All the sprites are moving all at once to random points on screen.
What I want to do is to detect collision between the sprites and then change their movement path.
Is it possible?
Iterate through every CCSprite in your array (call it A), and for every iteration iterate again through every CCSprite in the array (excluding A itself of course) (call this one B). Now, use CGRectIntersectsRect along with boundingBox to find a collision between them. It goes something like this:
for (CCSprite *first in mySprites) {
for (CCSprite *second in mySprites) {
if (first != second) {
if (CGRectIntersectsRect([first boundingBox], [second boundingBox])) {
// COLLISION! Do something here.
}
}
}
}
Edit: But of course, it is possible that if two sprites collide, the "collision event" will occur twice (first from the point of view of sprite A, and then from the point of view of sprite B).
If you only want the collision event to trigger once every check, you will need to memorize the pairs so that you can ignore collisions that already did happen on that check.
There are countless ways you could check for that, but here's an example (updated code):
Edited again:
NSMutableArray *pairs = [[NSMutableArray alloc]init];
bool collision;
for (CCSprite *first in mySprites) {
for (CCSprite *second in mySprites) {
if (first != second) {
if (CGRectIntersectsRect([first boundingBox], [second boundingBox])) {
collision = NO;
// A collision has been found.
if ([pairs count] == 0) {
collision = YES;
}else{
for (NSArray *pair in pairs) {
if ([pair containsObject:first] && [pair containsObject:second]) {
// There is already a pair with those two objects! Ignore collision...
}else{
// There are no pairs with those two objects! Add to pairs...
[pairs addObject:[NSArray arrayWithObjects:first,second,nil]];
collision = YES;
}
}
}
if (collision) {
// PUT HERE YOUR COLLISION CODE.
}
}
}
}
}
[pairs release];
Have a look at this S.O. answers.
You can do simple collision detection using CGRectIntersectsRect and the node boundingBox. If you need more advanced features, have a look at a physics engine like chipmunk or Box2D.
Ray Wenderlich has written a good tutorial about using Box2D just for collision detection, if you're interested in going that way. http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone
Check first that your sprites can be approximated by rectangles. If so then #Omega's answer was great. If they can't be, perhaps because they contain a lot of transparency or for some other reason, you might need to approximate your sprites with polys and work with those.
I am making a game in Cocos2d. Everything is okay, so far. I used Ray Wenderlich's tutorial to get collision detection to work. It works, but whenever an 'enemy' spawns where a bullet was deleted (because the bullet that was deleted hit a target, therefore, was deleted), the enemy is automatically deleted, too. I think it's because it doesn't remove the rect that was declared for the sprite. Note, it also can go through more than one enemy, even though the bullet is deleted. Any help is appreciated. Thanks!
EDIT:
I found out what the problem was. I had the shoot method set in a schedule:#selector method, with no set interval. That meant that it would fire bullets 60fps fast. So I was getting TWO bullets with ONE click. They were so close together, that it took me a while to notice it. I won't make that mistake again!!!
Are you using the following code? (from How To Make A Simple iPhone Game with Cocos2D Tutorial)
- (void)update:(ccTime)dt {
NSMutableArray *projectilesToDelete = [[NSMutableArray alloc] init];
for (CCSprite *projectile in _projectiles) {
CGRect projectileRect = CGRectMake(
projectile.position.x - (projectile.contentSize.width/2),
projectile.position.y - (projectile.contentSize.height/2),
projectile.contentSize.width,
projectile.contentSize.height);
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target in _targets) {
CGRect targetRect = CGRectMake(
target.position.x - (target.contentSize.width/2),
target.position.y - (target.contentSize.height/2),
target.contentSize.width,
target.contentSize.height);
if (CGRectIntersectsRect(projectileRect, targetRect)) {
[targetsToDelete addObject:target];
}
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
}
if (targetsToDelete.count > 0) {
[projectilesToDelete addObject:projectile];
}
[targetsToDelete release];
}
for (CCSprite *projectile in projectilesToDelete) {
[_projectiles removeObject:projectile];
[self removeChild:projectile cleanup:YES];
}
[projectilesToDelete release];
}
whenever an 'enemy' spawns where a bullet was deleted, the enemy is automatically deleted, too.
It sounds that the bullet is removed from the layer, but it is not removed from _projectiles array.
[_projectiles removeObject:projectile];
Are you sure that this code works?
Rect is not a seperate entity from your bullet. Rect is the property associated with the bullet. As soon as your "bullet is deleted" the rect will no longer be valid.
What you should be looking at is your collision checking code.
You probably want to surround your bullet collision check code with a condition like:
if(bullet exists)
{
check for collision
}
Since you haven't posted code I could only post pseudo code here. Maybe if you post your collision checking code I could show you in more detail.
I have a game that I wrote. I am about ready to call it finished but I found a bug. Basically the game gets slower as the longer you play. My guess is this is due to sprites that are still being drawn off screen. I will paste the code below but basically the sprite is created in the "addNewBall" method. In this method it is added to an array which calculates its motion. After the ball reaches a position where it is off the screen it is removed from the array which causes it to stop moving but it is still being "drawn" off screen. How do I remove the sprite so the processor no longer calculates it. Thanks in advance for your help!
Tanner
Code:
-(void) addNewBall {
NumberOfBalls = NumberOfBalls + 1;
int RandomXPosition = (arc4random() % 240) + 40;
NSString *BallFileString = #"OrangeBall.png";
switch (arc4random() % 5) {
case 1:
BallFileString = #"OrangeBall.png";
break;
case 2:
BallFileString = #"GreenBall.png";
break;
case 3:
BallFileString = #"YellowBall.png";
break;
case 4:
BallFileString = #"PinkBall.png";
break;
case 0:
BallFileString = #"BlueBall.png";
break;
}
Ball = [CCSprite spriteWithFile:BallFileString];
Ball.position = ccp(RandomXPosition, 520);
BallIsMoving = YES;
[self addChild:Ball z:10];
[AllObjectsArray_ addObject:Ball];
[BallArray_ addObject:Ball];
}
//And here is where it is removed...
if (Ball.position.y <= -100) {
[BallArray_ removeObject: Ball];
}
You seem to be missing some conditions in your removal method. Don't you also want to remove the ball if its y position is greater than the screen height, or if its x position is off-screen? At any rate, in the same place that you're removing the ball from the array, you should add:
[self removeChild:Ball cleanup: YES]
I should also point out that your BallArray is probably redundant, since you're adding all the balls to another node anyway. If the only children of that node are Balls, you can get the array of balls using its children property. In this case, the child array would be: self.children (See http://www.cocos2d-iphone.org/api-ref/latest-stable/interface_c_c_node.html#a5e739ecda0c314283a89ac389dfca2fa for more info.)
If you have non-Ball children on the same node, you might want to add an intermediate node to simplify the design so that you can use one less array.
You said you are removing the objects from the arrays, but you didn't mention that you are also removing the sprite from the parent CCNode.
Check the methods from CCNode to remove childs: http://www.cocos2d-iphone.org/api-ref/latest-stable/interface_c_c_node.html#a0d4e615f688458c74001acf10f0ae011
You could use:
[Ball removeFromParentAndCleanup:YES];
This will remove the ball from it's parent CCNode and will remove all actions and callbacks.
You need to specify your sprite,and you can use this following line..
[self removeChild:Ball cleanup: YES]
I am developing a game on Iphone using cocos2d. I have a CClayer containing 20 CCSprite. I am playing a sound and I would like to disable the touch events on all the CCSprite or on the entire layer while the sound is playing. I looked at the property of CCLayer called isTouchEnabled but the behavior doesn't propagate to the children (all the CCSprite). Unless it is not documented, there seems to be no equivalent property for CCsprite. Does anybody know an easy way to this?
Thanks
I ma using below method to disable touch on CCMenu items on a layer below on a view may be help you out.
Call the below method and disable all sub Menu or subNode.
[self MenuStatus:NO Node:self]; // to disable
method is:
-(void)MenuStatus:(BOOL)_enable Node:(id)_node
{
for (id result in ((CCNode *)_node).children)
{
if ([result isKindOfClass:[CCMenu class]])
{
for (id result1 in ((CCMenu *)result).children)
{
if ([result1 isKindOfClass:[CCMenuItem class]])
{
((CCMenuItem *)result1).isEnabled = _enable;
}
}
}
else
[self MenuStatus:_enable Node:result];
}
}
[self MenuStatus:YES Node:self]; // to enable**
A member of another forum posted this solution
So all your sprites normally receive touch events? If you know when the sound is playing, you just could have them check that and ignore the touch if the sound is playing. For example, if your sprites implement the CCTargetedTouchDelegate protocol, you could do something like:
- (BOOL)ccTouchBegan:(UITouch*)touch withEvent:(UIEvent*)event {
if (soundIsPlaying) {
return NO; // i.e., the sprite is currently uninterested in the touch
}
// Other checks and behaviour here.
return YES;
}