SpriteKit:在场景之间传递数据

Posted

技术标签:

【中文标题】SpriteKit:在场景之间传递数据【英文标题】:SpriteKit: Passing data between scenes 【发布时间】:2013-09-19 02:48:09 【问题描述】:

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

也许解决方案是归档,但我想实现一些更简单的东西,比如我们使用视图控制器的方式。

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

【问题讨论】:

我会为此使用单例 【参考方案1】:

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

 

【讨论】:

【参考方案2】:

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

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

Kobold Kit 实际上使这样的事情变得简单,无需自定义子类。该视图具有(并且任何节点都可以具有)KKModel 对象,它是整数类型(通过KKMutableNumber 实现的浮点数、整数等)和任意对象的键/值存储。

因此,您可以从任何节点通过将其绑定到视图来持久化和访问您的高分对象:

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

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

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

【讨论】:

+1 用于解释为什么单身人士不是正确的方式 - actually, they usually are not 同意不必要的单例。【参考方案3】:

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

1. userData的基本信息:

1.1。按住苹果“Command key”并在“userData”字符串(例如“self.userData;”)上按下鼠标左键(在 Xcode 中)。 您将获得以下信息:

// 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。第一个场景

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

这里我通过添加一个我的 score 对象来引用 secondScene 的 userData 。出于测试目的,它只有 6 个。我将添加我的 score 实例变量。您可以添加任何您想要的内容,因为它接受“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.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

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

Apple 文档指出 userData 是在Sprite Kit Best Practices 中存储节点特定数据的方法

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

因此,在原生使用 Sprite Kit 时,我会接受 @doctorBroctor 的答案作为正确答案。

但是,您应该记住在设置值之前为目标节点初始化 userData,正如@LearnCocos2d 在this 答案中指出的那样。您可以在您即将过渡到的 SKScene 子类的 initWithSize: 方法中执行此操作。

【讨论】:

【参考方案6】:
    // First Scene
    NSUserDefaults.standardUserDefaults().setInteger(12345, forKey:"SCORE")

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

【讨论】:

以上是关于SpriteKit:在场景之间传递数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中的两个场景之间传递数据?

Unity C#在场景之间传递数据[重复]

几种在场景之间传递数据的方式

几种在场景之间传递数据的方式

Jmeter接口测试实战-数据传递

Spritekit 场景内容被放大