将SKAction添加到Sprite队列一个接一个地运行 [英] add SKAction to Sprite queue run one after another

查看:18
本文介绍了将SKAction添加到Sprite队列一个接一个地运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I listen to touch and add SKAction to a sprite. If existing actions are not complete yet, I want the action to be added to a queue so it will execute one after another. Any experienced similar design?

我确实使用了数组和块.有没有更简单的方法?

I did using Array and Block. If there is any easier approach?

@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

推荐答案

一般情况下,您可以使用 group 方法让 SKActions 并发运行,并使用sequence 方法.

Generally, you can make SKActions run concurrently using the group method, and have them run sequentially using the sequence method.

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

But if you need a queuing system, rather than building your own, use the native operation queue to do this for you. So you can create a serial operation queue and add operations to it. The issue is that you don't want an operation to complete until the SKAction does.

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

So, you can wrap your SKAction in a concurrent NSOperation subclass that only completes when the SKAction does. Then you can add your operations to a serial NSOperationQueue, and then it will won't start the next one until it finishes the prior one.

所以,首先,创建一个 ActionOperation(继承自 NSOperation),如下所示:

So, first, create an ActionOperation (subclassed from NSOperation) that looks like:

// 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

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

You could then, for example, create a serial queue during the initialization process:

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

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

You can then add the operations to it:

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

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

and you can later add more actions:

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

而且因为队列是串行的,所以你知道 move2 直到 move1 完成后才会启动.

And because the queue is serial, you know that move2 will not be started until move1 is done.

这篇关于将SKAction添加到Sprite队列一个接一个地运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆