5

我听触摸并将 SKAction 添加到精灵。如果现有操作尚未完成,我希望将操作添加到队列中,以便一个接一个地执行。有没有经验过的类似设计?

我确实使用了数组和块。如果有更简单的方法?

@interface GAPMyScene()
@property(strong,nonatomic)SKSpriteNode*ufo;
@property(strong,nonatomic)NSMutableArray*animationQueue;
@property(copy,nonatomic)void(^completeMove)();
@end

@implementation GAPMyScene

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        self.ufo = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];
        self.animationQueue = [[NSMutableArray alloc] init];
        __unsafe_unretained typeof(self) weakSelf = self;
        self.completeMove = ^(void){
            [weakSelf.ufo runAction:[SKAction sequence:[weakSelf.animationQueue copy]] completion:weakSelf.completeMove];
            NSLog(@"removeing %@", weakSelf.animationQueue);
            [weakSelf.animationQueue removeAllObjects];
        };
        [self addChild:self.ufo];
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];
        SKAction*moveAnimation = [SKAction moveTo:location duration:2];
        if (![self.ufo hasActions]) {
            [self.ufo runAction:moveAnimation completion:self.completeMove];

        } else {
            [self.animationQueue addObject:moveAnimation];
            NSLog(@"in queue %@", self.animationQueue);
        }
    }
}

@end
4

1 回答 1

3

一般情况下,你可以SKActions使用该方法让它们同时group运行,并使用该方法让它们顺序运行sequence

但是,如果您需要一个排队系统,而不是自己构建,请使用本机操作队列来为您执行此操作。因此,您可以创建一个串行操作队列并向其添加操作。问题是您不希望操作在完成之前完成SKAction

因此,您可以将您的子类包装SKAction在一个并发NSOperation子类中,该子类仅在执行时SKAction完成。然后你可以将你的操作添加到一个序列NSOperationQueue中,然后它不会开始下一个,直到它完成前一个。

因此,首先,创建一个ActionOperation(从 子类化NSOperation),如下所示:

// ActionOperation.h

#import <Foundation/Foundation.h>

@class SKNode;
@class SKAction;

@interface ActionOperation : NSOperation

- (instancetype)initWithNode:(SKNode *)node action:(SKAction *)action;

@end

// ActionOperation.m

#import "ActionOperation.h"
@import SpriteKit;

@interface ActionOperation ()

@property (nonatomic, readwrite, getter = isFinished)  BOOL finished;
@property (nonatomic, readwrite, getter = isExecuting) BOOL executing;

@property (nonatomic, strong) SKNode *node;
@property (nonatomic, strong) SKAction *action;

@end

@implementation ActionOperation

@synthesize finished  = _finished;
@synthesize executing = _executing;

- (instancetype)initWithNode:(SKNode *)node action:(SKAction *)action
{
    self = [super init];
    if (self) {
        _node = node;
        _action = action;
    }
    return self;
}

- (void)start
{
    if ([self isCancelled]) {
        self.finished = YES;
        return;
    }

    self.executing = YES;

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [self.node runAction:self.action completion:^{
            self.executing = NO;
            self.finished = YES;
        }];
    }];
}

#pragma mark - NSOperation methods

- (BOOL)isConcurrent
{
    return YES;
}

- (void)setExecuting:(BOOL)executing
{
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    [self didChangeValueForKey:@"isExecuting"];
}

- (void)setFinished:(BOOL)finished
{
    [self willChangeValueForKey:@"isFinished"];
    _finished = finished;
    [self didChangeValueForKey:@"isFinished"];
}

@end

例如,您可以在初始化过程中创建一个串行队列:

self.queue = [[NSOperationQueue alloc] init];
self.queue.maxConcurrentOperationCount = 1;

然后,您可以向其中添加操作:

SKAction *move1 = [SKAction moveTo:point1 duration:2.0];
[self.queue addOperation:[[ActionOperation alloc] initWithNode:nodeToMove action:move1]];

您可以稍后添加更多操作:

SKAction *move2 = [SKAction moveTo:point2 duration:2.0];
[self.queue addOperation:[[ActionOperation alloc] initWithNode:nodeToMove action:move2]];

而且因为队列是串行的,所以你知道在完成move2之前不会开始move1

于 2014-04-12T13:17:44.370 回答