【cocos3.x+box2d+tileMap】制作马里奥游戏(二) 制作地图

梦里梦外; 2022-08-19 15:21 2645阅读 0赞

一、概念

  1. tileMap是一个开源的、跨平台的地图制作工具,地图存储为Tmx格式,而cocos则提供对tileMap的原生支持。
  2. 相关概念网上资料很多,如: [ cocos2dx\[3.4\](25)——瓦片地图TiledMap][cocos2dx_3.4_25_TiledMap],推荐初学者先去了解一下,这里主要记录制作过程。

二、素材

  1. 马里奥网络相关素材很多,不过基本都是低分辨率下的,要想手机中有比较好的效果,基本都需要放大。除非自己弄个高分辨率的。这里贴一下我用到的两张素材,如下:

SouthEastSouthEast 1

三、tileMap制作

到官网下载tileMap工具,然后开始制作流程:

  1. 新建地图,其中块大小16*16像素,是根据素材选择的。Tile layer format推荐使用压缩,可以大幅减小地图文件大小。Tile render order——Right down,表示地图文件会先从最顶一行,从左往右表述,直到最底部。

SouthEast 2

  1. 默认会建立一个图层,我们将这个图层命名为walls,用于存放一些不可移动、不可穿越的墙等元素。

  2. 导入图块。图块其实就是创建地图的砖头,一般是将这些砖头放入同一张图中,tileMap会在导入时,按照我们选择的素材块大小帮我们切割。

SouthEast 3

导入后如图:

SouthEast 4

  1. 然后就可以在中间的编辑器中用这些图块来创建地图了,注意使用上面的工具栏:

SouthEast 5

四、创建遮挡

  1. 地图制作出来,就可以在cocos中加载使用。不过现在的程度,和加载一张普通图片没有任何区别,所以我们还需要给地图加上其他属性,如墙——不可穿越、怪物——不可碰撞等等。怪物属性当前还没有用到,后面再更新。墙的实现尝试了两种方式,下面都讲一下:

1. 使用块属性

  1. 所有的块都可以添加属性,然后在代码中获取使用。这种方式常被用做怪物、金币等对象的实现。最开始我尝试也使用这种方式来实现墙,但是效果不太好,后来换用了第二种方式。使用方法如下:
  • TileMap中为块添加属性

    SouthEast 6

SouthEast 7

SouthEast 8

  • 代码中使用,检查属性,添加box2d静态刚体
  1. void MarioScene::initMap(){
  2. //给所有的墙加刚体属性
  3. //遍历所有层
  4. for(auto &object : _map->getChildren()){
  5. auto layer = static_cast<TMXLayer*>(object);
  6. if(layer){
  7. for(int x = 0;x < layer->getLayerSize().width;++x){
  8. for (int y = 0; y < layer->getLayerSize().height; ++y) {
  9. //遍历所有tiles
  10. auto tile = layer->getTileAt(Point(x,y));
  11. if(tile){
  12. tile->setAnchorPoint(Vec2(0.5,0.5));
  13. int gid = layer->getTileGIDAt(Point(x,y));
  14. auto properties = _map->getPropertiesForGID(gid);
  15. //如果是墙属性,则添加Fixture,便于后续碰撞处理
  16. if(!properties.isNull()
  17. && properties.asValueMap().find("wall") != properties.asValueMap().end()){
  18. tile->setName("wall");
  19. tile->setTag(CONTACT_TARGET);
  20. addBodyToWorld(tile, b2_staticBody,2);
  21. }
  22. }
  23. }
  24. }
  25. }
  26. }
  27. }
  • 这样,在box2d的世界中,这种块创建的地图,就会同样创建相同的静态刚体,其他动态刚体如马里奥会与其产生碰撞效果。

缺点:

  1. 每个小块单独产生一个刚体,增加运算量,且实际测试中,马里奥在小刚体之间滑动会有意外效果,如被弹起、阻挡等。

2.使用对象层

这个方法来源于文章:【COCOS2DX-BOX2D游戏开发之三】 读取tiledmap的tmx阻挡,我这里只是修改为3.9版本可用。且其中有一步增加对polyline的解析支持,在3.9版本中,官方已经添加,不过椭圆还是没有的,需要自己修改代码。

  • TileMap中添加对象层,命名为pyhsics

SouthEast 9

  • 然后按需要添加对象,注意使用菜单栏

SouthEast 10

  • 代码中,根据对象产生静态刚体墙
  1. bool MarioScene::createPhysical(float scale)
  2. {
  3. b2BodyDef body_def;
  4. body_def.type = b2_staticBody;
  5. body_def.position.SetZero();
  6. _pyhsicalBody = _b2World->CreateBody(&body_def);
  7. // 找出阻挡区域所在的层
  8. TMXObjectGroup* group = _map->getObjectGroup("physics");
  9. auto objects = group->getObjects();
  10. for(const auto v :objects)
  11. {
  12. auto dict = v.asValueMap();
  13. if (dict.size() == 0)
  14. continue;
  15. b2FixtureDef fixture_def;
  16. // 读取所有形状的起始点
  17. float x = dict["x"].asFloat() * scale;
  18. float y = dict["y"].asFloat() * scale;
  19. b2Shape* shape = NULL;
  20. //多边形
  21. if (dict.find("polygonPoints") != dict.end()) {
  22. auto polygon_points = dict["polygonPoints"].asValueVector();
  23. std::vector<b2Vec2> points;
  24. // 必须将所有读取的定点逆向,因为翻转y之后,三角形定点的顺序已经逆序了,构造b2PolygonShape会crash
  25. int c =polygon_points.size();
  26. points.resize(c);
  27. c--;
  28. for(auto obj : polygon_points)
  29. {
  30. // 相对于起始点的偏移
  31. float offx = obj.asValueMap()["x"].asFloat() * scale;
  32. float offy = obj.asValueMap()["y"].asFloat() * scale;
  33. points[c--] = (b2Vec2((x + offx) / PTM_RATIO, (y-offy) / PTM_RATIO));
  34. }
  35. b2PolygonShape *ps = new b2PolygonShape();
  36. ps->Set(&points[0], points.size());
  37. fixture_def.shape = ps;
  38. shape = ps;
  39. } else if (dict.find("polylinePoints") != dict.end()){
  40. auto polyline_points = dict["polylinePoints"].asValueVector();
  41. std::vector<b2Vec2> points;
  42. for(auto obj : polyline_points)
  43. {
  44. float offx = obj.asValueMap()["x"].asFloat() * scale;
  45. float offy = obj.asValueMap()["y"].asFloat() * scale;
  46. points.push_back(b2Vec2((x + offx) / PTM_RATIO, (y-offy) / PTM_RATIO));
  47. }
  48. b2ChainShape *ps = new b2ChainShape();
  49. ps->CreateChain(&points[0], points.size());
  50. fixture_def.shape = ps;
  51. shape = ps;
  52. }
  53. fixture_def.density = 1.0;
  54. fixture_def.friction = 0;
  55. fixture_def.restitution = 0;
  56. _pyhsicalBody->CreateFixture(&fixture_def);
  57. if (shape) {
  58. delete shape;
  59. shape = NULL;
  60. }
  61. }
  62. return true;
  63. }
  • 这样,产生的静态刚体墙就可以和马里奥产生碰撞效果。

发表评论

表情:
评论列表 (有 0 条评论,2645人围观)

还没有评论,来说两句吧...

相关阅读

    相关 地图制作

    二维地图制作: 工具:SuperMap IDesktop 9D 1. 地图概述:普通地图、专题地图(水利、国土等)。 2. 数据集成:获取制图所需的数据,并集成到Su