Swift/SpriteKit - pool/cache SKReferenceNodes 有什么方法吗?
Swift/SpriteKit - Any way to pool/cache SKReferenceNodes?
有没有办法在 SpriteKit 中使用 Swift pool/cache SKReferenceNodes?
我正在使用 xCodes 可视化关卡编辑器创建游戏。我正在使用可视化关卡编辑器创建不同的 .sks 文件,而不是在需要时调用代码。我在代码中调用它们是因为我使用它们来创建随机关卡或障碍,所以我不需要将它们全部添加到场景中。
目前我是这样做的
我为 SKReferenceNodes 创建了一个说服 init 方法来使用 URL 初始化它们。我这样做是因为存在某种直接通过文件名 (https://forums.developer.apple.com/thread/44090) 调用 SKReferenceNodes 的错误。
使用这样的扩展使得代码更简洁。
extension SKReferenceNode {
convenience init(roomName: String) {
let path: String
if let validPath = NSBundle.mainBundle().pathForResource(roomName, ofType: "sks") {
path = validPath
} else {
path = NSBundle.mainBundle().pathForResource("RoomTemplate", ofType: "sks")! // use empty roomTemplate as backup so force unwrap
}
self.init(URL: NSURL(fileURLWithPath: path))
}
}
而且在我的场景中我可以创建它们并像这样添加它们(大约每 10 秒)
let room = SKReferenceNode(roomName: "Room1") // will cause lag without GCD
room.position = ...
addChild(room)
这工作正常,但我在创建这些时得到了一些 lag/stutter。所以我正在使用 GCD 将其减少到基本上没有口吃。它运行良好,但我想知道我是否可以先预加载所有 .sks 文件。
我尝试使用数组来执行此操作,但我遇到了崩溃,而且它似乎不起作用(我还收到一条消息,已经添加了具有父节点的节点)。
我试图在应用启动时像这样预加载它们
let allRooms = [SKReferenceNode]()
for i in 0...3 {
let room = SKReferenceNode(roomName: "Room\(i)")
allRooms.append(room)
}
并且在我需要时使用数组。然而,这不起作用,我在尝试使用这样的代码时遇到了崩溃
let room = allRooms[0]
room.position =
addChild(room) // causes error/crash -> node already has parent
有没有人做过类似的事情?有没有其他方法可以 pool/cache 那些参考节点?。我在这里遗漏了什么吗?
说到 SKReferenceNode
预加载,我认为要遵循的策略是加载你的对象,找到它们的类型并使用 Sprite-Kit[ 中提供的官方预加载方法=24=]:
- SKTextureAtlas.preloadTextureAtlases(_:withCompletionHandler:)
- SKTexture.preloadTextures(_:withCompletionHandler:)
为避免此类错误,您应该创建单独的节点实例。
尝试这样做:
let room = allRooms[0]
room.position = ...
room.removeFromParent()
addChild(room)
我才明白,我只是个白痴。
像我想的那样使用数组很好,导致崩溃的问题如下。
首次加载游戏场景时,我添加了 3 个房间,但在使用数组进行测试时,我一直添加相同的房间
let room = allRooms[0]
而不是使用随机发生器。
这显然意味着我多次添加相同的实例,因此崩溃。
有了随机发生器,不会重复同一个房间,就不会发生这种情况。
此外,当我不再需要房间时,我会确保将它从场景中移除。我在房间 (roomRemover) 中有一个节点,它会在与玩家接触后触发 remove/create 一个新房间的方法。
这将是 DidBeginContact 中的代码。
guard let roomToRemove = secondBody?.node.parent?.parent?.parent?.parent else { return }
// secondBody is the roomRemover node which is a child of the SKReferenceNode.
// If I want to remove the whole SKReferenceNode I need to add .parent 4 times.
// Not exactly sure why 4 times but it works
for room in allRooms {
if room == roomToRemove {
room.removeFromParent()
}
}
loadRandomRoom()
希望这对尝试做同样事情的人有所帮助。
有没有办法在 SpriteKit 中使用 Swift pool/cache SKReferenceNodes?
我正在使用 xCodes 可视化关卡编辑器创建游戏。我正在使用可视化关卡编辑器创建不同的 .sks 文件,而不是在需要时调用代码。我在代码中调用它们是因为我使用它们来创建随机关卡或障碍,所以我不需要将它们全部添加到场景中。
目前我是这样做的
我为 SKReferenceNodes 创建了一个说服 init 方法来使用 URL 初始化它们。我这样做是因为存在某种直接通过文件名 (https://forums.developer.apple.com/thread/44090) 调用 SKReferenceNodes 的错误。 使用这样的扩展使得代码更简洁。
extension SKReferenceNode {
convenience init(roomName: String) {
let path: String
if let validPath = NSBundle.mainBundle().pathForResource(roomName, ofType: "sks") {
path = validPath
} else {
path = NSBundle.mainBundle().pathForResource("RoomTemplate", ofType: "sks")! // use empty roomTemplate as backup so force unwrap
}
self.init(URL: NSURL(fileURLWithPath: path))
}
}
而且在我的场景中我可以创建它们并像这样添加它们(大约每 10 秒)
let room = SKReferenceNode(roomName: "Room1") // will cause lag without GCD
room.position = ...
addChild(room)
这工作正常,但我在创建这些时得到了一些 lag/stutter。所以我正在使用 GCD 将其减少到基本上没有口吃。它运行良好,但我想知道我是否可以先预加载所有 .sks 文件。
我尝试使用数组来执行此操作,但我遇到了崩溃,而且它似乎不起作用(我还收到一条消息,已经添加了具有父节点的节点)。
我试图在应用启动时像这样预加载它们
let allRooms = [SKReferenceNode]()
for i in 0...3 {
let room = SKReferenceNode(roomName: "Room\(i)")
allRooms.append(room)
}
并且在我需要时使用数组。然而,这不起作用,我在尝试使用这样的代码时遇到了崩溃
let room = allRooms[0]
room.position =
addChild(room) // causes error/crash -> node already has parent
有没有人做过类似的事情?有没有其他方法可以 pool/cache 那些参考节点?。我在这里遗漏了什么吗?
说到 SKReferenceNode
预加载,我认为要遵循的策略是加载你的对象,找到它们的类型并使用 Sprite-Kit[ 中提供的官方预加载方法=24=]:
- SKTextureAtlas.preloadTextureAtlases(_:withCompletionHandler:)
- SKTexture.preloadTextures(_:withCompletionHandler:)
为避免此类错误,您应该创建单独的节点实例。
尝试这样做:
let room = allRooms[0]
room.position = ...
room.removeFromParent()
addChild(room)
我才明白,我只是个白痴。
像我想的那样使用数组很好,导致崩溃的问题如下。
首次加载游戏场景时,我添加了 3 个房间,但在使用数组进行测试时,我一直添加相同的房间
let room = allRooms[0]
而不是使用随机发生器。 这显然意味着我多次添加相同的实例,因此崩溃。
有了随机发生器,不会重复同一个房间,就不会发生这种情况。
此外,当我不再需要房间时,我会确保将它从场景中移除。我在房间 (roomRemover) 中有一个节点,它会在与玩家接触后触发 remove/create 一个新房间的方法。 这将是 DidBeginContact 中的代码。
guard let roomToRemove = secondBody?.node.parent?.parent?.parent?.parent else { return }
// secondBody is the roomRemover node which is a child of the SKReferenceNode.
// If I want to remove the whole SKReferenceNode I need to add .parent 4 times.
// Not exactly sure why 4 times but it works
for room in allRooms {
if room == roomToRemove {
room.removeFromParent()
}
}
loadRandomRoom()
希望这对尝试做同样事情的人有所帮助。