1

イベントが発生したときに、SKNode サブクラスは親シーンにどのように通知する必要がありますか?

ゲーム ロジックに基づいて、必要に応じてノードを再描画または削除することで、タッチ イベントを処理する SKNode サブクラスがあります。イベントが発生したことを親シーン (または他の兄弟 SKNode インスタンス) に通知するための iOS のベスト プラクティスは何ですか? 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
4

3 に答える 3

7

一般的なタッチや入力のようなものについては、個々のインスタンスでそれらを処理することは避けます。効率が悪いだけでなく、誰がタッチを受信し、どのようにタッチが他のノードに伝播するかを簡単に判断する方法がありません。

単純なケース: 2 つの重なり合ったノード - 一番上のノードのみを削除するか、タッチされた任意のノードだけを削除するか、またはすべてのノードをタッチした位置で削除しますか? この場合、中央の場所で入力を受け取り、「タッチ可能な」ノードを反復処理する方が適切です。

それ以外:

  • メッセージを別のオブジェクトに直接送信することで密結合が発生する場合は、委任を使用します
  • イベントに反応したいデリゲート候補が複数いて、そのイベントがあまり頻繁に発生しない (つまり、すべてのフレームではない) 場合は、通知を使用します。
  • 完全に怠惰で気にしない場合は、シングルトンを使用してください

概念的には、 Kobold Kitには、ゲーム コンポーネントの一種であるビヘイビアを介して、良い例と解決策があります。ノードごとのモデル ストレージ クラス KKModel も含まれています。これにより、変数のためだけにサブクラスを追加することなく、任意のノードにスコアなどを格納できます。

例えば:

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

その後、ラベル クラスで update メソッドを使用してスコアを取得できます。

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

効率性を (少し) 犠牲にしながら、メッセージング、委任、通知の必要性を回避します。

于 2013-10-18T17:29:17.283 に答える
1

ドキュメントには何も記載されていませんが、私は個人的に NSNotification センターを使用しています。これは、非常に疎結合であり、ゲーム ロジックとビューを分離しているためです。私は最初に cocos2d でプロジェクトを開始し、それを spritekit に移動したため、これは非常にうまく機能しました (理由はここでは省略します)。しかし、私がそれを使用していたので、移行は非常に簡単でした.

ゲームモデルから投稿された特定の通知をノードに「監視」させ、それに応じて応答または更新させました。インタラクションを使用する場合は、ポストバックし、モデルは対応する通知を監視します。

于 2013-10-18T17:30:04.383 に答える
0

これは、SKSpriteNode サブクラスを使用した例です。そのデリゲート BallDelegate には 4 つのオプション メソッドがあります。必須のメソッドが必要な場合は、オプションなしでメソッドを追加できます

@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)
   }
}

さらに詳しい情報が必要な場合は、Swift のドキュメントを参照してください。

Swift プログラミング言語 (Swift 2.2)

于 2016-06-21T19:57:51.177 に答える