我正在创建一个关卡,通过展示新场景来加载每个关卡。在物理设备上打开项目时,一半时间会说NSArray在枚举时发生变异。我认为它与我的animationManger类有关,它将多个SKTextureAtlases加载到集合中,然后使SKActions为场景中的每个节点设置动画。我将动画管理器放在GameViewController中,因此每次出现新级别时都不必加载纹理。有人可以给我一些关于做什么的建议
import UIKit
import SpriteKit
import GameplayKit
class GameViewController: UIViewController {
var AnimManager:AnimationManager?
var LvlManager:LevelManager?
var sceneView:SKView = SKView()
override func viewDidLoad() {
super.viewDidLoad()
//Load these 2
AnimManager = AnimationManager(sets: ["Launcher","Button","Launch"])
LvlManager = LevelManager(levels: 46)
NotificationCenter.default.addObserver(self, selector: #selector(self.createScene), name: NSNotification.Name(rawValue: "CreateScene"), object: nil)
//Create the SceneView
sceneView = self.view as! SKView
//Scene View Properties
sceneView.ignoresSiblingOrder = true
sceneView.showsFPS = true
sceneView.showsNodeCount = true
sceneView.showsPhysics = true
}
func createScene() {
//Create the new Scene
let scene = PilScene(Size: UIScreen.main.bounds.size, DataFile: "Levels", levelManager: LvlManager!, animationManager: AnimManager!)
//Present the Scene
print("presenting scene")
sceneView.presentScene(scene)
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
}
下面是为每个场景中的节点创建所有动画动作的类
class AnimationManager {
//Tuple contains Name of FrameSet, Forward Animation Action, and Backward Animation Action
var actions:[(String, SKAction, SKAction)] = []
//Starts loading the atlases when the manager is initialized
init(sets: [String]) {
loadAtlases(setNames: sets)
}
//Creates the atlases and preloads them immediately
func loadAtlases(setNames: [String]) {
for name in setNames {
let atlas = SKTextureAtlas(named: name)
atlas.preload {
self.createFrameSetAction(atlas: atlas, atlasName: name)
if name == setNames[setNames.count - 1] {
print("Game Finished Loading")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "CreateScene"), object: nil)
}
}
}
}
//Takes in the atlases and creates collections of sktextures
func createFrameSetAction(atlas: SKTextureAtlas, atlasName: String) {
var frameCollection:[SKTexture] = []
var loop = 0
while loop <= atlas.textureNames.count - 1 {
if loop < 10 {
frameCollection.append(atlas.textureNamed("Frames_0000\(loop)"))
}else if loop < 100{
frameCollection.append(atlas.textureNamed("Frames_000\(loop)"))
}else if loop > 99 && loop < 110 {
frameCollection.append(atlas.textureNamed("Frames_00\(loop)"))
}else{
frameCollection.append(atlas.textureNamed("Frames_00\(loop)"))
}
loop += 1
}
let animate = SKAction.animate(with: frameCollection, timePerFrame: 1/30)
let reverseAnimate = animate.reversed()
actions.append((atlasName, animate,reverseAnimate))
}
//Returns a collection of frames for a texture set by its name
func getAnimation(name: String) -> SKAction {
for action in actions {
if name == action.0 {
return action.1
}
}
return SKAction.animate(with: [SKTexture(imageNamed: name)], timePerFrame: 1/30)
}
}
以下是控制台中的内容:
2017-01-18 12:50:23.226 PilaTesting[7289:186676] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x610000646750> was mutated while being enumerated.'
*** First throw call stack:
(
0 CoreFoundation 0x00000001076ccd4b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010712e21e objc_exception_throw + 48
2 CoreFoundation 0x0000000107735f6c __NSFastEnumerationMutationHandler + 124
3 SpriteKit 0x0000000108247b6d -[SKNode _processSearchTokens:visited:usingBlock:stopPointer:] + 2440
4 SpriteKit 0x0000000108247082 -[SKNode _enumerateChildNodesWithName:usingBlock:stopPointer:] + 1127
5 SpriteKit 0x000000010824695a -[SKNode enumerateChildNodesWithName:usingBlock:] + 58
6 SpriteKit 0x0000000108246868 -[SKNode childNodeWithName:] + 148
7 PilaTesting 0x0000000106afe470 _TFC11PilaTesting9PilaScene6updatefSdT_ + 112
8 PilaTesting 0x0000000106afe65c _TToFC11PilaTesting9PilaScene6updatefSdT_ + 44
9 SpriteKit 0x000000010820fe37 -[SKScene _update:] + 365
10 SpriteKit 0x000000010822ee19 -[SKView _update:] + 950
11 SpriteKit 0x000000010822b682 __51-[SKView _vsyncRenderForTime:preRender:postRender:]_block_invoke.322 + 285
12 SpriteKit 0x000000010822aa4a -[SKView _vsyncRenderForTime:preRender:postRender:] + 611
13 SpriteKit 0x000000010822c2b6 __29-[SKView setUpRenderCallback]_block_invoke + 211
14 SpriteKit 0x0000000108263e73 -[SKDisplayLink _callbackForNextFrame:] + 335
15 QuartzCore 0x000000010e68b895 _ZN2CA7Display15DisplayLinkItem8dispatchEy + 57
16 QuartzCore 0x000000010e68b755 _ZN2CA7Display11DisplayLink14dispatch_itemsEyyy + 449
17 CoreFoundation 0x000000010765edb4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
18 CoreFoundation 0x000000010765ea43 __CFRunLoopDoTimer + 1075
19 CoreFoundation 0x000000010765e5ca __CFRunLoopDoTimers + 250
20 CoreFoundation 0x00000001076562f1 __CFRunLoopRun + 2065
21 CoreFoundation 0x0000000107655884 CFRunLoopRunSpecific + 420
22 GraphicsServices 0x000000010edc9a6f GSEventRunModal + 161
23 UIKit 0x000000010842fc68 UIApplicationMain + 159
24 PilaTesting 0x0000000106b029ff main + 111
25 libdyld.dylib 0x000000010b78068d start + 1
26 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException