【问题标题】:Subclass of SKSpriteNode in .sks file.sks 文件中 SKSpriteNode 的子类
【发布时间】:2015-01-12 18:07:57
【问题描述】:

我正在使用 SpriteKit .sks 文件我可以将 .sks 中的精灵制作成 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

有什么帮助吗?

谢谢。

【问题讨论】:

  • “不起作用”到底是什么意思?你给它块 1 的名字,你把它添加为孩子吗?
  • @LearnCocos2D 我的意思是 childNodeWithName 不适用于子类化。是的,我给了它 block1 名称,并将其作为子级添加到 .sks 文件中。我的问题是如何将 .sks 文件中的精灵与自定义子类相关联?!谢谢
  • 再次,“不起作用”到底是怎么回事?发生什么了?错误信息?碰撞?返回零?

标签: swift sprite-kit xcode6


【解决方案1】:

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

.sks 加载的工作原理

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

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

投射的工作原理

当你写这样的东西时:

myObj = childNodeWithName("block1") as Block

你告诉编译器类似:“嘿,你知道你从childNodeWithName得到的东西吗?你只知道它是一个SKNode,但我知道它真的是一个Block,所以请让我打电话给Block 方法。” (编译器说,“好吧,随便吧。”)

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

解决方法

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

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

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

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

  1. 创建一个执行上述节点交换技巧的方法。 (称之为replaceNode(_:withNode:)。)
  2. 为您的自定义类创建一个初始化器,该类接受 SKNodeSKSpriteNode,并让它从该节点设置其所有继承属性(或至少是您关心的属性,如颜色和纹理)。李>
  3. 使用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))
    }
    

【讨论】:

  • @Mariam 你可能会发现this 也很有用。
  • 多么棒的回应。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
相关资源
最近更新 更多