Cocos2D开发教程:Caterpillar游戏的移动和飞弹
- UID
- 863148
|
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)ccTouchBeganUITouch *)touch withEventUIEvent *)event {
- return YES;
- }
- // 2
- - (void)ccTouchMovedUITouch *)touch withEventUIEvent *)event {
- // 3
- CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
- CGPoint oldTouchLocation = [touch previousLocationInView:touch.view];
- oldTouchLocation = [[CCDirector sharedDirector] convertToGLldTouchLocation];
- oldTouchLocation = [self convertToNodeSpaceldTouchLocation];
- // 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)updateccTime)dt;
- @end
其中dirty属性会在将来代表飞散无法使用。可能由于游戏角色越出边界或者和其他游戏物体碰撞。因为飞弹永久失效,需要一阿update方法来做出一个动画效果。
现在往Missile.m里面加入以下代码:
- #import "Missile.h"
- #import "GameLayer.h"
- #import "GameConfig.h"
- @implementation Missile
- @synthesize dirty = _dirty;
- // 1
- - (id)initWithGameLayerGameLayer *)layer {
- if(self == [super initWithGameLayer:layer]) {
- self.sprite = [CCSprite spriteWithSpriteFrameName"missile.png"];
- }
- return self;
- }
- - (void)updateccTime)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)updateccTime)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(精灵)
最后实现的效果。
|
|
|
|
|
|