这一篇我们为我们的飞船添加各种敌人飞船。
首先,我们准备一下敌人飞船的各种图片:
boss.png:
bigdaddy.png:
powermaker.png:
speedkiller.png:
littleworm.png:
自己随便画的,名字瞎起的,勿喷O_o。
接着我们用TexturePacker将这些敌人飞船纹理图和敌人的4种子弹组装起来,publish生成4个文件:
enemy-ships-hd.pvr.gz
enemy-ships-hd.plist
enemy-ships.pvr.gz
enemy-ships.plist
接着把这些文件添加到Resources中。
下面我们添加代码。由于敌人飞船在属性上有自己的一些特性,所以这里我们在Entity的基础上,再抽象出一个EnemyShip类,接着不同的敌人我们由EnemyShip派生出不同的子类。
来看EnemyShip.h的定义:
#import"Entity.h"
#import"AirCraft.h"
@interfaceEnemyShip : Entity{
float shootFrequency;
ccTime nextShootTime;
ccTime shootTotalTime;
ccTime movedTime;
ccTime changeDirectionTime;
int currentMoveX; //+-1
int currentMoveY; //+-1
int enemyScoreWorth;
}
-(id)initWithSpriteCache:(CCSprite*) spriteCache andSpeed:(float) speedandHealth:(float) health andBulletType:(BulletTypes) bulletTypeandShootFrequency:(float) shootFreq;
- (void)reset;
-(void)shootBullets;
-(void)moveWithLength:(float) length andAreaLimitation:(float) areaLimitationmovedTime:(float)delta;
@property(readonly) int scoreWorth;
@end
注意我们这里导入了AirCraft.h这个头文件,原因是,后面在派生敌人飞船的子类的时候,我们会实现敌人飞船向我们的飞船射击的方法,这些方法里面会用到AirCraft类,所以这里我们在EnemyShip这个父类里面导入这个头文件。
下面看一下EnemyShip的实现:
EnemyShip.m:
#import"EnemyShip.h"
#import"CommonUtility.h"
#import"BulletCacheManager.h"
@implementationEnemyShip
-(id)initWithSpriteCache:(CCSprite*) spriteCache
andSpeed:(float) s
andHealth:(float) h
andBulletType:(BulletTypes)bulletType
andShootFrequency:(float) shootFreq{
if (self = [super init]) {
speed = s;
health = h;
healthRecord = h;
shootFrequency = shootFreq;
entitySprite = [spriteCache retain];
entitySprite.anchorPoint = CGPointZero;
entitySprite.position = CGPointMake([CommonUtility utility].screenWidth,([CommonUtility utility].screenHeight-300)*CCRANDOM_0_1()+200);
entitySprite.visible = NO;
currentMoveX = -1;
currentMoveY = -1;
}
return self;
}
- (void)reset{
entitySprite.position = CGPointMake([CommonUtility utility].screenWidth,([CommonUtility utility].screenHeight-300)*CCRANDOM_0_1()+200);
entitySprite.color = ccWHITE;
entitySprite.visible = YES;
[self unscheduleAllSelectors];
[self schedule:@selector(showUp:)];
}
-(void)shootBullets{
//left empty, for child class to overwrite
}
-(void)update:(ccTime)delta{
// shootTotalTime += delta;
// if (shootTotalTime > nextShootTime) {
// [self shootBullets];
// nextShootTime = shootTotalTime +shootFrequency;
// }
}
-(void)showUp:(ccTime)delta{
if (self.position.x >= [CommonUtility utility].screenWidth - [entitySpritecontentSize].width-50) {
[self moveByX:-(300*delta) andY:0];
}else{
[self unschedule:_cmd];
nextShootTime = 0;
[self scheduleUpdate];
}
}
-(void)moveWithLength:(float) length andAreaLimitation:(float) areaLimitationmovedTime:(float)delta{
movedTime += delta;
if (movedTime > changeDirectionTime) {
[self resetCurrentMoveXandY];
changeDirectionTime = movedTime+4;
}
float xMove = length*currentMoveX;
float yMove = 0;
float selfX = self.position.x;
float selfY = self.position.y;
float selfHeight = self.height;
float selfWidth = self.width;
yMove = length*currentMoveY;
if (yMove+selfY < [CommonUtility utility].enemyMovementAreaHeight
|| yMove+selfY+selfHeight > [CommonUtility utility].screenHeight) {
yMove = -yMove;
currentMoveY = -currentMoveY;
}
if (xMove+selfX < areaLimitation || xMove+selfX+selfWidth >[CommonUtility utility].screenWidth) {
xMove = -xMove;
currentMoveX = -currentMoveX;
}
[self moveByX:xMove andY:yMove];
}
-(void)resetCurrentMoveXandY{
if (CCRANDOM_0_1() > 0.5) {
currentMoveX = 1;
}else{
currentMoveX = -1;
}
if (CCRANDOM_0_1() > 0.5) {
currentMoveY = 1;
}else{
currentMoveY = -1;
}
}
- (int)scoreWorth{
return enemyScoreWorth;
}
- (BOOL)visible{
return entitySprite.visible;
}
- (void)dealloc{
[super dealloc];
}
@end
解释一下两个属性,shootFrequency是敌人射击的频率,我们自己的飞船是通过按钮进行射击的,敌人飞船是通过这个时间间隔自动发射子弹的;enemyScoreWorth是这个敌人飞船代表的分数,玩家打掉这个类型的飞船后得到得响应分数,敌人飞船越厉害,自然这个属性就越高。
初始化方法和Reset方法中,敌人飞船对应的精灵均被置为不可见,showUp方法是做什么用的呢?其实就是我们之前提到的,让敌人从屏幕外面飞入屏幕中的方法。还有一个地方要提一下,moveWithLength:andAreaLimitation:movedTime:这个方法中,areaLimitation是敌人飞船水平移动范围,加入这个限制是因为我们不想让敌人的飞船在整个屏幕上乱飞,他们只需要在屏幕右侧飞行并且射击就好了。同样,[CommonUtilityutility].enemyMovementAreaHeight这个属性是敌人飞船垂直飞行的限制,我们知道前景的山这个图层会挡住所有的飞船,那么敌人飞船如果一直在玩家的是野外,游戏就不好玩儿了,所以我们加一个高度限制,让敌人飞船不能低于这个高度飞行。你可能要问,为什么水平范围要用参数来限制,这里我们想让不同的敌人水平活动范围不同,所以这里用参数来控制。
接着,我们从EnemyShip派生出敌人飞船类,这里我们派生出5中敌人飞船类:BigDaddyShip、LittleWormShip、BOSSShip、SpeedKillerShip和PowerMakerShip,附上他们的代码(我们这里略去他们的.h文件,只贴出.m文件,这些子类均继承EnemyShip类,并且不包含任何本地变量、属性、方法声明):
BigDaddyShip.m:
#import"BigDaddyShip.h"
@implementationBigDaddyShip
-(id)initWithSpriteCache:(CCSprite *)sprite andSpeed:(float)spdandHealth:(float)life andBulletType:(BulletTypes)btandShootFrequency:(float)sf{
if (self = [super initWithSpriteCache:sprite andSpeed:spd andHealth:lifeandBulletType:bt andShootFrequency:sf]) {
enemyScoreWorth = 300;
}
return self;
}
-(void)shootBullets{
[self shootBulletAtPosition:[self gunPosition] bulletType:BigEnemyBullet];
}
-(CGPoint)gunPosition{
return ccp(entitySprite.position.x + entitySprite.contentSize.width * 93 / 198,entitySprite.position.y + entitySprite.contentSize.height * 3 / 71);
}
-(void)update:(ccTime)delta{
[super update:delta];
shootTotalTime += delta;
if (shootTotalTime > nextShootTime) {
[self shootBullets];
nextShootTime = shootTotalTime + shootFrequency;
}
[self moveWithLength:speed*delta andAreaLimitation:[CommonUtilityutility].enemyMovementSmallAreaWidth movedTime:delta];
}
- (void)dealloc{
[super dealloc];
}
@end
我们重载了并调用父类的initWithSpriteCache方法进行初始化,在其基础上为enemyScoreWorth属性特殊赋值,重载了父类的shootBullets方法,定义了gunPosition方法来返回子弹的发射位置(参考AirCraft类的类似方法)。在update方法中操作敌人飞船移动和射击。
LittleWormShip.m:
#import"LittleWormShip.h"
@implementationLittleWormShip
-(id)initWithSpriteCache:(CCSprite *)sprite andSpeed:(float)spdandHealth:(float)life andBulletType:(BulletTypes)btandShootFrequency:(float)sf{
if (self = [super initWithSpriteCache:sprite andSpeed:spd andHealth:lifeandBulletType:bt andShootFrequency:sf]) {
enemyScoreWorth = 120;
}
return self;
}
-(void)shootBullets{
[self shootBulletAtPosition:[self gunPosition] atTarget:[AirCraftsharedAirCraft].aimPos bulletType:SmallEnemyBullet];
}
-(CGPoint)gunPosition{
return ccp(entitySprite.position.x, entitySprite.position.y +entitySprite.contentSize.height * 19 / 73);
}
-(void)update:(ccTime)delta{
[super update:delta];
shootTotalTime += delta;
if (shootTotalTime > nextShootTime) {
[self shootBullets];
nextShootTime = shootTotalTime + shootFrequency;
}
[self moveWithLength:speed*delta andAreaLimitation:[CommonUtilityutility].enemyMovementSmallAreaWidth movedTime:delta];
}
- (void)dealloc{
[super dealloc];
}
@end
PowerMakerShip.m:
#import"PowerMakerShip.h"
@implementationPowerMakerShip
-(id)initWithSpriteCache:(CCSprite *)sprite andSpeed:(float)spdandHealth:(float)life andBulletType:(BulletTypes)btandShootFrequency:(float)sf{
if (self = [super initWithSpriteCache:sprite andSpeed:spd andHealth:lifeandBulletType:bt andShootFrequency:sf]) {
enemyScoreWorth = 150;
}
return self;
}
-(void)shootBullets{
[self shootBulletAtPosition:[self gunPositionAtIndex:1]bulletType:PoweredEnemyBullet];
[self shootBulletAtPosition:[self gunPositionAtIndex:2]bulletType:PoweredEnemyBullet];
}
-(CGPoint)gunPositionAtIndex:(int) gunIndex{
if (gunIndex == 1) {
return ccp(entitySprite.position.x + entitySprite.contentSize.width * 4 / 118,entitySprite.position.y + entitySprite.contentSize.height * 40 / 58);
}else{
return ccp(entitySprite.position.x + entitySprite.contentSize.width * 20 / 118,entitySprite.position.y + entitySprite.contentSize.height * 18 / 58);
}
}
-(void)update:(ccTime)delta{
[super update:delta];
shootTotalTime += delta;
if (shootTotalTime > nextShootTime) {
[self shootBullets];
nextShootTime = shootTotalTime + shootFrequency;
}
[self moveWithLength:speed*delta andAreaLimitation:[CommonUtilityutility].enemyMovementSmallAreaWidth movedTime:delta];
}
- (void)dealloc{
[super dealloc];
}
@end
SpeedKillerShip.m:
#import"SpeedKillerShip.h"
@implementationSpeedKillerShip
-(id)initWithSpriteCache:(CCSprite *)sprite andSpeed:(float)spdandHealth:(float)life andBulletType:(BulletTypes)btandShootFrequency:(float)sf{
if (self = [super initWithSpriteCache:sprite andSpeed:spd andHealth:lifeandBulletType:bt andShootFrequency:sf]) {
enemyScoreWorth = 180;
}
return self;
}
-(void)shootFastBullets{
Entity* player = [AirCraft sharedAirCraft];
[self shootBulletAtPosition:[self gunPositionAtIndex:1] atTarget:player.aimPosbulletType:SmallEnemyBullet];
[self shootBulletAtPosition:[self gunPositionAtIndex:2] atTarget:player.aimPosbulletType:SmallEnemyBullet];
}
-(void)shootPoweredBullet{
[self shootBulletAtPosition:[self gunPositionAtIndex:3]bulletType:PoweredEnemyBullet];
}
-(CGPoint)gunPositionAtIndex:(int) gunIndex{
if (gunIndex == 1) {
return ccp(entitySprite.position.x + entitySprite.contentSize.width * 9 / 80,entitySprite.position.y + entitySprite.contentSize.height * 50 / 65);
}else if (gunIndex == 2){
return ccp(entitySprite.position.x + entitySprite.contentSize.width * 39 / 80,entitySprite.position.y + entitySprite.contentSize.height * 50 / 65);
}else{
return ccp(entitySprite.position.x + entitySprite.contentSize.width * 8 / 80,entitySprite.position.y + entitySprite.contentSize.height * 20 / 65);
}
}
-(void)update:(ccTime)delta{
[super update:delta];
shootTotalTime += delta;
if (shootTotalTime > nextShootTime) {
if (CCRANDOM_0_1() > 0.3) {
[self shootFastBullets];
}else{
[self shootPoweredBullet];
}
nextShootTime = shootTotalTime + shootFrequency;
}
[self moveWithLength:speed*delta andAreaLimitation:[CommonUtilityutility].enemyMovementSmallAreaWidth movedTime:delta];
}
- (void)dealloc{
[super dealloc];
}
@end
这里我们的SpeedKillerShip能够发射两种不同的子弹,选择发射那种子弹随机决定。
BOSSShip.m:
#import"BOSSShip.h"
#import"GameLayer.h"
#import"SimpleAudioEngine.h"
@implementationBOSSShip
staticNSMutableArray* bossGunPositionsData;
-(id)initWithSpriteCache:(CCSprite *)sprite andSpeed:(float)spdandHealth:(float)life andBulletType:(BulletTypes)btandShootFrequency:(float)sf{
if (self = [super initWithSpriteCache:sprite andSpeed:spd andHealth:lifeandBulletType:bt andShootFrequency:sf]) {
enemyScoreWorth = 1000;
}
return self;
}
+(NSMutableArray*) bossGunPositions{
if (bossGunPositionsData == nil) {
bossGunPositionsData = [[NSMutableArray arrayWithObjects:
[NSValue valueWithCGPoint:ccp(10, 30)],
[NSValuevalueWithCGPoint:ccp(11, 40)],
[NSValue valueWithCGPoint:ccp(12, 50)],
[NSValue valueWithCGPoint:ccp(13, 60)],
[NSValue valueWithCGPoint:ccp(14, 70)],
[NSValue valueWithCGPoint:ccp(15, 80)],
[NSValue valueWithCGPoint:ccp(16, 90)],
[NSValue valueWithCGPoint:ccp(16, 100)],
[NSValuevalueWithCGPoint:ccp(17, 110)],
[NSValue valueWithCGPoint:ccp(20, 40)],
[NSValue valueWithCGPoint:ccp(30, 50)],
[NSValue valueWithCGPoint:ccp(40, 60)],
[NSValue valueWithCGPoint:ccp(40, 80)],
[NSValue valueWithCGPoint:ccp(41, 100)],
[NSValue valueWithCGPoint:ccp(42, 120)],
[NSValuevalueWithCGPoint:ccp(44, 140)],
[NSValue valueWithCGPoint:ccp(45, 160)],
[NSValue valueWithCGPoint:ccp(74, 143)],
[NSValue valueWithCGPoint:ccp(84, 141)],
[NSValue valueWithCGPoint:ccp(94, 138)],
[NSValue valueWithCGPoint:ccp(107, 135)],
[NSValue valueWithCGPoint:ccp(119, 131)],
[NSValuevalueWithCGPoint:ccp(129, 128)],
[NSValue valueWithCGPoint:ccp(143, 114)],
[NSValue valueWithCGPoint:ccp(89, 93)],
nil] retain];
}
return bossGunPositionsData;
}
-(void)shootCircleBullets{
if ([AirCraft sharedAirCraft].position.x < self.position.x) {
for (int i = -80; i < 90; i += 10) {
[self shootBulletAtPosition:[self gunPositionAtIndex:24] atAngle:ibulletType:BOSSBullet];
}
}else{
for (int i = 100; i < 260; i += 10) {
[self shootBulletAtPosition:[self gunPositionAtIndex:24] atAngle:ibulletType:BOSSBullet];
}
}
}
-(void)shootRandomBullets{
for (int i = 0; i < 30; i++) {
[self shootBulletAtPosition:[self gunPositionAtIndex:i]atAngle:CCRANDOM_0_1()*360 bulletType:SmallEnemyBullet];
}
}
-(void)shootAtPlayer{
int gunCount = [[BOSSShip bossGunPositions] count];
CGPoint playerPos = [AirCraft sharedAirCraft].aimPos;
float x = playerPos.x+gunCount;
float y = playerPos.y-gunCount;
for (int i = 0; i < gunCount; i++) {
[self shootBulletAtPosition:[self gunPositionAtIndex:i] atTarget:ccp(x-2*i,y+2*i) bulletType:BOSSBullet];
}
}
-(CGPoint)gunPositionAtIndex:(int) index{
index = index%[[BOSSShip bossGunPositions] count];
CGPoint gunPos = [[[BOSSShip bossGunPositions] objectAtIndex:index]CGPointValue];
return ccp(entitySprite.position.x + entitySprite.contentSize.width *gunPos.x/178, entitySprite.position.y + entitySprite.contentSize.height *gunPos.y/185);
}
-(void)update:(ccTime)delta{
[super update:delta];
shootTotalTime += delta;
if (shootTotalTime > nextShootTime) {
float rand = CCRANDOM_0_1();
if (rand > 0.7) {
[self shootCircleBullets];
}else if (rand > 0.3){
[self shootRandomBullets];
}else{
[self shootAtPlayer];
}
nextShootTime = shootTotalTime + shootFrequency;
}
[self moveWithLength:speed*delta andAreaLimitation:[CommonUtilityutility].enemyMovementLargeAreaWidth movedTime:delta];
}
- (void)explode{
}
- (void)dealloc{
if (bossGunPositionsData != nil) {
[bossGunPositionsData release];
bossGunPositionsData = nil;
}
[super dealloc];
}
@end
BOSS的子弹发射位置比较多,我们定义了一个数组方便我们获取,此外,BOSS能够发射三种子弹,代码比较容易懂,就不多做解释了。
好了,貌似离胜利不远了,我们下面开始考虑向场景中添加敌人了。首先,我们的场景中除了BOSS之外,其他类型的敌人飞船也会有很多一起出现,那么又回到那个问题,他们使用相同的纹理贴图!这个时候我们很自然地想到CCSpriteBatchNode,没错,还是用Cache来做。
首先我们添加EnemyShipCache类,EnemyShipCache.h定义如下:
#import"CCNode.h"
#import"EnemyShip.h"
#import"cocos2d.h"
#import"BigDaddyShip.h"
#import"LittleWormShip.h"
#import"SpeedKillerShip.h"
#import"PowerMakerShip.h"
#import"BOSSShip.h"
@interfaceEnemyShipCache : CCNode{
int nextIdleEnemyCachePosData;
CCSpriteBatchNode* enemysSpriteBatchNode;
NSMutableArray* enemyCaches;
}
@property(readonly) CCSpriteBatchNode* enemysSpriteBatchNode;
-(id)initWithFrameName:(NSString*) frameName
cacheCount:(int) cacheCount
andSpeed:(float) speed
andHealth:(float) health
andBulletType:(BulletTypes) bulletType
andShootFrequency:(float) shootFreq
enemyShipType:(EnemyShipTypes) enemyShipType;
-(EnemyShip*)nextIdleEnemyShip;
@property intnextIdleEnemyCachePos;
@end
EnemyShipCache.m的代码:
#import"EnemyShipCache.h"
@implementationEnemyShipCache
+(Class)getClassFromShipType:(EnemyShipTypes) shipType{
switch (shipType) {
case LittleWorm:
return [LittleWormShip class];
case BigDaddy:
return [BigDaddyShip class];
case SpeedKiller:
return [SpeedKillerShip class];
case PowerMaker:
return [PowerMakerShip class];
case BOSS:
return [BOSSShip class];
default:
return nil;
break;
}
} //getClassFromShipType
-(id)initWithFrameName:(NSString*) frameName
cacheCount:(int) cacheCount
andSpeed:(float) speed
andHealth:(float) health
andBulletType:(BulletTypes) bulletType
andShootFrequency:(float) shootFreq
enemyShipType:(EnemyShipTypes) enemyShipType{
if (self = [super init]) {
nextIdleEnemyCachePosData = 0;
enemyCaches = [[NSMutableArray arrayWithCapacity:cacheCount] retain];
CCSpriteFrameCache* frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
CCSpriteFrame* frame = [frameCache spriteFrameByName:frameName];
enemysSpriteBatchNode = [CCSpriteBatchNode batchNodeWithTexture:frame.texture];
enemysSpriteBatchNode.tag = 2000;
for (int i = 0; i < cacheCount; i++) {
CCSprite* enemyShipCache = [[CCSprite spriteWithSpriteFrameName:frameName]autorelease];
[enemysSpriteBatchNode addChild:enemyShipCache];
EnemyShip* enemyCache = [[[[EnemyShipCache getClassFromShipType:enemyShipType]alloc] initWithSpriteCache:enemyShipCache andSpeed:speed andHealth:healthandBulletType:bulletType andShootFrequency:shootFreq] autorelease];
[enemyCaches addObject:enemyCache];
}
}
return self;
} //initWithFrameName
-(CCSpriteBatchNode*)enemysSpriteBatchNode{
return enemysSpriteBatchNode;
} //enemysSpriteBatchNode
-(EnemyShip*)nextIdleEnemyShip{
EnemyShip* ship = [enemyCaches objectAtIndex:self.nextIdleEnemyCachePos];
if (ship.visible == NO) {
return ship;
}else{
return nil;
}
} //nextIdleEnemyShip
-(int)nextIdleEnemyCachePos{
int tempId = nextIdleEnemyCachePosData;
nextIdleEnemyCachePosData++;
if (nextIdleEnemyCachePosData >= [[enemysSpriteBatchNode children] count]) {
nextIdleEnemyCachePosData = 0;
}
return tempId;
} //nextIdleEnemyCachePos
-(void)setNextIdleEnemyCachePos:(int)nextIdleEnemyCachePos{
nextIdleEnemyCachePosData = nextIdleEnemyCachePos;
} //setNextIdleEnemyCachePos
- (void)dealloc{
[enemyCaches removeAllObjects];
[enemyCaches release];
[super dealloc];
} //dealloc
@end
唯一和之前BulletCache不同的是我们把EnemyShip的CCSprite属性添加到了CCSpriteBatchNode中去,这是因为EnemyShip不继承CCSprite,不能直接添加到CCSpriteBatchNode里,此外,我们添加了一个枚举和类转化的静态方法,剩下的其他的方法都和BulletCache类似。
接着我们来添加EnemyShipCacheManager类:
EnemyShipCacheManager.h:
#import"CCNode.h"
#import"EnemyShip.h"
#import"EnemyShipCache.h"
@interfaceEnemyShipCacheManager : CCNode{
NSMutableDictionary* enemyshipCacheMapData;
}
+(EnemyShipCacheManager*) sharedEnemyShipCacheManager;
-(EnemyShip*)getEnemyShip:(EnemyShipTypes) enemyShipType;
-(void)addEnemyShipCacheWithType:(EnemyShipTypes) enemyShipType
bulletType:(BulletTypes) bulletType
shipCacheCount:(int) shipCacheCount
shipFrameName:(NSString*) shipFrameName
shipSpeed:(float) speed
shipHealth:(float) health
shipShootFreq:(float) shootFreq;
@property(readonly) NSMutableDictionary* enemyshipCacheMap;
@end
EnemyShipCacheManager.m:
#import"EnemyShipCacheManager.h"
@implementationEnemyShipCacheManager
staticEnemyShipCacheManager* sharedEnemyShipCache;
+(EnemyShipCacheManager*) sharedEnemyShipCacheManager{
if (sharedEnemyShipCache == nil) {
sharedEnemyShipCache = [[[EnemyShipCacheManager alloc] init] autorelease];
}
return sharedEnemyShipCache;
} //sharedEnemyShipCacheManager
- (id)init{
if (self = [super init]) {
enemyshipCacheMapData = [[NSMutableDictionary dictionaryWithCapacity:5]retain];
[self addEnemyShipCacheWithType:SpeedKiller bulletType:SmallEnemyBulletshipCacheCount:40 shipFrameName:@"speedkiller.png" shipSpeed:240shipHealth:100 shipShootFreq:1.1];
[self addEnemyShipCacheWithType:PowerMaker bulletType:PoweredBulletshipCacheCount:30 shipFrameName:@"powermaker.png" shipSpeed:100shipHealth:500 shipShootFreq:1.2];
[self addEnemyShipCacheWithType:LittleWorm bulletType:SmallEnemyBulletshipCacheCount:40 shipFrameName:@"littleworm.png" shipSpeed:150shipHealth:200 shipShootFreq:0.8];
[self addEnemyShipCacheWithType:BigDaddy bulletType:BigEnemyBulletshipCacheCount:20 shipFrameName:@"bigdaddy.png" shipSpeed:60shipHealth:1500 shipShootFreq:1.3];
[self addEnemyShipCacheWithType:BOSS bulletType:BOSSBullet shipCacheCount:1shipFrameName:@"boss.png" shipSpeed:30 shipHealth:10000shipShootFreq:1.6];
}
return self;
} //init
-(void)addEnemyShipCacheWithType:(EnemyShipTypes) enemyShipType
bulletType:(BulletTypes) bulletType
shipCacheCount:(int) shipCacheCount
shipFrameName:(NSString*) shipFrameName
shipSpeed:(float) speed
shipHealth:(float) health
shipShootFreq:(float) shootFreq{
EnemyShipCache* enemyShipCache = [[[EnemyShipCache alloc]initWithFrameName:shipFrameName cacheCount:shipCacheCount andSpeed:speedandHealth:health andBulletType:bulletType andShootFrequency:shootFreqenemyShipType:enemyShipType] autorelease];
[self.enemyshipCacheMap setObject:enemyShipCache forKey:[NSNumbernumberWithInt:enemyShipType]];
[self addChild:enemyShipCache];
} //addEnemyShipCacheWithType
-(EnemyShip*)getEnemyShip:(EnemyShipTypes)enemyShipType{
EnemyShipCache* enemyShipCache = [self.enemyshipCacheMap objectForKey:[NSNumbernumberWithInt:enemyShipType]];
return [enemyShipCache nextIdleEnemyShip];
} //getEnemyShip
-(NSMutableDictionary*)enemyshipCacheMap{
return enemyshipCacheMapData;
} //enemyshipCacheMap
- (void)dealloc{
[enemyshipCacheMapData removeAllObjects];
[enemyshipCacheMapData release];
[sharedEnemyShipCache release];
sharedEnemyShipCache = nil;
[super dealloc];
} //dealloc
@end
和BulletCacheManager类似,我们也不多做说明了。
接着,我们需要在BulletCacheManager中添加敌人飞机的子弹Cache,修改BulletCacheManager的init方法如下:
- (id)init{
if (self = [super init]) {
bulletCacheMapData = [[NSMutableDictionary dictionaryWithCapacity:5] retain];
[self addBulletCacheWithType:PoweredBullet bulletCacheCount:100bulletFrameName:@"bullet.png" bulletSpeed:CGPointMake(500, 0)bulletDamage:80];
[self addBulletCacheWithType:SmallRoundBullet bulletCacheCount:300bulletFrameName:@"roundBullets.png" bulletSpeed:CGPointMake(800, 0)bulletDamage:40];
[self addBulletCacheWithType:SmallEnemyBullet bulletCacheCount:300bulletFrameName:@"smallenemybullet.png" bulletSpeed:CGPointMake(-550,100) bulletDamage:20];
[self addBulletCacheWithType:BigEnemyBullet bulletCacheCount:200bulletFrameName:@"bigenemybullet.png" bulletSpeed:CGPointMake(-380,0) bulletDamage:50];
[self addBulletCacheWithType:BOSSBullet bulletCacheCount:200bulletFrameName:@"bossbullet.png" bulletSpeed:CGPointMake(-280, 100)bulletDamage:80];
[self addBulletCacheWithType:PoweredEnemyBullet bulletCacheCount:100bulletFrameName:@"poweredenemybullet.png"bulletSpeed:CGPointMake(-330, 0) bulletDamage:150];
}
return self;
} //init
接着我们修改GameLayer来测试一下:
首先在GameLayer的initCaches方法中添加下面的代码:
[frameCacheaddSpriteFramesWithFile:@"enemy-ships.plist"];
EnemyShipCacheManager*enemyShipCacheManager = [EnemyShipCacheManager sharedEnemyShipCacheManager];
[self addChild:enemyShipCacheManager z:-1 tag:EnemyShipCacheManagerTag];
for (EnemyShipCache* enemyShipCache in [[enemyShipCacheManagerenemyshipCacheMap] objectEnumerator]) {
[self addChild:enemyShipCache.enemysSpriteBatchNode];
}
将敌人飞船的纹理贴图加载到Cache中,并且将敌人飞船的CCSpriteBatchNode加入当前层(不然无法渲染)。接着我们添加一个测试方法:
-(void)addEnemies{
EnemyShip* enemyShip = [[EnemyShipCacheManager sharedEnemyShipCacheManager]getEnemyShip:BOSS];
[self addChild:enemyShip z:3];
[enemyShip reset];
enemyShip = [[EnemyShipCacheManager sharedEnemyShipCacheManager]getEnemyShip:BigDaddy];
[self addChild:enemyShip z:3];
[enemyShip reset];
enemyShip = [[EnemyShipCacheManager sharedEnemyShipCacheManager]getEnemyShip:LittleWorm];
[self addChild:enemyShip z:3];
[enemyShip reset];
enemyShip = [[EnemyShipCacheManager sharedEnemyShipCacheManager]getEnemyShip:SpeedKiller];
[self addChild:enemyShip z:3];
[enemyShip reset];
enemyShip = [[EnemyShipCacheManager sharedEnemyShipCacheManager]getEnemyShip:PowerMaker];
[self addChild:enemyShip z:3];
[enemyShip reset];
}
这个方法向当前层中添加了各种类型的敌人飞船用于测试。
然后再init方法中在添加玩家飞船之后调用[selfaddEnemies];
好了,我们编译运行一下,效果如下图:
这一篇就到这儿,下一篇我们会完成GameLayer的制作,把所有的基本元素都补全。