Subclass SKNode Non-moving children

I have a sprite that cannot exist in my game without pairing SKFieldNode, so my solution was to subclass SKSpriteNodeand create a property for SKFieldNode, but that didn’t work because it was SKSpriteNodeacting strange (I don’t remember exactly what happened). Thus, my next approach was to change in the subclass SKNode, and then I will make the property SKSpriteNodeand SKFieldNodefor the new SKNode. But then it turns out that it touchesMovedwill only move one of the properties (depending on what is on top), which will always be SKSpriteNode.

What is the best approach to this problem and how can I fix it to have SKFieldNodefor everyone SKSpriteNode, while still checking the correctness of the actions and methods.

Current subclass code SKNode:

@interface Whirlpool : SKNode
- (instancetype)initWithPosition:(CGPoint)pos region:(float)region strength:(float)strength falloff:(float)falloff;
@property (nonatomic, strong) SKFieldNode *gravityField;
@end

#import "Whirlpool.h"
#import "Categories.h"

@implementation Whirlpool
- (instancetype)initWithPosition:(CGPoint)pos region:(float)region strength:(float)strength falloff:(float)falloff {
    if (self = [super init]) {
        // whirlpool sprite
        SKSpriteNode *whirlpoolSprite = [[SKSpriteNode alloc] initWithImageNamed:@"whirlpool"];
        whirlpoolSprite.size = CGSizeMake(100, 100);
        whirlpoolSprite.position = pos;
        //removing physicsBody and associated attributes for now so that the boat does not collide with the whirlpool
        //whirlpoolSprite.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:whirlpoolSprite.size.width / 2];
        //whirlpoolSprite.physicsBody.dynamic = NO;
        whirlpoolSprite.zPosition = 1;
        whirlpoolSprite.name = @"whirlpool";
        [whirlpoolSprite runAction:[SKAction repeatActionForever:[self sharedRotateAction]]];

        // whirlpool gravity field
        _gravityField = [SKFieldNode radialGravityField];
        _gravityField.position = pos;
        _gravityField.strength = strength;
        _gravityField.falloff = falloff;
        _gravityField.region = [[SKRegion alloc] initWithRadius:region];
        _gravityField.physicsBody.categoryBitMask = gravityFieldCategory;
        _gravityField.zPosition = 1;

        [self addChild:whirlpoolSprite];
        [self addChild:_gravityField];
    }

    return self;
}

- (SKAction *)sharedRotateAction {
    static SKAction *rotateWhirlpool;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        rotateWhirlpool = [SKAction rotateByAngle:-M_PI * 2 duration:4.0];
    });

    return rotateWhirlpool;
}

@end

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // we don't want the player to be able to move the whirlpools after the button is pressed
    if (_isRunning) {
        return;
    }

    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];
        SKNode *node = [self nodeAtPoint:location];
        // if the finger touches the boat or the whirlpool, update its location
        if ([node.name isEqualToString:@"boat"]) {
            node.position = CGPointMake(location.x, node.position.y);
        } else if ([node.name isEqualToString:@"whirlpool"]) {
            node.position = location;
        }
    }
}
+4
source share
2 answers

I believe that your problems boil down to the fact that the “whirlpool” is a child of your SKNode subclass. Therefore, when you determine that you are really touching the "maelstrom", you move it inside your parent (subclass SKNode) and SKFieldNode and parental stay. This small adjustment to the source code should work ... if I understand the problem correctly.

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // we don't want the player to be able to move the whirlpools after the button is pressed
    if (_isRunning) {
        return;
    }

    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];
        SKNode *node = [self nodeAtPoint:location];
        // if the finger touches the boat or the whirlpool, update its location
        if ([node.name isEqualToString:@"boat"]) {
            node.position = CGPointMake(location.x, node.position.y);
        } else if ([node.name isEqualToString:@"whirlpool"]) {
            //move the SKNode subclass the whirlpool is a child of
            node.parent.position = location;
        }
    }
}

Hope this helps.

+2
source

Yikes, , , - . :

, , :

//Whirlpool 
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
   for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self.parent];//Unless you are retaining the scene in the child, then use that
        self.position = location;
    }
}

:

//Boat 
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
   for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self.parent];//Unless you are retaining the scene in the child, then use that
        self.position.x = location.x;
    }
}

:

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // we don't want the player to be able to move the whirlpools after the button is pressed
    if (_isRunning) {
        return;
    }
    //At this point it should call the children on touch events
    [super.touchesMoved: touches withEvent:event];
}
0

All Articles