Определить, какой экземпляр SKSpriteNode был затронут?

Я использую этот код, чтобы определить и посмотреть, было ли касание пользователя внутри рамки моего SKSpriteNode, и если это так, удалить узел с экрана. Но я только хочу, чтобы узел, который был использован, исчез.

-(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];
        }
    }
}

В моем методе обновления я вызываю метод addCrate: для порождения узла каждую секунду.

- (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];

}

Это метод, который он вызывает.

- (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]]];
}

Но когда запускаю на своем айфоне, только иногда регистрируется тап и снимается блок с экрана, а иногда нет. Опять же, я хочу, чтобы узел, на который нажали, исчез, и только этот узел.

Благодарю вас!

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];

}

person Community    schedule 09.03.2014    source источник


Ответы (1)


Я думаю, вы должны использовать комбинацию установки свойства node.name при создании ящиков и проверки их в методе touchBegan:.

Что-то вроде этого:

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

И touchBegan: метод:

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

Обновление 1:

Вместо того, чтобы писать это:

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];
    }

использовать:

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

Обновление 2:

Не видите в своем коде, что вы устанавливаете userInteractionEnabled = YES для узлов ящика.

Обновление 3:

Вот пример:

//
//  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

Вы увидите следующий экран: введите здесь описание изображения

После нажатия на Hello, World! метки они будут удалены из родительского узла.

person AndrewShmig    schedule 09.03.2014
comment
Да, для параметра userInteractionEnabled установлено значение yes. Но я исправил, все равно не работает. - person ; 09.03.2014
comment
В методе touchBegan: как определить, какой узел был затронут? - person ; 09.03.2014
comment
Итак, откуда мне взять «touchedNode»? - person ; 09.03.2014
comment
@IsaRanjha, чтобы определить, какой узел был затронут, вы должны (на самом деле вы можете оставить name = nil и использовать свойство userData узла) установить свойство имени узла после его создания. После этого отметьте touchBegan: имя узла метода и выполните необходимые действия. См. (методы nodeAtPoint: и nodesAtPoint:) developer.apple.com/Library/ios/documentation/SpriteKit/: - person AndrewShmig; 09.03.2014
comment
Понятно. Но если я назову все одним и тем же (@crate), разве они не исчезнут? Как я узнаю, какой из них прослушивался? - person ; 09.03.2014
comment
@IsaRanjha, см. методы nodeAtPoint: и nodesAtPoint:. - person AndrewShmig; 09.03.2014
comment
Итак, SKNode *node = [self nodeAtPoint:location]; тогда что мне проверить с этим? - person ; 09.03.2014
comment
что-то вроде: if(node ​​!= self) { /* некоторые действия ... */ }. В документации четко сказано, что: потомок в поддереве, пересекающем точку, или получатель, если ни одна вершина не пересекает точку. - person AndrewShmig; 09.03.2014
comment
Итак, чтобы убедиться, что я делаю это правильно, как будут выглядеть мои последние штрихиBegan: метод? - person ; 09.03.2014
comment
@IsaRanjha, ваш вопрос был: определить, какой экземпляр SKSpriteNode был затронут? :) Как должен выглядеть ваш метод - решать вам. После того, как вы получили узел, к которому прикоснулись, вы можете делать с ним все, что захотите. Шаги для вас: 1) получить местоположение точки касания 2) получить узел, к которому коснулись 3) если узел != получатель, выполните некоторые действия 4) вот и все - person AndrewShmig; 09.03.2014
comment
Меня смущает шаг номер 2. Я не знаю, как это сделать в коде. - person ; 09.03.2014
comment
@IsaRanjha, SKNode *node = [self nodeAtPoint:touchPoint]; где self — ваша переменная экземпляра SKScene. Это может быть быстрее, если вы покажете нам, что вы уже сделали, а что именно не работает. - person AndrewShmig; 09.03.2014
comment
@IsaRanjha, см. файл SKButton.m ( stackoverflow.com/a/19199748/523630 ) и проверьте, как реализованы сенсорные методы. . Это должно помочь вам. - person AndrewShmig; 09.03.2014
comment
Итак: -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInNode:self]; SKNode *node = [self nodeAtPoint:местоположение]; if (узел! = self) { [self.crate removeFromParent]; } } - person ; 10.03.2014
comment
@IsaRanjha, так? это работает? Вы должны просто попробовать что-то, поэкспериментировать и посмотреть, что у вас получится. - person AndrewShmig; 10.03.2014
comment
Нет, этот код не работает. Я просто пытаюсь понять, как это вообще сработает. Но это не так. Кажется, что должен быть более простой способ сделать это, так как что-то простое, как нажатие на SKSpriteNode, не должно требовать потока на SO. Могу ли я использовать UIGestureRecognizer для нажатий? - person ; 10.03.2014
comment
@IsaRanjha, это самый простой способ. UIGestureRecognizer работает с UIViews, поэтому после тапа вам также нужно получить точку касания и узел, который был под тапом. Ухх... Я напишу пример. - person AndrewShmig; 10.03.2014
comment
@IsaRanjha, я обновил свой ответ рабочим примером. Видеть это. - person AndrewShmig; 10.03.2014
comment
Ладно, должно быть, я делаю это неправильно. Я обновил свой вопрос тем, что у меня есть, он не работает, меня никогда не удаляют из родителя в журнале? - person ; 10.03.2014
comment
@IsaRanjha, КОММЕНТИРУЙТЕ все self.crate.userInteractionEnabled = YES или установите для него значение NO. - person AndrewShmig; 10.03.2014
comment
Как освободить от этого SKLabelNode? - person ; 11.03.2014