效果

安装库

安装两个库,分别用来读xml和csv,如果有luarocks,执行下列命令

luarocks install xml2lua
luarocks install ftcsv

manoelcampos/xml2lua (github.com)

FourierTransformer/ftcsv

整体结构 tilemap.lua

引入要用的两个库,创建xml解析器,读取xml解析到的数据是从handler.root里读的,而不是parser

local xml2lua = require 'xml2lua'
local handler = require 'xmlhandler.tree'
local ftcsv = require 'ftcsv'
local parser = xml2lua.parser(handler)
local map = {}
local tileset = {}

在love.load执行两个回调函数加载图块集跟地图

function map:load(...)
map:loadTMX(love.filesystem.getWorkingDirectory() .. "/map/map.tmx")
end function tileset:load(...)
tileset:loadTSX(love.filesystem.getWorkingDirectory() .. "/map/tilemap_packed.tsx")
tileset:loadTile()
end

在游戏窗口绘制各个图块,图层从map列表获得,图块从tileset列表获得

function map:draw()
for _, layer in ipairs(map) do
for i = 1, map.height, 1 do
for k = 1, map.width, 1 do
if layer[i][k] ~= "0" then
love.graphics.draw(
tileset.image,
tileset[tonumber(layer[i][k])],
tileset.tilewidth * (k - 1),
tileset.tileheight * (i - 1)
)
end
end
end
end
end

加载文件用,找不到文件就报错

function openFile(filename)
local f = io.open(filename, 'r')
if f then
return f
else
error("no file exists", 2)
end
end

加载地图文件 tmx,先用xml解析器解析,然后用ftcsv解析各个图层保存到map里

tmx各个图层csv的最后一行末尾没有 , 符号会导致 ftcsv 出错,手动添加一个 , 符号

function map:loadTMX(filename)
local f = openFile(filename)
local tmx = f:read('a')
parser:parse(tmx)
local attr = handler.root.map._attr
map.width = tonumber(attr.width)
map.height = tonumber(attr.height)
for _, value in pairs(handler.root.map.layer) do
map[#map + 1] = ftcsv.parse(value.data[1] .. ',', ",", { headers = false, loadFromString = true })
end
end

加载 TSX 图块集的信息,包括图块大小,图块数量,列数,行数需要自己算,记得转换成 number 类型

function tileset:loadTSX(filename)
local f = openFile(filename)
local tsx = f:read('a')
parser:parse(tsx)
local attr = handler.root.tileset._attr
local image = handler.root.tileset.image._attr
tileset.tilewidth = tonumber(attr.tilewidth)
tileset.tileheight = tonumber(attr.tileheight)
tileset.tilecount = tonumber(attr.tilecount)
tileset.columns = tonumber(attr.columns)
tileset.rows = tileset.tilecount / tileset.columns
tileset.source = image.source
tileset.width = tonumber(image.width)
tileset.width = tonumber(image.height)
end

加载 TSX 图块集信息后,已经拿到图块数量,图块大小,图片集文件地址等信息。通过这些信息,我们使用加载图片集文件,然后使用 newQuad 将图片集各个部分,即图块,保存到tileset列表中

function tileset:loadTile()
self.source = string.gsub(self.source, "%.%.", "")
self.image = love.graphics.newImage(self.source)
for i = 0, tileset.rows - 1, 1 do
for j = 0, tileset.columns - 1, 1 do
tileset[#tileset + 1] = love.graphics.newQuad(
j * tileset.tilewidth, i * tileset.tileheight,
tileset.tilewidth, tileset.tileheight, self.image
)
end
end
end

返回map跟tileset

return {
map = map,
tileset = tileset
}

鼠标位置显示坐标 mouse.lua

根据鼠标在屏幕的x、y坐标绘制方块和文字

local mouse = {}

mouse.pos_x = 0
mouse.pos_y = 0
mouse.size = 32 function mouse:update(t)
mouse.pos_x, mouse.pos_y = love.mouse.getPosition()
end function mouse:draw()
local x = math.floor(self.pos_x / self.size)
local y = math.floor(self.pos_y / self.size)
love.graphics.rectangle("fill", x * self.size, y * self.size, self.size, self.size)
love.graphics.print(
string.format("(%d,%d)", x + 1, y + 1),
x * self.size + self.size,
y * self.size + math.floor(self.size / 2), 0, 2,
2)
end return mouse

游戏循环 main.lua

引入我们写的模块

local tilemap = require 'tilemap'
local map = tilemap.map
local tileset = tilemap.tileset
local mouse = require 'mouse'
require 'debugger'

原图块像素只有 16px,游戏画面需要放大几倍,如果按默认过滤模式,会出现“流血现象”(下图所示),全部改成nearest,单纯的像素放大。love 引擎加载时候加载了图块集与地图。

love.load = function()
love.graphics.setDefaultFilter("nearest", "nearest")
tileset:load()
map:load()
player = love.graphics.newImage("assets/player.png")
end

更新鼠标位置

love.update = function(t)
mouse:update(t)
end

先保存原视角状态,修改视角整体放大两倍,绘制地图,之后还原视角,再画玩家(32*32)跟鼠标。

love.draw = function()
love.graphics.push()
love.graphics.scale(2)
map:draw()
love.graphics.pop()
love.graphics.draw(player, 16 * 16, 192)
mouse:draw()
end

自己创建 TSX、TMX

用的一款工具 Tiled Map Editor by Thorbjørn (itch.io)

完整代码 tilemap.lua

local xml2lua = require 'xml2lua'
local handler = require 'xmlhandler.tree'
local ftcsv = require 'ftcsv'
local parser = xml2lua.parser(handler)
local map = {}
local tileset = {} function map:load(...)
map:loadTMX(love.filesystem.getWorkingDirectory() .. "/map/map.tmx")
end function tileset:load(...)
tileset:loadTSX(love.filesystem.getWorkingDirectory() .. "/map/tilemap_packed.tsx")
tileset:loadTile()
end function map:draw()
for _, layer in ipairs(map) do
for i = 1, map.height, 1 do
for k = 1, map.width, 1 do
if layer[i][k] ~= "0" then
love.graphics.draw(
tileset.image,
tileset[tonumber(layer[i][k])],
tileset.tilewidth * (k - 1),
tileset.tileheight * (i - 1)
)
end
end
end
end
end function openFile(filename)
local f = io.open(filename, 'r')
if f then
return f
else
error("no file exists", 2)
end
end function map:loadTMX(filename)
local f = openFile(filename)
local tmx = f:read('a')
parser:parse(tmx)
local attr = handler.root.map._attr
map.width = tonumber(attr.width)
map.height = tonumber(attr.height)
for _, value in pairs(handler.root.map.layer) do
map[#map + 1] = ftcsv.parse(value.data[1] .. ',', ",", { headers = false, loadFromString = true })
end
end function tileset:loadTSX(filename)
local f = openFile(filename)
local tsx = f:read('a')
parser:parse(tsx)
local attr = handler.root.tileset._attr
local image = handler.root.tileset.image._attr
tileset.tilewidth = tonumber(attr.tilewidth)
tileset.tileheight = tonumber(attr.tileheight)
tileset.tilecount = tonumber(attr.tilecount)
tileset.columns = tonumber(attr.columns)
tileset.rows = tileset.tilecount / tileset.columns
tileset.source = image.source
tileset.width = tonumber(image.width)
tileset.width = tonumber(image.height)
end function tileset:loadTile()
self.source = string.gsub(self.source, "%.%.", "")
self.image = love.graphics.newImage(self.source)
for i = 0, tileset.rows - 1, 1 do
for j = 0, tileset.columns - 1, 1 do
tileset[#tileset + 1] = love.graphics.newQuad(
j * tileset.tilewidth, i * tileset.tileheight,
tileset.tilewidth, tileset.tileheight, self.image
)
end
end
end return {
map = map,
tileset = tileset
}

完整代码 main.lua

local tilemap = require 'tilemap'
local map = tilemap.map
local tileset = tilemap.tileset
local mouse = require 'mouse'
require 'debugger' love.load = function()
love.graphics.setDefaultFilter("nearest", "nearest")
tileset:load()
map:load()
player = love.graphics.newImage("assets/player.png")
end love.update = function(t)
mouse:update(t)
end love.draw = function()
love.graphics.push()
love.graphics.scale(2)
map:draw()
love.graphics.pop()
love.graphics.draw(player, 16 * 16, 192)
mouse:draw()
end

完整项目

https://linxiaoxu.oss-cn-hangzhou.aliyuncs.com/static/files/2023/tinytown.zip

[Lua][Love] "图块集与地图" 加载显示功能 TileMap的更多相关文章

  1. Echarts使用及动态加载图表数据 折线图X轴数据动态加载

    Echarts简介 echarts,缩写来自Enterprise Charts,商业级数据图表,一个纯JavaScript的图表库,来自百度...我想应该够简洁了 使用Echarts 目前,就官网的文 ...

  2. Java中静态变量、静态代码块、非静态代码块以及静态方法的加载顺序

    在研究单例设计模式的时候,用到了静态变量和静态方法的内容,出于兴趣,这里简单了解一下这四个模块在类初始化的时候的加载顺序. 经过研究发现,它们的加载顺序为: 1.非静态代码块 2.静态变量或者静态代码 ...

  3. Tiled Editor 图块的两种导入方式

    一.图块集图块的导入. 打开或者创建地图后,新建 新图块. 弹出新图块面板 图块类型选择 "基于图块集图块",一定要选择"嵌入地图",否则需要另存为其他类型的文 ...

  4. CAD数据分块,偏移校准,加载到百度地图、高德地图、谷歌等地图上

    前面分享过一篇如何将CAD海量数据显示在百度地图上(百度地图Canvas实现十万CAD数据秒级加载),但是很多开发者在CAD数据提取时遇到了问题,所以接下来的文章将介绍如何将CAD数据提取. 准备软件 ...

  5. lua加载函数require和dofile

    lua加载函数require和dofile Lua提供高级的require函数来加载运行库.粗略的说require和dofile完成同样的功能但有两点不同: 1. require会搜索目录加载文件; ...

  6. OpenGL(二十二) gluBuild2DMipmaps 加载Mip纹理贴图

    当纹理被用于渲染一个面积比它本身小很多的对象时,会由于纹理图像的降采样率不足而导致混叠现象,主要的表现特征是纹理图像的闪烁,出现纹理躁动.特别是在场景远近移动变换时,这种闪烁情况更为明显,严重可能会影 ...

  7. lua加载动态库缺乏相应的系统库

    错误信息: 使用lua测试lm2动态库时,加载时出现如下错误 jfyuan@jfy11-B85M-D2V:~/temp/service/soft/code/ginger_resty/cores/lm2 ...

  8. (转载)arcgis for js - 解决加载天地图和WMTS服务,WMTS服务不显示的问题,以及wmts服务密钥。

    1 arcgis加载天地图和wmts服务 arcgis for js加载天地图的例子网上有很多,这里先不写了,后期有空再贴代码,这里主要分析下WMTS服务为什么不显示,怎么解决. 条件:这里的WMTS ...

  9. PIE SDK加载WMS服务数据

    1.   功能简介 WMS服务,WMS是OGC标准中比较简单也是比较重要的标准之一.它全称是“Web Map Service”(网络地图服务):利用具有地理空间位置信息的数据制作地图.其中将地图定义为 ...

  10. Web前台直接加载GIS格式数据分析

    本文以Flex直接加载Shp.DWG和MDB为例. 首先看一份现估测数据: 1)  加载Shp文件,目前直接由前台Flex代码完成: 图1 在ArcCatalog里面的Shp文件 图2 直接在前台加载 ...

随机推荐

  1. 2021-09-25:给定一个字符串数组,将字母异位词组合在一起。可以按任意顺序返回结果列表。字母异位词指字母相同,但排列不同的字符串。示例 1:输入: strs = [“eat“, “tea“, “

    2021-09-25:给定一个字符串数组,将字母异位词组合在一起.可以按任意顺序返回结果列表.字母异位词指字母相同,但排列不同的字符串.示例 1:输入: strs = ["eat" ...

  2. Selenium - 元素操作(5) - iframe切换

    Selenium - 元素操作 iframe切换 很多时候定位元素时候总是提示元素定位不到的问题,明明元素就在那里,这个时候就要关注你所 定位的元素是否在frame和iframe里面: frame标签 ...

  3. Linux搭建FTP服务

    欢迎来到千汐   博客名称:千秋云染博客网址:https://www.cnblogs.com/skyrainmom 寄语:在混乱不堪的世界里你只管前行,时间替会证明一切 world cookie He ...

  4. web自动化02-常见元素定位(不含xpath和css)

    1.熟悉前端基础   代码和元素是一一对应关系,程序需要通过代码中的某些特征,获取目标元素并进行操作 标签名     key = value      元素的属性和属性值   2.浏览器开发者工具   ...

  5. 《Generative Adversarial Nets》论文精读

    论文精读<Generative Adversarial Nets> 导言:生成模型是目前爆火的一个研究方向,据Microsoft对于ChatGPT-4的研究称"ChatGPT-4 ...

  6. Mysql DDL执行方式-pt-osc介绍 | 京东云技术团队

    1 引言 大家好,接着上次和大家一起学习了<MySQL DDL执行方式-Online DDL介绍>,那么今天接着和大家一起学习另一种MySQL DDL执行方式之pt-soc. 在MySQL ...

  7. 终极指南!Terraform的进阶技巧

    如果您已经对 Terraform 了如指掌,并期望自己的 IaC 技能有进一步提升的话,这篇文章很适合您!在本文中,我们将分享一些 Terraform 的高级使用技巧.从使用模块(module).工作 ...

  8. ChatGPT玩法(二):AI玩转Excel表格处理

    前言 在线免费体验ChatGpt:https://www.topgpt.one 你是否还在为记不住Excel的繁琐函数和公式而苦恼?如果是这样,那么不妨试试ChatExcel.即使你对函数一窍不通,也 ...

  9. WPF中关于转换器

    实例:关于播放器按钮状态的改变 说明:对Kind(种类)的绑定首先在viewmodel中声明一个属性IsPlay,然后在转换器中实现按钮的状态 转换器 在解决方案中的项目里新建一个Converters ...

  10. 龙芯下如何进行.net core程序开发部署

    龙芯LoongArch64已经发布了对.NETCore的支持,相关工具链也已完成,目前支持.NETCore3.1..NET6..NET7版本.本文以.NETCore3.1在loongnix-serve ...