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

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

一、触屏的实现

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或者1
	int 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)
			{
				//表明那个节点为NULL
				touchedPromptImgs[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;
}

四、效果执行图


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值