Reputation: 35933
I have a sprite using a custom SKSpriteNode class added to a scene.
I want to do this effect: suppose I have 3 sprites side by side. I want the sprite to scale a little bit if it is touched or while the finger is touching it and as soon as the finger is not touching it, it should scale back to the original size.
What I mean is this: suppose the user gives a big finger slide from left to right, starting on the first sprite and ending past the last sprite. As the finger is sliding, I want the first sprite to scale up as soon as the finger enters its frame. As the finger continues to slide to right and reaches the second sprite, I want the first one to detect that the finger is not on its area and scale down to its original size. At the same time, the second sprite would scale up, because now the finger is inside its area. At any time the finger leaves the surface during the slide, just after passing the last sprite.
My problem is that I want to do this using logic inside the sprite class but when I implement touchesBegan, touchesMoved, etc., on that sprite's class it is not working because touchesMoved continues to report the finger even if it is not inside its area.
This is my touch logic inside the sprite's class:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
SKAction *scaleUp = [SKAction scaleTo:1.2 duration:0.2];
[self runAction:scaleUp];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];
// CGPoint convertPT = [self convertPoint:touchLocation fromNode:self.parent];
NSLog(@"%@", NSStringFromCGPoint(touchLocation));
// if (CGRectContainsPoint(self.frame, touchLocation)) {
// NSLog(@"this is never fired?");
// }
}
The NSLog line will always print a location even if the finger is outside the layer...
I want TouchesMoved to stop firing after the finger is outside the sprite.
How do I do that?
Upvotes: 0
Views: 2771
Reputation: 19946
I put this in a sub class and got good results.
You will still need some logic for when the begins outside the rect from within the game scene class.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
SKAction *scaleUp = [SKAction scaleTo:1.2 duration:0.2];
[self runAction:scaleUp withKey:@"action"];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
UITouch* touch = [touches anyObject];
CGPoint loc = [touch locationInNode:self.parent];
if (![self containsPoint:loc]) {
SKAction *scaleDown = [SKAction scaleTo:1.0 duration:0.1];
[self runAction:scaleDown];
}
else if ([self containsPoint:loc]) {
SKAction *scaleUp = [SKAction scaleTo:1.2 duration:0.1];
[self runAction:scaleUp];
}
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self removeActionForKey:@"action"];
SKAction *scaleDown = [SKAction scaleTo:1.0 duration:0.1];
[self runAction:scaleDown];
}
I havent got the subclass method working to my liking, but I did get it working well from the main scene -- a mess of if statements
... but does the job
// add a ivar to scene enforce one zoom spite at a time, SKSpriteNode *_currentZoomRect;
- (void) addSomeBlocks
{
for (int i = 1; i <= 3; i++) {
SKSpriteNode *rect = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(70, 70)];
rect.position = CGPointMake(100 * i , 160);
rect.name = @"inner";
[self addChild:rect];
}
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
UITouch* touch = [touches anyObject];
CGPoint loc = [touch locationInNode:self];
NSArray *nodes = [self nodesAtPoint:loc];
for (SKNode *n in nodes) {
if ([n.name isEqualToString:@"inner"]) {
_currentZoomRect = (SKSpriteNode *) n;
SKAction *scaleUp = [SKAction scaleTo:2.0 duration:0.05];
[n runAction:scaleUp withKey:@"action"];
}
}
}
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
UITouch* touch = [touches anyObject];
CGPoint loc = [touch locationInNode:self];
NSArray *nodes = [self nodesAtPoint:loc];
for (SKNode *n in nodes) {
if ([n.name isEqualToString:@"inner"]) {
if (_currentZoomRect) {
// can only allow one zoom at a time
if (n == _currentZoomRect && !n.hasActions) {
SKAction *scaleUp = [SKAction scaleTo:2.0 duration:0.05];
[n runAction:scaleUp];
}
else if (n != _currentZoomRect) {
SKAction *scaleDown = [SKAction scaleTo:1.0 duration:0.05];
[_currentZoomRect runAction:scaleDown];
SKAction *scaleUp = [SKAction scaleTo:2.0 duration:0.05];
[n runAction:scaleUp];
_currentZoomRect = (SKSpriteNode *) n;
}
}
else {
SKAction *scaleUp = [SKAction scaleTo:2.0 duration:0.05];
[n runAction:scaleUp];
_currentZoomRect = (SKSpriteNode *) n;
}
}
}
if (![nodes count] && _currentZoomRect) {
SKAction *scaleDown = [SKAction scaleTo:1.0 duration:0.05];
[_currentZoomRect runAction:scaleDown];
_currentZoomRect = nil;
}
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (_currentZoomRect) {
SKAction *scaleDown = [SKAction scaleTo:1.0 duration:0.05];
[_currentZoomRect runAction:scaleDown];
_currentZoomRect = nil;
}
}
Upvotes: 1