(3) cocos2d-x Tile Map 教程(一)
原文来自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 我这里用的是2.2.1版本,所以后面没用的就不翻译了。 接着,创建一个名为MyTileGame的工程。(至于创建步骤,大家应该都懂)。 你将在工程中使用ARC,如果这是你第一次使用ARC,我推荐你看一下ARC教程系列,默认创建的工程是非ARC的,修改这个很简单, 点击EditRefactorConvert to Objective-c ARC.展开下拉,选中main.m,AppDelegate.cpp,HelloWorldScene.cpp然后点击Check,完成向导。 编译-》运行,确保一切ok,你就会看到正常的HelloWord程序了。 接下来,下载游戏的压缩包,这里面包含了以下东西:
一旦你下载好之后,解压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的地图,确保至少要添加一些建筑物,因为后面要用来做碰撞。 这里我就随便画了..... 为了画起来更方便,你可以看一下这些快捷键,下面是一些常用的:
你也许已经注意到在迷你地图中有一些新的功能,很不错的功能,让你能看迷你的地图。 来看一下在迷你地图的下面我尝试做的简单迷宫。红色的方框表示你在主编辑窗口能看到的地图。 当你要滚动区域的时候,记得用这个迷你地图功能。 注意,本教程的资源来自上述地图预先制作——可以免费使用,如果你懒得自己做。如果你要自己做,你应该在Tiled中打开地图,看一下它是怎样建立起来的。 画完地图后,双击图层窗口中得块层1,改名为Background.然后点文件保存,保存到游戏工程的MyTileGameResourcesTileGameResourcese目录,然后命名为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 returnscene; } // 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件事:
而这就变得非常棘手,所以接下来让我们解决它。 Tiled Object Layers and Setting Tile Map Position Tiled支持下面两种类型的图层:
所以,在Tiled工具中点击菜单栏上的图层添加对象层,命名为Objects,为了插入这个Object,选中工具栏上得插入矩形(R),为了知道当前显示的图层可以看Tiled工具的左下角: 如果你拖动地图,你会注意到并没有画图块,而是,画了个矩形框,你可以覆盖多个图块或是到处的移动。在最新版本中,你还可以其他的类型,如椭圆,多边形,折现等。 你只需要选择一小块,作为玩家开始的地方,所以在地图上选中一个区域并点击图块,矩形框的大小并不重要,因为我们只用x,y坐标。注意,如果你懒而使用样本地图,这将为你完成。 然后,右键刚刚添加的这个灰色的对象,选择对象属性...,给它一个名字SpawnPoint,然后点击 在以前的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"); intx = ((CCString)*spawnPoint->valueForKey("x")).intValue(); inty = ((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.本教程的重点关心的是 玩家精灵的位置。 在代码片最后,你把player的位置作为这个视图的位置。所以现在添加下面代码到HelloWorldScene.h中: void setViewPointCenter(CCPoint position); 然后在HelloWorldScene.cpp中添加实现方法: voidHelloWorld::setViewPointCenter(cocos2d::CCPointposition) { CCSizewinSize =CCDirector::sharedDirector()->getWinSize();
//防止玩家超出边界 intx =MAX(position.x,winSize.width/2); inty =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); CCPointactualPosition =ccp(x,y);
CCPointcenterOfView =ccp(winSize.width/2,winSize.height/2); CCPointviewPoint =ccpSub(centerOfView,actualPosition); this->setPosition(viewPoint); ok,来解释下这段代码,想象一下这功能是设置一个照相机的中心,它允许用户在地图上通过任意的 让屏幕超过地图的边界(它只是空白的)。 例如,看这个图解: 你看,是否相机的中心不到WinSize.width/2,Winsize.height/2,视图的部分就超出了屏幕。 同样的,重要的是要检查好上限边界,这正是setViewPointCenter做的。 这个完成了视图的中心位置减去实际的位置,然后把结果设为HelloWorld图层的位置。 唷,做了这么多,是时候看它动起来了。 运行程序,如果没错的话,你将看到一个忍者在屏幕上。 Making the Ninja Move 这是个好的开始,但是你的忍者只是站在那里,不像个真忍者。 你将让你的忍者在用户轻点的方向上做简单的移动,添加下面的代码到HelloWorldScene.h的pubic区: voidregisterWithTouchDispatcher(); voidsetPlayerPosition(CCPointposition); boolccTouchBegan(CCTouch*touch,CCEvent*event); voidccTouchEnded(CCTouch*touch,CCEvent*event); 然后打开HelloWorldScene.cpp添加这句到init()中,在return前: this->setTouchEnabled(true);这设置了让图层能够触摸,所以注意touch事件,再添加下面代码:
voidHelloWorld::registerWithTouchDispatcher() CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,true); } boolHelloWorld::ccTouchBegan(cocos2d::CCTouch*touch,cocos2d::CCEvent*event) { returntrue; voidHelloWorld::setPlayerPosition(cocos2d::CCPointposition) { _player->setPosition(position); } voidHelloWorld::ccTouchEnded(cocos2d::CCTouch*touch,51); font-family:Arial; font-size:14px; line-height:26px"> CCPointtouchLocation = touch->getLocationInView(); touchLocation =CCDirector::sharedDirector()->convertToGL(touchLocation); touchLocation =this->convertToNodeSpace(touchLocation); CCPointplayerPos =_player->getPosition(); CCPointdiff =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; 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方法被调用(多触摸的情况下)。你肯定想知道单触摸和多触摸之间的不同,在这种情况下用这两种都没关系。但是,如果你之前没见过这个方法,我想介绍给大家,因为它有明显的两个优点:
接下来,有一大段是讲坐标的,英语水平实在是渣,就不翻译了。 编译-》运行程序,现在忍者就可以在屏幕上移动了。 这是第一部分的教程。源码在这里 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |