Mac 下安装使用 Love2D

概述

Love2D 是一款开源的 2D 开发引擎, 使用 Lua, 支持Windows,Linux,Mac,Android以及iOS多种平台, 在国外的游戏开发者中很受欢迎, 官网地址, 今天试用了一下, 感觉非常简单, 很好上手.

需要注意的一点是, Love2D 在最近的版本里经常修改函数, 所以如果遇到以前的代码无法运行时可以查查官网文档, 看看是不是函数名做了修改.

如果你经常使用 Lua, 并且想用 Lua 做一些图形图像方面的编程试验, 那就可以试试它. 本文介绍如何在 Mac 下安装使用 Love2D.

安装

首先下载最新的版本Love2D-0.10.1-macosx-x64, 不幸的是这个地址的服务器是亚马逊的S3, 属于国内无法访问的地址, 所以提供一个网盘下载的地址Love2D-0.10.1-macosx-x64-网盘下载.

下载好之后, 双击解压, 得到一个名为 love.app 的应用程序, 为方便使用, 把它拖到应用程序中.

我们一般习惯在终端下通过命令来使用, 所以需要加一个简短的别名 love, 需要编辑文件~/.bash_profile, 加入这两行:

# alias to love
alias love="/Applications/love.app/Contents/MacOS/love"

保存后执行 source ~/.bash_profile, 这样, 你就可以直接在终端执行 love 命令了, 如果不带参数执行会启动一个新 Love2D窗口, 也可以查看版本号:

Air:love admin$ love --version
LOVE 0.10.1 (Super Toast)
Air:love admin$

第一个 Love2D 项目

新建项目

Love2D 写游戏非常方便, 首先新建一个目录 love(目录名可以随便起), 接着在该目录下新建一个文件 main.lua(该文件必须使用这个名字), 然后在 main.lua 中编写游戏逻辑即可, 可以试试这段代码:

function love.draw()
    love.graphics.print("Hello World", 400, 300)
end

执行命令是用 love 调用目录, 它会自动加载目录内的 main.lua 文件, 命令如下:

love ./love

它会新建一个窗口, 然后打印 Hello World.

项目配置文件

还可以新建一个名为 conf.lua 的文件, 用来进行各项设置, 可以参考的模板如下:

function love.conf(t)
    t.identity = nil                    -- The name of the save directory (string)
    t.version = "0.10.1"                -- The LÖVE version this game was made for (string)
    t.console = false                   -- Attach a console (boolean, Windows only)
    t.accelerometerjoystick = true      -- Enable the accelerometer on iOS and Android by exposing it as a Joystick (boolean)
    t.externalstorage = false           -- True to save files (and read from the save directory) in external storage on Android (boolean) 
    t.gammacorrect = false              -- Enable gamma-correct rendering, when supported by the system (boolean)
 
    t.window.title = "Untitled"         -- The window title (string)
    t.window.icon = nil                 -- Filepath to an image to use as the window's icon (string)
    t.window.width = 800                -- The window width (number)
    t.window.height = 600               -- The window height (number)
    t.window.borderless = false         -- Remove all border visuals from the window (boolean)
    t.window.resizable = false          -- Let the window be user-resizable (boolean)
    t.window.minwidth = 1               -- Minimum window width if the window is resizable (number)
    t.window.minheight = 1              -- Minimum window height if the window is resizable (number)
    t.window.fullscreen = false         -- Enable fullscreen (boolean)
    t.window.fullscreentype = "desktop" -- Choose between "desktop" fullscreen or "exclusive" fullscreen mode (string)
    t.window.vsync = true               -- Enable vertical sync (boolean)
    t.window.msaa = 0                   -- The number of samples to use with multi-sampled antialiasing (number)
    t.window.display = 1                -- Index of the monitor to show the window in (number)
    t.window.highdpi = false            -- Enable high-dpi mode for the window on a Retina display (boolean)
    t.window.x = nil                    -- The x-coordinate of the window's position in the specified display (number)
    t.window.y = nil                    -- The y-coordinate of the window's position in the specified display (number)
 
    t.modules.audio = true              -- Enable the audio module (boolean)
    t.modules.event = true              -- Enable the event module (boolean)
    t.modules.graphics = true           -- Enable the graphics module (boolean)
    t.modules.image = true              -- Enable the image module (boolean)
    t.modules.joystick = true           -- Enable the joystick module (boolean)
    t.modules.keyboard = true           -- Enable the keyboard module (boolean)
    t.modules.math = true               -- Enable the math module (boolean)
    t.modules.mouse = true              -- Enable the mouse module (boolean)
    t.modules.physics = true            -- Enable the physics module (boolean)
    t.modules.sound = true              -- Enable the sound module (boolean)
    t.modules.system = true             -- Enable the system module (boolean)
    t.modules.timer = true              -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update
    t.modules.touch = true              -- Enable the touch module (boolean)
    t.modules.video = true              -- Enable the video module (boolean)
    t.modules.window = true             -- Enable the window module (boolean)
    t.modules.thread = true             -- Enable the thread module (boolean)
end

这个文件实际上是执行了 love.conf(t) 函数来设置 Love2D 的各项配置参数, 如果有这个文件, 它会在所有其他文件之前被加载运行.

Love2D 的程序框架

如果你用过 Processing, 你会感觉这种程序结构非常熟悉, love.load() 只执行一次, love.update() 循环执行, 用于更新数据, love.draw() 循环执行, 用于绘制屏幕, 如下:

-- main.lua

-- Load some default values for our rectangle.
function love.load()
    x, y, w, h = 20, 20, 60, 20
end
 
-- Increase the size of the rectangle every frame.
function love.update(dt)
    w = w + 1
    h = h + 1
end
 
-- Draw a coloured rectangle.
function love.draw()
    love.graphics.setColor(0, 100, 100)
    love.graphics.rectangle("fill", x, y, w, h)
end

试试上面的程序.

对 shader 的支持

Love2D 支持 OpenGL, 不过好像支持的版本不高, glsl 1.2, 下面是一段来自半山无极:love2d教程11--着色器的例程:

function love.load()
    --为了方便书写
    gr, li, lf    = love.graphics, love.image, love.filesystem

    image            = gr.newImage('Love.jpg')
    width, height    = gr.getWidth(), gr.getHeight()
    effect = gr.newPixelEffect [[
        extern vec4 Cmin;
        extern vec4 Cmax;
        vec4 effect(vec4 color,Image tex,vec2 tc,vec2 pc)
        {    vec4 pixel = Texel(tex,tc);
            //vec4的四个分量分别是r,g,b,a
            //下面把图片在cmax和cmin之间的像素的alpha分量设为0,即透明
            if ((pixel.r<=Cmax.r && pixel.r>=Cmin.r) &&
                (pixel.g<=Cmax.g && pixel.g>=Cmin.g) &&
                (pixel.b<=Cmax.b && pixel.b>=Cmin.b))
            {pixel.a        = 0;}
            return pixel;
        }
        ]]

    --需要移除的像素范围,这与具体的图片相关,如此图,背景为蓝色,主体为粉红,
    --除了红色分量处的alpha不变,其他分量处的alpha都设为0
    remove_range = {
        r = { 0, 125 },
        g = { 0, 255 },
        b = { 0, 255 }
        }
    --opengl的颜色范围0.0--1.0,值越小表明此分量占的比例越小
    remove_min = {remove_range.r[1]/255,remove_range.g[1]/255,remove_range.b[1]/255,1}
    remove_max = {remove_range.r[2]/255,remove_range.g[2]/255,remove_range.b[2]/255,1}
    effect:send('Cmin',remove_min) --向cmin传值
    effect:send('Cmax',remove_max)
    remove = false --透明变换开关

    -- 颜色变换效果
    effect2= love.graphics.newPixelEffect [[
        extern number time;
        vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
        {
        //这些函数为了保证值在0.0--1.0之间,三角函数取值为-1.0--1.0
            return vec4((1.0+sin(time))/2.0, abs(cos(time)), abs(sin(time)), 1.0);
        }

    ]]
    change=false --颜色变换开关
end

function love.draw()
    --由于love是按先后顺序绘图,如果图片不透明,此据会被挡住
    gr.print('you can not see this ,before the img transparented',10,40)
    if remove then
        gr.setPixelEffect( effect )
        gr.draw( image )
        gr.setPixelEffect() --还原默认的效果
        else
        gr.draw( image )
    end
    if change then
        gr.setPixelEffect(effect2)
        gr.rectangle('fill', 10,305,790,285)
        gr.setPixelEffect()

    end

    gr.print( 'Press <r> to change background to transparent.', 10, 10)
    gr.print( 'Press <c> to see the beautiful color.', 10, 25)

end

local t=0
function love.update(dt)
     t = t + dt
    effect2:send("time", t)

end

function love.keypressed(key)
    if key == 'escape'    then love.event.push( 'quit' )    end
    if key=="c" then change = not change end
    if key == 'r'        then remove = not remove end
end

不过我们需要稍作修改, 因为有两个函数的名字变了, Love2D0.90 版本中把函数 love.graphics.newPixelEffect 改成了 love.graphics.newShader, 把函数 love.graphics.setPixelEffect 改成了 love.graphics.setShader.

修改了这两个函数就可以正常运行了.

参考

Love2D官网百科半山无极:使用lua开发游戏-love2d教程汇总