Question

I'm using this code to detect and see if the users tap was inside the frame of my SKSpriteNode, and if it is, remove the node from the screen. But I only want the node that was tapped to disappear.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */

    for (UITouch *touch in touches) {
            CGPoint location = [touch locationInNode:self];

        if ((location.x > self.crate.frame.origin.x && location.x < self.crate.frame.origin.x + self.crate.frame.size.width) &&
            (location.y > self.crate.frame.origin.y && location.y < self.crate.frame.origin.y + self.crate.frame.size.height)) {

            [self.crate removeFromParent];
        }
    }
}

In my update method, I am calling a method, addCrate: to spawn the node every second.

- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {

    self.lastSpawnTimeInterval += timeSinceLast;
    if (self.lastSpawnTimeInterval > 1) {
        self.lastSpawnTimeInterval = 0;
        [self addCrate];
    }
}

- (void)update:(NSTimeInterval)currentTime {
    // Handle time delta.
    // If we drop below 60fps, we still want everything to move the same distance.
    CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;
    self.lastUpdateTimeInterval = currentTime;
    if (timeSinceLast > 1) { // more than a second since last update
        timeSinceLast = 1.0 / 60.0;
        self.lastUpdateTimeInterval = currentTime;
    }

    [self updateWithTimeSinceLastUpdate:timeSinceLast];

}

This is the method that it is calling.

- (void)addCrate {

    // Create sprite
        self.crate = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(30, 30)];
        //self.crate.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.crate.frame.size];

    // Determine where to spawn the crate along the X axis
        int minX = self.crate.size.width / 2;
        int maxX = self.frame.size.width - self.crate.size.width / 2;
        int rangeX = maxX - minX;
        int actualX = (arc4random_uniform(rangeX)) + minX;

    // Create the crate slightly off-screen along the top,
    // and along a random position along the X axis as calculated above
        self.crate.position = CGPointMake(actualX, self.frame.size.height + self.crate.size.height/2);
        [self addChild:self.crate];
        self.crate.size = CGSizeMake(50, 50);


    // Determine speed of the crate
        int actualDuration = 3.5;

    // Create the actions
        SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX, -self.crate.size.height/2) duration:actualDuration];
        SKAction * actionMoveDone = [SKAction removeFromParent];
        [self.crate runAction:[SKAction sequence:@[actionMove, actionMoveDone]]];
}

But when I run on my iPhone, only sometimes the tap is registered and the block is removed from the screen, and sometimes it doesn't. Again, I want the node that was tapped on to disappear and only that node.

Thank you!

U1:

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {

        self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
        [self addCrate];
    }
        return self;
}

- (void)addCrate {

    // Create sprite
        self.crate = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(30, 30)];
    self.crate.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(30, 30)];
        self.crate.userInteractionEnabled = YES;
        //self.crate.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.crate.frame.size];

    // Determine where to spawn the crate along the X axis
        int minX = self.crate.size.width / 2;
        int maxX = self.frame.size.width - self.crate.size.width / 2;
        int rangeX = maxX - minX;
        int actualX = (arc4random_uniform(rangeX)) + minX;

    // Create the crate slightly off-screen along the top,
    // and along a random position along the X axis as calculated above
        self.crate.position = CGPointMake(actualX, self.frame.size.height + self.crate.size.height/2);
        [self addChild:self.crate];
        self.crate.size = CGSizeMake(50, 50);


    // Determine speed of the crate
        int actualDuration = 3.5;

    // Create the actions
        SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX, -self.crate.size.height/2) duration:actualDuration];
        SKAction * actionMoveDone = [SKAction removeFromParent];
        [self.crate runAction:[SKAction sequence:@[actionMove, actionMoveDone]]];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint touchLocation = [touch locationInNode:self];
    SKNode *touchedNode = [self nodeAtPoint:touchLocation];

    NSLog(@"touchLocation x: %f and y: %f", touchLocation.x, touchLocation.y);

    if (touchedNode != self) {
        NSLog(@"Removed from parent.");
        [touchedNode removeFromParent];
    }
}


- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {

    self.lastSpawnTimeInterval += timeSinceLast;
    if (self.lastSpawnTimeInterval > 1) {
        self.lastSpawnTimeInterval = 0;
        [self addCrate];
    }
}

- (void)update:(NSTimeInterval)currentTime {
    // Handle time delta.
    // If we drop below 60fps, we still want everything to move the same distance.
    CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;
    self.lastUpdateTimeInterval = currentTime;
    if (timeSinceLast > 1) { // more than a second since last update
        timeSinceLast = 1.0 / 60.0;
        self.lastUpdateTimeInterval = currentTime;
    }

    [self updateWithTimeSinceLastUpdate:timeSinceLast];

}
Was it helpful?

Solution

I think you should use combination of setting node.name property while creating crates and checking them in touchBegan: method.

Something like this:

SKSpriteNode *crate = [SKSpriteNode spriteNodeWithTexture:tex];
crate.name = @"crate";

And touchBegan: method:

.....
if ([touchedNode.name isEquelToString:@"crate"]){
   // do something with that node
}
.....

Upd1:

Instead of writing this stuff:

if ((location.x > self.crate.frame.origin.x && location.x < self.crate.frame.origin.x + self.crate.frame.size.width) &&
        (location.y > self.crate.frame.origin.y && location.y < self.crate.frame.origin.y + self.crate.frame.size.height)) {

        [self.crate removeFromParent];
    }

use:

if(CGRectContainsPoint(self.frame, touchPoint)){
   // do something
}

Upd2:

Don't see in your code that you are setting userInteractionEnabled = YES on crate nodes.

Upd3:

Here is an example:

//
//  BGMyScene.m
//  Test1
//
//  Created by AndrewShmig on 3/10/14.
//  Copyright (c) 2014 Bleeding Games. All rights reserved.
//

#import "BGMyScene.h"

@implementation BGMyScene

- (id)initWithSize:(CGSize)size
{
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */

        self.backgroundColor = [SKColor colorWithRed:0.15
                                               green:0.15
                                                blue:0.3
                                               alpha:1.0];

//      first label
        SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
//        myLabel.userInteractionEnabled = YES;
        myLabel.text = @"Hello, World!";
        myLabel.fontSize = 30;
        myLabel.position = CGPointMake(CGRectGetMidX(self.frame),
                                       CGRectGetMidY(self.frame));
        [self addChild:myLabel];

//      second label
        SKLabelNode *myLabel2 = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
//        myLabel2.userInteractionEnabled = YES;
        myLabel2.text = @"Hello, World!";
        myLabel2.fontSize = 30;
        myLabel2.position = CGPointMake(100, 100);
        [self addChild:myLabel2];
    }
    return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint touchLocation = [touch locationInNode:self];
    SKNode *touchedNode = [self nodeAtPoint:touchLocation];

    NSLog(@"touchLocation x: %f and y: %f", touchLocation.x, touchLocation.y);

    if (touchedNode != self) {
        NSLog(@"Removed from parent.");
        [touchedNode removeFromParent];
    }
}

- (void)update:(CFTimeInterval)currentTime
{
    /* Called before each frame is rendered */
}

@end

You'll see following screen: enter image description here

After tapping on "Hello, World!" labels they will be removed from parent node.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top