[Lua][Love] "图块集与地图" 加载显示功能 TileMap

效果

图片[1]-[Lua][Love] "图块集与地图" 加载显示功能 TileMap-五八三

安装库

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

powershell

luarocks install xml2lua
luarocks install ftcsv

manoelcampos/xml2lua (github.com)

FourierTransformer/ftcsv

整体结构 tilemap.lua

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

lua

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

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

lua

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列表获得

lua

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

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

lua

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 出错,手动添加一个 , 符号

lua

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 类型

lua

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列表中

lua

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

lua

return {
map = map,
tileset = tileset
}

鼠标位置显示坐标 mouse.lua

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

lua

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

引入我们写的模块

lua

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

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

lua

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

更新鼠标位置

lua

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

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

lua

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)

图片[2]-[Lua][Love] "图块集与地图" 加载显示功能 TileMap-五八三

完整代码 tilemap.lua

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

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

__EOF__

  • 本文作者: 小能正在往前冲
  • 本文链接: https://www.cnblogs.com/linxiaoxu/p/17655081.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • © 版权声明
    THE END
    喜欢就支持一下吧
    点赞0

    Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYaY5uiJ' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
    admin的头像-五八三
    评论 抢沙发
    头像
    欢迎您留下宝贵的见解!
    提交
    头像

    昵称

    图形验证码
    取消
    昵称代码图片