.sks 文件中 SKSpriteNode 的子类 [英] Subclass of SKSpriteNode in .sks file

查看:29
本文介绍了.sks 文件中 SKSpriteNode 的子类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using SpriteKit .sks file Can I make a sprite in .sks into an instance of subclass of SKSpriteNode?

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

This is the init method in my subclass:

    init(imageNamed: String) {

    let blockTexture = SKTexture(imageNamed: imageNamed)

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

在 GameScene.swift 中,我可以创建一个这样的实例:

In GameScene.swift I can create an instance like this:

var myObj = Block(imageNamed: "Block")

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

My question is how can I relate this instance with .sks file?

我试过这行代码,但没有用.

I tried this line of code but it doesn't work.

myObj     = childNodeWithName("block1") as Block

有什么帮助吗?

谢谢.

推荐答案

这里有几个问题需要解决...

There are a couple of issues here to address...

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

When you load a .sks file, SpriteKit instantiates everything within using NSKeyedUnarchiver. This means that all the nodes inside are loaded as whatever base classes they were specified as by Xcode when it created the .sks file — SKSpriteNode for sprites with texture art, SKLabelNode for text, SKFieldNode for physics fields, etc. And Xcode doesn't currently provide an option for setting custom classes for the nodes inside a .sks file.

(对此的一个例外是更改场景本身的运行时类——.sks 文件中所有内容的顶级容器.这仅仅是因为自定义 SKNode.在项目模板中为您提供了 unarchiveFromFile 实现.当您在存档中只有一个特定类的一个且只有一个实例时,它用于在加载时更改类的技术有效 - 对 SKScene 很有用,对于场景中的许多节点来说不是很好.)

(The one exception for this is changing the runtime class of the scene itself — the top level container for everything in the .sks file. And that's only because of the custom SKNode.unarchiveFromFile implementation provided for you in the project template. Its technique for changing classes at load time works when you have one and only one instance of a particular class in an archive — good for SKScene, not so good for the many nodes in a scene.)

当你写这样的东西时:

myObj = childNodeWithName("block1") as Block

你告诉编译器类似:嘿,你知道你从 childNodeWithName 得到的东西吗?你只知道它是一个 SKNode,但我知道它实际上是一个 Block,所以请让我在其上调用 Block 方法."(编译器说,好吧,随便.")

You're telling the compiler something like: "Hey, you know that thing you got from childNodeWithName? All you know is that it's an SKNode, but I know it's really a Block, so please let me call Block methods on it." (And the compiler says, "Okay, whatever.")

但是在运行时,你得到的东西最好真的是Block,否则你的应用会因为你试图用不是 Block 的东西做一些 Blocky.而且,根据上面关于 .sks 加载的一点,那个东西不是也不能是 Block — Xcode 不知道如何放置 Blocks 到 .sks 文件.所以你不能从中获取Block,所以你的应用肯定会崩溃.

But then at run time, that thing you got had better really be a Block, or your app will crash because you tried to do something Blocky with something that's not a Block. And, per the bit about .sks loading above, that thing isn't and can't be a Block — Xcode doesn't know how to put Blocks into a .sks file. So you can't get a Block out of it, so your app is guaranteed to crash.

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

So, if you can't put custom classes into a .sks file, what can you do? It depends a bit on what exactly you're trying to accomplish. But there's a good trick that might also be good game/app design in general: use the .sks file for general layout and configuration, and use a second pass to bring in things that need custom behavior.

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

For example, if you're building a level in a 2D platform game, you wouldn't really want to have the .sks file contain an instance of your Plumber class even if you could — that class probably has lots of details about how tall or fat the guy is, how high he jumps, the shape of his mustache, etc, and you don't want to have to set those up again every time you make a new level, much less have them saved again in each level's .sks file. Instead, the only thing you really need to know in each level file is the position he starts at. So, drag out an "Empty Node" in Xcode, and at load time, replace that node with an instance of your Plumber class, like so:

let spawnPoint = childNodeWithName("spawnPoint")
let player = Plumber()
player.position = spawnPoint.position
addChild(player)
spawnPoint.removeFromParent()

如果您想在 .sks 文件中设置更多配置详细信息,您可以考虑自动化该过程.

If you have more configuration details that you want to set in the .sks file, you might consider automating that process.

  1. 制作一个执行上述节点交换技巧的方法.(称之为replaceNode(_:withNode:).)
  2. 为采用 SKNodeSKSpriteNode 的自定义类创建一个初始化程序,并让它设置其所有继承的属性(或至少是您关心的属性,例如颜色和纹理)来自该节点.
  3. 使用 enumerateChildNodesWithName:usingBlock: 带有 搜索模式 用某种名称,并将它们替换为使用初始化程序创建的新节点.类似的东西:

  1. Make a method that does the above node-swapping trick. (Call it something like replaceNode(_:withNode:).)
  2. Make an initializer for your custom class that takes a SKNode or SKSpriteNode, and have it set all its inherited properties (or at least the ones you care about, like color and texture) from that node.
  3. Use enumerateChildNodesWithName:usingBlock: with a search pattern to find all the nodes in your scene with a certain kind of name, and replace them with a new node created using your initializer. Something like:

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))
}

这篇关于.sks 文件中 SKSpriteNode 的子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆