效果

安装库

安装两个库,分别用来读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

返回maptileset

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-11-30:给定一个数组arr,当拿走某个数a的时候,其他所有的数都+a, 请返回最终所有数都拿走的最大分数。 比如: [2,3,1], 当拿走3时,获得3分,数组变成[5,4]; 当拿走5

    2021-11-30:给定一个数组arr,当拿走某个数a的时候,其他所有的数都+a, 请返回最终所有数都拿走的最大分数. 比如: [2,3,1], 当拿走3时,获得3分,数组变成[5,4]: 当拿走5 ...

  2. mysql报错Unknown collation: utf8mb4_0900_ai_ci

    mysql报错Unknown collation: utf8mb4_0900_ai_ci 解决方案: 将文件内的所有 utf8mb4_0900_ai_ci 换成 utf8_general_ci utf ...

  3. jmeter跨线程组引用变量的3种方法

    利用BeanShell后置处理程序将参数设置为全局变量,用于跨线程传参(注:1.把提取变量的线程组放到引用变量的线程组前2.在测试计划中勾选"独立运行每个线程组") 方法1(jme ...

  4. Abaqus结构仿真软件的非线性问题与解决方案

    ​无论是什么FEA 软件,想要获得非线性问题的一些解决方法始终没有那么简单.遇到问题是很常见的,那么下面就来看看Abaqus用户克服这一类问题的解决方法吧. 1. 简化模型 从简化模型开始,通过逐渐添 ...

  5. tar 命令压缩时报错 Removing leading `/' from member names 解决方法

    原文:https://www.cnblogs.com/operationhome/p/9802554.html 在使用tar命令进行压缩打包的时候我们常常会遇到下面的错误.虽然它不会影响我们最后的压缩 ...

  6. 万字长文讲透 RocketMQ 4.X 消费逻辑

    RocketMQ 是笔者非常喜欢的消息队列,4.9.X 版本是目前使用最广泛的版本,但它的消费逻辑相对较重,很多同学学习起来没有头绪. 这篇文章,笔者梳理了 RocketMQ 的消费逻辑,希望对大家有 ...

  7. Qt+QtWebApp开发笔记(五):http服务器html中使用json触发ajax与后台交互实现数据更新传递

    前言   前面完成了页面的跳转.登录,很多时候不刷新页面就想刷新局部数据,此时ajax就是此种技术,且是异步的.  本篇实现网页内部使用js调用ajax实现异步交互数据.  在js中使用 ajax是通 ...

  8. 全同态(Fully Homomorphic Encryption, FHE)和半同态(Partially Homomorphic Encryption, PHE)介绍

    全同态(Fully Homomorphic Encryption, FHE)和半同态(Partially Homomorphic Encryption, PHE) 全同态加密(FHE)是指一种加密方案 ...

  9. Python异步编程之web框架 异步vs同步 Redis并发对比

    测试基本信息 主题:比较异步框架和同步框架在RedisIO操作的性能差异 python版本:python 3.8 数据库:redis 5.0.7 压测工具:locust web框架:同步:flask ...

  10. CKS 考试题整理 (02)-Apparmor

    Context Apparmor 已在 cluster 的工作节点 node02 上被启用.一个 Apparmor 配置文件已存在,但尚未被实施. Task 在 cluster 的工作节点 node0 ...