cocos2d-x游戏实例 《简单棋》入门尝试(五) 玩家控制效果的实现

来源:互联网 发布:mac系统绘画软件 编辑:程序博客网 时间:2024/05/18 17:42

在“入门尝试(四)”中已经对关于玩家的控制做了一个简单的分析。具体涉及到的点不再重复。直接上代码。

一、触屏的实现

1、分析

我希望这个游戏是能够在手机上玩,所以自然我需要实现触屏的效果。初步进行了有关触屏的了解,说需要重写ccTouchBegan、ccTouchMoved、ccTouchEnded等函数。因考虑程序处理过程中的一些传参问题,我采用利用构造函数传递相关参数,并在构造函数中注册触屏事件等。不多说,代码搞上先。

2、实现

(1)添加类MoveController,该类主要实现对棋子移动的控制等。

(2)在MoveController.h头文件中,添加类继承关系、构造函数、触屏相关的函数以及一些变量。其如下:

class MoveController:public CCLayer//因该类有触屏的效果,所以需要继承CCLayer类
public:MoveController(void);MoveController(CCTMXTiledMap *map);~MoveController(void);private:/* 触屏事件 */  virtual void registerWithTouchDispatcher();  virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);  virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);  virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);private:CCTMXTiledMap *map;
(3)在MoveController.cpp中,实现其对应函数。在以上定义中,我们暂时先不管触屏的效果。其先写完这些函数,然后再去添加内容。其实现如下:

首先,构造函数:

MoveController::MoveController(CCTMXTiledMap *map){this->map = map;this->setTouchEnabled(true);//设置是否可以触屏registerWithTouchDispatcher();//注册触屏事件}
然后相关的触屏函数:
void MoveController::registerWithTouchDispatcher()  {  CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);  //注册触屏事件}  bool MoveController::ccTouchBegan( CCTouch *pTouch, CCEvent *pEvent )  {  return true;}void MoveController::ccTouchMoved( CCTouch *pTouch, CCEvent *pEvent )  { } void MoveController::ccTouchEnded( CCTouch *pTouch, CCEvent *pEvent )  {  } 
现在,你在ccTouchMoved或者ccTouchEnded函数内部加入你希望响应的操作,然后点击下屏幕瞅瞅是否已经可以有触屏的效果了。

二、图片放大提示效果的实现

1、分析

该效果是希望实现点击要移动的精灵,该精灵会放大,提示玩家正在操作的棋子。再次点击该棋子,图片回复原装,认定为取消对该棋子的选择。该效果的实现,我就是重新做了一张比原图片大的图片,当用户点击屏幕时,我获取用户点击的相关数据(该数据定义在_TouchedInfo这个结构体中,详细定义可参考下文),根据这些数据加载一张新图还是撤销这张新图。

2、实现

(1)在MoveController.h头文件中添加存储点击屏幕的信息的结构体:
/*存储点击的点的相关数据*/typedef struct _TouchedInfo{int firstToucheLocation;//第一次点击时在坐标数组中对应的位置(-1表示空白, 1-21表示对应的坐标下标点)int currentActiveChessmanCount;//当前活动的棋子数量,0或者1int secondToucheLocation;//第二次点击时的位置(-1表示点击空白,0表示点击当前活动的棋子,1-21表示点击活动棋子要跳达的位置)_TouchedInfo(){firstToucheLocation = -1;currentActiveChessmanCount = 0;secondToucheLocation = -1;//默认点击都是空白位置}}*_pTouchedInfo;
(2)在MoveController.h头文件中添加私有变量:
_TouchedInfo touchedInfo;//存储点击的点的相关数据CCSprite *touchedSprite;//玩家点击精灵之后放大后的图片
(3)MoveController这个类肯定会用到有关其每个坐标点的信息,所以将Chessman中定义的变量pointsInfo作为一个外部变量操作。故在MoveController.cpp文件中添加头文件和变量:
#include "Common.h"extern struct _PointInfo pointsInfo[21];//用于存储棋盘中21个坐标点的数组
(4)获取点击屏幕的数据,如是否点击了精灵等,在MoveController.h文件中添加函数声明:
/***功能:根据传入的点击的点的坐标的信息,存储到变量touchedInfo中**touchLocation:点击的点的坐标**playerIsRed:当前点击的玩家是否为红方,其操作方(如红方)点击对方(如蓝方)的精灵图片也被认定为点击空白*/void GetTouchedPointInfo(CCPoint touchLocation, bool playerIsRed);/***功能:获取点击的精灵的大小区域*/static CCRect GetRect(CCSprite* pNode);
在MoveController.cpp中实现其声明:
void MoveController::GetTouchedPointInfo(CCPoint touchLocation, bool playerIsRed){if(playerIsRed == true)//如果玩家此时操作{/***********判断当前是否有活动棋子******************/if(touchedInfo.currentActiveChessmanCount == 0)//如果当前活动的棋子个数为0,即玩家处于选择将要移动的棋子的状态{touchedInfo.firstToucheLocation = -1;//先假设其点击的位置是空白的地方/************判断点击的为空白还是棋子精灵********/for (int i = 0; i < 21; i++){if(pointsInfo[i].currentSprite != NULL && pointsInfo[i].isRed == playerIsRed) //该结点存在精灵并且非对方精灵{if(CCRect::CCRectContainsPoint(GetRect(pointsInfo[i].currentSprite), touchLocation)){touchedInfo.firstToucheLocation = i + 1;//获取到了其点击的精灵对应下标值break;}}}}else//如果当前有活动棋子,即玩家处于选择将要移动的棋子放置于哪个方向的状态{/****判断点击的位置是否为空白、当前活动棋子、下一个可达位置*****/touchedInfo.secondToucheLocation = -1;//先假设其为空白位置if(CCRect::CCRectContainsPoint(GetRect(pointsInfo[touchedInfo.firstToucheLocation - 1].currentSprite), touchLocation))                                                                                          //根据firstToucheLocation,判断点击的是否为当前活动棋子{touchedInfo.secondToucheLocation = 0;//如果点击的为活动棋子}else//如果点击的不是活动的棋子{for (int j = 0; j < 4; j++)//判断是否为可以走下一步的棋子{if(CCRect::CCRectContainsPoint(GetRect(touchedPromptImgs[j].touchedSprite), touchLocation)){touchedInfo.secondToucheLocation = touchedPromptImgs[j].pointLocation;//如果点击的为下一步可达的棋子break;}}}} }else{touchedInfo.currentActiveChessmanCount = 0;touchedInfo.firstToucheLocation = -1;touchedInfo.secondToucheLocation = -1;}}CCRect MoveController::GetRect(CCSprite* pNode){CCRect rc;rc.origin = pNode->getPosition();rc.size = pNode->getContentSize();rc.origin.x -= rc.size.width*0.5;rc.origin.y -= rc.size.height*0.5;return rc;}
(5)根据获取的触屏数据,执行这些数据。因考虑后面的效果,此处实现暂时不写出来,在说完了怎样显示可下位置的提示图片之后一起完成。

三、可下位置图片提示的实现

1、分析

此处就是希望实现(四)中说的2.1.2说的效果。在这个的实现中,自然可以类似于放大图片效果提示一样,加载以及删除提示图片。但是因为考虑到获取坐标的问题,当提示位置如果没有图片不好利用上面已经写出的函数GetRect来判断点击是否在精灵位置上,所以,我采用了在程序初始化的时候初始了四张(最多四个可提示位置)提示图片,先设置位置在(-20, -20)不可见的位置,然后当某个坐标需要提示时,则移动到相应位置。提示完毕后,又移动到(-20, -20)去隐藏。

2、实现

(1)首先在Common.h中定义了一个结构体存放相应提示图片的信息:
typedef struct _PromptImage{int pointLocation;//对应的提示图片暂时显示的位置,-1表示不在棋盘21个坐标点上CCSprite *touchedSprite;//点击之后出现的提示精灵图片对象_PromptImage(){pointLocation = -1;touchedSprite = NULL;}}*_pPromptImage;
(2)回到Chessman.h头文件,添加函数声明:
/***功能:初始化提示图片*/void InitPromptImg(CCTMXTiledMap *map);
在Chessman.cpp中实现函数功能:
void Chessman::InitPromptImg(CCTMXTiledMap *map){for (int i = 0; i < 4; i++){CCSprite *sprite = CCSprite::spriteWithFile("image/prompt.png");sprite->setPosition(ccp(-20, -20));map->addChild(sprite);touchedPromptImgs[i].touchedSprite = sprite;} }
为了保存其图片,也在Chessman.cpp中定义了全局变量,(便于在MoveController中做外部变量)
struct _PromptImage touchedPromptImgs[4];//点击之后出现的四张提示图片
(3)表示头有点晕了,不废话了,直接加代码。在MoveController.h中添加如下声明:
/***功能:执行点击后的命令*/void ExecuteTouchedCommond();/***功能:显示提示的图片**location:显示图片的位置*/void ShowPromptImg(int location);/***功能:加入点击棋子之后放大的图片*/CCSprite * CreateTouchedSprite(char *path, CCPoint cp);/***功能:将四张提示图片隐藏到看不到的坐标点*/void RecoverPromptImgsLocation();/***功能:将处于firstTouchedLocation的棋子移动到secondTouchedLocation位置*/void RemoveOneChessmanSprite(int firstTouchedLocation, int secondTouchedLocation);/***功能:在location添加一张棋子精灵的图片*/void SetOnePointData(int location, char *path, bool isRed);

(4)已经将其图片移动的代码也敲进去了,在MoveController.cpp中添加如下代码:
extern struct _PromptImage touchedPromptImgs[4];//点击之后出现的四张提示图片

void MoveController::ExecuteTouchedCommond(){if(0 == touchedInfo.currentActiveChessmanCount)//第一次有效点击{if(touchedInfo.firstToucheLocation > 0)//点击了精灵{touchedInfo.currentActiveChessmanCount = 1;ShowPromptImg(touchedInfo.firstToucheLocation);//设置点击的棋子周围设置为可移动的图片touchedSprite = CreateTouchedSprite("image/redTouched.png", ccp(pointsInfo[touchedInfo.firstToucheLocation - 1].currentSprite->getPositionX(),pointsInfo[touchedInfo.firstToucheLocation - 1].currentSprite->getPositionY()));}}else{if(touchedInfo.secondToucheLocation == -1)//点击空白,不执行代码{}else if(0 == touchedInfo.secondToucheLocation)//其重复点击一个棋子{touchedInfo.currentActiveChessmanCount = 0;touchedSprite->removeFromParentAndCleanup(true);RecoverPromptImgsLocation();}else{//点击的是可以下一步可以走的touchedInfo.currentActiveChessmanCount = 0;touchedSprite->removeFromParentAndCleanup(true);RecoverPromptImgsLocation();RemoveOneChessmanSprite(touchedInfo.firstToucheLocation, touchedInfo.secondToucheLocation);//playerIsRed = false;}}}void MoveController::ShowPromptImg(int location){location = location - 1;for (int i = 0; i < 4; i++){int nearPoint = pointsInfo[location].nearLocations[i] - 1;if( nearPoint > 0){//表明周围还有邻节点if(pointsInfo[nearPoint].isNotEmpty == false){//表明那个节点为NULLtouchedPromptImgs[i].touchedSprite->setPosition(pointsInfo[nearPoint].currentPoint);touchedPromptImgs[i].pointLocation = nearPoint + 1;}}}}CCSprite * MoveController::CreateTouchedSprite(char *path, CCPoint cp){CCSprite *playerSprite = CCSprite::create(path);  //playerSprite->setScale(0.2);//缩放playerSprite->setPosition(cp);  map->addChild(playerSprite);  return playerSprite;}void MoveController::RecoverPromptImgsLocation(){for (int i = 0; i < 4; i++){touchedPromptImgs[i].touchedSprite->setPosition(ccp(-20, -20));touchedPromptImgs[i].pointLocation = -1;}}void MoveController::RemoveOneChessmanSprite(int firstTouchedLocation, int secondTouchedLocation){pointsInfo[firstTouchedLocation - 1].currentSprite->removeFromParentAndCleanup(true);pointsInfo[firstTouchedLocation - 1].currentSprite = NULL;pointsInfo[firstTouchedLocation - 1].isNotEmpty = false;if(pointsInfo[firstTouchedLocation - 1].isRed == true){SetOnePointData(secondTouchedLocation, "image/red.png", true);}else{SetOnePointData(secondTouchedLocation, "image/blue.png", false);}}void MoveController::SetOnePointData(int location, char *path, bool isRed){ location = location - 1;CCSprite *playerSprite = CCSprite::create(path);  //playerSprite->setScale(0.2);//缩放playerSprite->setPosition(pointsInfo[location].currentPoint); map->addChild(playerSprite);  //设置参数pointsInfo[location].currentSprite = playerSprite;pointsInfo[location].isNotEmpty = true;pointsInfo[location].isRed = isRed;}

四、效果执行图


原创粉丝点击