cocos2d精灵教程:第三部分
我们在第2部分教程中已经介绍了如何让dragon沿着8个不同的方向移动,并且播放相应的动画,同时,移动过程可以由用户touch屏幕来控制。cocos2d很酷吧!好了,今天我们将多干点活,我们将创建一大批村民--实际上是N个村民。我们会使用我们已经学习过的技术,从spritesheet里面加载精灵,同时建立相应的精灵动画。
这里有本教程的完整源代码。
那么,我们到底要做成什么样子呢---看了下面的图就明白了:
上面加载了好多村民,但是,屏幕的帧速率仍然是60 fps。这是因为我们做了优化。那么,究竟是如何做的呢?让我们马上开始学习吧。
首先,我们要创建我们的adventurer (冒险者)类。---它里面存储了我们的移动和行走动画的精灵实例。在屏幕上每一个冒险家,我们都会为之创建一个adventurer 类的实例。
Adventurer.h
#import "cocos2d.h"@inte易做图ce Adventurer : CCNode { CCSprite *_charSprite; CCAction *_walkAction; CCAction *_moveAction; BOOL _moving;}@property (nonatomic, retain) CCSprite *charSprite;@property (nonatomic, retain) CCAction *walkAction;@property (nonatomic, retain) CCAction *moveAction;@end
如果你愿意的话,你也可以从CCSprite继承,然后我们可以调用initWithFile方法来初始化我们的Adventure 类。但是,我更喜欢从CCNode继承,然后包含一个CCSprite的实例。
Adventurer.m
#import "Adventurer.h"@implementation Adventurer@synthesize charSprite = _charSprite;@synthesize moveAction = _moveAction;@synthesize walkAction = _walkAction;-(id) init{ self = [super init]; if (!self) { return nil; } return self;}- (void) dealloc{ self.charSprite = nil; self.walkAction = nil; self.moveAction = nil; [super dealloc];}@end
很简单的init函数,同时我们还定义了一个dealloc方法。(译者:大家一定要养成一个好习惯,定义init就马上定义dealloc,“创建-销毁”要成对,这个很重要,能减少很多内存问题。stackoverflow上面,有人直接把dealloc方法放在.m文件的最开头,作用不言而喻!ios内存有限啊!)---上面这段代码,我们再熟悉不过了。这里创建了一个非常简单的类,但是,也给我们一些提示,如何为游戏主角创建class。这里把所有的属性都定义了retain说明符,同时在dealloc方法里面调了self.xxx = nil来释放内存。这样就把内存管理与property关联起来了。objc的引用计数已经为我们程序员减少了对于内存管理的烦恼,因此,只需要养成良好的习惯,就可以减少大量与内存有关的问题发生。
现在,我们拥有角色了,让我们来使用之。。。先回到“PlayLayer.h” ,然后做下面一些变更:
#import "cocos2d.h"#import "SceneManager.h"#import "Adventurer.h"@inte易做图ce PlayLayer : CCLayer { CCTexture2D *_texture; CCSpriteSheet *_spriteSheet; NSMutableArray *_charArray;}@property (nonatomic, assign) CCTexture2D *texture;@property (nonatomic, assign) CCSpriteSheet *spriteSheet;@property (nonatomic, retain) NSMutableArray *charArray;@end
我们先导入 “Adventurer.h”,然后定义了3个实例变量。第一个变量 “_texture”用来加载adventurer 精灵表单。第二变量 “_spritesheet”是把我们将要创建的精灵都进行“批处理”,使之提高效率。最后,我们想要追踪所有的adventurers,所以,我们定义了一个“_charArray”.数组。同时我们为每一个实例变量都声明了属性,这样我们就可以在PlayLayer.m间接使用了。(另一种方法是定义tag,在init方法里面指定tag,然后在其它方法里面就可以用self getChildByTag:tag来获得想要的孩子了)
OK,现在我们有一堆类了。不过别担心,我们会在后面把它逐步分开讲解--首先,先让我们实现PlayLayer.m:
PlayLayer.m
#import "PlayLayer.h"#import "Adventurer.h"@implementation PlayLayer@synthesize texture = _texture;@synthesize spriteSheet = _spriteSheet;@synthesize charArray = _charArray;enum { kTagSpriteSheet = 1,};-(id) init{ self = [super init]; if (!self) { return nil; } CCSprite *background = [CCSprite spriteWithFile:@"Terrain.png"]; background.position = ccp(160, 240); [self addChild:background]; _texture = [[CCTextureCache sharedTextureCache] addImage:@"adventurer.png"]; _spriteSheet = [CCSpriteSheet spriteSheetWithTexture:self.texture capacity:100]; [self addChild:_spriteSheet z:0 tag:kTagSpriteSheet]; self.charArray = [[NSMutableArray alloc] init]; [self schedule:@selector(gameLogic:) interval:1.0f]; return self;}-(void)addAdventurer { NSLog(@"Add Adventurer"); NSMutableArray *animFrames = [NSMutableArray array]; [animFrames removeAllObjects]; for (int i = 0; i < 9; i++) { CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:self.texture rect:CGRectMake(i*16, 0, 16, 29) offset:CGPointZero]; [animFrames addObject:frame]; } Adventurer * adventurer = [[[Adventurer alloc] init] autorelease]; if (adventurer != nil) { CCSpriteFrame *frame1 = [CCSpriteFrame frameWithTexture:self.texture rect:CGRectMake(0, 0, 19, 29) offset:CGPointZero]; adventurer.charSprite = [CCSprite spriteWithSpriteFrame:frame1]; CGSize s = [[CCDirector sharedDirector] winSize]; int minY = adventurer.charSprite.contentSize.height/2; int maxY = s.height - adventurer.charSprite.contentSize.height/2; int rangeY = maxY - minY; int actualY = (arc4random() % rangeY) + minY; int minX = -300; int maxX = 0; int rangeX = maxX - minX; int actualX = (arc4random() % rangeX) + minX; adventurer.charSprite.position = ccp(actualX, actualY); CCAnimation *animation = [CCAnimation animationWithName:@"walk" delay:0.2f frames:animFrames]; CCAnimate *animate = [CCAnimate actionWithAnimation:animation restoreOriginalFrame:NO]; CCSequence *seq = [CCSequence actions: animate, nil]; adventurer.walkAction = [CCRepeatForever actionWithAction: seq ]; id actionMove = [CCMoveTo actionWithDuration:10.0f position:ccp(s.width + 200,actualY)]; id actionMoveDone = [CCCallFuncND actionWithTarget:self selector:@selector(spriteMoveFinished:data:)data:adventurer]; adventurer.moveAction = [CCSequence actions:actionMove, actionMoveDone, nil]; [adventurer.charSprite runAction:adventurer.walkAction]; [adventurer.charSprite runAction:adventurer.moveAction]; 
补充:综合编程 , 其他综合 ,