播放(动画)巨大精灵表的最佳技术

Posted

技术标签:

【中文标题】播放(动画)巨大精灵表的最佳技术【英文标题】:Best technique for playing(animating) huge sprite sheets 【发布时间】:2015-11-26 12:52:34 【问题描述】:

我必须运行几个精灵表动画,每个表都有数百帧。 我试过 SpriteKit 和 Cocos2D,每个都有内存和 CPU 加载时间问题。 任何人都可以推荐使用 Cocos2D、SpriteKit 或任何其他方法的最佳方法,以最大程度地减少 cpu 使用率并防止应用程序因内存过载而崩溃。

【问题讨论】:

也许你可以试试 SKVideoNode ***.com/a/30556711/3402095 它必须是交互式的,所以视频不是一个选项 @Simulator- 您的问题缺乏实质内容并且过于宽泛。尝试将您的问题缩小到特定问题,并展示您迄今为止所做的尝试。 【参考方案1】:

你可以通过扩展 spriteNode 使用你自己的自定义类来做到这一点,这里是目标 c 中的示例

在你的 .h 文件中创建一个新的 coca touch 类

#import <SpriteKit/SpriteKit.h>

@interface multiSpriteAnimation : SKSpriteNode



//variables
//starting frame of animation
@property (nonatomic,strong) SKTexture *startingFrame;
//sprite which hold all animtion
@property (nonatomic,strong) SKSpriteNode *animatedSprite;


@property (nonatomic,strong) NSMutableDictionary *allAnimation;
@property (nonatomic,strong) NSMutableDictionary *allAnimationFrameRates;
@property (nonatomic,strong) NSMutableDictionary *animationList;
//function
@property (nonatomic,strong) SKAction *currentAction;



-(id) copyWithZone: (NSZone *) zone;
- (instancetype)initSpritesAnimation:(SKTexture*)startingFrame;
//add animation
-(void)addAnimation:(NSMutableArray*)frames frameRate:(float)time withKey:(NSString*)Key;
-(void)playAnimation:(NSString*)label withType:(NSString*)type;

//play animation with sound
-(void)playAnimation:(NSString*)label withType:(NSString*)type withSound:(NSString*)soundname loopRequired:(BOOL)loop;

//clear all sounds
-(void)clearAllsounds;

@end

和.m文件包含

#import "multiSpriteAnimation.h"
@implementation multiSpriteAnimation

    SKTexture *__startingFrame;

- (instancetype)initSpritesAnimation:(SKTexture*)startingFrame

    self = [super init];
    if (self) 
        //init all animation dictionary
        _animationList=[[NSMutableDictionary alloc] init];
        _allAnimation=[[NSMutableDictionary alloc] init];
        _allAnimationFrameRates=[[NSMutableDictionary alloc] init];
        //draw first frame for the animation
        __startingFrame=startingFrame;
        _animatedSprite=[SKSpriteNode spriteNodeWithTexture:startingFrame];
        _animatedSprite.anchorPoint=CGPointMake(0.5, 0.5);
        [self addChild:_animatedSprite];

    
    return self;

-(void)addAnimation:(NSMutableArray*)frames frameRate:(float)time withKey:(NSString*)Key


    //add all animation only once for stable framerate
    [_allAnimation setObject:frames forKey:Key];
    [_allAnimationFrameRates setObject:[NSNumber numberWithFloat:1/time] forKey:Key];



-(void)playAnimation:(NSString*)label withType:(NSString*)type

    //total frame to play animation
    NSMutableArray *frames=[_allAnimation objectForKey:label];
    //frame rate of a animation
    float time=[[_allAnimationFrameRates objectForKey:label] floatValue];
    SKAction *Animation = [SKAction animateWithTextures:frames timePerFrame:time resize:TRUE restore:TRUE];
    //play in a loop
    if([type isEqualToString:@"loop"])
    
        _currentAction = [SKAction repeatActionForever:Animation ];
    
    //play once with complete handler
    else if([type isEqualToString:@"playonce"])
    
        _currentAction=Animation;
    
    [_animatedSprite runAction:_currentAction];
    //only one hero have cap

//clear all sounds
-(void)clearAllsounds

    [self removeActionForKey:@"sound"];


-(id) copyWithZone: (NSZone *) zone


    multiSpriteAnimation *copy = [[[self class] allocWithZone:zone] initSpritesAnimation:__startingFrame];
    return copy;

-(void)playSound:(NSString *)path withLoop:(BOOL)loop

    SKAction *sound;
    if(loop)
    
        sound = [SKAction playSoundFileNamed:path waitForCompletion:YES];
        [self runAction:[SKAction repeatActionForever:sound] withKey:@"sound"];
    
    else
    
        sound = [SKAction playSoundFileNamed:path waitForCompletion:NO];
        [self runAction:sound withKey:@"sound"];
    


//play animation with sound
-(void)playAnimation:(NSString*)label withType:(NSString*)type withSound:(NSString*)soundname loopRequired:(BOOL)loop

    //total frame to play animation
    NSMutableArray *frames=[_allAnimation objectForKey:label];
    //frame rate of a animation
    float time=[[_allAnimationFrameRates objectForKey:label] floatValue];
    SKAction *Animation = [SKAction animateWithTextures:frames timePerFrame:time resize:TRUE restore:TRUE];
    //play in a loop
    if([type isEqualToString:@"loop"])
    
        _currentAction = [SKAction repeatActionForever:Animation ];
        [self playSound:soundname withLoop:loop];
    
    //play once with complete handler
    else if([type isEqualToString:@"playonce"])
    
        _currentAction=Animation;
        [self playSound:soundname withLoop:loop];
    
    [_animatedSprite runAction:_currentAction];
    //only one hero have cap




@end

现在在你的任何场景中导入这个类并一个一个地添加你的所有动画

multiSpriteAnimation *player=[[multiSpriteAnimation alloc] initSpritesAnimation:A1[0]];
//where A1[0] is first frame of your animation

    //and A1 as a array of frames or textures with a key 

    [player addAnimation:A1 frameRate:30.0f withKey:@"run"];

    player.position=CGPointMake(200.0f, 400.0f);
    [self addChild:player];
//play animation by key
    [player playAnimation:@"run" withType:@"loop"];

this way you can handle multiple animation remember save all animation frames or textures as a singleton for further use 

【讨论】:

它最初仍然无法解决 10-15 秒的 CPU 峰值问题,我正在添加 19 个节点,每个节点大约有 40 帧。 您是否正在为动画预加载纹理,请从图集获取纹理并预加载它们以供进一步使用,例如从图集加载纹理并将它们保存在数据类或单例类中......您是否将纹理图集加载到内存中以供进一步使用 您可以从Here下载代码

以上是关于播放(动画)巨大精灵表的最佳技术的主要内容,如果未能解决你的问题,请参考以下文章

带有精灵表的 Android 动画

v2.x OGE-example 第三节 播放精灵动画

更改正在动画的精灵表时 HTML5 Canvas 挂起(逐帧播放视频)

将精灵表转换为 gif 动画

改变精灵动画速度(pygame)

纹理包装动画图像/精灵表有效-Libgdx