从 UIVIewController 向 SKScene 传递数据

Posted

技术标签:

【中文标题】从 UIVIewController 向 SKScene 传递数据【英文标题】:Passing Data to SKScene from UIVIewController 【发布时间】:2016-07-19 04:12:35 【问题描述】:

我想要完成的是(至少应该是..)非常简单:我想展示一个SKScene,其中包含我在展示这个场景的UIViewController 中拥有的数据。换句话说,我有一个变量chapter,声明如下:

#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>

@interface ViewController : UIViewController

@property (nonatomic) NSInteger chapter;

@end

我已经用日志测试了变量 chapter 实际上是声明的(在我的情况下,我只是将它测试为 4)。

这是我的 ViewController.m 文件以及我如何呈现我的场景:

- (void)viewDidLoad 
    [super viewDidLoad];
    .
    .
    .
    // Configure the view.
    SKView *skView = (SKView *)self.view;

    if (!skView.scene) 
        skView.showsFPS = YES;
        skView.showsNodeCount = YES;

        // Create and configure the scene.
        scene = [OLevel sceneWithSize:CGSizeMake(skView.bounds.size.width, skView.bounds.size.height)];
        scene.scaleMode = SKSceneScaleModeResizeFill;

        // Set the SKScene chapter #
        scene.chapter = self.chapter;     // <<<< NOT WORKING?
        NSLog(@"CHAP TO PASS: %u", self.chapter);
        NSLog(@"CHAP RECEIVED: %u", scene.chapter);

        // Present the scene.
        [skView presentScene:scene];


场景定义如下,viewDidLoad 为上图所示:(我有它的子类)

@interface ViewController () 
    OLevel *scene;


@end

@implementation ViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    .
    .
    .

这是我的 OLevel.h 课程:

#import <SpriteKit/SpriteKit.h>
#import <GameplayKit/GameplayKit.h>

@interface OLevel : SKScene <SKPhysicsContactDelegate, GKAgentDelegate>

@property (nonatomic) NSInteger chapter;

@end

还有我的OLevel.m*

- (id)initWithSize:(CGSize)size 

    if (self = [super initWithSize:size]) 
        NSLog(@"Creating scene");

        NSLog(@"CHAP: %u", self.chapter);

        [self setUpScene];       
    

    return self;

我很困惑为什么这种方法不起作用。我已将 ViewController 中的属性设置为所需的章节值,然后告诉我的 Olevel 它是什么值并将其自己的章节属性设置为该值,并且然后正确呈现场景。为什么我继续得到0??

2016-07-18 23:52:32.189 TESTAPP[2038:684620] CHAP TO PASS: 4
2016-07-18 23:52:32.193 TESTAPP[2038:684620] CHAP RECEIVED: 0
2016-07-18 23:52:32.195 TESTAPP[2038:684620] Creating scene
2016-07-18 23:52:32.195 TESTAPP[2038:684620] CHAP: 0

我知道这个问题已经回答了here,方法与我在寻找答案之前最初使用的方法相同,但我还没有让它起作用..

如果有人知道我做错了什么,请帮助我。

【问题讨论】:

【参考方案1】:

你用错误的语法初始化你的场景,没有类型:

...      
// Create and configure the scene.
OLevel *scene = [OLevel sceneWithSize:CGSizeMake(skView.bounds.size.width, skView.bounds.size.height)];
scene.scaleMode = SKSceneScaleModeResizeFill;

// Set the SKScene chapter #
scene.chapter = self.chapter; 
...

如果你愿意,你也可以在章节中继承 init 方法

OLevel.h

@interface GameScene : SKScene <SKPhysicsContactDelegate, GKAgentDelegate>

@property (nonatomic) NSInteger chapter;

-(id)initWithSize:(CGSize)size chapter:(NSInteger)chapter;
+(id)sceneWithSize:(CGSize)size chapter:(NSInteger)chapter;

@end

OLevel.m

#import "GameScene.h"
@implementation GameScene

    -(id)initWithSize:(CGSize)size chapter:(NSInteger)chapter 

     if (self = [super initWithSize:size]) 
        self.chapter = chapter;
        //some custom code here
        NSLog(@"Creating scene");
        NSLog(@"CHAP: %ld", (long)self.chapter);

     
     return self;
    

    +(id)sceneWithSize:(CGSize)size chapter:(NSInteger)chapter 
          return ((GameScene *)[[self alloc] initWithSize:size chapter:chapter]);
    

    -(void)didMoveToView:(SKView *)view  
      ...
    

在这种情况下,您可以将场景创建为:

   // Create and configure the scene.
    scene = [OLevel sceneWithSize:CGSizeMake(skView.bounds.size.width, skView.bounds.size.height) chapter:self.chapter];
    scene.scaleMode = SKSceneScaleModeResizeFill;

【讨论】:

我尝试将其调整为将场景初始化为Olevel *scene,但它似乎没有改变任何东西。我最终做的是运行一个单独的函数,将数据直接传递给运行良好的 Olevel 类。 Olevel *scene *scene 允许将您的场景属性标识为 Olevel 类型并对其进行修改,以便您可以查看章节属性。事实上,如果你在 OLevel.m 中签入,在 didMoveToView 中,你可以看到章节值已修改。 在你的代码中你想在 INIT 方法中看到它,你可以修改 INIT 方法来接收章节值作为输入值 我之前已经尝试过了,但我没有在初始化 OLevel * 时这样做,所以也许这确实可行。 就像我说的,这就是我最终为解决方案所做的事情。我很困惑,因为SKScene 类有一个内置方法instancetype _Nonnull sceneWithSize:(CGSize),所以当你提到制作自定义传递方法时,我以为你的意思是编辑它。不过感谢您的帮助!【参考方案2】:

您也可以尝试使用 NSNotificationCenter 传递您的数据

[[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(receiveTestNotification:) 
        name:@"TestNotification"
        object:nil];

NSDictionary *userInfo = [NSDictionary dictionaryWithObject:myObject forKey:@"someKey"];
    [[NSNotificationCenter defaultCenter] postNotificationName: @"TestNotification" object:nil userInfo:userInfo];

【讨论】:

这可行,但考虑到 objc 提供的可用选项,解决方案应该更直接。

以上是关于从 UIVIewController 向 SKScene 传递数据的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Swift 中的 UITableViewRowAction 向 UIViewController 传递数据?

Swift - 从AppDelegate向View Controller添加子视图

如何从 UIViewController 传递变量来委托 UITableViewController

从 SKScene 呈现 UIViewController 显示黑屏

从 UIViewController 中删除子视图

如何从 AppDelegate 实例化 UIViewController?