问题 在Sprite Kit iOS中使用一个图像精灵表


我有一个精灵表,上面有我的精灵的动画图片。 我如何将这些图像放入SKTextureAtlas(因此我可以在SKAction中制作动画)而不拆分单个文件? 我以前见过并做过这个,但没有使用SpriteKit和/或SKTextures。

如果不拆分文件,这是否可行?


3498
2017-11-28 17:26


起源

感谢您提出此问题并发布结果代码。这正是我所需要的。 - Sungwon Jeong


答案:


感谢@ LearnCocos2D指点我使用 textureWithRect:inTexture: 我在自定义中创建了一个自定义init方法 Entity : SKSpriteNode 允许使用带有所有图像的精灵表的类。我试图包含一些注释来解释代码。我有这个版本扫描x,因为我的动画是水平的。只能使用调用的方法更改Y.不在此版本的方法中。

一定要把它放在界面中!

alloc-initing的示例:

Entity *cookie = [[Entity alloc] initWithSpriteSheetNamed:@"cookie_sheet" withinNode:map sourceRect:CGRectMake(0, 0, 32, 32) andNumberOfSprites:6];

实体中的方法:SKSpriteNode

- (id) initWithSpriteSheetNamed: (NSString *) spriteSheet withinNode: (SKSpriteNode *) scene sourceRect: (CGRect) source andNumberOfSprites: (int) numberOfSprites {

    // @param numberOfSprites - the number of sprite images to the left
    // @param scene - I add my sprite to a map node. Change it to a SKScene
    // if [self addChild:] is used.

    NSMutableArray *mAnimatingFrames = [NSMutableArray array];

    SKTexture  *ssTexture = [SKTexture textureWithImageNamed:spriteSheet];
    // Makes the sprite (ssTexture) stay pixelated:
    ssTexture.filteringMode = SKTextureFilteringNearest;

    float sx = source.origin.x;
    float sy = source.origin.y;
    float sWidth = source.size.width;
    float sHeight = source.size.height;

    // IMPORTANT: textureWithRect: uses 1 as 100% of the sprite.
    // This is why division from the original sprite is necessary.
    // Also why sx is incremented by a fraction.

    for (int i = 0; i < numberOfSprites; i++) {
        CGRect cutter = CGRectMake(sx, sy/ssTexture.size.width, sWidth/ssTexture.size.width, sHeight/ssTexture.size.height);
        SKTexture *temp = [SKTexture textureWithRect:cutter inTexture:ssTexture];
        [mAnimatingFrames addObject:temp];
        sx+=sWidth/ssTexture.size.width;
    }

    self = [Entity spriteNodeWithTexture:mAnimatingFrames[0]];

    animatingFrames = mAnimatingFrames;

    [scene addChild:self];

    return self;
}

12
2017-11-29 01:48



很酷,我会试试这段代码。但是,我主要是试图避免不得不手动切碎一些spritesheets。 Shoebox解决了我的问题,因为我现在可以使用提取的精灵制作纹理图集。 textureWithRect很快吗?我相信TextureAtlas也会优化绘图,因为它会从相同的纹理中拉出所有内容。所以对我来说似乎更好。 - prototypical
我不确定速度,但据我所知,所有.atlas确实将多个图像放在一起。我相信所有图像仍然需要存储在一个数组中,以便稍后使用,因为[SKAction animateWithTextures:]采用数组。我将来也可以使用该程序。好消息是textureWithRect每次启动只需要发生一次。但如果它是由Apple编写的,它可能会更好。 - Keely
在参考资料中,它说“Sprite Kit使用纹理图集来提高渲染性能。”另外 - “如果将每个纹理视为一个单独的对象,那么Sprite Kit和图形硬件必须更加努力地渲染场景 - 并且你的游戏性能可能会受到影响。具体来说,Sprite Kit必须至少为每个纹理制作一个绘图通道。” - prototypical
因此,纹理图集只有1个纹理,并且可能只是在给定纹理上存储给定帧的位置和尺寸,它可能会明显更快,特别是如果你有大量的纹理。 ShoeBox解决方案是一个非常小的一次性提取,它允许我获得单个纹理的渲染优化。 - prototypical
我也在整个文档中。请参见清单2-8。地图集使一个图像存储在内存中。然后浏览它并将atlas中的每个纹理存储到一个数组中。 (供以后使用)。在那之后:“如果你已经有了一个SKTexture对象,你可以创建引用它的一部分的新纹理。这种方法很有效,因为新的纹理对象在内存中引用相同的纹理数据。(这种行为类似于纹理地图集。)“真的,对我来说,这取决于艺术家和程序员的个人工作流程。 - Keely


您需要将每个动画帧作为单独的图像。然后,您可以使用SKAction为图像设置动画,可选择使用SKTextureAtlas。

所以,是的,你必须拆分现有的工作表,除非你编写一个自定义动画处理程序来手动更改动画精灵的纹理矩形。您可以使用spriteesheet纹理创建较小的纹理 textureWithRect:inTexture:


3
2017-11-28 17:43



谢谢,正是我需要知道的。 - Keely
@Keely如果你为此目的创建一个类,我会非常感兴趣。我有这个在我的名单上,在下周解决。想到可能已经有了一个解决方案。我有一些我想要使用的精灵表,而不必将它们分开。虽然也可能有这样的工具!前往谷歌... - prototypical
renderhjs.net/shoebox/extractSprites.htm  - 非常酷,如果你需要从spritesheet到单个图像。 - prototypical
@prototypical很酷的链接。但我之前决定上课。无论如何,它运作良好。我认为代码相对干净。我对任何建议持开放态度。 (是新的“接受的答案”) - Keely