简体   繁体   English

SpriteKit:在场景之间传递数据

[英]SpriteKit: Passing data between scenes

I am stuck trying to pass data between scenes "SKScene" in SpriteKit. 我试图在SpriteKit中的场景“SKScene”之间传递数据。 For instance I would like to pass the score from level A to Level B. 例如,我想将分数从A级传递到B级。

Maybe the solution is archiving but I would like to implement something more simpler like the way we use with view controllers. 也许解决方案是归档,但我想实现更简单的东西,就像我们使用视图控制器一样。

Any clue in this regard will be very much appreciated. 在这方面的任何线索将非常感谢。

If you're going to be passing around the score to a lot of different scenes, you might want to store it in NSUserDefaults or some accessible storage mechanism. 如果您要将分数传递到许多不同的场景,您可能希望将其存储在NSUserDefaults或某些可访问的存储机制中。 However, if you're looking to pass data between SpriteKit objects, every SKNode (including SKScene ) has a dictionary property called userData that you can use for whatever you so desire. 但是,如果您希望在SpriteKit对象之间传递数据,则每个SKNode (包括SKScene )都有一个名为userData的字典属性,您可以将其用于您想要的任何内容。 Here's an example of how you might pass the score between scenes: 以下是如何在场景之间传递分数的示例:

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

 }

Store the score in your view controller instance, or subclass the SKView and store it there. 将分数存储在视图控制器实例中,或者将SKView子类化并将其存储在那里。 This will retain any object for the lifetime of the view. 这将保留视图生命周期内的任何对象。

If you need the scores to be persisted between app restarts, use NSUserDefaults . 如果您需要在应用重新启动之间NSUserDefaults分数,请使用NSUserDefaults

Kobold Kit actually makes stuff like this easy with no custom subclasses. Kobold Kit实际上使这样的东西变得容易,没有自定义子类。 The view has (and any node can have) a KKModel object which is a key/value storage for both integral types (float, int, etc via KKMutableNumber ) and arbitrary objects. 视图具有(并且任何节点可以具有) KKModel对象,该对象是两个整数类型(通过KKMutableNumber float,int等)和任意对象的键/值存储。

So you can persist and access your highscores object from any node by tying it to the view: 因此,您可以通过将其绑定到视图来持久化并从任何节点访问您的highscores对象:

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

The kkView property is shorthand for writing (KKView*)self.view . kkView属性是写入的简写(KKView*)self.view

There's absolutely no need to use or benefit in using singletons for objects whose lifetime is tied either to the scene or the view. 对于寿命与场景或视图相关联的对象, 绝对不需要使用或受益于使用单例 They belong to either the scene or the view, period. 它们属于场景或视图,时期。

This approach worked for me and I think it is correct. 这种方法对我有用,我认为这是正确的。 So far this is the easiest and fastest way to pass data between scenes which I found. 到目前为止,这是在我发现的场景之间传递数据的最简单,最快捷的方法。

1. Basic informations about userData: 1.关于userData的基本信息:

1.1. 1.1。 Hold the apple "Command key" and press the left mouse button (in Xcode) on the "userData" string (for example. "self. userData ;"). 按住苹果“Command key”并在“userData”字符串上按下鼠标左键(在Xcode中)(例如“ self.userData ;”)。 You will get the following info: 您将获得以下信息:

// 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. 1.2。 Visit the apple docs:userData 访问apple docs:userData

1.3 userData is an NSMutableDictionary which is basically an special array. 1.3 userData是一个NSMutableDictionary,它基本上是一个特殊的数组。 Beside the value it contains a key which is bind to the value. 除了值之外,它还包含一个绑定到值的键。 With this key you can find values. 使用此键,您可以找到值。 This might be helpful aswell: apple docs:NSMuttableDictionary 这可能会有所帮助: apple docs:NSMuttableDictionary

2. The solution: 2.解决方案:

2.1. 2.1。 firstScene 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];

Here I am refering to the userData of the secondScene by adding a object which is my score . 这里我通过添加一个对象来引用secondScene的userData。 For test purpose it is just 6. I will add my score instance variable. 出于测试目的,它只是6.我将添加我的分数实例变量。 You can add what ever you want since it accepts objects of type "id". 您可以添加任何您想要的内容,因为它接受“id”类型的对象。 The key is important. 关键很重要。 You will use it in the secondScene.m to access the object value since. 您将在secondScene.m中使用它来访问对象值。 Check that you dont type it wrong. 检查你输错了。

[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 is my secondScene. * WBMGameEndsScene是我的第二名。 I created it in Xcode with "File - New File ..." as :SKScene . 我在Xcode中用“File - New File ...”创建了它:SKScene。 It will contain the userData shown later on. 它将包含稍后显示的userData。

2.2. 2.2。 secondScene secondScene

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

These next lines of code check if the value has been correctly added: 下一行代码检查是否正确添加了值:

-(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"]);
}

Console output is: 控制台输出是:

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

If I got something wrong please correct me :). 如果我出错了,请纠正我:)。 Specs: iOS 7.0 ,Xcode Version 5.1 (5B130a), OS X 10.9.2 规格:iOS 7.0,Xcode版本5.1(5B130a),OS X 10.9.2

Where/how are you transitioning between the scenes? 你在哪里/如何在场景之间转换? If could you show just the code where you create your new scene that would help. 如果你能显示你创建新场景的代码,那将有所帮助。 I may be missing the point of the question but if you have a 'scene manager'/navigator of some sort to do this then simply save the score in a local var temporarily and pass that into your new scene. 我可能会忽略问题的重点,但如果您有某种“场景管理器”/导航器来执行此操作,则只需将分数暂时保存在本地变量中并将其传递到新场景中。

Apple documentation states that userData is the way to go for storing node specific data here in Sprite Kit Best Practices Apple文档声明userData是在Sprite Kit最佳实践中存储节点特定数据的方法

Use the userData property on nodes to store game-specific data, especially if you are not implementing your own subclasses. 在节点上使用userData属性来存储特定于游戏的数据,尤其是在您没有实现自己的子类时。

Therefore I would accept @doctorBroctor's answer as the correct one for when using Sprite Kit natively. 因此,我会接受@ doctorBroctor的答案作为本机使用Sprite Kit的正确答案。

However, you should remember to initialize userData for the target node before setting a value as @LearnCocos2d points out in this answer. 但是,您应该记住在设置值之前初始化目标节点的userData,如@ LearnCocos2d在答案中指出的那样。 You can do this inside initWithSize: method of the SKScene subclass you are about to transition into. 您可以在要转换到的SKScene子类的initWithSize:method中执行此操作。

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM