doublea doublea - 4 months ago 8
iOS Question

How should SKNode subclasses communicate with parent Scenes and sibling nodes?

How should a SKNode subclasses notify parent Scenes when events have taken place?

I have a SKNode subclass that handles touch events by redrawing or removing the Node as appropriate, based on the game logic. What are the iOS best practices for notifying parent scenes, (or other sibling SKNode instances) that the event has taken place? Should I be using NSNotification center? Some form of delegation? I want to avoid tight coupling. I can think of a couple ways to get it done but wondering if there are standard practices, as there seem to be for non-game MCV iOS designs (e.g. NSNotification for communication between models, or model -> controller, and delegation or target-action for view -> controller, etc.)

Conceptually, I like the idea of the SKNode subclass essentially serving the role of a 'View', and interpreting the touch event, then communicating 'semantic' game information to the containing scene or other nodes.

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


// SampleBallNode.m

#include "SampleBallNode.h"

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

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


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

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



For something like touches and input in general I would avoid handling those in each individual instance. Not just because it's inefficient, you also have no easy way to decide who receives a touch and how touches should propagate to other nodes.

Simple case: two overlapping nodes - do you only want the topmost to be removed, or just any one that's touched, or all at the location of the touch? In this case it's better to receive input at a central location and then iterate over "touchable" nodes.

Other than that:

  • use delegation when otherwise you would have tight coupling by sending a message directly to another object
  • use notification if you have multiple potential delegates who might want to react to the event, and that event isn't happening too often (ie definitely not every frame)
  • use singletons when you're like totally lazy and don't care

Conceptually you'll find good examples and solutions in Kobold Kit via behaviors, which are a form of game components. Also includes a per-node model storage class KKModel, which allows you to store things like score in any node without having to add a subclass just for variables.

For example:

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

You can then just use the update method in a label class to get the score:

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

Avoids the need for messaging, delegation, notification while compromising (a little) on efficiency.