游戏邦在:
杂志专栏:
gamerboom.com订阅到鲜果订阅到抓虾google reader订阅到有道订阅到QQ邮箱订阅到帮看

基于Cocos2D-X的砖块地图教程(一)

发布时间:2013-11-26 14:48:37 Tags:,,,,

作者:Jorge Jordán

这是Cocos2D-X砖块地图教程系列,你将在此创造一款有关沙漠中的忍者寻找美味的西瓜的简单游戏。

需要注意的是该教程是关于Cocos2D-X,即Cocos2D-iPhone的跨平台C++移植。所以你在此编写的代码将适用于iPhone,Android和更多平台上!

在本系列文章的第一部分中,你将学习如何添加砖块地图到游戏中,跟着玩家滚动地图,并使用对象图层。你将学到如何使用地图编辑器去创造砖块地图本身。

而第二部分是关于如何在地图上创造碰撞领域,如何使用砖块属性,如何创造可收集的道具并动态地修改地图,以及如何确保你的忍者不会吃太多东西。

注:本篇教程类似于Cocos2D-iPhone教程。

让我们开始创造砖块地图吧!

开始

对于这一教程,你需要安装最新的Cocos2D-X版本(游戏邦注:在写本篇教程的时候更新到2.1.4)。如果你还未拥有最新版本的Cocos2D-X,先下载它并在终端运行如下命令去安装模版:

cd ~/Downloads/cocos2d-x-2.1.4
./install-templates-xcode.sh -f -u

然后使用iOS\cocos2d-x\cocos2dx模版在Xcode创造一个新项目。点击Next,将项目命名为TileGame,将项目设置为Universal,点击Next然后点击Create。

你将在这一项目中使用ARC,所以如果这是你第一次听到ARC,我会鼓励你先了解下它。模版并不是默认使用ARC,但幸运的是,我们能够轻松地进行修改。前往Edit\Refactor\Convert to Objective-C ARC。往下拉并只选择文件main.m, AppDelegate.cpp, HelloWorldScene.cpp,然后点击Check并完成向导的步骤。

select targets(from raywenderlich)

select targets(from raywenderlich)

创建并运行,然后确保一切都还正常运行—-你应该能够看到标准的“你好世界”屏幕。

接下来下载游戏资源的压缩文件。压缩文件包含如下内容:

你将面向玩家对象使用的精灵。

一些伴随着cfxr效用所创造的音效(你将会在教程中用到)。

一些伴随着Garage Band所创造的背景音乐。

你将用到的一些砖块设置—-这将伴随着你将使用的地图编辑器,但我认为我们能够更轻松地将其与其它内容包含在一起。

一些额外的“特别”砖块,将在之后进行详细解释。

当你下载了资源后,打开它并将TileGameResources文件夹拖到项目的Resources群组中。在项目菜单里,右击Resources群组,并选择Add Files to “TileGame”…选择Resources/TileGameResources文件夹,核实选中了Copy items into destination group’s folder (if needed)以及Create groups for any added folders,然后点击完成。

如果一切顺利的画,所有的文件都将出现在你的项目中。

你的项目应该如下:

tile game(from raywenderlich)

tile game(from raywenderlich)

现在我们将开始创造地图!

创造地图

Cocos2D-X支持基于开放源Tiled Map Editor去创造地图并将其以TMX格式进行保存。

下载Tiled Map Editor。在编写本篇教程的时候,其最新版本是0.9.0。

然后运行Tiled,前往File\New,并如下填写对话内容:

new map(from raywenderlich)

new map(from raywenderlich)

在定向区域中,你可以在Orthogonal或Isometric间做出选择。在此你将选择Orthogonal。

接下来你将设置地图的大小。记住这是在砖块中,而不是像素中。你将创造一个较小的地图,所以在此你应该选择50×50。Tiled将基于像素呈现给你总体地图的大小,即在New Map对话的最底部。这是在长度和宽度的基础上将地图大小(50个砖块)乘以砖块的大小(32像素)所计算出来的。

最后,你将明确宽度和高度。你在此所选择的是取决于美术人员所设置的砖块。对于本篇教程,你将使用一些伴随着Tiled编辑器的样本砖块,即32×32规格,选择它便点击OK。

接下来你必须添加砖块设置去绘制你的地图。在菜单栏上点击Map,然后关掉New Tileset…,并如下填写对话框内容:

new tileset(from raywenderlich)

new tileset(from raywenderlich)

为了获得图像,点击Browse并导航至你自己的TileGame/Resources/TileGameResources文件夹,然后选择你之前从资源压缩中下载的tmw_desert_spacing.png文件,并将其添加到项目中。它将自动根据文件名填写名字。

你可以将宽度和高度设置为32×32,因为这也是砖块的大小。对于边缘和间隔:

边缘是关于在Tiled开始寻找真正的砖块像素前应该为当前的砖块略过多少多少像素(包括宽度和高度)。

间隔是关于Tiled在明确了实际砖块像素并转向下一个砖块数据之后应该前进多少像素(包括宽度和高度)。

如果你着眼于tmw_desert_spacing.png,你将发现每个砖块都围绕着一个1像素的黑色边缘,这也解释了边缘和间隔为1的设置。

tile(from raywenderlich)

tile(from raywenderlich)

当你点击OK时,你将看到砖块呈现在Tilesets窗口中。现在你可以开始绘制了。点击工具栏的Stamp Brush图标,然后点击地图上的任何一个位置去放置一个砖块。

tileset(from raywenderlich)

tileset(from raywenderlich)

所以继续绘制地图—-尽可能发挥创造性!确保添加至少一些建筑到地图上,因为你在之后将需要一些碰撞内容。

tileset(from raywenderlich)

tileset(from raywenderlich)

为了更轻松地绘制内容,你可以着眼于一些快捷方法。以下是最常用到的一些方法:

你可以在Tileset选择器中围绕着一系列砖块拖曳一个盒子,并同时放下多个相邻的砖块。

你可以通过View\Zoom In和View\Zoom Out进行放大和缩小。

z键将在基于Stamp Brush工具编辑地图时进行旋转。

在一些新功能中你可能会注意到Mini-map。这是一个很棒的功能,它让你能够看到一个迷你地图!着眼于我在Mini-map最下方的迷宫中的糟糕尝试。红色盒子代表你在主要编辑窗口中看到的区域。

tileset(from raywenderlich)

tileset(from raywenderlich)

当你在阅读下一个区域中的滚动时牢牢记住这一Mini-map视图。

需要注意的是这一教程的资源是出现在地图前的——所以如果你很懒的话便可以直接利用它。如果你这么做,你应该在Tiled打开地图并明确它是如何设置的。

当你完成地图的绘制时,在Layers视图中双击Tile Layer,将名字改为Background。然后点击File\Save,并将文件保存到TileGame项目中的TileGame\Resources\TileGameResources,将文件命名为TileMap.tmx,并覆盖现有的文件。

你将在之后使用Tiled做其它事,但是现在让我们将这一地图带进游戏中!

添加Tiled地图到Cocos2D-X场景中

打开HelloWorldScene.h,在#include “cocos2d.h”之后添加如下内容:

using namespace cocos2d;

这能指导编辑器去使用cocos2d命名空间,所以你不需要为所有内容加上cocos2d的前缀。

然后添加以下内容到类定义中,即在花括号之后:

private:
CCTMXTiledMap *_tileMap;
CCTMXLayer *_background;

这创造了一个实例变量去追踪砖块地图本身,并创造了另一个实例变量去追踪地图的背景层。你将在之后学到更多有关砖块地图层面的内容。

接下来,用如下内容换掉HelloWorldScene.cpp:

#include “HelloWorldScene.h”

using namespace cocos2d;

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
bool HelloWorld::init()
{
if ( !CCLayer::init() )
{
return false;
}

_tileMap = new CCTMXTiledMap();
_tileMap->initWithTMXFile(“TileMap.tmx”);
_background = _tileMap->layerNamed(“Background”);

this->addChild(_tileMap);

return true;
}

在此你将调用CCTMXTiledMap类,命令它从你之前用Tiled创造的砖块地图文件中创造一张地图。

一些快捷背景:当CCTMXTiledMap是CCNode时,你可以设置它的位置和规格。节点的孩子是砖块地图的层面,这里也有一个辅助函数layerNamed,你可以通过名字去找到它们—-就像你获得背景一样。从性能来看,每个层面都是CCSpriteSheet的子类—-但这也意味着你在每个层面只能拥有一个砖块集。

所以上述源代码保存了一个参考到砖块地图和背景层面上,然后添加了砖块地图到HelloWorld层面上。

在你的iPad模拟器上创建并运行你的代码,你将在左下角看到地图:

simulator(from raywenderlich)

simulator(from raywenderlich)

还不错!但是为了让它成为真正的游戏,你还需要三样内容:

1.玩家

2.放置玩家的起始点

3.移动你的视角如此你便能够看到玩家

从这里开始事情就变得棘手了。让我们继续!

Tiled对象层面和设置砖块地图位置

Tiled支持两种层面类型:

砖块层面:这是你到目前为止所处理的。

对象层面:这让你能够围绕着地图部分绘制盒子去明确事物发生的区域。例如,你可能会创造出怪物出现的区域,或者致命的区域。在本篇教程中,你将为玩家的刷怪点创造一个区域。

所以前往Tiled中的菜单栏,并选择Layer\Add Object Layer,将层面命名为Objects。插入一个Object,从工具栏中选择InsertRectangle(R)。为了弄清楚现在呈现的是什么层面,你只需要着眼于左下角便可以。

background(from raywenderlich)

background(from raywenderlich)

如果你在地图上绘制,你将注意到它并不能绘制一个砖块。相反地,它将会指出一个矩形,而你可以扩展它去覆盖多个砖块或进行移动。在最新的填充版本中,你也可以绘制其它形状的对象,如椭圆形,多边形和折线。

你只需要为玩家选择一个砖块让他们进入。所以在地图上选择一个位置并点击砖块。盒子的大小并不重要,因为你将只是使用x和y轴。注意如果你很懒的话这种方法将成为你的偷懒工具(尽管你也需要将所提供的对象重命名为“SpawnPoint”)。

background(from raywenderlich)

background(from raywenderlich)

然后右击你刚刚添加的灰色对象,并选择Object Properties…,为其命名为SpawnPoint并点击OK:

object properties(from raywenderlich)

object properties(from raywenderlich)

在之前的Cocos2D-X版本中你将对象的Type设置为Cocos2D-X的类名,但却因为问题的出现而删除了它,所以Type这一栏是空白的,这将创造一个CCDictionary,你可以在此访问各种对象元素,包括x和y轴。

保存地图,回到Xcode,打开HelloWorldScene.h。伴随着其它私有变量,在私有变量声明中添加如下代码:

CCSprite *_player;

接下来打开HelloWorldScene.cpp并在初始化方法中添加如下内容,即在设置完->addChild(_tileMap)之后:

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

if(objectGroup == NULL){
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 = new CCSprite();
_player->initWithFile(“Player.png”);
_player->setPosition(ccp(x,y));

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

最后一行有个预兆——但不要担心,你很快就能到达那里。

让我们暂停一会并解释对象层面和对象群组。首先注意你是通过在CCTMXTiledMap对象中(而不是layerNamed)通过objectGroupNamed方法检索对象层面。它返回了一个特殊的CCTMXObjectGroup对象。

然后objectGroup调用了objectNamed方法去获得一个CCDictionary,并包含了一些有关对象的有用信息,如x和y轴,宽度和高度。在教程的这一部分,你需要关心的便是x和y轴,将其设置为玩家精灵的位置。

在代码块的最后你设置了视图去明确玩家的位置。所以现在添加如下内容到HelloWorldScene.h中:

// In the public section
void setViewPointCenter(CCPoint position);

并添加一个新方法到HelloWorldScene.cpp(在文件的最下方最好):

void HelloWorld::setViewPointCenter(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 * this->_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);
}

这是关于砖块的解释。想象这一函数设置了摄像机的中心位置。它让用户能够进入地图中x,y轴的任何位置—-但是你有可能不想呈现出某些点,如你可能不想要屏幕超过地图的边缘(那么它便只会呈现出黑边!)。

如下图:

diagram(from raywenderlich)

diagram(from raywenderlich)

如果摄像机的中心小于winSize.width/2或winSize.height/2,那么部分视角是否会脱离屏幕?同样的,检查最上方的界限也很重要,这也是setViewPointCenter所做的。

到目前为止这一函数被当成设置了摄像机所面对的中心位置。然而,这并不是它真正做的。这是在Cocos2D-X中操控CCNode的摄像机的一种方法,但使用它会比你将使用的解决方法(移动整个层面)更复杂。

着眼于这一图解:

diagram(from raywenderlich)

diagram(from raywenderlich)想象一个大世界,你将着眼于坐标轴,即从0到winSize.height/width。你的视图的中心是centerOfView,你便能清楚自己想要以哪里为中心(actualPosition)。所以为了用实际位置去匹配视图中心位置,你需要做的便是向下倾斜地图!

通过从视图中心减去实际位置你便能够做到这点,然后将HelloWorld层面设为该位置。

说了这么多理论,是时候执行它们了!创建并运行项目,如果一切运行正常,你将在屏幕上看到忍者,并且视图会不断移动去呈现他的行动。

simulator(from raywenderlich)

simulator(from raywenderlich)

让忍者移动

这是个好的开始,但是你的忍者还只是站在那里!这并不像真正的忍者。你将朝着用户敲打的方向移动忍者而让他动起来。添加如下代码到HelloWorldScene.h的公共部分:

void registerWithTouchDispatcher();

void setPlayerPosition(CCPoint position);

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

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

然后打开HelloWorldScene.cpp并将如下代码添加到init:

this->setTouchEnabled(true);

这将层面设置为可碰触的,所以它将关注于碰触事件。接下来添加如下方法到文件最底端:

#pragma mark – handle touches

void HelloWorld::registerWithTouchDispatcher() {
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
}

bool HelloWorld::ccTouchBegan(CCTouch *touch, CCEvent *event)
{
return true;
}

void HelloWorld::setPlayerPosition(CCPoint position) {
_player->setPosition(position);
}

void HelloWorld::ccTouchEnded(CCTouch *touch, 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方法(复数情况)。

你可能会好奇单数情况和复数情况有什么区别。不过在这种情况下我们没有必要去弄清楚这些问题。但是我还是想向所有人介绍这一方法,因为它带有2个主要优势:

“你不需要处理NSSets,调度程序能够区分它们。每次调用你将获得一个UITouch。”

“你可以通过在ccTouchBegan返回YES而要求一个UITouch。要求碰触的更新只会被发送到要求它们的委托中。所以如果你删除/结束/取消更新,你就需要确保它是你的碰触。这将让你无需在执行多点碰触时做各种检查。”

不管怎样,在你的ccTouchEnded位置上,你像往常那样将位置转换成视图坐标轴,然后再转换成GL坐标轴。而新任务便是你调用了this->convertToNodeSpace(touchLocation)。

这是因为碰触位置将提供给你用户在视口中轻敲的坐标轴(例如100,100)。但是你可能已经滚动了地图,所以它将匹配(800,800)的位置。所以调用这一方法将基于你如何移动层面而抵消碰触。

接下来你将明确碰触点和玩家位置的区别。你将基于碰触选择一个方向,所以首先你应该决定是上下移动还是左右移动。然后你将判断是正数还是复数而进行上下移动。

你将相对地调整玩家位置,然后将视图中心设置为玩家的位置,这是你在上部分便写下的内容!

注意你必须添加一个安全检查以确保不会将玩家带离地图外部!

所以创建并运行项目,然后尝试它!现在你应该能够轻敲屏幕去移动忍者了!

simulator(from raywenderlich)

simulator(from raywenderlich)

最后

这时候你已经知道如何创造地图并将其整合到游戏中了。而在第二部分教程中你将进一步学习如何添加碰撞检测到地图中以避免忍者能够轻松地穿越墙壁。

本文为游戏邦/gamerboom.com编译,拒绝任何不保留版权的转载,如需转载请联系:游戏邦

Cocos2D-X Tile Map Tutorial: Part 1

By Jorge Jordán

This is a 2-part Cocos2D-X tile map tutorial series, where you’ll create a simple game about a ninja in the desert, in the search for a tasty watermelon.

Note that this tutorial is about Cocos2D-X, the cross-platform C++ port of Cocos2D-iPhone. So the code you’ll write here will work on iPhone, Android, and more!

Note: This tutorial is a port of a similar tutorial for Cocos2D-iPhone. If you are looking for the Cocos2D-iPhone version, you can check it out here.
In this first part of the series, you’ll learn how to add a tile map to the game, scroll the map to follow the player, and use object layers. You’ll also learn how to use a map editor to create the tile maps themselves.

The second part of this series covers how to make collidable areas in the map, how to use tile properties, how to make collectable items and modify the map dynamically and how to make sure your ninja doesn’t overeat.

If you haven’t already, you may wish to start with the Cocos2D-X Tutorial for iOS and Android: Space Game, since that covers most of the basics that you’ll build upon here.

Ok, so let’s have some fun with tile maps!

Getting Started

For this tutorial you will need the latest version of Cocos2D-X installed (2.1.4 at the time of writing this tutorial). If you don’t have it already, download it now and install the templates by running the following commands in Terminal:

Then create a new project in Xcode with the iOS\cocos2d-x\cocos2dx template. Click Next, name the project TileGame, select the options to make the project Universal, click Next and then click Create.

You are going to use ARC in this project so if this is the first time you have heard about ARC, I encorage you to take a look at the Beginning ARC series. By default the template isn’t set up to use ARC but, luckily, fixing it is really easy. Just go to Edit\Refactor\Convert to Objective-C ARC. Expand the dropdown and select only the files main.m, AppDelegate.cpp, HelloWorldScene.cpp, then click Check and finish the steps of the wizard.

And that’s it! Build and Run and make sure everything still works OK – you should see the normal Hello World screen.

Next, download this zip file of resources for the game. The zip file contains the following:

A sprite you’ll use for your player object. This may look familiar from the How to Make A Simple iPhone Game with Cocos2D Tutorial!

Some sound effects made with the excellent cfxr utility that you’ll use in the tutorial.

Some background music made with Garage Band (see this post for more info).

The tile set you’ll be using – it actually comes with the map editor you’ll be using, but I thought it would be easier to include it with everything else.

Some additional “special” tiles explained a bit later.
Once you have the resources downloaded, unzip it and drag the TileGameResources folder to the Resources group in your project. In the project menu, right click the Resources group, and select Add Files to “TileGame”…. Select the Resources/TileGameResources folder, verify that Copy items into destination group’s folder (if needed) is checked and that Create groups for any added folders is selected, then click Finish.

If all works well, all of the files should be listed in your project.

Your project should look like this:

That’s it for now – time to have some fun and make your map!

Making a Map with Tiled
Cocos2D-X supports maps created with the open source Tiled Map Editor and saved in TMX format.

Visit the above link and download Tiled if you don’t have it already. At the time of writing this tutorial, the latest version is 0.9.0.

Then run Tiled, go to File\New, and fill in the dialog as follows:

In the orientation section, you can choose between Orthogonal (think: the Legend of Zelda) or Isometric (think: Disgaea). You’re going to pick Orthogonal here.

Next you get to set up the map size. Keep in mind that this is in tiles, not pixels. You are going to make a smallish sized map, so choose 50×50 here. Tiled will show you the total map size in pixels, at the bottom of the New Map dialog. This is calculated by multiplying the map size (50 tiles) by the tile size (32 px) in both height and width.

Finally you specify the tile width and height. What you choose here depends on the tile set that your artist will be making. For this tutorial, you are going to use some sample tiles that come with the Tiled editor which are 32×32, so choose that and click OK.

Next, you have to add the tile set that you’ll be using to draw your map. Click on Map in the menu bar, then chose New Tileset…, and fill in the dialog as follows:

To get the image, just click Browse and navigate to your TileGame/Resources/TileGameResources folder, and pick the tmw_desert_spacing.png file that you downloaded from the resource zip and added to your project. It will automatically fill out the name based on the filename.

You can leave the width and height as 32×32 since that is the size of the tiles. As for margin and spacing, this is what they mean:

Margin is how many pixels Tiled should skip (for both width and height) for the current tile before it starts looking for actual tile pixels.

Spacing is how many pixels Tiled should advance (for both width and height) after it reads the actual tile pixels to get to the next tile data.

If you take a look at tmw_desert_spacing.png, you’ll see that each tile has a 1px black border around it, which would explain the settings of margin and spacing as 1.

Once you click OK, you will see the tiles show up in the Tilesets window. Now you can start drawing away! Simply click the Stamp Brush icon in the toolbar, then click a tile, then click anywhere on the map you’d like to place a tile.

So go ahead and draw yourself a map – be as creative as you’d like! Make sure to add at least a couple buildings on the map, because you’ll need something to collide into later!

To make the drawing easier, you can take a look to the keyboard shortcuts. These are some of the most used:

You can drag a box around a series of tiles in the Tileset picker, to put down multiple adjacent tiles at the same time.

You can use the Bucket Fill Tool button in the toolbar to paint areas.

You can zoom in and out with View\Zoom In and View\Zoom Out.

The z key will rotate the tile when editing a map with the Stamp Brush tool.
There is a new feature you might have noticed Mini-map. This is an awesome feature, it let you see a (you guessed it) Mini-map! Take a look at my poor attempt at a maze in the bottom of the Mini-map below. The red box indicates the area you see in the main editing window.

Keep this Mini-map view in mind when you read about about scrolling in the next section.

Note that the resources for this tutorial comes the above map pre-made – feel free to use it if you’re feeling lazy. If you do so, you should open the map in Tiled and take a peek how it’s set up.

Once you’re done drawing the map, double click on the Tile Layer 1 in the Layers view, and change the name to Background. Then click File\Save and save the file to TileGame\Resources\TileGameResources in the TileGame project, and name the file TileMap.tmx, overriding the existing file.

You’re going to do some more stuff with Tiled later, but for now let’s get this map into the game!

Adding the Tiled Map to the Cocos2D-X Scene
Open up HelloWorldScene.h, and add right after the #include “cocos2d.h” line:

This directs the compiler to use the cocos2d namespace so you don’t have to prefix everything with cocos2d:: here on out.

Then add these lines to the class definition, right after the opening curly brace:

This creates a private instance variable to keep track of the tile map itself, and another instance variable to keep track of the background layer in the map. You’ll learn more about tile map layers later.

Next, replace the contents of HelloWorldScene.cpp with the following:

Here you make a call to the CCTMXTiledMap class, instructing it to create a map from the tile map file you created before with Tiled.

Some quick background: As CCTMXTiledMap is a CCNode, you can set its position, scale, etc. The children of the node are the layers of the tile map and there’s a helper function, layerNamed, where you can look them up by name – as you did to get the background. Each layer is a subclass of CCSpriteSheet for performance reasons – but this also means that you can only have one tileset per layer.

So the above source code saves a reference to the tile map and the background layer and then add the tile map to the HelloWorld layer.

And that’s it! Build and run your code on your iPad simulator, and you should see the bottom left corner of your map:

Not bad! But, for this to be a game, you need three things:

1.a player

2.a starting point to put the player

3.to move your view so that you are looking at the player

And this is where it gets tricky. So let’s tackle this next!

Tiled Object Layers and Setting Tile Map Position
Tiled supports two kinds of layers:

Tile layers: These are which you’ve been working with so far.

Object layers: These allows you to draw boxes around portions of the maps to specify areas where things might happen. For example, you might make an area where monsters spawn, or an area that is deadly to enter. In this tutorial, you’re going to create an area for the spawn point of the player.
So go to the menu bar in Tiled and pick Layer\Add Object Layer, name the layer Objects. To insert an Object, select the Insert Rectangle(R) item from the toolbar. To know what layer is currently shown, you just look to the bottom left corner.

If you draw on the map, you’ll notice it doesn’t draw a tile. Instead, it draws a rectangle, which you can expand to cover multiple tiles or move around. In the latest version of tiled you can also draw other types of object shapes as ellipses, polygons and polylines.

You just need to select one tile for the player to start in. So choose somewhere on your map and click the tile. The size of the box doesn’t really matter, since you will just use the x, y coordinates. Note that this will be done for you already if you were lazy and used the sample map (although you will have to rename the provided object to “SpawnPoint” or you’ll get a crash – keep reading to learn how).

Then right click the gray object you just added, and select Object Properties…. Give it a name of SpawnPoint and click OK:

In previous versions of Cocos2D-X you could set the Type of the object to a Cocos2D-X class name but was removed due to issues with it, so leave the Type blank, which will create a CCDictionary where you can access the various aspects of the object, including the x, y coordinates.

Save the map, go back to Xcode, and open HelloWorldScene.h. Add the following inside the private variables declaration, with the other private variables:

Next open HelloWorldScene.cpp and add the following inside the init method, after setting this->addChild(_tileMap):

There will be a warning on that last line – don’t worry, you’ll get to it in a second.

Let’s stop for a second and explain the bit about the object layer and object groups. First note that you retrieve object layers via the objectGroupNamed method on the CCTMXTiledMap object (rather than layerNamed). It returns a special CCTMXObjectGroup object.

Then objectGroup calls the objectNamed method to get a CCDictionary containing a bunch of useful info about the object, including x and y coordinates, width, and height. In this point of the tutorial all you need to care about is the x, y coordinates to set them as the position of your player sprite.

At the end of the code block you are setting the view to focus on where the player is. So now add the following line to HelloWorldScene.h:

and the new method to HelloWorldScene.cpp (at the bottom of the file is fine):

Ok, here is the explanation of this block. Imagine this function is setting the center of a camera. It allows the user to pass in any x,y coordinate in the map here – but if you think about it there are some points that you don’t want to be able to show – for example you don’t want the screen to extend beyond the edges of the map (where it would just be blank space!).

For example, take a look at this diagram:

See how if the center of the camera is less than winSize.width/2 or winSize.height/2, part of the view would be off the screen? Similarly, is important to check the upper bounds as well, and that’s exactly what does setViewPointCenter.

Now so far this function has been treated as if it was setting the center of where a camera was looking. However… that isn’t exactly what it’s doing. There is a way in Cocos2D-X to manipulate the camera of a CCNode, but using that can make things more difficult than the solution you’re going to use: moving the entire layer instead.

Take a look at this diagram:

Imagine a big world, and you’re looking at the coordinates from 0 to winSize.height/width. The center of your view is centerOfView, and you know where you want the center to be (actualPosition). So to get the actual position to match up to the center of view, all you do is slide the map down to match!

This is accomplished by subtracting the actual position from the center of view, and then setting the HelloWorld layer to that position.

Phew! Enough theory – is time to see it in action! Build and run the project, and if all goes well you should see your ninja in the scene, with the view moved to show him strutting his stuff!

Making the Ninja Move

This is a good start, but your ninja is just sitting there! And that’s not very ninja-like.

You will make the ninja move simply by moving him in the direction the user taps. Add the following code to the public section of HelloWorldScene.h:

Making the Ninja Move
This is a good start, but your ninja is just sitting there! And that’s not very ninja-like.

You will make the ninja move simply by moving him in the direction the user taps. Add the following code to the public section of HelloWorldScene.h:

This sets the layer to be touch enabled so it pays attention to touch events. Next add these methods to the bottom of the file:

Here you override the registerWithTouchDispatcher method to register yourself to handle targed touch events. This will result in ccTouchBegan/ccTouchEnded methods being called (singular case), instead of ccTouchesBegan/ccTouchesEnded methods (plural case).

You may wonder what’s the difference between the singular case and the plural case. In this case it doesn’t matter either way. However, I wanted to introduce everyone to this method in case you hadn’t seen it already, because it has two significant advantages (these are listed verbatim from the cocos2D-X source):

“You don’t need to deal with NSSets, the dispatcher does the job of splitting them. You get exactly one UITouch per call.”

“You can *claim* a UITouch by returning YES in ccTouchBegan. Updates of claimed touches are sent only to the delegate(s) that claimed them. So if you get a move/ended/cancelled update you’re sure it’s your touch. This frees you from doing a lot of checks when doing multi-touch.”

Anyway, inside your ccTouchEnded location, you convert the location to view coordinates and then to GL coordinates as usual. What is new is you call this->convertToNodeSpace(touchLocation).

This is because the touch location will give you coordinates for where the user tapped inside the viewport (for example 100,100). But you might have scrolled the map a good bit so that it actually matches up to (800,800) for example. So calling this method offsets the touch based on how you have moved the layer.

Next, you figure out the difference between the touch and the player position. You have to choose a direction based on the touch, so first you decide whether to move up/down or side to side based on whichever is the greatest distance away. Then you just see if it’s positive or negative to move up or down.

You adjust the player position accordingly, and then set the viewpoint center to be the player position, which you already wrote in the last section!

Note you have to add a safety check to make sure you’re not moving your player off the map as well!

So Build and Run the project and try it out! You should now be able to tap the screen to move the ninja around.

Where To Go From Here?
That’s all for this part of the tutorial. At this point you should know the basics about creating maps and importing them into your game.

Here’s a sample project with the code you’ve developed so far.

In the part 2 of the tutorial you will learn how to add collision detection into the map to prevent your ninja from happily walking through the walls!(source:raywenderlich)


上一篇:

下一篇: