【问题标题】:Custom Slider In SpriteKitSpriteKit 中的自定义滑块
【发布时间】:2017-07-12 07:46:01
【问题描述】:

我正在尝试在 SpriteKit 中创建一个水平滑块,如下所示(在 Objective C for Mac OS 中)。

我肯定做错了什么,因为滑块的“旋钮”永远不会向左移动,它只会向右移动,我不确定问题出在哪里。我正在使用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

【问题讨论】:

  • 你的 x 锚点是什么? if 为 0.5 你必须更改为 else if (x
  • 添加到@SimonePistecchia 的评论我会猜测_background.position.x 是你背景的中心,你应该使用_background.frame.minX_background.frame.maxX 而不是position.x 和@ 987654329@。如果您将旋钮设置为背景的子级,那么您只需要担心[-width/2 , width/2],因为旋钮将与其父级相关。 (我会推荐这样的格式)另外,我预测你的下一个问题将是用旋钮移动那个栏,我建议查看 SKCropNode 来实现这个效果。
  • 感谢大家的回复。我的所有节点的锚点都是 (0, 0.5) 所以我认为我的计算很好@SimonePistecchia 对吗? _knob 不是 _background 的子代。我将更新代码,以便您看到整个班级。
  • 如果没有其他条件,_knob 可以向后滑动吗?
  • 尝试使用SKConstrain

标签: objective-c macos sprite-kit slider


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 2023-04-05
    • 2021-11-04
    • 2019-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-28
    • 2016-12-10
    相关资源
    最近更新 更多