SKNode Subclass Not Moving Children

时间:2016-02-25 18:20:13

标签: ios xcode sprite-kit

我有一个精灵在我的游戏中不存在配对SKFieldNode所以我的解决方案是创建一个SKSpriteNode的子类并为SKFieldNode创建一个属性但它没有用,因为SKSpriteNode表现得很奇怪(我不记得到底发生了什么)。所以我的下一个方法是将子类更改为SKNode,然后我将SKSpriteNodeSKFieldNode作为此新SKNode的属性。但后来证明touchesMoved只会移动其中一个属性(以顶部为准),结果始终为SKSpriteNode

解决此问题的最佳方法是什么,以及如何解决此问题,以便每个SKFieldNode都可以SKSpriteNode,同时仍然确保操作和方法仍能正常运行

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

2 个答案:

答案 0 :(得分:2)

我相信你的问题归结为&#34;漩涡&#34;是您的SKNode子类的子级。因此,当你发现自己确实正在接触一个&#34;漩涡&#34;你正在它的父(SKNode子类)和SKFieldNode和父留下来移动它。如果我正确理解了问题,那么对原始代码的这一小调整应该有效。

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

希望这有帮助。

答案 1 :(得分:0)

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