2013-10-18 45 views
1

當事件發生時,SKNode子類應該如何通知父級場景?SKNode子類應該如何與父級場景和兄弟節點通信?

我有一個SKNode子類,通過根據遊戲邏輯適當地重繪或移除節點來處理觸摸事件。通知父級場景的iOS最佳實踐(或其他同級SKNode實例)有哪些事件發生?我應該使用NSNotification中心嗎?某種形式的授權?我想避免緊密耦合。我可以考慮一些方法來完成它,但想知道是否有標準做法,因爲似乎適用於非遊戲MCV iOS設計(例如用於模型間通信的NSNotification,或模型 - >控制器,以及委派或目標 - 動作視圖 - >控制器等)

從概念上講,我喜歡SKNode子類的想法,它基本上服務於'視圖'角色,並解釋觸摸事件,然後將'語義'遊戲信息傳遞給包含場景或其他節點。

// SampleScene.m 

#include "SampleScene.h" 
#include "SampleBallNode.h" 

@implementation SampleScene 
- (void)didMoveToView:(SKView *)view { 
    if (!self.contentCreated) { 
    [self createSceneContents]; 
    self.contentCreated = YES; 
    } 
} 

- (void)createSceneContents { 
    self.backgroundColor = [SKColor whiteColor]; 
    self.scaleMode = SKSceneScaleModeAspectFit; 
    [self addBall]; 
} 

- (void)addBall { 
    SampleBallNode *ball = [[SampleBallNode alloc] init]; 
    ball.position = CGPointMake(100, 100); 
    [self addChild:ball]; 
} 

@end 

// SampleBallNode.m 

#include "SampleBallNode.h" 

- (id)init { 
    if ([super init]) { 
    self.name = @"ball"; 
    self.userInteractionEnabled = YES; 
    [self drawSelf]; 
    } 
    return self; 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    [self removeFromParent]; 

    // TELL SCENE THAT I'VE DIED HERE... TO UPDATE SCORE OR SOMETHING... 
} 

- (void)drawSelf { 
    UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect ... 

    SKShapeNode *tokenBall = [[SKShapeNode alloc] init]; 
    tokenBall.path = ovalPath.CGPath; 
    [self addChild:tokenBall]; 
} 

@end 

回答

6

對於類似觸摸和輸入的一般情況,我會避免處理每個單獨實例中的那些。不僅因爲它效率低下,您也沒有簡單的方法來決定誰接觸觸摸以及觸摸應該如何傳播到其他節點。

簡單情況:兩個重疊的節點 - 您只希望最上面的部分被刪除,還是隻有任何被觸摸的部分,或者全部位於觸摸位置?在這種情況下,最好在中心位置接收輸入,然後遍歷「可觸摸」的節點。

其他:

  • 使用委託時,否則你就必須緊密結合,直接將消息發送到另一個對象
  • 使用的通知,如果您有誰可能要對事件作出反應的多個潛在的代表和該事件沒有發生太頻繁(即絕對不是每一幀)
  • 使用時的單身你像完全懶惰,不關心

從概念上講,您會通過行爲找到Kobold Kit中的很好的示例和解決方案,這些行爲是game components的一種形式。還包括每節點模型存儲類KKModel,它允許您在任何節點中存儲分數等內容,而不必爲變量添加子類。

例如:

[self.scene.model setDouble:score forKey:@"score"]; 

然後,您可以只使用一個標籤類的更新方法來獲得分數:

double score = [self.scene.model doubleForKey:@"score"]; 

避免了消息,代表團通知的需要,同時影響(一點)效率。

+0

感謝:如果你想要一些必要的方法,你可以,如果你願意,你可以看到斯威夫特的文檔的詳細信息沒有可選

@objc protocol BallDelegate { @objc optional func ball(ball:Ball, touchesBegan touches: Set<UITouch>, withEvent event: UIEvent?) @objc optional func ball(ball:Ball, touchesMoved touches: Set<UITouch>, withEvent event: UIEvent?) @objc optional func ball(ball:Ball, touchesEnded touches: Set<UITouch>, withEvent event: UIEvent?) @objc optional func ball(ball:Ball, touchesCancelled touches: Set<UITouch>?, withEvent event: UIEvent?) } class Ball: SKSpriteNode { var delegate:BallDelegate? override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?){ self.delegate?.ball?(self, touchesBegan: touches, withEvent: event) } override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { self.delegate?.ball?(self, touchesMoved: touches, withEvent: event) } override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { self.delegate?.ball?(self, touchesEnded: touches, withEvent: event) } override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) { self.delegate?.ball?(self, touchesCancelled: touches, withEvent: event) } } 

添加方法。有趣和非常有幫助。後續問題:在遍歷列表時檢測/觸摸哪個可觸摸節點的最簡單方法是什麼?這真的很有可能是計算效率更高?非常感謝 – doublea

+0

CGRectContainsPoint將可觸點節點轉換爲世界空間。它更有效率,因爲您可以按照可能按下的順序來處理節點(如果有偏好),並且一旦找到節點就可以提前退出,否則所有節點都必須執行檢查。 – LearnCocos2D

+0

Gotcha。謝謝。 – doublea

1

我不知道文檔中的任何內容,但是我個人使用NSNotification中心,因爲它有一個非常鬆散的耦合,我將遊戲邏輯和視圖分開。這對我來說非常好,因爲我最初是在cocos2d中開始我的項目並將其移動到spritekit。(我將離開原因離開這裏)。但是由於我使用了它,所以過渡非常簡單。

我有我的節點「監視」來自遊戲模型的某些發佈的通知,並讓他們響應或更新相應。對於使用交互,我會回發,模型會監視相應的通知。

相關問題