原文来自http://www.raywenderlich.com/39113/cocos2d-x-tile-map-tutorial-part-1

这是我很喜欢的一个学习网站。在里面能学到很多东西,同时也推荐给小伙伴们。

这是一个两部分的Cocos2d-x Tile Map系列教程,你将会创建一个关于荒漠中忍者寻找可口西瓜的简单游戏。

注意,这是关于Cocos2d-x的教程,它是用C++移植cocos2d-iphone的跨平台引擎。所以这里的代码可以在iPhone,Android或者更多的平台上使用。

在第一部分,你将会学到怎样添加一个图块地图到游戏中,玩家跟随地图移动,使用对象层等,你还会学到怎样使用地图编辑器创建图块地图。

第二部分,涵盖了如何在地图上加入可碰撞区域,怎样用图块属性,怎样收集东西和动态修改地图,还有怎样确保忍者不会吃撑了。

注意,这个教程是类似Cocos2d-iphone教程的移植版,如果你正在寻找Cocos2d-iphone版,你可以点这里。

如果你之前不懂Cocos2d-x,那你可以先看看Cocos2d-x:太空游戏教程,它包含了很多基础的东西,有助于你学习这篇教程。

OK,来玩玩图块地图吧!

Getting Started

这篇教程需要最新的cocos2d-x版本(写这篇文章时是2.1.4版),如果你没有.....

我这里用的是2.2.1版本,所以后面没用的就不翻译了。

接着,创建一个名为MyTileGame的工程。(至于创建步骤,大家应该都懂)。

你将在工程中使用ARC,如果这是你第一次使用ARC,我推荐你看一下ARC教程系列,默认创建的工程是非ARC的,修改这个很简单,

点击Edit\Refactor\Convert to Objective-c ARC.展开下拉,选中main.m,AppDelegate.cpp,HelloWorldScene.cpp然后点击Check,完成向导。

编译-》运行,确保一切ok,你就会看到正常的HelloWord程序了。

接下来,下载游戏的压缩包,这里面包含了以下东西:

  • 你要用来做玩家对象的一个精灵,可能看起来眼熟SimpleGame
  • 使用一个不错的声效工具cfxr制作的一些声效。
  • 用Garage Band制作的一些背景音乐
  • 要用的图块集合,实际上地图编辑器自带得有,只是这样做起来更容易些。
  • 一些特殊的图块,呆会再做说明
一旦你下载好之后,解压TileGameResources文件到工程的Resources目录下,在工程菜单中,右键Resources文件夹,选着Add Files to "TileGame"...
选择Resources/TileGameResources文件夹,确认Copy items into desination group's folder(if needed)被选中,然后Create groups for any added folders
也是选中的,最后点击Finish.
上面的都完成好后,所有的文件应该被列到了工程中。就像这样:

是到玩玩地图的时候了。

Make a Map with Tiled

cocos2d-x支持用开源的Tile Map Editor创建的地图,保存为TMX格式。

如果你没有这个工具,可以通过上面的链接去下载,此时最新版是0.9.1.

打开Tiled,文件\新文件,将会出现下面的对话框:

各个参数都保持默认,然后点击OK

接着,就要绘画地图,所以要添加图块集合,在菜单栏上选择地图\新图块,然后按照下面填写内容:

为了得到图像,只需要点击浏览,然后到MyTileGame/Resources/TileGameResources文件件下,选择tmw_desert_spacing.png文件,然后就会自动帮你填好上面的名称。

你可以将宽度和高度设为32x32,因为这是图块的尺寸。至于边距和间距的意思:

  • 边距 是当前图块在搜索实际像素前,应该跳多少像素(适用于宽度和高度)。
  • 间距 是在读取实际像素后得到下一个图块的数据,图块应该前进多少像素(适用于宽度和高度)。

如果你看一下tmw_desert_spacing.png,你就会看到每一图块周围都有1像素的黑色边框,这就解释了边距和间距设置为1。

点击OK,就会看到这些图块显示在图块窗口,现在可以开始画了!简单的点击一下工具栏上的图章刷,然后点击一个图块,点击地图上的任意一个地方放上图块。

So,来画一个DIY的地图,确保至少要添加一些建筑物,因为后面要用来做碰撞。

这里我就随便画了.....

为了画起来更方便,你可以看一下这些快捷键,下面是一些常用的:

  • 你可以在图块选择器中拖动一个框系列的图块,能够同时放下多个相邻的图块
  • 你可以用工具栏上的填充工具,填充一块区域
  • 你可用视图中的放大和缩小工具
  • 在你用图章刷工具编辑地图时,可用z键来旋转图块

你也许已经注意到在迷你地图中有一些新的功能,很不错的功能,让你能看迷你的地图。

来看一下在迷你地图的下面我尝试做的简单迷宫。红色的方框表示你在主编辑窗口能看到的地图。

当你要滚动区域的时候,记得用这个迷你地图功能。

注意,本教程的资源来自上述地图预先制作——可以免费使用,如果你懒得自己做。如果你要自己做,你应该在Tiled中打开地图,看一下它是怎样建立起来的。

画完地图后,双击图层窗口中得块层1,改名为Background.然后点文件\保存,保存到游戏工程的MyTileGame\Resources\TileGameResourcese目录,然后命名为TileMap.tmx,覆盖以前存在的那个文件。

以后你将要用Tiled做更多的东西,现在先让这张地图进入游戏。

Adding the Tiled Map to the cocos2d-x Scene

打开HelloWorldScene.h文件,添加下面一行到#include "cocos2d.h"下面:

USING_NS_CC;

这表示编译器使用cocos2d的命名空间,这样就不必每个开头都加上cocos2d::前缀了。

然后在类定义的做大括号的右后面,添加这些代码:

private:

CCTMXTiledMap *_tileMap;

CCTMXLayer *_background;

为了跟踪地图本身和背景层地图,创建了两个private变量。以后将会学到更多的图块地图图层。

接下来,用下面代码替换HelloWorldScene.cpp中的内容。

#include "HelloWorldScene.h"

USING_NS_CC;

CCScene* HelloWorld::scene()

{

// 'scene' is an autorelease object

CCScene *scene =CCScene::create();

// 'layer' is an autorelease object

HelloWorld *layer =HelloWorld::create();

// add layer as a child to scene

scene->addChild(layer);

// return the scene

return scene;

}

// on "init" you need to initialize your instance

boolHelloWorld::init()

{

//

// 1. super init first

if ( !CCLayer::init() )

{

return  false;

}

//加载地图,背景层

_tileMap =newCCTMXTiledMap();

_tileMap->initWithTMXFile("TileMap.tmx");

_background =_tileMap->layerNamed("Background");

this->addChild(_tileMap);

return  true;

}

这里,你调用了CCTMXTileMap类,让它用你之前用Tiled创建的地图文件来创建一个地图。

快速扫盲:CCTMXTileMap也是一个CCNode,可以设置它的位置,大小等,该节点的子节点是图块地图的图层,并有一个辅助的函数layerNamed;

按名称查找,让你得到这个背景。考虑到性能的原因,每一个层都是CCSpriteSheet的子类,这也意味着每一层你只能有一个图块集。

所以,上面的代码保存了图块地图和背景层的引用,然后添加到HelloWorld的层上。

在ipad模拟器上编译-》运行代码,你应该会看到地图的左下角。

还不错,但是对于这个游戏,你还需要做3件事:

  1. 一个玩家
  2. 玩家开始位置
  3. 为了能看到玩家需要能够移动地图视图

而这就变得非常棘手,所以接下来让我们解决它。

Tiled Object Layers and Setting Tile Map Position

Tiled支持下面两种类型的图层:

  • 图块图层:这些是你至今一直使用到的。
  • 对象图层:为了识别事情发生的区域,它们允许你在地图上绘制矩形框。例如,你要做一个怪兽出来的地方,或者一个进入就死的地方。在本教程中,你将为玩家的出生点创建一个区域。

所以,在Tiled工具中点击菜单栏上的图层\添加对象层,命名为Objects,为了插入这个Object,选中工具栏上得插入矩形(R),为了知道当前显示的图层可以看Tiled工具的左下角:

如果你拖动地图,你会注意到并没有画图块,而是,画了个矩形框,你可以覆盖多个图块或是到处的移动。在最新版本中,你还可以其他的类型,如椭圆,多边形,折现等。

你只需要选择一小块,作为玩家开始的地方,所以在地图上选中一个区域并点击图块,矩形框的大小并不重要,因为我们只用x,y坐标。注意,如果你懒而使用样本地图,这将为你完成。

然后,右键刚刚添加的这个灰色的对象,选择对象属性...,给它一个名字SpawnPoint,然后点击OK

在以前的cocos2d-x版本中,你可以设置对象的类型,但是由于会带来问题所以被移除了。所以把类型设为空白。我们创建了一个

CCDictionary,能够访问这个对象的很多属性,包括x,y坐标。

保存这个地图,返回Xcode,打开HelloWorldScene.h,添加下面到私有变量声明那里:

CCSprite *_player;

接下来,打开HelloWorldScene.cpp,添加下面代码到init()中,在this->addChild(_tileMap)的后面。

CCTMXObjectGroup *objectGroup =_tileMap->objectGroupNamed("Objects");

if (!objectGroup) {

CCLog("tile map has no objects object layer");

return  false;

}

CCDictionary *spawnPoint = objectGroup->objectNamed("SpawnPoint");

int x = ((CCString)*spawnPoint->valueForKey("x")).intValue();

int y = ((CCString)*spawnPoint->valueForKey("y")).intValue();

_player =newCCSprite();

_player->initWithFile("Player.png");

_player->setPosition(ccp(x,y));

this->addChild(_player);

this->setViewPointCenter(_player->getPosition());

在最后面一行将会有个错误,别担心我们呆会再解决它。

我们停下来解释一下关于这个对象层和对象组。首先注意你得到对象层是通过CCTMXTiledMap对象上的objectGroupNamed方法

(而不是layerNamed).它返回一个特殊的CCTMXObjectGroup对象。

然后objectGroup调用objectNamed方法得到一个包含有这个对象一些有用信息的字典,有x,y,width,height.本教程的重点关心的是x,y坐标,把它们作为

玩家精灵的位置。

在代码片最后,你把player的位置作为这个视图的位置。所以现在添加下面代码到HelloWorldScene.h中:

void setViewPointCenter(CCPoint position);

然后在HelloWorldScene.cpp中添加实现方法:

void HelloWorld::setViewPointCenter(cocos2d::CCPoint position)

{

CCSize winSize =CCDirector::sharedDirector()->getWinSize();\

//防止玩家超出边界

int x = MAX(position.x, winSize.width/2);

int y = MAX(position.y, winSize.height/2);

x = MIN(x, (_tileMap->getMapSize().width *_tileMap->getTileSize().width) - winSize.width/2);

y = MIN(y, (_tileMap->getMapSize().height *_tileMap->getTileSize().height) - winSize.height/2);

CCPoint actualPosition =ccp(x,y);

CCPoint centerOfView =ccp(winSize.width/2, winSize.height/2);

CCPoint viewPoint =ccpSub(centerOfView, actualPosition);

this->setPosition(viewPoint);

}

ok,来解释下这段代码,想象一下这功能是设置一个照相机的中心,它允许用户在地图上通过任意的x,y,但是如果你仔细想想几点,你不希望看到——如,你不想

让屏幕超过地图的边界(它只是空白的)。

例如,看这个图解:

你看,是否相机的中心不到WinSize.width/2,Winsize.height/2,视图的部分就超出了屏幕。

同样的,重要的是要检查好上限边界,这正是setViewPointCenter做的。

这个完成了视图的中心位置减去实际的位置,然后把结果设为HelloWorld图层的位置。

唷,做了这么多,是时候看它动起来了。

运行程序,如果没错的话,你将看到一个忍者在屏幕上。

Making the Ninja Move

这是个好的开始,但是你的忍者只是站在那里,不像个真忍者。

你将让你的忍者在用户轻点的方向上做简单的移动,添加下面的代码到HelloWorldScene.h的pubic区:

void registerWithTouchDispatcher();

void setPlayerPosition(CCPoint position);

bool ccTouchBegan(CCTouch *touch,CCEvent *event);

void ccTouchEnded(CCTouch *touch,CCEvent *event);

然后打开HelloWorldScene.cpp添加这句到init()中,在return前:

this->setTouchEnabled(true);

这设置了让图层能够触摸,所以注意touch事件,再添加下面代码:

void HelloWorld::registerWithTouchDispatcher()

{

CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);

}

boolHelloWorld::ccTouchBegan(cocos2d::CCTouch *touch,cocos2d::CCEvent *event)

{

return true;

}

void HelloWorld::setPlayerPosition(cocos2d::CCPoint position)

{

_player->setPosition(position);

}

voidHelloWorld::ccTouchEnded(cocos2d::CCTouch *touch,cocos2d::CCEvent *event)

{

CCPoint touchLocation = touch->getLocationInView();

touchLocation = CCDirector::sharedDirector()->convertToGL(touchLocation);

touchLocation = this->convertToNodeSpace(touchLocation);

CCPoint playerPos =_player->getPosition();

CCPoint diff =ccpSub(touchLocation, playerPos);

if ( abs(diff.x) > abs(diff.y) ) {

if (diff.x >0) {

playerPos.x +=_tileMap->getTileSize().width;

} else {

playerPos.x -=_tileMap->getTileSize().width;

}

} else {

if (diff.y >0) {

playerPos.y +=_tileMap->getTileSize().height;

} else {

playerPos.y -=_tileMap->getTileSize().height;

}

}

// safety check on the bounds of the map

if (playerPos.x <= (_tileMap->getMapSize().width * _tileMap->getTileSize().width) &&

playerPos.y <= (_tileMap->getMapSize().height *_tileMap->getTileSize().height) &&

playerPos.y >=0 &&

playerPos.x >=0 )

{

this->setPlayerPosition(playerPos);

}

this->setViewPointCenter(_player->getPosition());

}

这里,你覆盖了registerWithTouchDispatcher方法,注册自己来处理目标触摸事件。这将导致ccTouchBegan/ccTouchEnded方法被调用。(单触摸的情况下)

而不是ccTouchesBegan/ccTouchesEnded方法被调用(多触摸的情况下)。

你肯定想知道单触摸和多触摸之间的不同,在这种情况下用这两种都没关系。但是,如果你之前没见过这个方法,我想介绍给大家,因为它有明显的两个优点:

  • 你不需要处理NSSets,调度器做了分离它们的工作。每次只有一个UITouch调用。
  • 你可以“要求”一个UITouch在ccTouchBegan返回true,要求它们更新只发送给代理。所以,如果你得到一个move/ended/cancelled更新确定是你的触摸,当多点触摸的时候这会检查释放。

接下来,有一大段是讲坐标的,英语水平实在是渣,就不翻译了。

编译-》运行程序,现在忍者就可以在屏幕上移动了。

这是第一部分的教程。源码在这里

接下来会过几天翻译学习第二部分教程。

要过年了,希望在新的一年里,能够学到更多的东西。

cocos2d-x Tile Map 教程(一)相关推荐

  1. cocos2d-x Tile Map教程(二)

    原文来自:http://www.raywenderlich.com/40544/cocos2d-x-tile-map-tutorial-part-2 欢迎来到Cocos2d-x tile map 教程 ...

  2. tilemap 菱形_带高度的isometric tile map 斜45度 2d 地图制作

    常见的 tile map 游戏是 不带 高度变化的 也就是 地面都在一个水平面上 这样 3种 坐标 之间的变换 是比较简单的 3 种坐标系统 可以参看 这篇文章 而带有高度的 tile map 中 存 ...

  3. Unity实现瓦片地图tile map

    2019独角兽企业重金招聘Python工程师标准>>> Unity自定义mesh绘制  基于上篇的mesh修改,实现tile map 第一步,修改mesh 顶点和三角片信息,生成方格 ...

  4. java map 教程_Java Map接口

    Java Map接口 在本教程中,我们将学习Java Map接口及其方法. Java collections框架的Map接口提供了Map数据结构的功能. 它实现了Collection接口. map的工 ...

  5. java map 教程_Map和Set

    JavaScript的默认对象表示方式{}可以视为其他语言中的Map或Dictionary的数据结构,即一组键值对. 但是JavaScript的对象有个小问题,就是键必须是字符串.但实际上Number ...

  6. tensorflow tf.tile 使用教程·

    该方法将张量按照指定的维度复制多份 a = tf.constant([[1, 2, 3], [4, 5, 6]], tf.int32) b = tf.constant([3, 2], tf.int32 ...

  7. 用ZB生成高度图(Height Map)教程

    一.输出Height Map尺寸设置 二.调整画布大小 重置画布尺寸后需要重新调整画布显示. 1.缩放画布 2.调整模型与画布的比例 衍生问题:怎么把模型充满画布(做四方连续的时候会用到) 1.缩小画 ...

  8. (译)如何使用cocos2d制作基于tile地图的游戏教程:第一部分

    免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播.同时,转载时不要移除本申明.如产生任何纠纷,均与本博客所有人.发表该翻译稿之人无任何关系.谢谢合作 ...

  9. 译)如何使用cocos2d制作基于tile地图的游戏教程:第一部分

    (译)如何使用cocos2d制作基于tile地图的游戏教程:第一部分 免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播.同时,转载时不要移除本申明. ...

最新文章

  1. StringUtils详解
  2. 使用MyEclipse构建MAVEN项目 - 我的漫漫程序之旅 - BlogJava
  3. 基于python的随机森林回归实现_随机森林理论与python代码实现
  4. 二叉树删除节点,(查找二叉树最大值节点)
  5. dijkstra算法代码_数据科学家需要知道的5种图算法(附代码)
  6. 你可能不知道console强大
  7. mysql的service name_【Oracle】service_name和service_names的关系
  8. windows qt 使用openssl API
  9. 域管理中经常用到的组策略禁止修改IP及计算机名
  10. JavaScript创建与读写本地文件(IEFirefox)
  11. Android AdapterViewFlipper
  12. Confluence 6 配置数字格式
  13. Vue中配置代理服务器
  14. C预处理器和C函数库
  15. 域名解析ip地址的过程
  16. 十大web安全扫描工具
  17. js数字金额滚动动画(vue)
  18. 应届生入职半年被裁员了,我该怎么办?
  19. 迎接2016,一个程序员的总结
  20. mysql数据库实验报告jdbc_Jdbc连接数据库实验报告(1)

热门文章

  1. 嵌入式开发(三):海思Hi3559a交叉编译live555
  2. 微信小程序电商首页开发基本思路
  3. Python seek()和tell()函数详解
  4. 高效率工具推荐,让你快速提高效率
  5. RGB图片处理(1)——RGB概念理解
  6. python读取pdf文件并转换成txt文件
  7. 阿里云ECS服务器Linux第一次登录 提示Login Incorrect的解决方法
  8. python实部和虚部都是浮点数_python实部和虚部都是浮点数_python——Numpy库
  9. 计算机如何寻找ppt文件,电脑上没保存的PPT怎么找回来
  10. HBuildX的下载安装教程