基于cocos2d tileMap的一个小游戏


上一篇文章中我们介绍了cocos2d tileMap的一些基本知识,这一节我们基于cocos2d做一个简单的游戏,下载地址:http://download.csdn.net/detail/lennonchan/5903037

这是一款收集宝石的小游戏,主要任务是指挥鸟在不碰雷德前提下收集所有的宝石,节目如下:

      

通过右下角的按钮控制鸟的行走方向,也可以通过Windows小键盘区的数字键控制方向。windows上esc键重新开始,Android上menu键重新开始。

为了游戏增加游戏的灵活性,地图是通过程序计算出来的,所以每次初始化的界面可能都不一样。

 

下来看下代码,我们只看CGameMap类。

class CGameMap : public cocos2d::CCTileMapAtlas
{
public:
	static CGameMap* getInstance();
	CGameMap* create(unsigned int width,unsigned int height,int seed = 0);
	~CGameMap();
	CCPoint getStartPosition();
	CCPoint	getEndPosition(CCPoint,eDirect);
	eMapType moveStart(eDirect drct);
	CCSize getMapSize();
	bool isCollectOver();
private:
	CGameMap();
	sImageTGA* grid2Image(char* pGrid);
	char cFlag2Tile(char cFlag);
private:
	unsigned int m_Width;
	unsigned int m_Height;
	unsigned int m_iCollectedGems;
	unsigned int m_iTotalGems;
	CCPoint m_StartPosition;
	ccColor3B m_CurrentType;
	static CGameMap* m_pInstance;
};
CGameMap继承自cocos2d::CCTileMapAtlas,接口很少。

getInstance :获取单例对象

create : 创建一个tileMap,比较重要

getStartPosition: 获取鸟所在的位置

getEndPosition:获取鸟从某一点开始,沿某一方向能走得最远距离。

moveStart: 沿某一方向走一步,并将目标位置的类型返回。

  getMapSize: 获取地图大小

isCollectOver:判断地图上的宝石是否收集完毕

   

我们从create函数看起:

CGameMap* CGameMap::create( unsigned int width,unsigned int height,int seed)
{
	m_Width = width;
	m_Height = height;
	m_iTotalGems = 0;
	if(seed <= 0)
	{
		seed = (int)time(NULL);
	}
	int iseed = seed;
	random_state *rs = random_new((char*)&iseed, sizeof(int));
	char * grid = gengrid(m_Width,m_Height,rs);
	sImageTGA* pInfor = grid2Image(grid);
	releaseMap();
	//tgaDestroy(m_pTGAInfo);
	if (initWithTGAInfo(_TILE_IMG_, pInfor, _TILE_WIDTH_, _TILE_HEIGHT_))
	{
		//autorelease();
	}
	m_CurrentType.r = eBlank;
	return this;
}
函数有三个参数,宽高和一个随机种子。注意:这里的宽高的单位并不是像素,而是格子,也就是地图会有w*h个cell。

if(seed <= 0)
{
seed = (int)time(NULL);
}

如果随机种子小于0,则用当前时间作为随机种子。

接下来用随机种子生成一个随机状态:

random_state *rs = random_new((char*)&iseed, sizeof(int));

接下来用随机状态和宽高成生一个原始的网格:

char * grid = gengrid(m_Width,m_Height,rs);

文章开头上传的代码中有gengrid的源码,这里不复述。

然后调用私有函数grid2Image将原始数据转为tga格式的图片格式。

sImageTGA* CGameMap::grid2Image(char* pGrid)
{
	sImageTGA* pImage = new sImageTGA();
	pImage->flipped = 0;
	pImage->type = 1;
	pImage->pixelDepth = 24;
	pImage->width = m_Width;
	pImage->height = m_Height;
	pImage->imageData = new unsigned char[m_Width*m_Height*3];
	for (int i = 0;i < m_Width; i++)
	{
		for (int j = 0;j < m_Height; j++)
		{
			pImage->imageData[(j*m_Width+i)*3] = cFlag2Tile(pGrid[i*m_Width+j]);
			if(pImage->imageData[(j*m_Width+i)*3] == eStart)
				m_StartPosition = ccp(i,j);
			else if(pImage->imageData[(j*m_Width+i)*3] == eGem)
				m_iTotalGems++;
			pImage->imageData[(j*m_Width+i)*3+1] = 0;
			pImage->imageData[(j*m_Width+i)*3+2] = 0;
		}
	}
	return pImage;
}

releaseMap();其实在这里没什么作用,因为我们没用到tga的解析。


然后调用我们的创建的函数,通过tgainfo初始化一个map,函数原型如下:

bool CCTileMapAtlas::initWithTGAInfo(const char *tile, sImageTGA* pInfo, int tileWidth, int tileHeight)
{

	if(!pInfo)
		return false;
	m_pTGAInfo = pInfo;
	this->calculateItemsToRender();

	if( CCAtlasNode::initWithTileFile(tile, tileWidth, tileHeight, m_nItemsToRender) )
	{
		m_pPosToAtlasIndex = new CCDictionary();
		this->updateAtlasValues();
		this->setContentSize(CCSizeMake((float)(m_pTGAInfo->width*m_uItemWidth),
			(float)(m_pTGAInfo->height*m_uItemHeight)));
		return true;
	}
	return false;
}
将解析tga的过程换成直接赋值:m_pTGAInfo = pInfo;

注:如果朋友们要运行下载的工程,需要将此函数自己复制到CCTileMapAtlas.cpp,再在头文件中声明。

下来看另外一个比较重要的函数:moveStart

eMapType CGameMap::moveStart( eDirect drct )
{
	if(drct == eNON)
		return eStart;

	CCPoint pEnd = m_StartPosition;
	switch (drct)
	{
	case eUp:
		pEnd.y++;
		break;
	case eDown:
		pEnd.y--;
		break;
	case eLeft:
		pEnd.x--;
		break;
	case eRight:
		pEnd.x++;
		break;
	case eUpLeft:
		pEnd.y++;
		pEnd.x--;
		break;
	case eUpRight:
		pEnd.y++;
		pEnd.x++;
		break;
	case eDownLeft:
		pEnd.y--;
		pEnd.x--;
		break;
	case eDownRight:
		pEnd.y--;
		pEnd.x++;
		break;
	default:
		break;
	}

	if(pEnd.y < 0 || pEnd.y >= m_Height ||
		pEnd.x < 0 || pEnd.x >= m_Width)
	return eStart;

	ccColor3B r = tileAt(pEnd);
	ccColor3B c = r;
	switch (c.r)
	{
	case eMine:
	case eGem:
	case eStop:
	case eBlank:
		if(m_CurrentType.r == eGem)
		{
			m_iCollectedGems++;
			m_CurrentType.r = eBlank;
		}
		setTile(m_CurrentType,m_StartPosition);
		m_StartPosition = pEnd;
		m_CurrentType = c;
		c.r = eStart;
		setTile(c,m_StartPosition);
		break;
	case eStart:
	case eWall:
	default:
		break;
	}
	return (eMapType)r.r;
}

用于游戏中移动鸟的位置,参数为移动方向。

首先我们将目标位置标记为鸟所在的位置:

CCPoint pEnd = m_StartPosition;

然后通过移动方向进行坐标计算:

switch (drct)
	{
	case eUp:
		pEnd.y++;
		break;
	case eDown:
		pEnd.y--;
		break;
	case eLeft:
		pEnd.x--;
		break;
	case eRight:
		pEnd.x++;
		break;
	case eUpLeft:
		pEnd.y++;
		pEnd.x--;
		break;
	case eUpRight:
		pEnd.y++;
		pEnd.x++;
		break;
	case eDownLeft:
		pEnd.y--;
		pEnd.x--;
		break;
	case eDownRight:
		pEnd.y--;
		pEnd.x++;
		break;
	default:
		break;
	}
接下来判断目标位置是啥玩意:

ccColor3B r = tileAt(pEnd);
ccColor3B c = r;

分情况判断:

switch (c.r)
	{
	case eMine:
	case eGem:
	case eStop:
	case eBlank:
		if(m_CurrentType.r == eGem)
		{
			m_iCollectedGems++;
			m_CurrentType.r = eBlank;
		}
		setTile(m_CurrentType,m_StartPosition);
		m_StartPosition = pEnd;
		m_CurrentType = c;
		c.r = eStart;
		setTile(c,m_StartPosition);
		break;
	case eStart:
	case eWall:
	default:
		break;
	}
如果是炸弹、宝石、停止或者空白则将鸟移动到当前位置,否则不做处理。

最后返回目标位置的类型return (eMapType)r.r;

游戏先将这么多吧,因为大家可以下到源码,如果有什么问题我们在讨论。

最后说一点tile图片制作时要注意的地方:

图片的第一个cell要空出来,原因看上一篇文章。为了达到网格的效果,每个cell的上下左右各留一个空格的黑色像素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值