SpriteKit:在场景之间传递数据

时间:2013-09-19 02:48:09

标签: iphone ios ios7 sprite-kit

我试图在SpriteKit中的场景“SKScene”之间传递数据。例如,我想将分数从A级传递到B级。

也许解决方案是归档,但我希望实现更简单的方式,就像我们使用视图控制器一样。

非常感谢这方面的任何线索。

6 个答案:

答案 0 :(得分:15)

如果您要将分数传递到许多不同的场景,您可能希望将其存储在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];

 }

答案 1 :(得分:6)

将分数存储在视图控制器实例中,或者将SKView子类化并存储在那里。这将保留视图生命周期内的任何对象。

如果您需要在应用重新启动之间保留分数,请使用NSUserDefaults

Kobold Kit实际上使这样的东西很容易,没有自定义子类。视图具有(并且任何节点都可以)一个KKModel对象,它是两个整数类型(float,int等通过KKMutableNumber)和任意对象的键/值存储。

因此,您可以通过将其绑定到视图来持久存取并访问来自任何节点的

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

kkView属性是写(KKView*)self.view的简写。

对于其生命周期与场景或视图相关联的对象,绝对不需要使用或受益于使用单例。它们属于场景或视图,期间。

答案 2 :(得分:4)

这种方法对我有用,我认为这是正确的。到目前为止,这是在我发现的场景之间传递数据的最简单,最快捷的方式。

<强> 1。有关userData的基本信息:

1.1。按住苹果“Command键”并在“userData”字符串上按下鼠标左键(在Xcode中)(例如“self。 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];

这里我通过添加一个作为我得分的对象来引用secondScene的userData。出于测试目的,它只是6.我将添加我的分数实例变量。您可以添加任何您想要的内容,因为它接受“id”类型的对象。关键很重要。您将在secondScene.m中使用它来访问对象值。检查你输错了。

[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 ...”创建了它:SKScene。它将包含稍后显示的userData。

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

答案 3 :(得分:0)

你在哪里/如何在场景之间转换?如果你能显示你创建新场景的代码,那将有所帮助。我可能会忽略问题的重点,但如果您有某种“场景管理器”/导航器,那么只需将分数暂时保存在本地变量中并将其传递到新场景中。

答案 4 :(得分:0)

Apple文档声明userData是在Sprite Kit Best Practices

中存储节点特定数据的方法
  

使用节点上的userData属性来存储特定于游戏的数据,尤其是在您没有实现自己的子类时。

因此,我会接受@ doctorBroctor的答案作为本地使用Sprite Kit的正确答案。

但是,您应该记住在设置值之前初始化目标节点的userData,因为@ LearnCocos2d在this回答中指出。您可以在要转换到的SKScene子类的initWithSize:方法中执行此操作。

答案 5 :(得分:0)

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

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