播放(动画)巨大精灵表的最佳技术
Best technique for playing(animating) huge sprite sheets
我必须 运行 几个精灵 sheet 动画,每个 sheet 有数百帧。
我已经尝试过 SpriteKit 以及 Cocos2D,每个都有内存和 CPU 加载时间问题。
任何人都可以推荐使用 Cocos2D、SpriteKit 或任何其他方法来解决它的最佳方法,以最大限度地减少 cpu 使用并防止应用程序因内存过载而崩溃。
您可以通过扩展 spriteNode 使用您自己的自定义 class 来完成这里是 objective c
中的示例
创建一个新的 coca touch class .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
现在将此 class 导入到您的任何场景中,并一个一个地添加所有动画
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
我必须 运行 几个精灵 sheet 动画,每个 sheet 有数百帧。 我已经尝试过 SpriteKit 以及 Cocos2D,每个都有内存和 CPU 加载时间问题。 任何人都可以推荐使用 Cocos2D、SpriteKit 或任何其他方法来解决它的最佳方法,以最大限度地减少 cpu 使用并防止应用程序因内存过载而崩溃。
您可以通过扩展 spriteNode 使用您自己的自定义 class 来完成这里是 objective c
中的示例创建一个新的 coca touch class .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
现在将此 class 导入到您的任何场景中,并一个一个地添加所有动画
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