TiledMap 浅谈

news2024/11/14 19:29:56

Tiled Map Editer

制作TiledMap的工具很多,这里推荐一个免费的工具。

Tiled Map Editer

官网网站:https://doc.mapeditor.org/

简单的Tiled Map Editer教程

安装Tiled Map Editer,打开。

在这里插入图片描述

点击新建地图

在这里插入图片描述

块大小建议为32的倍数

地图方向

正常(普通地图)

在这里插入图片描述

45度

在这里插入图片描述

等角(交错)

在这里插入图片描述

六角(交错)

在这里插入图片描述

创建地图

在这里插入图片描述

创建图块的图集
在这里插入图片描述

打开之后
在这里插入图片描述

会根据下面的块设置将图片分隔成小块

在这里插入图片描述

随便铺满之后为

在这里插入图片描述

坐标系

对于瓦片地图来说,坐标系为:

原点:在左上角。

单位:瓦片数量

X轴正方向:从左到右

Y轴正方向:从上到下

坐标从(0,0)开始

将指针指向地图块,编辑器会在左下角显示

在这里插入图片描述

坐标和GID(全局表示ID)

地图层

在这里插入图片描述
在这里插入图片描述

编辑器提供了三种:对象层、图块层和图像图层。

图块层 TMXLayer

图块层提供了一种存储填充图块数据的大区域的有效方法。该数据是简单的图块引用数组,因此不能为每个位置存储附加信息。唯一存储的额外信息是一些标志,它们允许平铺图形垂直、水平或反对角线翻转(以支持 90 度增量旋转)。

渲染每个图块层所需的信息与地图一起存储,该信息根据方向和各种其他属性指定图块的位置和渲染顺序。

尽管只能引用图块,但图块层对于定义关卡中的各种非图形信息也很有用。碰撞信息通常可以使用特殊的图块集来传达,并且任何不需要自定义属性并且始终与网格对齐的对象也可以放置在图块层上。

在这里插入图片描述

每一个地图层可以被表示为TMXLayer类,并设置了名称。(如下图有三个地图层:Meta、Foreground、BackGround)

每一个单一的瓦片被表示为Sprite类,父节点为TMXLayer

每一个地图层只能由一套瓦片素材组成,否则会出问题。(如下面的右图所示,有两套瓦片素材(tile、meta),但是一个地图层只能使用一套瓦片素材)
在这里插入图片描述

简单来说,图块层用来绘制一些地图基本要素,这些地图要素基本上是固定的,如云、鸟、树木、仙人掌和草地等,相当于背景图

对象层 TMXObjectGroup

对象层很有用,因为它们可以各种图块层存储不了的数据。对象可以被随意放置、调整大小、旋转。对象层还可以进行个性化的配置。对象层有以下几种:

  • Rectangle(矩形)-用来标记自定义的矩形区域
  • Ellipse(椭圆形)-用来标记自定义的椭圆形区域或者圆形区域
  • Point(点)-用来标记准确的位置
  • Polygon(多边形)-用来标记当矩形或者椭圆形无法表示的对象(通常是碰撞区域)
  • Polyline(折线)-用来标记游戏路线或者墙的碰撞路径
  • Tile(图块)-用来进行任意放置、缩放,还有旋转图块的对象
  • Text(文本-用来记录自定义文字、标注)

所有的对象都可以被命名,命名之后,他们的名字就会在他们上边显示(默认情况下,当你选择对象时显示)。对象也可以被定义类型,这样可以很方便地定义它们标签的颜色,还在一些有用的自定义属性。对于图块对象来说,这种类型可以是继承而来的。

对于大多数地图类型,对象都是以普通像素定位的。唯一的例外是等距地图(不是等距交错)。对于等距地图,将其位置存储在投影坐标空间中被认为是有用的。为此,假设等轴测图块表示投影的正方形,其两侧等于图块高度。如果在等轴测游戏中对对象使用不同的坐标空间,则需要相应地转换这些坐标。

对象的宽和高绝大多数是以像素的方式存储。对于等距地图,所有对象的形状(矩形、点、椭圆形、多边形、折线)都是投射到相同的坐标空间的。这是假设所有的这些对象被用来在地图上标记区域的情况。

在这里插入图片描述

作用:

  1. 用来添加除背景以外的游戏元素信息,如道具、障碍物等对象
  2. 一个对象层可以添加多个对象,每个对象的区域形状的单位是:像素点。
  3. 对象层中的对象在TMX文件中以键值对(key-value)形式存在,因此可以直接在TMX文件中对其进行修改

在这里插入图片描述

总的说来,对象层中可以圈出一些区域,一个区域就是一个对象,用来设置一些属性,我们可以获得通过代码获得这些对象属性。地图中对象与场景中精灵关联

图像层

图像图层提供了一种快速包含单个图像作为地图前景或背景的方法。它们目前的功能有限,您可以考虑将图像添加为 Tileset 并将其放置为Tile Object。这样,您就可以自由缩放和旋转图像。

但是,图像层可以通过其“重复 X”和“重复 Y”属性沿各自的轴重复 。

使用图像图层的另一个优点是,它可以避免在使用“选择对象”工具时选择/拖动图像。然而,从 Tiled 1.1 开始,这也可以通过锁定包含您想要避免交互的图块对象的对象层来实现。

GID

在cocos2dx中,每一个瓦片素材都有一个对应的全局唯一标识GID。瓦片的GID是指该块使用了哪个对应的图块素材。

在这里插入图片描述

注意,对应的图块集中,GID是延续之前的,也就是从1开始到当前图集的最后一个,下一个图集第一个是延续上一个图集的。

属性值(Properties)

在这里插入图片描述

每一个图层都会有一个属性,给瓦片图块设置“碰撞检测”属性、给对象层的某一对象设置“敌人类型”属性等等……

这些自定义的属性可以在地图编辑器中进行设置,并且可以在代码中获取这些属性以及对应的属性值

代码

大概的结构是
在这里插入图片描述

TMXTiledMap

瓦片地图类

包含了所有的地图层、对象层、以及瓦片地图的尺寸信息。

  • MapSize :瓦片地图的尺寸。(以瓦片数量为单位)

  • TileSize :瓦片的尺寸。(以像素点为单位)

对应的函数为:

    const Size& getMapSize() const { return _mapSize; }
    
    /** Set the map's size property measured in tiles. 
     *
     * @param mapSize The map's size property measured in tiles.
     */
    void setMapSize(const Size& mapSize) { _mapSize = mapSize; }

    /** The tiles's size property measured in pixels. 
     *
     * @return The tiles's size property measured in pixels.
     */
    const Size& getTileSize() const { return _tileSize; }
    
    /** Set the tiles's size property measured in pixels. 
     *
     * @param tileSize The tiles's size property measured in pixels.
     */
    void setTileSize(const Size& tileSize) { _tileSize = tileSize; }

两个创建函数:

//使用 .tmx 格式的文件创建瓦片地图
static TMXTiledMap* create(const std::string& tmxFile);

static TMXTiledMap* createWithXML(const std::string& tmxString, const std::string& resourcePath);

获取指定名称的地图层 TMXLayer

TMXLayer* getLayer(const std::string& layerName) const;

获取 指定名称的对象层 TMXObjectGroup

TMXObjectGroup* getObjectGroup(const std::string& groupName) const;

获取指定名称的属性值

Value getProperty(const std::string& propertyName) const;

获取所有属性。(键-值对)

ValueMap& getProperties();

通过GID获取图块的属性,返回ValueMap,即(键-值对)

Value getPropertiesForGID(int GID) const;

获取所有对象层。返回对象数组 Vector

const Vector<TMXObjectGroup*>& getObjectGroups() const { return _objectGroups; }

Vector<TMXObjectGroup*>& getObjectGroups() { return _objectGroups; }

TMXLayer

TMXLayer类为地图层类。包含了该地图层中,每个瓦片格子的信息。

该类继承于SpriteBatchNode。所有TMXLayer对象具有批量渲染的能力,Tile地图层就是由大量重复的图片构成,它们需要渲染提高性能

所以,每一个瓦片(Tile)都是一个Sprite类。

//获取地图层名字
const std::string& getLayerName() { return _layerName; }
//重新设置地图层名字
void setLayerName(const std::string& layerName) { _layerName = layerName; }

//获取 地图层的propertyName属性值
Value getProperty(const std::string& propertyName) const;

// 获取 地图层的所有自定义属性字典
ValueMap& getProperties();

// 获取地图层尺寸。一般等于瓦片地图的尺寸。(单位:瓦片数量)
Size& getLayerSize() const;

// 设置瓦片尺寸的大小。一般与瓦片地图的瓦片尺寸是一样的。(单位:像素)
Size& getMapTileSize() const;

// 获取 指定tile坐标的瓦片(Sprite)
Sprite* getTileAt(const Vec2& tileCoordinate);

// 通过Tile片坐标获得像素坐标,瓦片坐标y轴方向与像素坐标y轴方向相反。
// 指定tile坐标的瓦片对应的OpenGL坐标位置
Point getPositionAt(const Point& tileCoordinate);

// 通过Tile片坐标获得GID值。指定tile坐标的瓦片,所使用的图块的GID
int getTileGIDAt(const Point& tileCoordinate);

// 设置 指定tile坐标的瓦片,将其图片变为GID的图块
void setTileGID(uint32_t gid, const Vec2& tileCoordinate);

// 删除 也可以使用removeChild(sprite, cleanup)
void removeTileAt(const Vec2& tileCoordinate);
void removeChild(Node* child, bool cleanup) override;

TMXObjectGroup

对象层中的对象组合,继承于Ref,包含了该对象层中,每个对象的信息。

每一个对象,其所有属性,被存储为ValueMap。

ValueVector类型的别名是std::vector,vector是C++的容器类,它能够存放任意类型的动态数组,std是命名空间。

ValueMap类型的别名是std::unordered_map,unordered_map也是C++的容器类,它是一种无序的map类型,map是“键-值”对类型。

// 获取 对象层的名称
std::string& getGroupName();

// 重新设置对象层名称
void setGroupName(const std::string& groupName); 

// 获取 对象层的propertyName属性值
Value getProperty(const std::string& propertyName) const;

// 获取 对象层所有属性
ValueMap& getProperties();

// 获取对象层指定的objectName对象,其所有属性被存储为ValueMap
ValueMap getObject(const std::string& objectName) const;

// 获取对象层的所有对象
ValueVector& getObjects();

TileMapAtlas

除了用TMXTiledMap创建瓦片地图类,还可以用贴图地图类TileMapAtlas。

需要用到TGR,TGR类似于地图图素排列的数据,也可以由相应的编辑器编辑

// 创建 tile地图图素集的图片路径,TGR图片的路径
 static TileMapAtlas * create(const std::string& tile, const std::string& mapFile, int tileWidth, int tileHeight);

目前比较通用的方法是Tile编辑器,所以这种方法现在一般不用,其函数的功能也较TMXTiledMap少。

瓦片地图的锚点

瓦片地图的锚点默认为( 0,0),每个瓦片的锚点默认也为(0,0),锚点是可以设置的。

(1)普通瓦片锚点信息

在这里插入图片描述

(2)斜45°瓦片锚点信息

在这里插入图片描述

(3)斜45°交错瓦片锚点信息

在这里插入图片描述

坐标转换

普通瓦片

OpenGL坐标:原点为屏幕左下角(单位:像素)

Tile坐标:原点为瓦片地图的左上角(单位:瓦片)

// OpenGL坐标 转成 格子坐标
Vec2 tileCoordForPosition(const Vec2& position) {
    Size mapSize = tiledMap->getMapSize();
    
    Size tileSize = tiledMap->getTileSize();
    
    int x = position.x / tileSize.width;
    
    int y = (mapSize.height * tileSize.height - position.y) / tileSize.height;
    
    return Vec2(x, y);

}

// Tile坐标 转成 瓦片格子中心的OpenGL坐标

Vec2 positionForTileCoord(const Vec2& tileCoord) {
    Size mapSize = tiledMap->getMapSize();
    
    Size tileSize = tiledMap->getTileSize();
    
    int x = tileCoord.x * tileSize.width + tileSize.width/2;
    
    int y = (mapSize.height - tileCoord.y) * tileSize.height - tileSize.height/2;
    
    return Vec2(x, y);
}

层级关系

每个地图层的 zOrder(渲染顺序)会根据在地图编辑器中设置的前后关系进行设置。由下往上设置 zOrder 值,最靠后的 zOrder = 0,随后每个图层zOrder+1

(1)地图层之间

在这里插入图片描述

(2)瓦片之间

渲染顺序为:从左往右,从上到下。

在这里插入图片描述

下边的瓦片可以遮住上边的瓦片,右边的瓦片可以遮住左边的瓦片

例子

主要看Lua的。

在官方的例子中,有TileMapTest.lua文件。

TileMapAtlas

local layer = createTileDemoLayer("Editable TileMapAtlas")

local  map = cc.TileMapAtlas:create(s_TilesPng, s_LevelMapTga, 16, 16)
-- Create an Aliased Atlas
map:getTexture():setAliasTexParameters()
local  s = map:getContentSize()
local function updateMap(dt)
     local  tilemap = layer:getChildByTag(kTagTileMap)
     local c = tilemap:getTileAt(cc.p(13,21))
    c.r = c.r + 1
    c.r = c.r % 50
    if( c.r==0) then
        c.r=1
    end
    tilemap:setTile(c, cc.p(13,21) )
end
;;........

TMXTiledMap

// 创建TileMap
local  map = cc.TMXTiledMap:create("TileMaps/orthogonal-test2.tmx")
layer:addChild(map, 0, kTagTileMap)

// 获取大小
local  s = map:getContentSize()
cclog("ContentSize: %f, %f", s.width,s.height)

//遍历子节点
local  pChildrenArray = map:getChildren()
local  child = nil
local  pObject = nil
local i = 0
local len = table.getn(pChildrenArray)

for i = 0, len-1, 1 do
    child = pChildrenArray[i + 1]

    if child == nil then
        break
    end
    child:getTexture():setAntiAliasTexParameters()
end


// 获取 Layer层 然后获取每一个瓦片块 
map:setAnchorPoint(cc.p(0, 0))

local layer  = map:getLayer("Layer 0")
local s      = layer:getLayerSize()

local sprite = layer:getTileAt(cc.p(0,0))
sprite:setScale(2)
sprite       = layer:getTileAt(cc.p(s.width-1,0))
sprite:setScale(2)
sprite       = layer:getTileAt(cc.p(0,s.height-1))
sprite:setScale(2)
sprite       = layer:getTileAt(cc.p(s.width-1,s.height-1))
sprite:setScale(2)

//获取对象层
local  group   = map:getObjectGroup("Object Group 1")
local  objects = group:getObjects()

local  dict    = nil
local  i       = 0
local  len     = table.getn(objects)

//对象层小块获取和操作
for i = 0, len-1, 1 do
    dict = objects[i + 1]

    if dict == nil then
        break
    end
    --------cclog("object: %x", dict)
    
    local key = "x"
    local x = dict["x"]
    key = "y"
    local y = dict["y"]--dynamic_cast<NSNumber*>(dict:objectForKey("y")):getNumber()
    key = "width"
    local width = dict["width"]--dynamic_cast<NSNumber*>(dict:objectForKey("width")):getNumber()
    key = "height"
    local height = dict["height"]--dynamic_cast<NSNumber*>(dict:objectForKey("height")):getNumber()
    
    local color = cc.c4f(1,1,1,1)
    drawNode:drawLine( cc.p(x, y), cc.p((x+width), y), color)
    drawNode:drawLine( cc.p((x+width), y), cc.p((x+width), (y+height)), color)
    drawNode:drawLine( cc.p((x+width), (y+height)), cc.p(x, (y+height)), color)
    drawNode:drawLine( cc.p(x, (y+height)), cc.p(x, y), color)
end

// 动态修改 Zorder层级
local function repositionSprite(dt)
    local p = cc.p(m_tamara:getPosition())
    p = CC_POINT_POINTS_TO_PIXELS(p)
    local map = ret:getChildByTag(kTagTileMap)

    -- there are only 4 layers. (grass and 3 trees layers)
    -- if tamara < 48, z=4
    -- if tamara < 96, z=3
    -- if tamara < 144,z=2

    local newZ = 4 - math.floor((p.y / 48))
    newZ = math.max(newZ,0)

    map:reorderChild(m_tamara, newZ)
end

参考

http://www.taodudu.cc/news/show-1950915.html?action=onClick

https://www.codenong.com/cs106334928/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/988105.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Commonsense Knowledge Base Completion with Structural and Semantic Context

摘要 与研究较多的传统知识库(如Freebase)相比&#xff0c;常识性知识图(如ATOMIC和ConceptNet)的自动知识库补全提出了独特的挑战。常识知识图使用自由形式的文本来表示节点&#xff0c;与传统知识库相比&#xff0c;导致节点数量增加了几个数量级(与Freebase (FB15K237)相比…

分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测

分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测 目录 分类预测 | MATLAB实现PCA-GRU(主成分门控循环单元)分类预测预测效果基本介绍程序设计参考资料致谢 预测效果 基本介绍 Matlab实现基于PCA-GRU主成分分析-门控循环单元多输入分类预测&#xff08;完整程序和数据…

DataGridView选中的单元格求和

DataGridView单元格求和功能的基本思路是先得到选中的单元格&#xff0c; 1&#xff0c;在内存中定义两张表&#xff0c;一张存放列名&#xff0c;一张存放列名和数个。这样这两张表就开成了一对多的父子关系。 2&#xff0c;在将两张定及他们的父子关系添加到DataSet对象中 4…

5款无广告的小软件,先收藏再下载

​ 最近后台收到好多小伙伴的私信&#xff0c;今天继续推荐五款小工具&#xff0c;都是免费使用的&#xff0c;大家可以去试试看。 1.写作软件——Effie ​ Effie是一款极简风格的写作软件&#xff0c;它可以帮助您优雅地写作和记录&#xff0c;把思想变成价值。Effie支持多种…

嵌入式学习笔记(19)SDRAM引入

SDRAM的特性&#xff08;容量大、价格低、掉电易失性、随机读写、总线式访问&#xff09; SDRAM/DDR都属于动态内存&#xff08;相对于静态内存SRAM&#xff09;&#xff0c;都需要先运行一段初始化代码来初始化才能使用&#xff0c;不像SRAM开机上电后就可以直接运行。类似于…

2023-大数据应用开发-工业可视化参考结果

工业可视化 任务一&#xff1a;用柱状图展示设备历史各个状态持续时长 编写Vue工程代码&#xff0c;根据接口&#xff0c;用柱状图展示接口所有数据中各设备各个状态持续时长&#xff08;秒&#xff09;&#xff0c;同时将用于图表展示的数据结构在浏览器的console中进行打印…

ipad手写笔一定要买苹果的吗?apple pencil二代平替笔推荐

近年来&#xff0c;随着Apple pencil的出现&#xff0c;在工作和学习上给小伙伴们带来了许多便捷。但原装的价格对于我们这些“贫民窟”的小伙伴来说真的是太贵了&#xff0c;而且感觉只是偶尔书写和业余画画&#xff0c;没必要入手这么贵的电容笔。所以咱们国货出现了许多平替…

day53 补

1143.最长公共子序列 力扣题目链接(opens new window) 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长公共子序列的长度。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff0…

配置远程访问:让外部网络用户能够使用公司内部的OA办公系统

文章目录 前言1. 确认在内网下能够使用IP端口号登录OA办公系统2. 安装cpolar内网穿透3. 创建隧道映射内网OA系统服务端口4. 实现外网访问公司内网OA系统总结 前言 现在大部分公司都会在公司内网搭建使用自己的办公管理系统&#xff0c;如OA、ERP、金蝶等&#xff0c;员工只需要…

VSCode中调试通过torchrun实现的分布式训练启动程序

train.sh文件实现torchrun如下 #!/bin/bashpy3clean ./ CUDA_VISIBLE_DEVICES3 torchrun --nproc_per_node1 --master_port9006 tools/train.py \configs/basicvsr_plusplus_vimeo90k_bd.py \--seed 0 \ 需要进行更改来DeBug&#xff0c;改成launch.json如下所示&#xff0c;…

问道管理:沪指跌0.43%坚守3100点,地产、石油等板块走弱

8日早盘&#xff0c;沪指再度回调&#xff0c;检测3100点支撑&#xff1b;深成指、创业板指均下挫&#xff1b;两市半日成交约4000亿元。 到午间收盘&#xff0c;沪指跌0.43%报3108.84点&#xff0c;深成指跌0.69%&#xff0c;创业板指跌0.72%&#xff0c;科创50指数微涨0.01%…

蓝桥杯打卡Day5

文章目录 日志排序重复者 一、日志排序IO链接 本题思路:本题就是根据就是排序的知识点&#xff0c;在sort内部可以使用仿函数来改变此时排序规则。 #include <bits/stdc.h>const int N10010; int n; std::string logs[N];int main() {std::ios::sync_with_stdio(false)…

Linux下的系统编程——共享存储映射(十)

前言&#xff1a; mmap是一种内存映射文件的方法&#xff0c;即将一个文件或者其它对象映射到进程的地址空间&#xff0c;实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后&#xff0c;进程就可以采用指针的方式读写操作这一段内存&…

数据结构与算法:概述

目录 算法 评价标准 时间的复杂度 概念 推导原则 举例 空间的复杂度 定义 情形 运用场景 数据结构 组成方式 算法 在数学领域&#xff0c;算法是解决某一类问题的公式和思想&#xff1b; 计算机科学领域&#xff0c;是指一系列程序指令&#xff0c;用于解决特定的…

30 秒使用 Sealos 搭建个人密码管理器 Vaultwarden

我与 LastPass 的曲折恋情 超过 8 年网龄的我&#xff0c;注册过很多网站帐号&#xff0c;每个网站的密码我都用不同的复杂密码。一开始我全靠脑力记忆这些密码&#xff0c;后来渐渐觉得记起来很困难&#xff0c;就记录在笔记本上。但是随着时间推移&#xff0c;我发现这种方法…

什么样的蓝牙耳机戴着舒服,佩戴舒适的蓝牙耳机推荐

什么样的蓝牙耳机戴着舒服&#xff1f;相信大家肯定有这么一个困扰&#xff0c;就是在入耳式耳机佩戴时间久了&#xff0c;总感觉耳道内部不舒服&#xff0c;那么今天我要向大家介绍一种备受骨传导爱好者推崇的神奇装置——骨传导耳机。首先&#xff0c;让我们来了解一下骨传导…

亚信安慧荣膺“信创工委会技术活动单位”

近日&#xff0c;以亚信科技AntDB数据库团队为基础组建而成的湖南亚信安慧科技有限公司&#xff08;简称&#xff1a;亚信安慧&#xff09;被中国电子工业标准化技术协会、信息技术应用创新工作委员会(简称&#xff1a;信创工委会)授予“信息技术应用创新工作委员会技术活动单位…

小程序分销机制介绍,小程序二级分销功能有哪些?

为什么有越来越多的用户选择使用小程序&#xff1f;跟“高大上”的APP相比&#xff0c;小程序不仅可以减少下载安装的复杂流程&#xff0c;还具备操作便捷、沉淀私域数据的优势。蚓链分销小程序具备裂变二维码、实时分佣、分销身份升级、层级分佣、商品个性化佣金设定等功能&am…

geopandas 笔记: datasets 数据集

geopandas 自带的几个数据集 1 世界各个国家 import geopandas as gpd import pandas as pdpd.set_option(display.max_rows,None) gpd.read_file(gpd.datasets.get_path(naturalearth_lowres)) pop_est人口数量continent国家所在的大陆name国家的名称iso_a3国家的三个字母的…

谷歌霸屏推广怎么做?

答案是&#xff1a;可以使用GLB外推技术实现谷歌霸屏推广。 谷歌霸屏推广是一种Google SEO策略&#xff0c;旨在确保品牌或关键词在Google搜索结果的第一页上占据多个位置。 正确地执行此策略可以大大提高品牌的在线曝光度&#xff0c;从而增加流量和潜在客户。 那么&#x…