标签:cocos2d-x 游戏 github android 博客
在 cocos2d-x之道~制作第一款文字游戏(一)中,使用cocos2d-x把主界面显示出来,分别有每个级别提供的初始短语TileView,和目标短语TargetView。初步接触了cocos2d-x的基本概念和基础用法。这篇博客将会基本实现游戏的逻辑,完成游戏的主体部分。采用以下步骤:
使TileView可拖动
捕获TileView停止移动的事件
分析TileView是否放在正确的位置上
创建与原来Layer区分的层,放置按钮、菜单和分数等等。
添加计时和分数
现在开始,继续cocos2d-x之道!
1) 拖放TileView
在TileView的initWithLetter函数中,其实还有一部分工作没完成。现在要实现拖放效果,就得让TileView处理手势事件,在函数的最后添加下面代码
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(tile,0,true);
class TileView: public CCNode, public CCTargetedTouchDelegate
int xOffset; int yOffset; bool isControl;
bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
实现这几个重要函数前,先把isControl初始化,同样是在initWithLetter的最后添加
tile->isControl = false;
bool TileView::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){ if(!containTouchLocation(pTouch)){ return false; } isControl = true; this->setZOrder(999); CCPoint point = pTouch->getLocationInView(); CCPoint touchPoint = CCDirector::sharedDirector()->convertToGL(point); this->xOffset = touchPoint.x - this->getPositionX(); this->yOffset = touchPoint.y - this->getPositionY(); return true; } void TileView::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent){ if(!isControl){ return; } CCPoint point = pTouch->getLocationInView(); CCPoint touchPoint = CCDirector::sharedDirector()->convertToGL(point); float x = touchPoint.x - this->xOffset; float y = touchPoint.y - this->yOffset; this->setPosition(ccp(x,y)); } void TileView::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){ CCPoint point = pTouch->getLocationInView(); CCPoint touchPoint = CCDirector::sharedDirector()->convertToGL(point); if(isControl){ isControl = false; } } void TileView::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent){ ccTouchEnded(pTouch, pEvent); }
ccTouchMoved就是在拖动过程中,不断的改变TileView的坐标,记得把偏移量减掉。
ccTouchEnded就是手指离开屏幕了,把isControl重新设为false。可以看出,isControl的作用就是控制在整个手势过程中,标记TileView是否被拖动着。当ccTouchEnded或者ccTouchCancelled后,就需要复原。
运行一下,是否可以拖动了?神奇吧。
2) 放下TileView
拖动TileView后,总会有放下的一刻。当放下TileView时,我们就要判断它是否被放在正确的目标TargetView上。这些判断需要MainScene去处理,所以得建立一个TileDropDelegate
class TileDropDelegate{ public: virtual void dropToPoint(TileView * tile,cocos2d::CCPoint point) = 0; };
class MainScene : public cocos2d::CCLayer, public TileDropDelegate
实现dropToPoint方法
void MainScene::dropToPoint(TileView * tile,CCPoint point){ TargetView * target = NULL; CCObject * tv; CCARRAY_FOREACH(pTargets,tv){ TargetView* pTarget = (TargetView*) tv; if(pTarget->containPoint(point)){ target = pTarget; break; } } }
if(target != NULL){ if(target->getLetter() == tile->getLetter()){ // 1 单词匹配 }else{ // 2 单词不匹配 } }1.检查拖动的TileView所代表的字母与TargetView的字母(不可见)是匹配
2.两个字母是不匹配的,需要进行后续工作
实现了回调函数,还得设置进去给TileView,在dealRandomAnagram中的 tile->randomize(); 这句后面添加
tile->setTileDropDelegate(this);记得在TileView类里添加setTileDropDelegate函数。
然后,就进行字母匹配后处理,需要将TileView覆盖到TargetView上,
void MainScene::placeTile(TileView * tile,TargetView * target){ tile->setMatch(true); target->setMatch(true); tile->removeTouchDelegate(); CCActionInterval * actionTo = CCMoveTo::create(0.35,ccp(target->getPositionX(),target->getPositionY())); tile->runAction(actionTo); tile->setRotation(0); target->setVisible(false); }代码中把tile和target设置成已匹配,去掉tile的拖放代理,使用CCMoveTo把tile移动到target位置上,并摆正
在1 单词匹配后添加以下语句
placeTile(tile,target);在2 单词不匹配后添加
tile->randomize(); CCActionInterval * actionTo = CCMoveTo::create(0.35, ccp(tile->getPositionX() + Common::random(-20,20), tile->getPositionY() + Common::random(-20,30))); tile->runAction(actionTo);
有了检测匹配函数,就可以判断是否成功完成游戏。在MainScene中添加
void MainScene::checkForSuccess(){ CCObject * tv; CCARRAY_FOREACH(pTargets,tv){ TargetView* pTarget = (TargetView*) tv; if(pTarget->getIsMatch() == false){ return; } } CCLog("Game Over!"); }
checkForSuccess();运行游戏,就会发现当所有字母都匹配了,就能打印出Game Over消息
3) 创建HUD层
这是一种游戏设计理念,就是把游戏一些界面上的东西分离到HUD层上,这层的内容主要作用是辅助游戏内容,比如倒计时,按钮,结束界面等等
首先,我们来创建倒计时,类名为StopWatchView,头文件如下
class StopWatchView : public CCLabelAtlas{ public: StopWatchView(){} static StopWatchView * initView(); void setSecond(int seconds); CREATE_FUNC(StopWatchView); };主体部分为setSecond是把秒数拆分成mm:ss形式
void StopWatchView::setSecond(int second){ char strTime[50]; float minutes = second / 60; minutes = (minutes > 0.0) ? floor(minutes + 0.5) : ceil(minutes - 0.5); int minu = (int)minutes; int sec = second % 60; sprintf(strTime," %02d:%02d",minu,sec); this->setString(strTime); }下面创建HUDView,头文件如下
class HUDView : public CCLayer{ public: // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone virtual bool init(); // implement the "static node()" method manually CREATE_FUNC(HUDView); private: StopWatchView * pWatch; CounterPointView * pPointView; CCMenuItemImage * pButton; CCMenu * pMenu; CCLabelTTF * pLabel; public: friend class MainScene; };其中,CounterPointView, CCmenuItemImage, CCMenu, CCLabelTTF这些是以后使用。friend class MainScene是让MainScene可以访问HUDView的成员变量。
HUDView.cpp 内只有一个函数,如
bool HUDView::init(){ if(! CCLayer::init()){ return false; } pWatch = StopWatchView::initView(); pWatch->setSecond(0); pWatch->setPosition(ccp(Common::getCameraWith()*0.5, Common::getCameraHeight() * 0.95)); pWatch->setScale(0.7); this->addChild(pWatch); return true; }
然后需要把HUDView添加到MainScene中,所以在MainScene.h里添加
HUDView * pHUD;添加这个成员变量后,就在MainScene的init函数里,this->addChild(bg)这句后面添加
pHUD = HUDView::create(); this->addChild(pHUD);然后运行游戏,可以看到如图所示
使用艺术字体
StopWatchView * StopWatchView::initView(){ StopWatchView * p = (StopWatchView*)(CCLabelAtlas::create("11","fonts/tuffy_bold_italic-charmap.plist")); return p; }加载艺术字体后,如图所示
4) 添加Level计时器
在MainScene.h中添加
int mTimeLeft;然后在MainScene 中 添加启动计时器,如
void MainScene::startStopWatch(){ mTimeLeft = pLevel->mTimeToSovle; pHUD->pWatch->setSecond(mTimeLeft); schedule(schedule_selector(MainScene::downTime),1.0f); }使用schedule方法,每隔一秒执行一次downTime。有启动计时,就得停止计时
void MainScene::stopStopWatch(){ unschedule(schedule_selector(MainScene::downTime)); }unschedule后就不会再计时,下面实现downTime函数
void MainScene::downTime(float dt){ mTimeLeft --; pHUD->pWatch->setSecond(mTimeLeft); if(mTimeLeft == 0){ stopStopWatch(); } }内容比较简单,就是实现mTimeLeft的递减和设置给TimeWatchView,并且在归0时停止计时
启动计时的地方在dealRandomAnagram函数中,在最后处添加
startStopWatch();如图所示,游戏开始时就进行倒计时
当然,游戏结束时别忘了要停止计时,在checkForSuccess的最后添加
stopStopWatch();
游戏中计分是很重要的设定,有了计分,才有成就感。下面就开始为游戏添加计分功能
新增Data类,用来存放分数
class Data : public CCObject{ public: Data(); virtual ~Data(){} void setPoint(int point); int getPoint(); void addPoint(int point); void subtractPoint(int point); private: int mPoints; };函数的实现如下
Data::Data(){ mPoints = 0; } void Data::setPoint(int point){ if(point > 0){ mPoints = point; }else{ mPoints = 0; } } int Data::getPoint(){ return mPoints; } void Data::addPoint(int point){ mPoints += point; } void Data::subtractPoint(int point){ mPoints -= point; }当玩家拖放TileView,放到正确的位置上后,就添加分数,如果放错,则扣分。
在MainScene.h中添加变量
Data * pData;
在MainScene的init函数中,申请变量
pData = new Data();
在dropToPoint中,如果匹配成功,则
pData->addPoint(pLevel->mPointPerTile);
如果匹配失败,则减一半的分
pData->subtractPoint(pLevel->mPointPerTile / 2);
分数应该实时显示给玩家看,需要显示则需要使用Label,所以新增CounterPointView
class CounterPointView: public CCLabelAtlas{ public: static CounterPointView* initWithValue(int v); void countTo(int p, float duration); void updateValueBy(float dt); void setValue(int v); CREATE_FUNC(CounterPointView); private: CounterPointView(){}; int value; float mDelta; int mEndValue; float mValueDelta; };
value是指当前的分数值, mEndValue是新的分数值,下面先来初始化
CounterPointView* CounterPointView::initWithValue(int v){ CounterPointView * p = (CounterPointView*)(CCLabelAtlas::create("11","fonts/tuffy_bold_italic-charmap.plist")); char strPoint[10]; sprintf(strPoint,"%d",v); p->setString(strPoint); p->value = v; p->setScale(0.5); return p; }CCLabelAtlas类是能快速渲染的类,用来做变化的数字最合适(FPS的数字就是使用了CCLabelAtlas)
void CounterPointView::setValue(int v){ this->value = v; char strPoint[10]; sprintf(strPoint,"%d",v); setString(strPoint); }设置分数
void CounterPointView::updateValueBy(float dt){ this->value += (int)mValueDelta; if((int)mValueDelta > 0){ if(this->value > mEndValue){ this->value = mEndValue; return; } }else{ if(this->value < mEndValue){ this->value = mEndValue; return; } } setValue(value); schedule(schedule_selector(CounterPointView::updateValueBy),mDelta); }
void CounterPointView::countTo(int to, float duration){ this->mDelta = duration / (abs(to - value) + 1); if(mDelta < 0.05) mDelta = (float)0.05; mEndValue = to; unscheduleAllSelectors(); if(to - this->value > 0){ mValueDelta = 1; updateValueBy(1); }else{ mValueDelta = -1; updateValueBy(-1); } }
在HUDView中添加变量CounterPointView后,在init函数中添加
pPointView = CounterPointView::initWithValue(0); pPointView->setColor(ccc3(97,25,9)); pPointView->setPosition(ccp(Common::getCameraWith()*0.05,Common::getCameraHeight() * 0.9)); this->addChild(pPointView);
则可以如图所示,看到分数
回到MainScene.cpp中,在 pData->addPoint(pLevel->mPointPerTile); 这句后面添加
pHUD->pPointView->countTo(pData->getPoint(),1.5);
pHUD->pPointView->countTo(pData->getPoint(),0.75);
7)结语
第二篇就到此结束了,因为时间实在是不够用,所以写得很慢而且很懒散,几乎是了了几句(掩面)。从文字上看,这实在不是一篇好教程,不过我觉得从中可以学习的是制作游戏过程的思路。
在开发过程中,不断的往主框架里添加新东西,然后让整个游戏变得充实丰满。主要的游戏逻辑在这篇已经完成了,剩下的就是一些优化方面的东西,还有就是添加一些炫的效果等。使用cocos2d-x开发会很方便,也很有code的感觉,但是C++实在是门不容易驾驭的语言,要非常注意指针和内存方面的使用。不过也会收益匪浅,起码在code方面会提升。最后,放上AnagramPuzzle完整版的代码,欢迎大家拍砖。
cocos2d-x之道~制作第一款文字游戏(二),布布扣,bubuko.com
标签:cocos2d-x 游戏 github android 博客
原文地址:http://blog.csdn.net/u011781834/article/details/24317209