首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何通过预加载优化大型SKTextureAtlas文件中的图形?

如何通过预加载优化大型SKTextureAtlas文件中的图形?
EN

Stack Overflow用户
提问于 2015-05-22 19:02:29
回答 1查看 142关注 0票数 0

我有一个4纹理地图集的游戏。每个地图集大小为4096 x 4096,包含大约300个精灵,大小约为15kb - 50kb。在纹理包装器中没有优化,它们每个大约是2- 4MB,优化后大约是一半。

它们包含用于绘制字符的资源,但我发现绘制单个字符(大约24个节点)~ 0.5秒非常慢。这是因为对[atlas textureNamed:textureName]进行了多次调用

为了加快速度,我想预加载地图集。理想情况下,我会将它们保存在内存中,因为我总是需要它们。所以我的第一个问题是,用这种大小的地图集,这是可能的吗?我试着调用[SKTextureAtlas preloadTextureAtlases:@[MaleFeatureAtlas] withCompletionHandler...],但我得到了一个崩溃,没有堆栈跟踪,只是失去了与设备的连接。

目前,我有一个AtlasManager类,它有初始化到每个纹理地图集的静态变量:

代码语言:javascript
复制
static SKTextureAtlas *MaleFeatureAtlas;
static SKTextureAtlas *MaleItemAtlas;
static SKTextureAtlas *FemaleFeatureAtlas;
static SKTextureAtlas *FemaleItemAtlas;

@implementation AtlasManager
{
}

#pragma mark - Initialisation Methods

+ (void)initialize
{
    MaleFeatureAtlas = [SKTextureAtlas atlasNamed:MaleFeatures];
    MaleItemAtlas = [SKTextureAtlas atlasNamed:MaleItems];
    FemaleFeatureAtlas = [SKTextureAtlas atlasNamed:FemaleFeatures];
    FemaleItemAtlas = [SKTextureAtlas atlasNamed:FemaleItems];
}

每个字符子画面都有一个AtlasManager实例,但由于SKTextureAtlases是静态变量,我认为它们绘制起来会很快。但是对[atlas textureNamed:textureName]的持续调用确实减慢了绘制速度。我存储了一个节点绘制后的NSDictionary,所以重画非常快,但初始绘制花费的时间太长了。渲染8个字符,总共只有100多个节点,大约需要5秒。

那么,单例方法比使用静态变量更好吗?预加载这种大小的地图集是否明智?

EN

回答 1

Stack Overflow用户

发布于 2015-05-22 21:24:07

对于你的问题有很大的不同意见的空间。牢记这一点,我建议如下:

在创建纹理地图集时,您应该始终提前计划真正需要的内容。例如,你有5种不同类型的敌人,但游戏的第一级只显示敌人#1和#2。在这种情况下,你应该创建一个纹理地图集,其中只包含你的第一级(敌人#1和#2)所需的资源。

单例优点:将所有代码集中到一个类中。你只需要有一个类的实例。避免了必须重复加载某些资产。

单例缺点:如果有大量资产需要管理,代码量可能会变得不堪重负。

sprite子类化的优点:将你的所有代码和资产放在一个类中处理,以满足精灵的需求。

子类化缺点:在某些情况下,不同的类可能会多次加载相同的动画或图像。例如,某个类型的展开可能被一个或多个子类利用。

我更喜欢使用单例方法,因为我喜欢集中我的代码。下面是我如何做到这一点的一个简化示例。在创建纹理图集时,我也使用TexturePacker和头文件选项。我的单例类叫做Animations。

在Animations头文件中,我有以下内容:

代码语言:javascript
复制
-(void)loadPlayer0Atlas;
@property (strong) SKTexture *player0_startLeft;
@property (strong) SKAction *player0_idleLeft;
@property (strong) SKAction *player0_idleRight;
@property (strong) SKAction *player0_walkLeft;
@property (strong) SKAction *player0_walkRight;

在Animations实现文件中:

代码语言:javascript
复制
-(void)loadPlayer0Atlas {
    if(self.player0Atlas == nil) {
        self.player0Atlas = [SKTextureAtlas atlasNamed:PLAYER0ATLAS_ATLAS_NAME];
        [SKTextureAtlas preloadTextureAtlases:[NSArray arrayWithObject:self.player0Atlas] withCompletionHandler:^{
            [self loadPlayer0Assets];
        }];
    } else {
        [[NSNotificationCenter defaultCenter]postNotificationName:@"player0AtlasLoaded" object:self];
    }
}

-(void)loadPlayer0Assets {
    self.player0_startLeft = PLAYER0ATLAS_TEX_PLAYERIDLEL__000;
    self.player0_idleLeft = [SKAction repeatActionForever:[SKAction animateWithTextures:PLAYER0ATLAS_ANIM_PLAYERIDLEL timePerFrame:0.2]];
    self.player0_idleRight = [SKAction repeatActionForever:[SKAction animateWithTextures:PLAYER0ATLAS_ANIM_PLAYERIDLE timePerFrame:0.2]];
    self.player0_walkLeft = [SKAction repeatActionForever:[SKAction animateWithTextures:PLAYER0ATLAS_ANIM_PLAYERWALKL timePerFrame:0.1]];
    self.player0_walkRight = [SKAction repeatActionForever:[SKAction animateWithTextures:PLAYER0ATLAS_ANIM_PLAYERWALK timePerFrame:0.1]];

    [[NSNotificationCenter defaultCenter]postNotificationName:@"player0AtlasLoaded" object:self];
}

上面的代码允许我通过调用方法loadPlayer0Atlas来加载玩家的资源。此方法检查是否已创建地图集。如果是,它会发布一个NSNotification来指明这一点。如果不是,它将加载图集,将资源分配给类属性,然后发布NSNotification。

回到调用loadPlayer0Atlas的类中,您需要在init或didMoveToView方法中注册NSNotification。

代码语言:javascript
复制
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(myMethod)
                                             name:@"player0AtlasLoaded"
                                           object:nil];

一旦接收到通知,myMethod就可以在知道播放器图集现在已加载的情况下继续进行代码。

为了保持良好的内务管理,请记住从NSNotifications中删除调用类,如下所示:

代码语言:javascript
复制
-(void)willMoveFromView:(SKView *)view {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

来回答你最后一个关于预加载地图集的问题。是的,预先加载你的地图集总是明智的,因为它可以让你的游戏玩得更流畅。必须在游戏中加载资源可能会导致延迟。请记住,仅加载当前所在场景所需的资源。好的计划会给你带来好的结果。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30395040

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档