2014-04-04 90 views
4

我聽觸摸並將SKAction添加到一個精靈。如果現有的動作尚未完成,我希望將動作添加到隊列中,以便它將一個接一個地執行。 任何經驗類似的設計?將SKAction添加到Sprite隊列運行一個接一個

我沒有使用數組和塊。如果有更簡單的方法?

@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 
+0

只是我們的好奇心:Xcode向我展示了'__unsafe_unretained typeof(self)weakSelf = self;'的ARC Retain Cycle警告。代碼是否正確? –

+0

我這麼認爲。爲了防止保留週期,我必須使其成爲弱參考。 –

+0

好的,在使用[本答案](http://stackoverflow.com/a/17011096/867635)代碼後警告消失了。關於你的問題:我還沒有找到一個更簡單的動畫隊列方法。 –

回答

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; 

然後,您可以添加操作ations它:

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完成。

+0

之外嗨,謝謝你的回答,但是發送給SKAction和Node的參數需要在運行時決定。例如。我只知道在第一次SKAction結束後SKAction上運行哪個節點 –

+0

@ElliotYap沒關係。你沒有向我們展示它是如何知道你想要執行哪個節點的(因此我很難向操作對象展示必要的更改以實現此目的),但是您可以將任何您所指定的邏輯在這個ActionOperation中(例如,或者使用塊/委託模式,所以調用者可以指定如何確定這個)。我的觀點是,只要你已經存在,你不應該重新創建隊列機制。 – Rob

+0

明白,我現在正在閱讀NSOperation,感謝您讓我朝着正確的方向:) –

相關問題