2014-04-04 9 views
4

나는 터치를 듣고 SKAction을 스프라이트에 추가합니다. 기존 작업이 아직 완료되지 않은 경우 작업을 하나씩 실행되도록 대기열에 추가해야합니다. 경험 많은 비슷한 디자인?SKAction을 Sprite 큐에 추가합니다.

나는 Array and Block을 사용했다. 더 쉬운 접근법이 있다면?

@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 보유 기간 경고를 보여줍니다. 그 코드가 맞습니까? –

+0

나는 그렇게 생각한다. 블록에서 사이클을 유지하지 못하도록 약한 참조를 만들어야합니다. –

+0

좋아요, [이 답변] (http://stackoverflow.com/a/17011096/867635)의 코드를 사용하면 경고가 사라졌습니다. 질문에 관해서 : 아직 애니메이션 대기열에 대한 더 쉬운 접근법을 찾지 못했습니다. –

답변

3

일반적으로, 당신은 동시에 group 방법을 사용하여 SKActions 실행을하고, 그들이 sequence 방법을 사용하여 순차적으로 실행할 수 있습니다.

그러나 자신 만의 큐를 만드는 대신 대기열 시스템이 필요한 경우이를 위해 네이티브 작업 대기열을 사용하십시오. 따라서 직렬 작업 대기열을 생성하고 작업을 추가 할 수 있습니다. 문제는 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; 

oper 그것에 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]]; 

그리고 큐가 직렬이기 때문에, 당신은 move1이 완료 될 때까지 move2이 시작되지 않습니다 것을 알고

.

+0

안녕하세요, 귀하의 답변 주셔서 감사합니다,하지만 SKAction 및 노드에 보낼 매개 변수는 런타임에 결정해야합니다. 예 : 난 오직 첫 번째 SKAction의 끝 후에 SKAction에서 어떤 노드를 실행할 지 알 것입니다. –

+0

@ElliotYap 괜찮습니다. 어떤 작업을 수행 할 노드를 어떻게 알았는지 알 수 없으므로 (이렇게하면 작업 객체에 필요한 변경 사항을 표시하기가 어렵습니다.)하지만 알 수있는 논리를 통합 할 수는 있습니다 이 ActionOperation (예 : 호출자가이를 결정하는 방법을 지정할 수 있도록 블록/위임 패턴 사용). 저의 요점은 큐 메커니즘이 이미 존재할 때 큐 메커니즘을 다시 작성하면 안된다는 것입니다. – Rob

+0

이해, NSOperation을 읽고 있습니다. 올바른 방향으로 안내해 주셔서 감사합니다. –