Reputation: 317
I have a player object in my SpriteKit game and at the moment I'm moving it using the following code:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (touches.count == 1)
{
[self touchesMoved:touches withEvent:event];
}
}
-(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
if (touches.count == 1)
{
[_player runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:0.01]];
}
}
But I only want to move the player node when the touch is within a specific range of the location.
Upvotes: 2
Views: 1652
Reputation: 42325
Since it looks like you only care about the distance of the touch from your _player
object, I would move the radius detection logic to your _player
object and use an SKRegion
to handle it.
Note: If you need to know if your touch is within the radius of multiple nodes then you might want to use a method from this question instead.
To use an SKRegion
to determine if your touch is within a certain radius of _player
, add an SKRegion
instance to your _player
object and initialize it with the radius you want. In [_player init]
or wherever it makes the most sense for your project:
self.touchRegion = [[SKRegion alloc] initWithRadius:radius];
Then add a method to determine if a point is within that region:
- (BOOL)pointIsInTouchRegion:(CGPoint)point {
return [self.touchRegion containsPoint: point];
}
Next change your touchesMoved
method to something like:
-(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
if (touches.count == 1)
{
UITouch *touch = [touches anyObject];
CGPoint point = [self locationInNode:_player]; // NOTE: It's important to use _player here!
if ([_player pointIsInTouchRegion: point]) {
[_player runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:0.01]];
}
}
}
Note: Using _player
in [self locationInNode:_player];
is critical since your SKRegion
will be defined in the _player
node's coordinate system.
One more note: You don't really have to put all that logic in _player
, that's just the way I would do it. You could just as easily store the SKRegion
in your scene's class and call [region containsPoint: point]
on it directly.
Update: iOS 7 method
The main difference with doing this for iOS 7 is that you need to store the actual radius you're interested in rather than an SKRegion
(since it's only available in iOS 8), and then do the calculation yourself in pointIsInTouchRegion:
.
So, in _player
, set your touch radius where you were setting the touchRegion
before:
self.touchRadius = radius
Then change the pointIsInTouchRegion:
method so that it does the actual distance calculation.
- (BOOL)pointIsInTouchRegion:(CGPoint)point {
CGPoint centerOfNode = CGPointMake(self.frame.size.width / 2.0, self.frame.size.height / 2.0); // NOTE: If this is in an SKSpriteNode, you might want to use self.anchorPoint instead
CGFloat distanceToCenter = return hypotf(point.x - centerOfNode.x, point.y - centerOfNode.y);
return (distanceToCenter <= self.radius);
}
The code in touchesMoved
should not need any changes.
Upvotes: 3
Reputation: 12753
The following demonstrates how to 1) select a sprite that is within a specified distance from a touch event and 2) drag and drop the selected sprite to a new location.
@interface MyScene()
@property (weak) SKSpriteNode *selectedNode;
@end
@implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
// Add three sprites to scene
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(32, 32)];
sprite.name = @"Blue";
sprite.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame)-64);
[self addChild:sprite];
sprite = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(32, 32)];
sprite.name = @"Red";
sprite.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame) + 64);
[self addChild:sprite];
sprite = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(32, 32)];
sprite.name = @"Green";
sprite.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
[self addChild:sprite];
}
return self;
}
#define kRadius 64
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
_selectedNode = nil;
CGFloat minDistance = kRadius+1;
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
for (SKSpriteNode *node in self.children) {
CGFloat dx = location.x - node.position.x;
CGFloat dy = location.y - node.position.y;
// Compute distance from sprite to tap point
CGFloat distance = sqrtf(dx*dx+dy*dy);
if (distance <= kRadius) {
if (distance < minDistance) {
// Select the closest node so far
_selectedNode = node;
minDistance = distance;
}
}
}
}
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if (_selectedNode) {
// Move selected node to current touch position
_selectedNode.position = location;
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// Unselect node
_selectedNode = nil;
}
- (void) update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
}
@end
Upvotes: 1
Reputation: 29
I think you should add this, forgive me if I mis understand your question however:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [touch locationInView:self.view];
if (touches.count == 1) && (point.x == yourObjectsXPosition) && (point.y == yourObjectsYPosition)
{
[self touchesMoved:touches withEvent:event];
}
}
Upvotes: 0