SKTransitions 从场景到场景缓慢

SKTransitions from scene to scene slow

我正在编写一个 OS X SpriteKit 应用程序。我正在从我的主菜单场景过渡到主场景,但过渡大约需要 3 秒才能开始。在我的主场景中,我有一个以编程方式生成的屏幕钢琴。大约有 55 个精灵需要加载。有什么办法可以加快速度吗?

在我的主要 SKScene LevelScene 中,这是 didMoveToView 方法调用的内容:

-(void)didMoveToView:(SKView *)view {
    _piano = [[Keyboard alloc] init]; //creates on screen piano keyboard
    [self addChild:_piano]; 
    [_piano setPosition:[[self childNodeWithName:@"piano"] position]];
    [_piano setAnchorPoint:CGPointMake(1, 0)];

    _midiController = [[MIDIController alloc] initWithAudio:YES];

    [self initGameStateMachine];
    [self initLevel]; //this involves loading a couple more sprites onto the screen
}

加载所有纹理一次并保留对它们的引用。您可以将所有纹理存储在共享数组或字典中。事实上,您可以创建一个 class 来管理它。这样你的所有纹理都已经加载到内存中,因此创建节点应该更快,这将导致快速场景转换。

还有一个关于 Yosemite 的错误,当纹理是图集的一部分时,从图集中按名称加载精灵需要很长时间(并且实际上会使游戏停止)。我猜这是一个与低效搜索图集路径有关的错误。从图集手动加载是一种解决方法。不确定这个错误是否会影响您,但我想我还是提到了它。不管怎样,按照我上面说的去做应该可以解决你的问题。


更新答案以包含代码:
我很快就写了一些代码来向您展示我所说的加载和卸载资产的意思。在此示例中,我们有一个单例 class,即 SharedAssetsManager,它负责从内存中加载和卸载您的资产。出于性能原因,最好将所有纹理保存在图集中。如果您有一些不是的纹理(我将其包含在示例代码中),您会发现必须手动将其添加到字典中(尽管您可能会想出一个更快的解决方案,例如对文件进行分组或使用 plist描述图像的名称)。在下面的代码中,您可以看到加载资产然后卸载它们的示例。如果您的游戏足够小,您可以在 AppDelegate 或某个等效区域中加载一次,但如果您的游戏太大,您将需要在场景之间动态加载,可能需要使用加载屏幕,您可以看到 [=11= 的示例]:最后,您可以看到我使用常量来引用文件名,而不是对它们进行硬编码。您不应该为精灵帧动画执行此操作,例如 Walk_0、Walk1_1、Walk_2 等。相反,您可以想出另一个 class 来管理动画。希望这段代码能提供一个良好的起点。

import SpriteKit

struct FileNameConstants {
    static let LEVEL1_ATLAS = "Level1_Atlas"
    static let SOME_TEXTURE1 = "Some_Texture_In_Atlas"
    static let SOME_TEXTURE2 = "Some_Texture_Not_In_Atlas"
}

class SharedAssetsManager {
    static let sharedInstance = SharedAssetsManager()

    //Keep these private for safety.
    private init() {}
    private(set) var level1Assets: [String : SKTexture]!

    func getAssetsDictionaryFromAtlasNamed(atlasNamed: String) -> [String : SKTexture] {
        let atlas = SKTextureAtlas(named: atlasNamed)
        var textures: [String : SKTexture] = Dictionary(minimumCapacity: atlas.textureNames.count)
        for textureName in atlas.textureNames as [String] {
            textures[textureName.stringByDeletingPathExtension] = atlas.textureNamed(textureName)
        }
        return textures
    }

    func loadLevel1Assets() {
        level1Assets = getAssetsDictionaryFromAtlasNamed(FileNameConstants.LEVEL1_ATLAS)
        //Textures that are not part of the atlas but should be part of level1 assets can be added here:
        level1Assets[FileNameConstants.SOME_TEXTURE2] = SKTexture(imageNamed: FileNameConstants.SOME_TEXTURE2)

    }
    func unloadLevel1Assets() {
        level1Assets = nil
    }
}

//When loading level 1:
let sam = SharedAssetsManager.sharedInstance
sam.loadLevel1Assets()

//When assigning textures:
let someNode1 = SKSpriteNode(texture: sam.level1Assets[FileNameConstants.SOME_TEXTURE1]!)
let someNode2 = SKSpriteNode(texture: sam.level1Assets[FileNameConstants.SOME_TEXTURE2]!)

//When cleaning up (if needed).
sam.unloadLevel1Assets()