2017-07-12 69 views
1

我试图在SpriteKit(Objective C for Mac OS)中创建一个如下所示的水平滑块。SpriteKit中的自定义滑块

enter image description here

我肯定做错了什么,因为滑块的“旋钮”永不移至左侧,只向右移动,我不知道是什么问题。我正在使用mouseDragged:方法来处理所有事情。这里的代码如下:

Slider.m

#import "Slider.h" 

@interface Slider() 

@property CGSize dimensions; 
@property SKSpriteNode *background, *foreground, *knob; 

@end 

@implementation Slider 

-(instancetype) initWithDimensions:(CGSize)dimensions Percentage:(double)percentage { 
    if (self = [super init]) { 
     _dimensions = dimensions; 
     _percentage = percentage; 
     [self initBackgroundSprite]; 
     [self initForegroundSprite]; 
     [self initKnob]; 
     self.userInteractionEnabled = YES; 
    } 
    return self; 
} 

-(void) initBackgroundSprite { 
    _background = [SKSpriteNode spriteNodeWithImageNamed:@"sliderBG"]; 
    _background.centerRect = CGRectMake(6.0/13.0, 5.0/11.0, 1.0/13.0, 1.0/11.0); 
    [_background setAnchorPoint:CGPointMake(0, 0.5)]; 
    double xScale = _dimensions.width/_background.frame.size.width; 
    double yScale = _dimensions.height/_background.frame.size.height; 
    [_background setXScale:xScale]; 
    [_background setYScale:yScale]; 
    [self addChild:_background]; 
} 

-(void) initForegroundSprite { 
    _foreground = [SKSpriteNode spriteNodeWithImageNamed:@"sliderFG"]; 
    _foreground.centerRect = CGRectMake(6.0/13.0, 5.0/11.0, 1.0/13.0, 1.0/11.0); 
    [_foreground setAnchorPoint:CGPointMake(0, 0.5)]; 
    double xScale = _dimensions.width*_percentage/_foreground.frame.size.width; 
    double yScale = _dimensions.height/_foreground.frame.size.height; 
    [_foreground setXScale:xScale]; 
    [_foreground setYScale:yScale]; 
    [self addChild:_foreground]; 
} 

-(void) initKnob { 
    _knob = [SKSpriteNode spriteNodeWithImageNamed:@"sliderKnob"]; 
    _knob.centerRect = CGRectMake(6.0/13.0, 5.0/11.0, 1.0/13.0, 1.0/11.0); 
    [_knob setAnchorPoint:CGPointMake(0, 0.5)]; 
    double scaleFactor = 2/(_knob.frame.size.height/_background.frame.size.height); 
    NSLog(@"%f, %f", _knob.frame.size.height, _background.frame.size.height); 
    [_knob setScale:scaleFactor]; 
    [_knob setZPosition:2]; 
    [_knob setName:@"knob"]; 
    [self addChild:_knob]; 
} 

-(void) mouseDragged:(NSEvent *)event { 
    CGPoint location = [event locationInNode:self]; 
    NSArray *nodes = [self nodesAtPoint:location]; 

    for (SKNode *node in nodes) { 
     if ([node isKindOfClass:[SKSpriteNode class]]) { 
      SKSpriteNode *sprite = (SKSpriteNode*)node; 

      if ([sprite.name isEqualToString:@"knob"]) { 
       [self updateKnobPositionWithLocation:location]; 
      } 

     } 
    } 
} 

-(void) updateKnobPositionWithLocation:(CGPoint)location { 
    double x = location.x; 
    double y = _knob.position.y; //don't want the y-pos to change 

    double bgX = _background.position.x; //x pos of slider 
    double width = _background.frame.size.width; //width of slider 
    if (x > bgX + width)//if knob goes beyond width of slider, restrict to width 
     x = bgX + width; 
    else if (x < bgX) 
     x = bgX; 

    [_knob setPosition:CGPointMake(x, y)]; 
} 

下面就来说明行为的视频:

https://drive.google.com/open?id=0B8Zfr1yQCdf-OG5kZFRWNFgxd1k

+1

你有什么x锚点?如果是0.5,则必须更改为else if(x

+1

添加到@SimonePistecchia的评论我会猜测_background.position.x是你的背景的中心,你应该使用'_background.frame.minX'和'_background.frame.maxX'而不是'position.x '和'position.x + width'。如果你把旋钮做成你的背景的一个孩子,那么你只需要担心'[宽度/ 2, 宽度/ 2]',因为旋钮是相对于其父母。 (我会建议像这样格式化)另外,我会预测你的下一个问题将会随着旋钮移动到那个栏,我会建议寻找SKCropNode来达到这个效果。 – Knight0fDragon

+0

谢谢你们的回复。我的所有节点的定位点(0,0.5),所以我认为我的计算很好@SimonePistecchia对不对? '_knob'不是'_background'的孩子。我会更新代码,以便看到整个班级。 – 02fentym

回答

0

我已经解决了所有的问题与滑块类。感谢大家的帮助。如果有人有兴趣,这里是全码:

Slider.h

#import <SpriteKit/SpriteKit.h> 

@interface Slider : SKSpriteNode 

@property double percentage; 

-(instancetype) initWithDimensions:(CGSize)dimensions Percentage:(double)percentage; 

@end 

Slider.m

#import "Slider.h" 

@interface Slider() 

@property CGSize dimensions; 
@property SKSpriteNode *background, *foreground, *knob; 
@property double backgroundWidth, foregroundWidth; 
@property bool isBeingUsed; 
@property SKLabelNode *percentageLabel; 

@end 

@implementation Slider 

//creates a slider with certain dimensions and at a specific starting percentage clamped [0, 1] 
-(instancetype) initWithDimensions:(CGSize)dimensions Percentage:(double)percentage { 
    if (self = [super init]) { 
     _dimensions = dimensions; 
     _percentage = percentage; 
     _isBeingUsed = NO; 
     [self initBackgroundSprite]; 
     [self initForegroundSprite]; 
     [self initKnob]; 
     [self initPercentageLabel]; 
     self.userInteractionEnabled = YES; 
    } 
    return self; 
} 

//sprite initialization 
-(void) initBackgroundSprite { 
    _background = [SKSpriteNode spriteNodeWithImageNamed:@"sliderBG"]; 
    _background.centerRect = CGRectMake(6.0/13.0, 5.0/11.0, 1.0/13.0, 1.0/11.0); 
    _backgroundWidth = _background.frame.size.width; 
    [_background setAnchorPoint:CGPointMake(0, 0.5)]; 
    double xScale = _dimensions.width/_backgroundWidth; 
    double yScale = _dimensions.height/_background.frame.size.height; 
    [_background setXScale:xScale]; 
    [_background setYScale:yScale]; 
    [self addChild:_background]; 
} 

-(void) initForegroundSprite { 
    _foreground = [SKSpriteNode spriteNodeWithImageNamed:@"sliderFG"]; 
    _foreground.centerRect = CGRectMake(6.0/13.0, 5.0/11.0, 1.0/13.0, 1.0/11.0); 
    [_foreground setAnchorPoint:CGPointMake(0, 0.5)]; 
    _foregroundWidth = _foreground.frame.size.width; 
    double xScale = _dimensions.width*_percentage/_foregroundWidth; 
    double yScale = _dimensions.height/_foreground.frame.size.height; 
    [_foreground setXScale:xScale]; 
    [_foreground setYScale:yScale]; 
    [self addChild:_foreground]; 
} 

-(void) initKnob { 
    _knob = [SKSpriteNode spriteNodeWithImageNamed:@"sliderKnob"]; 
    _knob.centerRect = CGRectMake(6.0/13.0, 5.0/11.0, 1.0/13.0, 1.0/11.0); 
    [_knob setAnchorPoint:CGPointMake(0.5, 0.5)]; 
    double scaleFactor = 2/(_knob.frame.size.height/_background.frame.size.height); 
    [_knob setScale:scaleFactor]; 
    [_knob setPosition:CGPointMake(_foreground.frame.size.width, -_knob.frame.size.height*0.05)]; 
    [_knob setZPosition:2]; 
    [_knob setName:@"knob"]; 
    [self addChild:_knob]; 
} 

-(void) initPercentageLabel { 
    _percentageLabel = [SKLabelNode labelNodeWithFontNamed:@"Hiragino Kaku Gothic Std"]; 
    [_percentageLabel setText:[NSString stringWithFormat:@"%.0f%%", _percentage*100]]; 
    [_percentageLabel setFontSize:15]; 
    double x = _dimensions.width * 1.05; 
    double y = _knob.frame.size.height*0.05; 
    [_percentageLabel setPosition:CGPointMake(x, y)]; 
    [_percentageLabel setHorizontalAlignmentMode:SKLabelHorizontalAlignmentModeLeft]; 
    [_percentageLabel setVerticalAlignmentMode:SKLabelVerticalAlignmentModeCenter]; 
    [self addChild:_percentageLabel]; 
} 

-(void) mouseDragged:(NSEvent *)event { 
    CGPoint location = [event locationInNode:self]; 
    _isBeingUsed = YES; 
    [self updateKnobPositionWithLocation:location]; 
} 

-(void) mouseDown:(NSEvent *)event { 
    [super mouseDown:event]; 
    CGPoint location = [event locationInNode:self]; 
    _isBeingUsed = YES; 
    [self updateKnobPositionWithLocation:location]; 
} 

-(void) mouseUp:(NSEvent *)event { 
    [super mouseUp:event]; 
    _isBeingUsed = NO; 
} 


-(void) updateKnobPositionWithLocation:(CGPoint)location { 
    if (_isBeingUsed) { 
     double x = location.x; 
     double y = _knob.position.y; //don't want the y-pos to change 

     double bgX = _background.position.x; //x pos of slider 
     double width = _background.frame.size.width; //width of slider 
     if (x > bgX + width)//if knob goes beyond width of slider, restrict to width 
      x = bgX + width; 
     else if (x < bgX) 
      x = bgX; 

     [_knob setPosition:CGPointMake(x, y)]; 
     [self updateForegroundPercentage]; 
     //NSLog(@"(%f, %f)", _knob.position.x, _knob.position.y); 
    } 
} 

-(void) updateForegroundPercentage { 
    _percentage = _knob.position.x/_background.frame.size.width; 
    double xScale = _dimensions.width*_percentage/_foregroundWidth; 
    [_foreground setXScale:xScale]; 

    [_percentageLabel setText:[NSString stringWithFormat:@"%.0f%%", _percentage*100]]; 
} 

@end