0
votes

I want to run a SKAction if my SKSpriteNode Sorcerer is touched. With my current code, whenever I touch, my SpriteNode 'stone' will move to the Sorcerer. I could call the location of the touch with specific x and y coord., but since the 'Sorcerer' is moving, I can't do that. How can I fix this?

- (void)Sorcerer {

Sorcerer = [SKSpriteNode spriteNodeWithImageNamed:@"Sorcerer.png"];
Sorcerer.size = CGSizeMake(85, 85);
Sorcerer.zPosition = 2;

Sorcerer.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(50, 50)];
Sorcerer.physicsBody.dynamic = NO;
Sorcerer.physicsBody.allowsRotation = NO;
Sorcerer.physicsBody.usesPreciseCollisionDetection = YES;
Sorcerer.physicsBody.restitution = 0;

Sorcerer.position = CGPointMake(self.frame.size.width * 1.25, self.frame.size.height / 2.2);

SKAction * actionMove = [SKAction moveToX:self.frame.size.width / 2 duration:10];

[Sorcerer runAction:[SKAction repeatActionForever:[SKAction sequence:@[actionMove]]]];

[self addChild:Sorcerer];

}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:Sorcerer];

Stone = [SKSpriteNode spriteNodeWithImageNamed:@"Stone.png"];

Stone.position = Human.position;
Stone.zPosition = 1;
Stone.scale = 0.6;

SKAction *action = [SKAction moveTo:Sorcerer.position duration:0.5];
SKAction *remove = [SKAction removeFromParent];

[Stone runAction:[SKAction sequence:@[action,remove]]];

[self addChild:Stone];

}
2

2 Answers

0
votes

//give stone or Sorcere a name

through this name you can easily access that node

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];

// decide if the node is of interest or can be ignored, something like this:



if ([node.name isEqualToString:@“stone”]) {
      //apply action on stone

       }

}

0
votes

There are many situations when SKNode needs to inform its scene about some events or wants to force particular behavior only scene can provide.

Of course you can implement a touchesEnded: method in the scene and iterate through node but what if you have couple of thousands of them on the screen? The cleanest possible way of doing this is either by using delegation or notifications.

Delegation

We will create a protocol and set a scene as its delegate. Sourcerer will call delegate's method when it's touched. Let's define the protocol:

@class Sorcerer;
@protocol SorcererInteractionDelegate <NSObject>

- (void)sorcererTapped:(Sorcerer)sorcerer;

@end

Add a delegate property to Sorcerer class:

@interface Sorcerer : SKSpriteNode
@property (nonatomic, weak) id <SorcererInteractionDelegate> delegate;
@end

Finally, implement the touchesEnded: method.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];

    if ([_delegate respondsToSelector:@selector(sorcererTapped:)])
    {
        [_delegate performSelector:@selector(sorcererTapped:)
                        withObject:self];
    }
}

Remember to set userInteractionEnabled to YES in your init method of Sourcerer class. When creating a sourcerer in your scene, set the delegate:

Sourcerer *sourcerer = ...
sourcerer.delegate = self;

and implement the sorcererTapped: method:

- (void)sorcererTapped:(Sorcerer)sorcerer;
{
    // Do stuff with sorcerer.
}

Notifications

Delegation is cool but what if you need to inform several objects at once about the change. Then, you should use notifications.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];

    [[NSNotificationCenter defaultCenter]
             postNotificationName:@"UserDidTapSourcererNotification" object:self];
}

Your scene needs to register as an observer of @"UserDidTapSourcererNotification" notification and handle it.

 [[NSNotificationCenter defaultCenter] addObserver:self

                                             selector:@selector(handleUserDidTapSourcererNotification:)
                                                 name:@"UserDidTapSourcererNotification";
                                               object:nil]; 

- (void)handleUserDidTapSourcererNotification:(NSNotification *)notification
{
    Sorcerer *sorcerer = (Sorcerer *)[notification object];

    // Do stuff with sorcerer.
}

Hope it helps.