周末闲着没事,搞了一个手机版的特训99,这是一款pc上的经典小游戏,就是满大街的“是男人就挺过20s”。游戏比较简单,通过手指拖动飞猪躲避四面八方的子弹,也算是学习cocos2d-x的小demo,主要的小知识点:

1. cocos2d-x实现帧动画
2. 使用Box2D进行碰撞检测
3. 一些粒子特效
4. cocos2d-x 3.0在android平台添加admob广告
5. xml解析和cocos2d-x显示中文
共三个场景:首页、游戏中、游戏结束。

首先切换到cocos2d-x-3.0alpha1\tools\project-creator目录,执行:

 python create_project.py -p SuperMan -k com.alexzhou.superman -l cpp
这篇文章我们要实现一只不停飞着的猪,就是咱们的英雄,然后用手指可以拖动它。
创建游戏的主角:飞猪,这里类命名为Plane,因为之前想用飞机素材的,后来发现飞机没有动画图片。飞猪的资源图片如下:

Plane类目前很简单,只有一个init函数,内容如下:

bool Plane::init()
{
 bool ret = false;
 do {
  CC_BREAK_IF(!this->initWithSpriteFrameName("hero_01.png"));
  auto self_anim = createAnimation("hero_%02d.png", 7, 10);
  this->runAction(RepeatForever::create(Animate::create(self_anim)));
  ret = true;
 }while(0);
 return ret;
}

一共7帧,因为第一帧和最后一帧图片是一样的,所以上面只看到六帧。
createAnimation是根据图片名、帧数、每帧时间创建动画的函数,以后的子弹类也用得到,可以抽出来作为一个工具函数使用。

Animation* createAnimation(const char* path, int frame_count, int fps)
{
 Array *frames = Array::createWithCapacity(frame_count);
 for(int i = 1; i <= frame_count; ++ i) {
  const char* img_name = String::createWithFormat(path, i)->getCString();
  //log("img_name=%s", img_name);
  SpriteFrame *frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(img_name);
  frames->addObject(frame);
 }
 return Animation::createWithSpriteFrames(frames, 1.0 / fps);
}

接下来删除引擎生成的HelloWorldScene.h和cpp文件,创建游戏的主场景GameScene类,前面创建的主角飞猪需要添加到场景中显示。代码如下:

class GameScene: public cocos2d::Layer
{
public:
 GameScene();

 virtual ~GameScene();

 virtual bool init();

 static cocos2d::Scene* scene();
 void onTouchesBegan(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event *unused_event);
 void onTouchesMoved(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event *unused_event);
 void onTouchesEnded(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event *unused_event);

CREATE_FUNC(GameScene);

private:
 Plane *_plane;
 bool _isFlying;
 cocos2d::Size _screenSize;
};

这里因为需要实现拖动飞猪,所以重写了onTouchesXXX这三个函数。三个变量分别是:飞猪、判断飞猪是否可以移动的变量、屏幕尺寸。
在init函数中添加Plane对象,设置它的坐标:

bool GameScene::init() 
{
 bool bRet = false;
 do
 {
  CC_BREAK_IF(! Layer::init());
  _screenSize = Director::getInstance()->getVisibleSize();
  auto origin = Director::getInstance()->getVisibleOrigin();

  SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pig.plist");

  _plane = Plane::create();
  _plane->setScale(2.0f);
  _plane->setPosition(Point(origin.x + _screenSize.width / 2, origin.y + _screenSize.height / 2));
  this->addChild(_plane, 100);

  auto listener = EventListenerTouchAllAtOnce::create();
  listener->onTouchesBegan = CC_CALLBACK_2(GameScene::onTouchesBegan, this);
  listener->onTouchesMoved = CC_CALLBACK_2(GameScene::onTouchesMoved, this);
  listener->onTouchesEnded = CC_CALLBACK_2(GameScene::onTouchesEnded, this);
  _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

  bRet = true;
 }while(0);
 return bRet;
}

cocos2d-x 3.0使用了c++ 11的特性,这里触摸函数使用了bind和function的方式,下面来实现这三个函数:

void GameScene::onTouchesBegan(const vector<Touch*>& touches, Event *unused_event)
{
 vector<Touch*>::const_iterator touchIter = touches.begin();
 Touch *pTouch = (Touch*)(*touchIter);
 Point location = pTouch->getLocation();
 Rect rect = _plane->getBoundingBox();

 if(rect.containsPoint(location))
 {
  _isFlying = true;
 }
}

void GameScene::onTouchesMoved(const vector<Touch*>& touches, Event *unused_event)
{
 vector<Touch*>::const_iterator touchIter = touches.begin();
 Touch *pTouch = (Touch*)(*touchIter);
 Point location = pTouch->getLocation();
 Point start = pTouch->getStartLocation();
 Point direction = (location - start).normalize();
 Rect screen = Rect(0, 0, _screenSize.width, _screenSize.height);

 if(_isFlying)
 {
  if(screen.containsPoint(location)) {
   _plane->setPosition(location);
  }
 }
}

void GameScene::onTouchesEnded(const vector<Touch*>& touches, Event *unused_event)
{
 _isFlying = false;
}

逻辑比较简单,没啥好说的。就是手指拖动飞猪的时候更新飞猪的坐标,然后判断只能在屏幕内拖动飞猪。
最后更新AppDelegate.cpp的代码,在director->setOpenGLView(eglView);后面添加:
eglView->setDesignResolutionSize(720, 1280, ResolutionPolicy::SHOW_ALL);
指定资源的分辨率为720×1280,然后把main.cpp中游戏窗口大小改成(360, 640)。

cocos2d-x手游性能优化总结

近段时间在使用cocos2d-x开发2D手游,技术方案使用的是cocos2d-x+lua,因为游戏使用的是cocos2d-x 2.1.5版本,有些优化方案在最新版的cocos2d-x版本已经实现...

阅读全文

cocos2dx-html5 实现网页版flappy bird游戏

我也是第一次使用cocos2d_html5,对js和html5也不熟,看引擎自带的例子和引擎源码,边学边做,如果使用过cocos2d-x的话,完成这个游戏还是十分简单的。游戏体...

阅读全文

【cocos2d-x开发实战 特训99-终结篇】移植到android平台和添加admob广告

上一篇已经完成特性99在win32平台下的开发,现在把它移植到android上,首先修改Android.mk文件,内容如下: LOCAL_PATH := $(call my-dir) include $(CLEAR_...

阅读全文

8 条评论

  1. 不好意思,我刚没说明白,刚学cocos2d-x,就是将飞机加入游戏场景中,创建飞机对象:_plane = Plane::create();这句会报这样的错误 error C2440: “=”: 无法从“cocos2d::Sprite *”转换为“Plane *”。求大神指点。。。

  2. 请问为什么出现这个错误 1 error C2440: “=”: 无法从“cocos2d::Sprite *”转换为“Plane *”

欢迎留言