标题:
Cocos2D开发教程:Caterpillar游戏的移动和飞弹
[打印本页]
作者:
Dianzizd
时间:
2011-12-28 23:00
标题:
Cocos2D开发教程:Caterpillar游戏的移动和飞弹
Tut7做了一利用Cocos2D引擎来制作毛虫游戏的个
系列教程
,并提供了详细的代码。我们节选了其中
关于移动和导弹的教程
,希望能够为开发者带来帮助。Cocos2D是一个开源2D游戏框架,分别有Python版本和Objective-C版本。其衍生出一个跨平台版本叫做Cocos2D-x。如果你也在用Cocos2D-x开发的话,也可以到CSDN发起的
跨平台开发工具调查
中,投上一票,或者吐上一槽。
第一步:操控游戏角色
加入以下代码到GameLayer.m的init方法里:
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
这行代码允许GmaiLayer陈为一个触控代理去接受触控通知。现在,我们家两个方法进去:
// 1
- (BOOL)ccTouchBegan
UITouch *)touch withEvent
UIEvent *)event {
return YES;
}
// 2
- (void)ccTouchMoved
UITouch *)touch withEvent
UIEvent *)event {
// 3
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
CGPoint oldTouchLocation = [touch previousLocationInView:touch.view];
oldTouchLocation = [[CCDirector sharedDirector] convertToGL
ldTouchLocation];
oldTouchLocation = [self convertToNodeSpace
ldTouchLocation];
// 4
int xChange = touchLocation.x - oldTouchLocation.x;
int yChange = touchLocation.y - oldTouchLocation.y;
int newX = self.player.position.x + xChange;
int newY = self.player.position.y + yChange;
// 5
іf(newX <
kGameAreaStartX + kGameAreaWidth - kGridCellSize &&
newX > kGameAreaStartX &&
newY > kGameAreaStartY + kGridCellSize / 2 &&
newY <
kGameAreaStartY + (kGridCellSize * 3)) {
__block BOOL collide = NO;
CGPoint oldPosition = self.player.position;
// 6
self.player.position = ccp(newX,newY);
// 7
[self.sprouts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *ѕtοр) {
Sprout *sprout = (Sprout *)obj;
CGRect sproutRect = [sprout getBounds];
CGRect playerRect = [self.player getBounds];
іf(CGRectIntersectsRect(sproutRect, playerRect)) {
collide = YES;
*ѕtοр = YES;
}
}];
// 8
іf(collide) {
self.player.position = oldPosition;
}
}
}
让我们对这些代码做一些注释:
首先我们需要实现ccTouchesBegan方法,使得调用器知道我们正在响应触控操作。一旦遗漏程序就会崩溃。
接下来,用户手指在屏幕上滑动时候调用ccTouchesMoved方法方法。
获取当前触摸位置的坐标引用,和之前的坐标。
获取新旧位置的变化,用来定义下一步游戏角色应该怎走多远。
至此我们得到了一串方格来确保角色不会约出边界。
更新角色的位置。
检查是否角色会碰上障碍。我们需要严格限定角色的走位。
最后,如果有碰撞,则回到上一个比较安全的位置。
第二步:飞弹
为了让角色和其他目标进行互动,游戏角色会以一个恒定的速率发射当前级别的飞弹。我们得先需要几个常数,在GameConfig.h里加上以下代码:
#define kMissileSpeed 1.0
#define kMissileMaxSpeed 10.0
#define kMissilesTotal 20
#define kMissileFrequency .6 //seconds
#define kMinMissileFrequency .2
现在创建一个GameObject subclass,命名为Missile,然后把以下代码加到Missile.h里:
#import "cocos2d.h"
#import "GameObject.h"
@interface Missile : GameObject
@property (nonatomic, assign) BOOL dirty;
- (void)update
ccTime)dt;
@end
其中dirty属性会在将来代表飞散无法使用。可能由于游戏角色越出边界或者和其他游戏物体碰撞。因为飞弹永久失效,需要一阿update方法来做出一个动画效果。
现在往Missile.m里面加入以下代码:
#import "Missile.h"
#import "GameLayer.h"
#import "GameConfig.h"
@implementation Missile
@synthesize dirty = _dirty;
// 1
- (id)initWithGameLayer
GameLayer *)layer {
if(self == [super initWithGameLayer:layer]) {
self.sprite = [CCSprite spriteWithSpriteFrameName
"missile.png"];
}
return self;
}
- (void)update
ccTime)dt {
// 2
int inc = kMissileSpeed * (self.gameLayer.level + 1.5);
// 3
if(inc > kMissileMaxSpeed) {
inc = kMissileMaxSpeed;
}
// 4
int y = self.position.y + inc;
self.position = ccp(self.position.x,y);
// 5
if(self.position.y > kGameAreaStartY + kGameAreaHeight) {
self.dirty = YES;
}
}
@end
这里的init方法和之相似,之负责创建飞弹。
飞弹的移动速度。会根据当前级别进行加速。
有时候飞弹的速度会失控,我们需要限制一个最大速度。
这两行代码实际上是让飞弹超前运动,我们计算一个新飞弹的y值,同时更新位置。
最后,如果飞弹碰撞到顶部边框(没有碰到障碍物),就设置成_dirty属性为真。我们会在GmaeLayer里使用垃圾回收机制将这些dirty的飞弹回收掉。
第三步:开火
通常当你有一大票的对象,比如飞弹这种,你绝对不想每次都重新分配。因此我们需要创建两个数组,一个用来hold住所有发出的飞弹(in play),另一个hold住还未发出的飞弹(pool)。最后我们把所有dirty属性的飞弹都放到pool数组里面。
将以下属性添加到GameLayer.h:
@property (nonatomic, retain) NSMutableArray *missilesWaiting;
@property (nonatomic, retain) NSMutableArray *missilesFiring;
然后在GameLayer.m中import Missile.h,在init方法中加入以下代码:
// 1
_missilesWaiting = [[NSMutableArray alloc] initWithCapacity:kMissilesTotal];
_missilesFiring = [[NSMutableArray alloc] initWithCapacity:kMissilesTotal];
// 2
for(int x = 0; x < kMissilesTotal; x++) {
Missile *missile = [[Missile alloc] initWithGameLayer:self];
[self.missilesWaiting addObject:missile];
[missile release];
}
初始化每个飞弹数组。
循环kMissilesTotal几次,创建足够多的飞弹。然后将它们添加到missilesWaiting数组。
然后跳转到update方法,添加以下代码:
// 1
static
float missleFireCount = 0;
- (void)update
ccTime)dt {
// ...Caterpillar code...
// 2
float frequency = kMinMissileFrequency;
if(kMissileFrequency / (self.level * 1.25) > kMinMissileFrequency) {
frequency = kMissileFrequency / self.level;
}
// 3
if(missleFireCount < frequency) {
missleFireCount += dt;
} else {
missleFireCount = 0;
// 4
if([self.missilesWaiting count] > 0) {
Missile *missile = [self.missilesWaiting objectAtIndex:0];
[self.missilesFiring addObject:missile];
[self.missilesWaiting removeObjectAtIndex:0];
missile.position = self.player.position;
[self.spritesBatchNode addChild:missile.sprite];
}
}
// 5
__block Missile *dirty = nil;
[self.missilesFiring enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
Missile *missile = (Missile *)obj;
[missile update:dt];
if(missile.dirty) {
dirty = missile;
*stop = YES;
}
}];
// 6
if(dirty) {
dirty.dirty = NO;
[self.missilesWaiting addObject:dirty];
[self.missilesFiring removeObject:dirty];
[self.spritesBatchNode removeChild:dirty.sprite cleanup:NO];
}
}
我们需要创建一个静态计数器。
计算飞弹开火频率,不同级别有不同的开火频率。
如果频率更快,或者达到的级别,就释放一种新的飞弹。
把一个飞弹拉出pool的数组,把它加到正在开火的数组中。
枚举所有的飞弹,检查是否有dirty属性的飞弹。一旦发现,标记它以便移回pool的数组里。
如果有dirty属性的飞弹,从pool数组里移动到正在开火的数组同时从batch node中移除sprite(精灵)
最后实现的效果。
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0