【问题标题】:SKTransitions from scene to scene slowSKTransitions 从一个场景到另一个场景很慢
【发布时间】:2015-07-09 04:35:52
【问题描述】:

我正在编写一个 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
}

【问题讨论】:

  • 显示一些代码?加载 55 个精灵应该几乎是瞬时的,精灵的图像纹理有多大?
  • 所有正在加载的对象都在几个不同的类中,所以这里要发布很多代码。一半精灵的图像纹理为 110x478 像素。另一个精灵比那个小。我会将我的 didMoveToView 方法放在最上面,因为这是创建所有内容的地方。
  • 如果没有详细的代码知识,很难提出任何合理的建议。如果您在游戏开始之前绝对需要加载所有内容,请添加“加载”消息。如果您不需要预先加载所有内容,请仅加载游戏前几秒钟所需的内容,然后将其余内容放在后台。
  • 我同意这种做法。如果我使用这种加载资源的方法,我是不是只使用 GCD 将所有其他场景资源加载到单独的线程上,并将主菜单资源加载到主线程上?也许我离基地很远,但我想我记得以前看过这样的代码。此外,我刚刚意识到,每次我为每个场景调用didMoveToView 时,它都会重新加载我认为的所有资源。出于某种原因,它只是第一次加载 SKScene 时速度很慢。

标签: macos sprite-kit sktransition


【解决方案1】:

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

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


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

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

【讨论】:

  • 将它们加载到该共享类中的最佳做法是什么?对文件名进行硬编码是否合适,或者有更好、更灵活的方法吗?
  • @02fentym 取决于您的实施。您可以将文件名映射到键值,然后使用该键从字典中检索纹理。如果您只使用图集,您实际上可以在运行时从图集构建字典,方法是遍历图集纹理并使用名称作为键。我实际上没有一本大字典,而是有很多字典,因为我有这么多资产,设备会耗尽内存。所以我有加载和卸载每个字典的方法。我按照资产出现的位置组织资产。
  • @02fentym 例如菜单资产、一级资产、全局资产等
  • @02fentym 哎呀,用 Swift 我忘了你的帖子是在 Obj-C 中的。 Obj-C 中的每个方法都是公共的,因此您可以忽略访问控制。是的,地图集中的名称用作字典中的键。当您将纹理映射到精灵时,您应该能够确定纹理应该是什么。看到这真的取决于你的游戏是如何设置的。如果您在世界上有很多节点并且您希望能够将它们配对,那么您肯定需要使用 plist。您可以制作一个包含所有节点位置、旋转、纹理键等的 plist。然后解析它并
  • 它只是一个实例变量。为了安全起见,您可以将其设为只读属性。因为 SharedAssetsManager 是一个单例实例。您编写的所有内容都将成为实例的一部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多