love2d教程4--材质和贴图

”说明,在love2d的wiki上以下的这些操作都比较费时,建议不要在draw和update里重复加载同样的数据,
而是创建以后保存以重复使用。”

材质可以简单的说是一些图片素材,love2d可以从文件和ImageData(可以看作内存中的图像数据)
载入图片image=love.graphics.newImage(path或imagedata),返回一个Image对象(可以被画在屏幕上)
说明只能从main.lua所在文件夹为相对路径,载入图片,不能使用外面的图片。
显示图片使用love.graphics.draw(image, x, y),x、y为显示在屏幕上的坐标(说明draw其它参数下面
有解释)。

    说明在有些较老的显卡上只支持显示为2的整数幂分辨率的图片,下面这段代码可以把图片修改
为2的整数幂,不过最新的0.8已经不需要了。

--修改图片为2的倍数
function newPaddedImage(filename)
    local source = love.image.newImageData(filename)
    local w, h = source:getWidth(), source:getHeight()
    
    -- Find closest power-of-two.
    local wp = math.pow(2, math.ceil(math.log(w)/math.log(2)))
    local hp = math.pow(2, math.ceil(math.log(h)/math.log(2)))
    
    -- Only pad if needed:
    if wp ~= w or hp ~= h then
        local padded = love.image.newImageData(wp, hp)
        padded:paste(source, 0, 0)
        return love.graphics.newImage(padded)
    end
    
    return love.graphics.newImage(source)
end

下面说一下如何从一副大图片中提取所需的部分。
love2d提供了Quad类型,可以通过quad = love.graphics.newQuad( x, y, width, height, sw, sh )
创建一个quad对象,其中x、y是大图中小图左顶点的坐标,width、height是小图的宽和高,sw、sh是
大图的宽和高。
显示所需的小图使用love.graphics.drawq(image,quad, x, y, r, sx, sy, ox, oy, kx, ky )
其中image是大图(需要在绘图前使用image=love.graphics.newImage(path)创建),quad是我们刚才
创建的quad对象,x、y在屏幕上显示的坐标;(以下的几个参数有默认值,没特殊要求不用)r为逆时针
旋转的度数(弧度制);sx、sy是以原图为中心沿x、y轴方向的缩放系数,可以为负,当x为负时,相当
于左右翻转后再缩放,y为负时即上下颠倒后再缩放;ox、oy即显示的坐标与原x、y坐标分别向左、向下
便宜ox、oy像素;kx、ky wiki上解释为Shearing factor ,不知到什么意思(如果你恰好知道,请告诉我)
,我试了一下发现这种变换会偏离原坐标中心,而且当kx、ky都为1时居然没显示,但为其它值却可以显示。

接着我们学习一下贴图(tile,中文意思为贴瓷砖)。贴图实际是重复利用图片的一种方法,但要求这些图片
可以无缝拼接,即把小图片拼装成大图后没有缝隙。对于小图的管理可以有两种方法,一种是把许多小图片放
到一个大图片中(地图多用),另一种则就是把小图按一定名称和顺序编号,直接存贮(人物图像多用)。
wiki上的Tutorial:Tile-based Scrolling,是采用的第二种方法,我就不重复了,下面我介绍一下第一种方法。

请在网上下载Tiled,最新版本是0.8.1。 (说明最新的是0.9了,你可以直接点链接下载0.8.1的)
1、文件-新建,如下图,把地图大小的宽和高都改为10

image

2、在视图菜单里把显示网格和对齐网格都勾上,你会看到一副网格

image

3、地图-新图块

image

如下图,把边距和间距都设为1(这个间距是根据图片来的,你可以打开tmw_desert_spacing.png,放大后可以看见网格,我
就用1试了一下正好),点击浏览,打开自带的example下的"tmw_desert_spacing.png"图片

image

4、用鼠标选择右边的图块中的小图,在坐标的网格里便可以绘图了,按住鼠标左键不放拖动,可以连续画。
画错了,在工具栏中有橡皮擦。如下图,标有红色的是我选的几幅小图。

image 

5、打开地图--地图属性,我们为tmw_desert_spacing.png添加五个属性,如下图,即水平和竖直方向图块的个数,
图块的宽和高,图片的格式。

image 

接着 文件-导出为,在弹出的对话框下面的“保存类型”选择"lua文件。

6、把刚导出的lua文件和刚才的tmw_desert_spacing.png图片都复制到love2d工程下,把图片放到assets文件夹里。

下面我们来看看这个lua文件,它只有一行,而且返回了一个table。
你可以手动把它换一下行,或者把notepad++的视图菜单--自动换行勾上。
可以看到有一个data表如下
data =
{
30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }
这不就是我们刚才选择的图块的编号在网格里的顺序吗?

下面我们可以直接把data复制出来,更好的是写一个读取该文件的函数。
其中我感兴趣的有图片路径,可是这个路径在love2d里用不了,但图片
的名字到可以用(在tilesets下的name),还有imagewidth,imageheight,
tilewidth,tileheight,width(图块水平的个数),height(图块竖直的个数)
spacing(水平间隔), margin (竖直间隔)。
再看看tmw_desert_spacing.png,发现是265*199像素,正好水平方向32*8+1*7+1*2,竖直方向32*6+1*5+1*2
(1*2是图片四周的框)。其实我们希望没有这个间隔,这样好计算点。
下面是运行的截图

代码下载http://pan.baidu.com/share/link?shareid=125787&uk=1913510140

 

image

以下是代码
main.lua

tilemap=require('tilemap')
require('tutor4')
--地图在屏幕上显示的x,y坐标
mapX,mapY=100,100
quadtable={}

--那些注释是我试验坐标时用的,坐标不易确定啊
function love.load()
    image=love.graphics.newImage("assets/" .. tilemap["tilesets"][1].name ..tilemap["properties"]["format"])
    makeQuad(tilemap)
    
    --quad1=love.graphics.newQuad(1,1,32,32,265,199)
    --quad2=love.graphics.newQuad(34,1,32,32,265,199)
end



function love.draw()
    drawMap(tilemap,image)
    --love.graphics.drawq(image,quad1,100,100)
    --love.graphics.drawq(image,quad2,132,100)
end

function love.update(dt)
    --按键检测
    if(love.keyboard.isDown("up")) then
    mapY=mapY-20
    end
    if(love.keyboard.isDown("down")) then
    mapY=mapY+20
    end
    if(love.keyboard.isDown("left")) then
    mapX=mapX-20
    end
    if(love.keyboard.isDown("right")) then
    mapX=mapX+20
    end
    --边界检测省略

end

function love.keypressed(key)

end


tutor4.lua  ,不好意思代码错了,以下标有红色的是更正的. --2012.12.16

--计算一个长为width的矩阵中第num个数所在的x列,y行
function calcXY(num,width)
    local x=num%width
    local y=num/width
    if(x~=0) then
    y=math.ceil(y)
    else
   x=width
  end return x,y end --从大图生成quad表 function makeQuad(map) --大图的高和宽 local imageheight=map["tilesets"][1].imageheight local imagewidth=map["tilesets"][1].imagewidth --大图水平和竖直方向图块的数目 local numx=tonumber(map["properties"]["numx"]) local numy=tonumber(map["properties"]["numy"]) --水平及竖直间距 local spacing= map["tilesets"][1].spacing local margin=map["tilesets"][1].margin --图块的宽和高 local blockx=tonumber(map["properties"]["blockx"]) local blocky=tonumber(map["properties"]["blocky"]) --水平及竖直方向图块的个数 local width=map["layers"][1].width local height=map["layers"][1].height --图块排列表 local array=map["layers"][1].data --统计不同的图块数目 local j=1 for i=1,#array do if(array[i]~=array[i-1]) then local x,y=calcXY(array[i],numx) --创建一个quad图像参数 需要显示的小图的左顶点在大图中的x,y坐标,每个小图的宽、高,大图的宽、高 quadtable[j]=love.graphics.newQuad((x-1)*blockx+x*spacing,(y-1)*blocky+y*margin,blockx,blocky,imagewidth,imageheight) j=j+1 end end end --画地图 function drawMap(map,image) --图块排列表 local array=map["layers"][1].data --水平方向图块的个数 local width=map["layers"][1].width --图块的宽和高 local blockx=tonumber(map["properties"]["blockx"]) local blocky=tonumber(map["properties"]["blocky"]) local j=0 for i=1,#array do local x,y=calcXY(i,width) if(array[i]~=array[i-1]) then j=j+1 end love.graphics.drawq(image,quadtable[j],mapX+(x-1)*blockx,mapY+(y-1)*blocky) end end
posted @ 2012-12-11 11:59  半山th  阅读(4904)  评论(0编辑  收藏  举报