Reputation: 1062
I have a sprite that can't exist in my game without a pairing SKFieldNode
so my solution was to create a subclass of SKSpriteNode
and create a property for the SKFieldNode
but it didn't work because the SKSpriteNode
was acting weird (I don't remember exactly what happened). So my next approach was to change the subclass to SKNode
and then I would make the SKSpriteNode
and the SKFieldNode
a property of this new SKNode
. But then it turns out that touchesMoved
will only move one of the properties (whichever is on top) which turns out to always be the SKSpriteNode
.
What's the best approach to this problem, and how can I fix it so that I can have an SKFieldNode
for every SKSpriteNode
while still making sure that actions and methods still work properly.
Current code of SKNode
subclass:
@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;
}
}
}
Upvotes: 4
Views: 197
Reputation: 3812
I believe your issues comes down to that fact that "whirlpool" is a child of your SKNode subclass. So when you are identifying that you are indeed touching a "whirlpool" you are moving it within its parent (the SKNode subclass) and the SKFieldNode and parent stay put. This little adjustment to your original 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;
}
}
}
Hopefully that helps.
Upvotes: 2
Reputation: 16837
Yikes, the problem here is the way you are grabbing nodes, you may be grabbing the wrong nodes due to all the children. Instead take this approach:
We already know that you are subclassing your sprites, so in your subclasses, add the following code:
//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;
}
}
Then:
//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;
}
}
Then for your Scene, do this:
- (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];
}
Upvotes: 0