In my app I've use the particle designer to produce an animation when bodies collide,
the code is....
-(void)collision
{
for (IceCream *iceCream in [iceDict allValues]) {
if (CGRectIntersectsRect(iceCream.sprite.boundingBox, player.boundingBox)) {
if(actualType == 0)
{
[self increaseLooseCounts];
[self updateLives];
}
else{
[self increaseWinCounts];
[self updateLives];
}
//DEFINING THE PARTICLE ANIMATION
particle = [CCParticleSystemQuad particleWithFile:#"part.plist"]; //alt plist working with rainbow.plist
particle.position = ccp(iceCream.sprite.boundingBox.origin.x,iceCream.sprite.boundingBox.origin.y);
[self addChild:particle z:2];
[particle release];
//CALLING SELECTOR TO END THE PARTICLE ANIMATION
[self performSelector:#selector(killBlast) withObject:nil afterDelay:0.3f];
int icecreamKey = iceCream.sprite.tag;
[self removeChild:iceCream.sprite cleanup:YES];
[iceDict removeObjectForKey:[NSNumber numberWithInt:icecreamKey]];
}
}
}
-(void)killBlast{
[particle removeFromParentAndCleanup:YES];
}
But as soon as the killBlast is called the app crashes.
Please help !!
Remove this line:
[particle release];
You don't own particle object so you don't need to release it. You get it from autoreleased method and then it's retained when becomes added as a child. It will be released once it's removed from parent
Related
Here is the code i'm using to detect if 2 UIImageViews hit each other.
if (CGRectIntersectsRect(Appy.frame, Bottom.frame)) {
[self GameOver];
}
At the moment its detecting the edge of the object.
How do i change it to detect the edge of the image inside the UIImageView.
The image inside has a transparent background and is "practically circle" so they are colliding if the corner of UIImageView hits the corner of another UIImageView but the image is not actually hitting so its making things look a little "messy"
EDIT*
these are the errors im getting
this is my .h
EDIT: below is what my code now looks like
.m Method
if (CGRectIntersectsRect([self: RectBox:Appy].frame, Bottom.frame)) {
[self GameOver];
}
.h
-(UIImageView *)RectBox:(UIImageView *)box;
i put this just above the very last #end on my .h just to be sure.
Im still "getting use of undeclared identifier 'RectBox'"
EDIT
EDIT
As requested here is the code in which i call the method
-(void) PipeMoving2{
PipeTop2.center = CGPointMake(PipeTop2.center.x -2, PipeTop2.center.y);
PipeBottom2.center = CGPointMake(PipeBottom2.center.x -2, PipeBottom2.center.y);
if (PipeTop2.center.x < -53+33) {
[self PlacePipe2];
}
if (PipeTop2.center.x == 62) {
[self Score];
}
if (CGRectIntersectsRect(Appy.frame, PipeTop2.frame)) {
[self GameOver];
}
if (CGRectIntersectsRect(Appy.frame, PipeBottom2.frame)) {
[self GameOver];
}
if (CGRectIntersectsRect(Appy.frame, Top.frame)) {
[self GameOver];
}
if (CGRectIntersectsRect([self RectBox:Appy].frame, Bottom.frame)) {
[self GameOver];
}
}
i think this is all u need to see right?
Change it to the following:
if(CGRectIntersectsRect([self RectBox:Image].frame, Bottom.frame))
Another thing I noticed from your image is that you are placing the method within another method.
Ex: (what I see from your image, it seems)
- (void)yourMethod
{
......
if (CGRectIntersectsRect([self RectBox:Image].frame, Bottom.frame))
{
[self GameOver];
}
.....
//etc etc
//and then you have this
-(UIImageView *)RectBox:(UIImageView *)box
{
box.frame = CGRectMake(box.frame.origin.x +15,
box.frame.origin.y +15,
box.frame.size.width -30,
box.frame.size.height-30);
return box;
}
....
}
You should extract that and place it outside of your method, so it becomes:
- (void)yourMethod
{
......
if (CGRectIntersectsRect([self RectBox:Image].frame, Bottom.frame))
{
[self GameOver];
}
.....
//etc etc
....
}
//take it out and place it here, for example
- (UIImageView *)RectBox:(UIImageView *)box
{
box.frame = CGRectMake(box.frame.origin.x +15,
box.frame.origin.y +15,
box.frame.size.width -30,
box.frame.size.height-30);
return box;
}
Update to questions in comments not exactly related to the original question, but here is my finding from your code:
The reason you character is changing size may stem from the fact that you are changing its frame in your RectBox method.
Here is a rough redefinition of the method, so that we could "preserve" the frame of your character:
- (CGRect)RectBox:(UIImageView *)box
{
CGRect tempRect = CGRectMake(box.frame.origin.x +15,
box.frame.origin.y +15,
box.frame.size.width -30,
box.frame.size.height-30);
return tempRect;
}
And make changes to the call.
Ex:
if (CGRectIntersectsRect([self RectBox:Image], Bottom.frame))
{
[self GameOver];
}
Regarding the movements, check the frequency you set for your NSTimer. I wouldn't go more frequent than 0.1.
Hope this helps.
Try this
.h
-(UIImageView *)RectBox:(UIImageView *)box;
.m
if (CGRectIntersectsRect([self RectBox:Image].frame, Bottom.frame))
{
[self GameOver];
}
-(UIImageView *)RectBox:(UIImageView *)box
{
box.frame = CGRectMake(box.frame.origin.x +15,
box.frame.origin.y +15,
box.frame.size.width -30,
box.frame.size.height-30);
return box;
}
Try this code
CGPoint a = imageViewA.center;
CGPoint b = imageViewB.center;
CGFloat distance = sqrt(pow((b.x - a.x),2) + pow((b.y - a.y),2));
if(distance < (imageViewA.bounds.size.width/2.0 + imageViewB.bounds.size.width/2.0)){
//images are touching.
}
var attributes = [UICollectionViewLayoutAttributes]()
for att in cache {
if (att.frame.intersects(rect))
{
attributes.append(att)
}
}
In swift 3 You can use like this.
I am making a game in which when 2 objects (object A and B) collide, the game gets over. Object A's position changes each time update is called. Object B's position is the same. The code is:
[self enumerateChildNodesWithName:#"objA" usingBlock:^(SKNode *node, BOOL *stop) {
if ([objB intersectsNode:node])
{
[node removeFromParent];
[self GameOver];
}
The problem is: I want objA NOT to disappear after the collision. So, for that I removed [node removeFromParent]; , but since update is called again and again. My number of nodes increases and the sound that i have added never seems to end. So, what i tried was adding:
[self performSelector:#selector(pauseGame) withObject:Nil afterDelay:0.1];
-(void) pauseGame
{
self.scene.view.paused = YES;
[self performSelector:#selector(gameOver) withObject:Nil afterDelay:0.1];
}
I had to use performSelector with delay, because putting self.scene.view.paused = YES; within the update wouldn't allow me to go to gameOver. However, I do not want any delays! is there a way to do this??
Thanks
Just use a state variable in your scene which will indicate the current state.
Use this state to run updates on your scene objects.
For example (pseudocode) :
update()
if (state == GAME_PLAY) {
// Update relevant game nodes
} else if (state == GAME_OVER) {
// Update only what needs to be updated when the game is over
}
This way you do not need to stop your entire scene and add only what is relevant to the current game state
In the game I'm making I have a heart count at the bottom. The idea is to remove one heart when the user touches a "bomb". Right now, I create all hearts at the beginning of the program and name each one "heart1" "heart2" and "heart3". In the doDamage method, add 1 to the hitCount when the user touches a bomb. Then I proceed to remove the heart. I have this code right now. Is there any better and more efficient solution for this? Heere's the code I'm using right now.
- (void) doDamage {
//Sets the isDamaged value to yes and adds a hit point
isDamaged = YES;
hitCount++;
NSLog(#"The hit count is %i ", hitCount);
//calls the damageDone method after a second to avoid being damaged all the frames the bomb touches the basket
[self performSelector:#selector(damageDone) withObject:nil afterDelay:0.5];
//This lengthy code is used to test what heart should be removed each time...
[self enumerateChildNodesWithName:#"heart1" usingBlock:^(SKNode *node, BOOL *stop){
//If the hitCount is the same as the heart we want to remove, then we'll remove it from the parent
if (hitCount == 1) {
[node removeFromParent];
}
}];
[self enumerateChildNodesWithName:#"heart2" usingBlock:^(SKNode *node, BOOL *stop){
if (hitCount == 2) {
[node removeFromParent];
}
}];
[self enumerateChildNodesWithName:#"heart3" usingBlock:^(SKNode *node, BOOL *stop){
if (hitCount == 3) {
[node removeFromParent];
}
}];
}
I would suggest hiding the heart nodes instead of removing them, because then you can bring them back anytime (powerups or something).
SKNode *heartNode;
switch (hitCount)
{
case 1:
heartNode = [self childNodeWithName:#"heart1"];
break;
case 2:
heartNode = [self childNodeWithName:#"heart2"];
break;
case 3:
heartNode = [self childNodeWithName:#"heart3"];
break;
}
if (heartNode)
{
[heartNode setHidden:TRUE];
}
Appreciate this already has an accepted answer, but if code speed is important wouldn't this be quicker...
SKNode *heartNode = [self childNodeWithName:[NSString stringWithFormat:#"heart%d",hitCount]];
[heartNode setHidden:TRUE];
If heartNode is nil then the setHidden does nothing
Just not sure if doing stringWithFormat is quicker than a switch statement
I have a sprite-kit game where I need to be checking often to see if the player has lost
- (void)update:(NSTimeInterval)currentTime
{
for (SKSpriteNode *sprite in self.alienArray ) {
if (sprite.position.y < 10) {
LostScene *lostScene = [[LostScene alloc] initWithSize: CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds))];
NSLog(#"about to present");
[self.view presentScene:lostScene transition:[SKTransition fadeWithDuration:0.5]];
}
}
}
but when this method gets called (which I know is happening), no scene presents. What am I doing wrong? I believe it has something to do with the transition, because when I take it out, it works fine
You should add a property of the existing scene like: BOOL playerHasLost and edit your update method:
- (void)update:(NSTimeInterval)currentTime
{
if(!playerHasLost)
{
for (SKSpriteNode *sprite in self.alienArray )
{
if (sprite.position.y < 10)
{
playerHasLost = YES;
LostScene *lostScene = [[LostScene alloc] initWithSize: CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds))];
NSLog(#"about to present");
[self.view presentScene:lostScene transition:[SKTransition fadeWithDuration:0.5]];
break;//to get out of for loop
}
}
}
}
So this way as soon as the sprite get to position that you treat as lost position it will set the variable to YES, present the scene and it will not do it again.
The reason is simply that the update method gets called every frame, with a running transition the scene will be presented anew every frame and thus it appears as if nithing is happening. You should see the NSLog spamming the log console.
I'm building a Cocos2D game in which after two certain sprites collide (by simple bounding box technique), I call
[[CCDirector sharedDirector] replaceScene:gameOverScene];
to change to the game over scene.
Once it initializes the game over scene with everything in it, the game crashes and goes to this method in ccArray.m class:
void ccArrayRemoveAllObjects(ccArray *arr)
{ while( arr->num > 0 )
CC_ARC_RELEASE(arr->arr[--arr->num]);
}
with the message:
Thread 1: Program received signal: "EXC_BAD_ACCESS".
I tried to debug using breakpoints and figured out that once my gameOver scene gets initialized and ready to display, the dealloc method in the previous class (the gameplay class, which called the replace scene) gets called and after which it throws this error.
My update method:
-(void)update:(ccTime)dt
{
if (CGRectIntersectsRect(plane.boundingBox, enemy.boundingBox)) {
CCScene *gameOverScene = [GameOverLayer sceneWithWon:NO];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
} }
My dealloc method:
- (void) dealloc
{
[super dealloc];
[_monsters release];
_monsters = nil;
[mole release];
mole = nil;
[text release];
text = nil;
[mBG1 release];
mBG1 = nil;
[mBG2 release];
mBG2 = nil; }
I have no clue why this is happening. Please help.
Thanking you in anticipation.
You are calling super's dealloc before you are deallocating your gameplay scene.
Call super's dealloc at the end of your dealloc method :
- (void) dealloc {
[_monsters release];
_monsters = nil;
[mole release];
mole = nil;
[text release];
text = nil;
[mBG1 release];
mBG1 = nil;
[mBG2 release];
mBG2 = nil;
[super dealloc];
}
When you are calling super's dealloc first you are releasing your instance making it members invalid so accessing them after the dealloc will create memory bad access issues
because you didn't show enough code,i can only guess that some of these objects,such as _monsters,mole,text,mBG1,mBG2,were autoreleased before you release them in the dealloc funtion.So,they can not be released anymore.This is concerned ARC-automaic reference counting which you should know, it's basis of ios.
try this only:
- (void) dealloc {
[super dealloc];
}