SpriteKit: передача данных между сценами

Я застрял, пытаясь передать данные между сценами "SKScene" в SpriteKit. Например, я хотел бы передать счет с уровня A на уровень B.

возможно, решение архивирование, но я хотел бы реализовать что-то более простое, как то, как мы используем с контроллерами view.

любая подсказка в этом отношении будет очень признательна.

6 ответов


если вы собираетесь передавать счет на много разных сцен, вы можете сохранить его в NSUserDefaults или какой-то доступный механизм хранения. Однако, если вы хотите передать данные между объектами SpriteKit, каждый SKNode (включая SKScene) имеет свойство словаря под названием userData что вы можете использовать для чего угодно вы так желаете. Вот пример того, как вы можете передать счет между сценами:

 - (void)changeScene
 {
      SKView *spriteView = (SKView *) self.view;
      SKScene *currentScene = [spriteView scene];
      SKScene *newScene = [MySceneClass scene];
      [newScene.userData setObject:[currentScene.userData objectForKey:@"score"] forKey:@"score"];
      [spriteView presentScene:newScene];

 }

сохраните счет в экземпляре контроллера вида или подклассе SKView и сохраните его там. Это сохранит любой объект на время существования представления.

Если вам нужно, чтобы баллы сохранялись между перезапусками приложений, используйте NSUserDefaults.

Комплект Кобольд на самом деле делает вещи, как это легко, без пользовательских подклассов. Представление (и любой узел может иметь)KKModel объект, который является хранилищем ключей / значений для обоих интегральных типов (float, int и т. д KKMutableNumber) и произвольные объекты.

так можно сохранить и открыть свои рекорды объекта из любого узла привязав его к виду:

[self.kkView.model setObject:highscores forKey:@"highscores"];

свойство kkView является сокращением для записи (KKView*)self.view.

здесь абсолютно не нужно использовать или использовать преимущества в использовании singletons для объектов, время жизни которых привязано либо к сцене, либо к виду. Они принадлежат либо сцене, либо виду, периоду.


этот подход работал для меня, и я думаю, что это правильно. Пока это самый простой и быстрый способ передачи данных между сценами, которые я нашел.

1. Основная информация о userData:

1.1. Удерживайте apple "Command key" и нажмите левую кнопку мыши (в Xcode) в строке "userData" (например. "личность.userData ;"). Вы получите следующую информацию:

// An optional dictionary that can be used to hold user data pretaining to the node. Defaults to nil. 
@property (SK_NONATOMIC_IOSONLY, retain) NSMutableDictionary *userData;

1.2. Посетите apple docs: userData

1.3 userdata-это NSMutableDictionary, по сути, это специальный массив. Рядом со значением он содержит ключ, который привязан к значению. С помощью этого ключа можно найти значения. Это может быть полезно также:Apple docs: NSMuttableDictionary

2. Решение:

2.1. firstScene

//somewhere in firstScene.m
//how the tranisiton from firstScene to secondScene is going to look and how long it is goint to take   
SKTransition *reveal = [SKTransition moveInWithDirection:SKTransitionDirectionDown duration:0.5];
 SKView * skView = (SKView *)self.view;
SKScene *secondScene = [WBMGameEndsScene sceneWithSize:skView.bounds.size];
//You need to initialize the NSMD since it is by default nil.
secondScene.userData = [NSMutableDictionary dictionary];

здесь я ссылаюсь на userData secondScene, добавив объект, который является моим счетом . Для тестовой цели это всего 6. Я добавлю переменную экземпляра score. Вы можете добавить то, что вы хотите, так как он принимает объекты типа "id". Ключ очень важен. Вы будете использовать его в secondScene.m для доступа к значению объекта since. Убедитесь, что вы не напечатали его неправильно.

[secondScene .userData setObject:@"6" forKey:@"score"];
//Testing
NSLog(@"Is it finally working -- %@",[secondScene .userData objectForKey:@"score"]);
//The secondScene will scale to fit the whole SKView
secondScene.scaleMode = SKSceneScaleModeAspectFill;
 //present the secondScene
[self.scene.view presentScene: secondScene transition:reveal];

*WBMGameEndsScene является моим вторым. Я создал его в Xcode с "File-New File ... as: SKScene . Он будет содержать пользовательские данные ниже.

2.2. secondScene

//secondScene.m ( ex. in my :"@implementation WBMGameEndsScene")

эти следующие строки кода проверяют, правильно ли добавлено значение:

-(void)didMoveToView:(SKView *)view
{
    NSLog(@"-- -(void)willMoveFromView:(SKView *)view --");
    NSLog(@"Working score is : %@",[self.userData valueForKey:@"score"]);
    NSLog(@"Working score is : %@",[self.userData objectForKey:@"score"]);
}

выход консоли:

2014-03-12 15:29:06.804 AppTest[4841:60b] -(id)initWithSize:(CGSize)size
2014-03-12 15:29:06.806 AppTest[4841:60b] scoreLabel
2014-03-12 15:29:06.812 AppTest[4841:60b] successMessage
2014-03-12 15:29:06.815 AppTest[4841:60b] Is it finally working -- 6
2014-03-12 15:29:06.815 AppTest[4841:60b] -- -(void)willMoveFromView:(SKView *)view --
2014-03-12 15:29:06.816 AppTest[4841:60b] Working score is : 6
2014-03-12 15:29:06.816 AppTest[4841:60b] Working score is : 6

если я что-то не так, пожалуйста, исправьте меня :). Технические характеристики: iOS 7.0, Xcode версии 5.1 (5B130a), OS X 10.9.2


где / как вы переходите между сценами? Если бы вы могли показать только код, в котором вы создаете свою новую сцену, это помогло бы. Возможно, я упускаю суть вопроса, но если у вас есть "менеджер сцены" /навигатор, чтобы сделать это, просто сохраните счет в локальном var временно и передайте это в свою новую сцену.


в документации Apple указано, что userData-это способ хранения данных узла здесь в Лучшие Практики Sprite Kit

использовать userData свойство на узлах для хранения игровых данных, особенно если вы не реализуете свои собственные подклассы.

поэтому я бы принял ответ @doctorBroctor как правильный для использования Sprite Kit изначально.

, ты должен помнить инициализируйте userData для целевого узла перед установкой значения, как @LearnCocos2d указывает в этой ответ. Вы можете сделать это внутри метода initWithSize: подкласса SKScene, в который вы собираетесь перейти.

    // First Scene
    NSUserDefaults.standardUserDefaults().setInteger(12345, forKey:"SCORE")

    // Second Scene
    if let myScore: AnyObject = NSUserDefaults.standardUserDefaults().objectForKey("SCORE") {
        println(myScore)
        finalScore = myScore as IntegerLiteralType
    }