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



我必须运行几个精灵表动画,每个表有数百帧。我尝试过SpriteKit和Cocos2D,它们都存在内存和CPU加载时间问题。谁能推荐使用Cocos2D, SpriteKit或任何其他方法的最佳方法,以尽量减少cpu使用并防止应用程序因内存过载而崩溃?

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

创建一个新的coca touch类,其中.h文件包含

#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 

最新更新