2013-10-21 17 views
11

Nell'apprendimento di SpriteKit, sto cercando di realizzare un piccolo gioco di avventura. Sto creando un eroe e aggiungendolo alla scena, e successivamente, durante il touchesBegan:, rilevo se il tocco è originato sull'eroe e agisco di conseguenza.Custom SKSpriteNode non rilevato durante il tocco

Se aggiungo l'eroe come SKSpriteNode il tocco lo rileva. Se lo aggiungo come sottoclasse di SKSpriteNode il tocco non lo fa! La differenza di aggiungere:

_heroNode = [SKSpriteNode spriteNodeWithImageNamed:@"hero.png"]; 

vs

_heroNode = [[ADVHeroNode alloc] init]; 

L'init si presenta così:

- (id) init { 
    if (self = [super init]) { 

     self.name = @"heroNode"; 
     SKSpriteNode *image = [SKSpriteNode spriteNodeWithImageNamed:@"hero.png"]; 
     [self addChild:image]; 
    } 
    return self; 
} 

Aggiunta l'eroe come una sottoclasse di SKSpriteNode funziona, nel senso che viene aggiunto alla la scena, ma il tocco non lo rileva. Il mio touchesBegan: assomiglia a questo:

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

    UITouch *touch = [touches anyObject]; 
    CGPoint location = [touch locationInNode:self]; 
    SKNode *node = [self nodeAtPoint:location]; 
    if (YES) NSLog(@"Node name where touch began: %@", node.name); 

    //if hero touched set BOOL 
    if ([node.name isEqualToString:@"heroNode"]) { 
     if (YES) NSLog(@"touch in hero"); 
     touchedHero = YES; 
    } 
} 

Frustrante, questo codice funziona bene quando si aggiunge una sottoclasse verso l'alto SKSpriteNode, e non la mia di esso. Eventuali suggerimenti?

risposta

22

seguito alcuni esempi di metodi per sottoclasse dell'Eroe

SKNode

sottoclasse un SKNode questo metodo richiede il nodo per monitorare tocchi, quindi la proprietà self.userInteractionEnabled.

@implementation HeroSprite 

- (id) init { 
    if (self = [super init]) { 
     [self setUpHeroDetails]; 
     self.userInteractionEnabled = YES; 
    } 
    return self; 
} 

-(void) setUpHeroDetails 
{ 
    self.name = @"heroNode"; 
    SKSpriteNode *heroImage = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"]; 
    [self addChild:heroImage]; 
} 


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *touch = [touches anyObject]; 
    CGPoint locationA = [touch locationInNode:self]; 
    CGPoint locationB = [touch locationInNode:self.parent]; 
    NSLog(@"Hit at, %@ %@", NSStringFromCGPoint(locationA), NSStringFromCGPoint(locationB)); 
} 

@end 

SKSpriteNode

L'altro modo "facile", se si desidera solo per sottoclasse un SKSpriteNode. Questo funzionerà essenzialmente allo stesso modo in cui sei usato (prima di voler sottoclassi il tuo Hero). Quindi i tuoi tocchi, come previsto nella tua domanda, funzioneranno.

@implementation HeroSprite 

- (id) init { 
    if (self = [super init]) { 
     self = [HeroSprite spriteNodeWithImageNamed:@"Spaceship"]; 
     [self setUpHeroDetails]; 

    } 
    return self; 
} 

-(void) setUpHeroDetails { 
    self.name = @"heroNode"; 
} 

@end 
+0

Sebbene non conosca SpriteKit e Objective-C in generale, non vedo come creiamo un'istanza di queste classi? – Jide

+0

Non ho inserito quel codice, creo semplicemente come si crea un normale SKSprite, ma usa HeroSprite. – DogCoffee

+0

Fantastico modo di farlo! Impressionante – Septronic

0

Il tuo ADVHeroNode è uno SkNode o SkSpriteNode senza immagine. Né avranno alcuna estensione, sono punti per intenderci. Non saranno trovati da nodeAtPoint: ma il figlio di immagini SKSpriteNode lo farà. Dal momento che stai verificando esplicitamente il nome del nodo, il controllo fallisce.

È possibile assegnare un nome all'immagine, verificarlo e quindi fare riferimento al relativo genitore per ottenere l'istanza ADVHeronode. Oppure controlla direttamente il nome di node.parent.

1

Ha appena rilevato il tocco solo su questo sprite.

Quando si crea un oggetto SKSpriteNode, esso si controllerà. Significa che quando un tocco inizia su di esso, significa che questo oggetto non riceve questo SKView.

Quindi, se si desidera rilevare questo tocco, è necessario scrivere questo codice su questo oggetto non su SKView. Se vuoi fare qualcosa su SKView quando un tocco si verifica su SKSpriteNode, puoi usare delegato per farlo.

Sentiti libero di chiedere di più se non riesci a capire cosa rispondo.

+0

anche se l'OP non ha mai richiesto questo, mi piacerebbe vedere il codice della soluzione delegato di cui stai parlando. Sto gestendo con successo touchEnded nella mia sottoclasse SKSpriteNode ma vorrei anche attivare il metodo touchesEnded in SKView, che non è il caso se abiliti userInteractionEnabled nella sottoclasse. – stvn

3

Di solito controllo il genitore del nodo toccato finché non trovo la classe che voglio controllare. Ecco uno snippet di codice.

while (touchedNode.parent) 
    { 
     if ([touchedNode isKindOfClass:[GameObject class]]) 
      break; 
     else 
      touchedNode = (SKSpriteNode*)self.touchedNode.parent; 
    } 
+0

Ho avuto un problema quando tocco SKLabelNode nel mio contenitore, ma con questa riga "touchedNode = (SKSpriteNode *) self.touchBeganNode.parent;" salva la mia giornata. – Beto

+0

è self.touchBeganNode una variabile personalizzata? – josef

+0

Sì, era nel mio codice ma penso che intendessi TouchedNode, ho appena aggiornato la risposta. – membersheep

9

Assicurati di aggiungere questo nel metodo di inizializzazione.

self.userInteractionEnabled = YES; 

Per alcuni motivi questo non è abilitato di default quando si sottoclasse. Almeno per me ha funzionato solo quando abilitato manualmente.

Problemi correlati