swift - .sks 文件中 SKSpriteNode 的子类

标签 swift sprite-kit xcode6

我正在使用 SpriteKit .sks 文件 我可以将 .sks 中的 Sprite 制作成 SKSpriteNode 子类的实例吗?

这是我的子类中的 init 方法:

    init(imageNamed: String) {

    let blockTexture = SKTexture(imageNamed: imageNamed)

    super.init(texture: blockTexture, color: nil, size: blockTexture.size())
}

在 GameScene.swift 中,我可以创建一个这样的实例:
var myObj = Block(imageNamed: "Block")

我的问题是如何将此实例与 .sks 文件相关联?

我尝试了这行代码,但它不起作用。
myObj     = childNodeWithName("block1") as Block

有什么帮助吗?

谢谢。

最佳答案

这里有几个问题需要解决......
.sks 加载如何工作

当您加载 .sks 文件时,SpriteKit 会使用 NSKeyedUnarchiver 实例化其中的所有内容。这意味着里面的所有节点都被加载为 Xcode 在创建 .sks 文件时指定的任何基类 - SKSpriteNode 用于具有纹理艺术的 Sprite ,SKLabelNode 用于文本,SKFieldNode 用于物理场等。目前 Xcode 没有提供一个选项来为 .sks 文件中的节点设置自定义类。

(对此的一个异常(exception)是更改场景本身的运行时类 — .sks 文件中所有内容的顶级容器。这只是因为项目模板中为您提供的自定义 SKNode.unarchiveFromFile 实现。它在以下位置更改类的技术当存档中只有一个特定类的一个实例时,加载时间有效——对 SKScene 有利,对场景中的许多节点不利。)

类型转换的工作原理

当你写这样的东西时:

myObj = childNodeWithName("block1") as Block

你在告诉编译器这样的事情:“嘿,你知道你从 childNodeWithName 得到的东西吗?你只知道它是一个 SKNode ,但我知道它真的是一个 Block ,所以请让我调用 Block 方法(编译器说,“好吧,随便吧。”)

但是在运行时,你得到的东西最好 真的是 a Block ,否则你的应用程序会崩溃,因为你试图用不是 Block 的东西做一些 Block y 的事情。而且,根据上面加载的 .sks 位,那个东西不是也不能是 Block — Xcode 不知道如何将 Block 放入 .sks 文件中。所以你不能从中得到 Block,所以你的应用程序肯定会崩溃。

解决方法

那么,如果您不能将自定义类放入 .sks 文件中,您能做什么?这在一定程度上取决于您究竟要完成什么。但是有一个很好的技巧,通常也可能是好的游戏/应用程序设计:使用 .sks 文件进行一般布局和配置,并使用第二遍引入需要自定义行为的东西。

例如,如果您在 2D 平台游戏中构建关卡,即使可以,您也不会真的希望 .sks 文件包含 Plumber 类的实例——该类可能有很多关于高度或高度的详细信息这个人很胖,他跳多高, mustache 的形状等等,你不想每次创建新关卡时都重新设置,更不用说在每个关卡的 .sks 文件中再次保存它们.相反,在每个级别文件中您真正需要知道的唯一事情是他开始的位置。因此,在 Xcode 中拖出一个“空节点”,并在加载时,将该节点替换为 Plumber 类的实例,如下所示:
let spawnPoint = childNodeWithName("spawnPoint")
let player = Plumber()
player.position = spawnPoint.position
addChild(player)
spawnPoint.removeFromParent()

如果您想在 .sks 文件中设置更多配置详细信息,则可以考虑自动化该过程。
  • 制作一个执行上述节点交换技巧的方法。 (称之为 replaceNode(_:withNode:) 之类的东西。)
  • 为您的自定义类创建一个初始化程序,它采用 SKNodeSKSpriteNode ,并让它从该节点设置其所有继承属性(或至少您关心的属性,如颜色和纹理)。
  • 使用 enumerateChildNodesWithName:usingBlock: search pattern 查找场景中具有某种名称的所有节点,并将它们替换为使用初始化程序创建的新节点。就像是:
    enumerateChildNodesWithName("//brick_[0-9]*") { node, stop in
        self.replaceNode(node, withNode: BrickBlock(node))
    }
    enumerateChildNodesWithName("//question_[0-9]*") { node, stop in
        self.replaceNode(node, withNode: QuestionBlock(node))
    }
    
  • 关于swift - .sks 文件中 SKSpriteNode 的子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27908165/

    相关文章:

    UICollectionViewCell 在第一次出现时不会自动调整 subview 的大小

    swift - 如何为 AppDelegate 编写单元测试?

    ios - 检查数组的当前索引是什么对象

    ios - 如何使 SKScene 具有固定宽度?

    ios - 我应该如何缩放我的物理 body ?

    iphone - 有没有办法暂停 SKActions?

    facebook - 在 Xcode 中使用 Swift 解析 Facebook SDK 设置

    ios - 使用 Core Data 将文本字段中的文本分配给托管对象上下文

    ios - swift 链接器命令失败,退出代码为 1 Google Maps iOS Util pod install

    ios - UIImage imageNamed 返回 nil