【问题标题】:Detect touch within a radius of a node in SpriteKit在 SpriteKit 中检测节点半径内的触摸
【发布时间】:2014-08-17 20:31:52
【问题描述】:

我的 SpriteKit 游戏中有一个玩家对象,目前我正在使用以下代码移动它:

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

但我只想在触摸在位置的特定范围内时移动播放器节点。

【问题讨论】:

    标签: objective-c xcode sprite-kit


    【解决方案1】:

    由于您似乎只关心触摸与您的_player 对象的距离,我会将半径检测逻辑移至您的_player 对象并使用SKRegion 来处理它。

    注意: 如果您需要知道您的触摸是否在多个节点的半径内,那么您可能需要使用this question 中的方法。 p>

    要使用SKRegion 来确定您的触摸是否在_player 的某个半径内,请将SKRegion 实例添加到您的_player 对象并使用您想要的半径对其进行初始化。在[_player init] 或任何对您的项目最有意义的地方:

    self.touchRegion = [[SKRegion alloc] initWithRadius:radius];

    然后添加一个方法来确定一个点是否在该区域内:

    - (BOOL)pointIsInTouchRegion:(CGPoint)point {
        return [self.touchRegion containsPoint: point];
    }
    

    接下来将您的 touchesMoved 方法更改为:

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

    注意: [self locationInNode:_player]; 中使用_player 至关重要,因为您的SKRegion 将在_player 节点的坐标系中定义。

    还有一点需要注意:您实际上不必将所有这些逻辑都放在_player 中,这正是我的做法。您可以轻松地将 SKRegion 存储在场景的类中,然后直接调用 [region containsPoint: point]


    更新:iOS 7 方法

    对 iOS 7 执行此操作的主要区别在于,您需要存储您感兴趣的实际半径而不是 SKRegion(因为它仅在 iOS 8 中可用),然后在 @ 中自己进行计算987654342@。

    因此,在_player 中,将您的触摸半径设置为您之前设置touchRegion 的位置:

    self.touchRadius = radius

    然后更改pointIsInTouchRegion: 方法,让它进行实际距离计算。

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

    touchesMoved 中的代码不需要任何更改。

    【讨论】:

    • 它在 Apple 文档上说它仅在 iOS 8 及更高版本中可用,此代码在 iOS 7 中不起作用吗?
    • 是的,抱歉,我没有意识到这是一个仅限 iOS 8 的课程。我可以使用适用于 iOS 7 的方法更新答案。
    【解决方案2】:

    以下演示如何 1) 选择距触摸事件指定距离内的精灵,以及 2) 将选定的精灵拖放到新位置。

    @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
    

    【讨论】:

      【解决方案3】:

      我认为你应该添加这个,如果我误解了你的问题,请原谅我:

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

      【讨论】:

      • 你知道给它添加一个半径吗,例如如果我在玩家附近触摸它仍然会移动
      • 我会做的只是说如果 x 大于某个点并且小于某个点,那么我也会对 y 做同样的事情。 (使用对象的完整左侧作为 x 的大于值,使用完整的右侧作为小于值。顶部和底部也用于 y 值。
      猜你喜欢
      • 1970-01-01
      • 2014-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多