您的位置:首页 > 移动开发 > Cocos引擎

基于cocos2d tileMap的一个小游戏

2013-08-10 14:31 267 查看
上一篇文章中我们介绍了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的上下左右各留一个空格的黑色像素。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: