Modules - kuimoani/defold GitHub Wiki

Modules

Lua ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋ฉด ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์กฐํ™” ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฉ”๋‰ด์–ผ์€ Defold์—์„œ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ํ”„๋กœ์ ํŠธ์˜ ์ค‘๋ณต์„ ํ”ผํ•˜๋Š”๋ฐ ์ข‹์€ ์•„์ด๋””์–ด์ž…๋‹ˆ๋‹ค. ๊ฐ๊ธฐ ๋‹ค๋ฅธ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌ ๋ถ™์—ฌ๋„ฃ๊ธฐ๋กœ ๋ณต์ œ ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ„ ๊ณต์œ ํ•ด์„œ ๋‹จ์ผ ์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋“ค์—๊ฒŒ ์ฆ‰๊ฐ์ ์œผ๋กœ ์˜ํ–ฅ์„ ์ฃผ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Defold๋Š” ๊ณต์œ  ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์— ๋‹ค๋ฅธ ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ค๋‹ˆ๋‹ค. ๋˜ํ•œ Lua ๋ชจ๋“ˆ์€ GUI ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ๊ณผ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์˜ ๋ฐ์ดํ„ฐ์™€ ๊ธฐ๋Šฅ์„ ์บก์Аํ™” ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Requiring files

์šฐ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ๋‚˜๋น„๋ฅผ ํŠน์ง•์œผ๋กœ ๊ฐ€์ง„ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœ์ค‘์ด๋ผ๊ณ  ๊ฐ€์ •ํ•ด ๋ด…์‹œ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด ๋‚˜๋น„๋“ค์˜ ๋ช‡๋ช‡ ๋™์ž‘์„ ๋งŒ๋“ค๊ณ  ์ด ๋™์ž‘์„ ๊ณต์œ ํ•˜๋ ค ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ž‘์—…์„ ์œ„ํ•ด์„œ๋Š” ์šฐ์„  ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์— ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

Blue butterfly

"blue_butterfly.script"์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค:

require "modules_example.flying"

function init(self)
        fly_randomly()
end

function on_message(self, message_id, message, sender)
        if message_id == hash("fly_randomly_done") then
                fly_randomly()
        end
end

์šฐ๋ฆฌ๋Š” fly_randomly() ๋ฅผ init() ์—์„œ ํ˜ธ์ถœํ•ด์„œ ๋‚˜๋น„๋ฅผ ๋žœ๋คํ•œ ์œ„์น˜๋กœ ๋‚ ์•„๊ฐ€๊ฒŒ ํ•  ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์™„๋ฃŒ๋˜๋ฉด, "fly_randomly_done" ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ›์•„์„œ ๋˜ ๊ทธ ์ฆ‰์‹œ ๋‚˜๋น„๋ฅผ ์ƒˆ ๋žœ๋ค ์œ„์น˜๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์ค„ "require modules_example.flying"๋Š” "modules_example" ํด๋”(์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์ด ์ €์žฅ๋œ ์œ„์น˜์—์„œ)์—์„œ "flying.lua" ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์„ ์ฝ์Šต๋‹ˆ๋‹ค.

require ๊ตฌ๋ฌธ์— ํ•„์š”ํ•œ ํŒŒ์ผ๋ช…์˜ ๋ฌธ๋ฒ•์€ ์กฐ๊ธˆ ํŠน๋ณ„ํ•ฉ๋‹ˆ๋‹ค. Lua๋Š” ํŒŒ์ผ๋ช…์˜ .(์ฉœ) ๋ฌธ์ž๋ฅผ ๊ฒฝ๋กœ ๊ตฌ๋ถ„์ž(path separators)๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. (Mac OS X์™€ Linux์—์„œ /, Windows์—์„œ )

"flying.lua"์„ ์ƒ์„ฑํ•˜๋ ค๋ฉด ํ”„๋กœ์ ํŠธ์— ์ƒˆ Lua Module File์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ด๋ฆ„์„ ๋ฐ”๊พธ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

New module

New module name

-- ์›๋ž˜ ์œ„์น˜๋ฅผ ์ €์žฅํ•ด์•ผํ•จ
local origin

-- ์›๋ณธ ์œ„์น˜์—์„œ "radius" ๊ฑฐ๋ฆฌ๋งŒํผ ๋žœ๋คํ•œ ์œ„์น˜๋กœ ๋‚ ๋ ค๋ณด๋ƒ„
-- ๋‚ ๋ ค ๋ณด๋‚ธ ํ›„ "fly_randomly_done" ๋ฉ”์„ธ์ง€๋ฅผ ๋˜๋Œ๋ ค ๋ณด๋ƒ„
function fly_randomly(radius)
        -- radius ๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์•˜์œผ๋ฉด 100์œผ๋กœ ์…‹ํŒ…
        radius = radius or 100
        local go_id = go.get_id()
        -- ์›๋ž˜ ์œ„์น˜ ์ €์žฅ
        if origin == nil then
                origin = go.get_world_position(go_id)
        end

        -- ์›๋ž˜ ์œ„์น˜์—์„œ "radius" ๊นŒ์ง€์˜ ์ตœ๋Œ€ ๊ฑฐ๋ฆฌ์˜ ๋žœ๋ค ์œ„์น˜ ์•Œ์•„๋‚ด๊ธฐ
        local rand_angle = math.random(0, 3.141592 * 2)
        local rand_radius = math.random(radius)
        local offset = vmath.rotate(vmath.quat_rotation_z(rand_angle),
                                    vmath.vector3(rand_radius, 0, 0))
        local rand_pos = origin + offset
        -- ๋„ˆ๋ฌด ๋น ๋ฅธ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด radius์— ๋Œ€ํ•ด ์Šค์ผ€์ผ๋œ ๋žœ๋ค ์žฌ์ƒ์‹œ๊ฐ„(duration)์„ ์…‹ํŒ…ํ•จ
        local rand_duration = math.random(radius) / 100 + (radius / 200)
        -- ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฒ˜๋ฆฌ, ์™„๋ฃŒ ํ›„์— ๋ฉ”์„ธ์ง€๋ฅผ ๋Œ๋ ค๋ณด๋ƒ„
        go.animate(".", "position", go.PLAYBACK_ONCE_FORWARD,
                rand_pos, go.EASING_INOUTSINE, rand_duration, 0.0,
                function ()
                        msg.post("#", "fly_randomly_done")
                end)
end

์ด ์ฝ”๋“œ๋Š” ์•„์ฃผ ์ž˜ ๋™์ž‘ํ•˜๋ฉฐ ๋‚˜๋น„๋ฅผ ์›๋ž˜ ์œ„์น˜(origin) ์ฃผ๋ณ€์œผ๋กœ ๋žœ๋คํ•˜๊ฒŒ ์›€์ง์ด๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ์šฐ๋ฆฌ๋Š” ๋…ธ๋ž€์ƒ‰ ๋‚˜๋น„์˜ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ปฌ๋ ‰์…˜์— ์ถ”๊ฐ€ํ•ด ๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค.

Blue and yellow butterflies

๋žœ๋คํ•˜๊ฒŒ ๋‚ ์•„๋‹ค๋‹ˆ๋Š” ์ฝ”๋“œ๋Š” ์ด๋ฏธ ์žˆ์œผ๋ฏ€๋กœ, ๋…ธ๋ž€์ƒ‰ ๋‚˜๋น„์— ์•„๋ž˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ด…์‹œ๋‹ค.

require "modules_example.flying"

function init(self)
        -- ๋…ธ๋ž€ ๋‚˜๋น„๋Š” ๋” ๋„“์€ ๋น„ํ–‰ ๋ฐ˜๊ฒฝ์„ ๊ฐ€์ง
        fly_randomly(200)
end

function on_message(self, message_id, message, sender)
        if message_id == hash("fly_randomly_done") then
                fly_randomly(200)
        end
end

์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋‘ ๋‚˜๋น„๊ฐ€ ๋™์ผํ•œ ์›์ ์„ ๊ธฐ์ค€์œผ๋กœ ๊ฒน์ณ ๋‚ ์•„๋‹ค๋‹ˆ๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ผ์–ด๋‚˜๋Š” ์ผ์„ ์ดํ•ดํ•˜๋ ค๋ฉด, Defold๊ฐ€ Lua contexts๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค์‹œ ์‚ดํŽด๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—” ํŒŒ๋ž€์ƒ‰๊ณผ ๋…ธ๋ž€์ƒ‰ ๋‚˜๋น„์—๊ฒŒ๋Š” ๋‘ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ„ ๊ธ€๋กœ๋ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•˜๋ฉด์„œ ์ƒ๊ธด ๋ถ€์ž‘์šฉ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. origin ๋ณ€์ˆ˜์˜ ์ •์˜(definition)๋ถ€๋ถ„์„ ๋‹ค์‹œ ์‚ดํŽด๋ด…์‹œ๋‹ค.

-- ์›๋ž˜ ์œ„์น˜๋ฅผ ์ €์žฅํ•ด์•ผํ•จ
local origin

"local"๋กœ ์ •์˜ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ํ˜„์žฌ Lua context์˜ local ์ด๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋“ค์ด ๋™์ผํ•œ Lua context์—์„œ ํ‰๊ฐ€(evaluate)๋œ ํ›„, ๋…ธ๋ž€์ƒ‰๊ณผ ํŒŒ๋ž€์ƒ‰ ๋‚˜๋น„๋Š” ์™„์ „ ๋™์ผํ•œ origin ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋น„ ์˜ค๋ธŒ์ ํŠธ ์ค‘ ํ•˜๋‚˜๋Š” ์ด origin ๋ณ€์ˆ˜๋ฅผ ์…‹ํŒ…ํ•˜๊ณ , ๋‹ค๋ฅธ ๋‚˜๋น„ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๋˜ ์ด origin ๋ณ€์ˆ˜์˜ ๊ฐ™์€ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

        -- "origin"์„ ๋™์ผํ•œ ์ปจํ…์ŠคํŠธ์—์„œ ๋ˆ„๊ฐ€ ์ด๋ฏธ ์…‹ํŒ…ํ–ˆ๋‹ค๋ฉด ๋˜ ์…‹ํŒ…ํ•  ํ•„์š” ์—†์Œ
        if origin == nil then
                origin = go.get_world_position(go_id)
        end

์šฐ๋ฆฌ๋Š” ์ด ๋ฒ„๊ทธ๋ฅผ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณง ์‚ดํŽด๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ์„  ๋” ๋ฏธ๋ฌ˜ํ•œ ๋ฌธ์ œ๋ถ€ํ„ฐ ์‚ดํŽด ๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค.

Name spaces

์œ„์˜ Lua ํŒŒ์ผ์—์„œ, ์šฐ๋ฆฌ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” origin ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ณ€์ˆ˜๋ช…์€ ๋‚˜์ค‘์— ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ „ํ˜€ ๋‹ค๋ฅธ ์ƒํ™ฉ์˜ "origin" ์ด๋ผ๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋ฉฐ ๋‹ค๋ฅธ ์ข…๋ฅ˜๋กœ ๋™์ž‘ํ•˜๋Š” ๋‚˜๋น„๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ด…์‹œ๋‹ค. ์ด๊ฒƒ์€ ์ด๋ฆ„ ์ถฉ๋Œ์ด ์ผ์–ด๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฆ„ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋Š” ๋ณ€์ˆ˜๋‚˜ ํ•จ์ˆ˜ ๋ชจ๋‘์—๊ฒŒ ํŒŒ์ผ๋ช…์œผ๋กœ ์ ‘๋‘์–ด๋ฅผ ๋ถ™์ด๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

local flying_origin

function flying_fly_randomly(radius)
        ...

์ด ๋ฐฉ๋ฒ•์€ ์ž˜ ๋™์ž‘ํ•˜์ง€๋งŒ, Lua๋Š” ๋ฐ์ดํ„ฐ์™€ ์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐ„๋‹จํ•˜๊ณ  ์šฐ์•„ํ•œ ๋ฐฉ๋ฒ•์ธ ๋ชจ๋“ˆ(modules)์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Modules

Lua ๋ชจ๋“ˆ์€ ๋™์ž‘(behaviours)๊ณผ ํ•จ์ˆ˜(functions)๋ฅผ ์œ„ํ•œ ์ปจํ…Œ์ด๋„ˆ๋กœ ์‚ฌ์šฉํ•˜๋Š” Lua ํ…Œ์ด๋ธ”์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ "flaying.lua"์˜ ๋ชจ๋“ˆ ๋ฒ„์ „์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—” ์œ„์—์„œ ๋‹ค๋ฃจ์—ˆ๋˜ ๋ฐ์ดํ„ฐ ๊ณต์œ  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์ˆ˜์ •์‚ฌํ•ญ๋„ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

-- "M" ํ…Œ์ด๋ธ”์— ๋ชจ๋“ˆ์„ ํฌํ•จ์‹œํ‚ด
local M = {}

-- ํ…Œ์ด๋ธ”์„ ์›๋ž˜ ์œ„์น˜๋ฅผ ์ €์žฅํ•˜๋„๋ก ์‚ฌ์šฉํ•จ
-- ๋ชจ๋“ˆ์ด ๋ชจ๋“  ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ๊ณต์œ ๋œ Lua context์˜ ์ผ๋ถ€๋ถ„์ด ๋˜๋ฏ€๋กœ origin ๋ณ€์ˆ˜๋ฅผ ์ง์ ‘์ ์œผ๋กœ ์ €์žฅํ•  ์ˆ˜ ์—†์Œ, ํ•˜๋‚˜ ์ด์ƒ์˜ GO๊ฐ€ ์ด ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฎ์–ด ์”Œ์›Œ์ง
M.origins = {}

-- ์›๋ณธ ์œ„์น˜์—์„œ "radius" ๊ฑฐ๋ฆฌ๋งŒํผ ๋žœ๋คํ•œ ์œ„์น˜๋กœ ๋‚ ๋ ค๋ณด๋ƒ„
-- ๋‚ ๋ ค ๋ณด๋‚ธ ํ›„ "fly_randomly_done" ๋ฉ”์„ธ์ง€๋ฅผ ๋˜๋Œ๋ ค ๋ณด๋ƒ„
function M.fly_randomly(radius)
        -- radius ๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์•˜์œผ๋ฉด 100์œผ๋กœ ์…‹ํŒ…
        radius = radius or 100
        -- ์›๋ž˜ ์œ„์น˜๋ฅผ ์ธ๋ฑ์‹ฑํ•˜๋Š” ํ˜„์žฌ ์˜ค๋ธŒ์ ํŠธ์˜ id๊ฐ€ ํ•„์š”ํ•จ
        -- "."์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ
        local go_id = go.get_id()
        -- ์ €์žฅ๋œ์ ์ด ์—†์œผ๋ฉด ํ˜„์žฌ ์œ„์น˜๋ฅผ origins์— ์ €์žฅํ•จ
        if flying.origins[go_id] == nil then
                flying.origins[go_id] = go.get_world_position(go_id)
        end

        -- ์›๋ž˜ ์œ„์น˜์—์„œ "radius" ๊นŒ์ง€์˜ ์ตœ๋Œ€ ๊ฑฐ๋ฆฌ์˜ ๋žœ๋ค ์œ„์น˜ ์•Œ์•„๋‚ด๊ธฐ
        local rand_angle = math.random(0, 3.141592 * 2)
        local rand_radius = math.random(radius)
        local offset = vmath.rotate(vmath.quat_rotation_z(rand_angle),
                                    vmath.vector3(rand_radius, 0, 0))
        local rand_pos = flying.origins[go_id] + offset
        -- ๋„ˆ๋ฌด ๋น ๋ฅธ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด radius์— ๋Œ€ํ•ด ์Šค์ผ€์ผ๋œ ๋žœ๋ค ์žฌ์ƒ์‹œ๊ฐ„(duration)์„ ์…‹ํŒ…ํ•จ
        local rand_duration = math.random(radius) / 100 + (radius / 200)
        -- ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฒ˜๋ฆฌ, ์™„๋ฃŒ ํ›„์— ๋ฉ”์„ธ์ง€๋ฅผ ๋Œ๋ ค๋ณด๋ƒ„
        go.animate(".", "position", go.PLAYBACK_ONCE_FORWARD,
                rand_pos, go.EASING_INOUTSINE, rand_duration, 0.0,
                function ()
                        msg.post("#", "fly_randomly_done")
                end)
end

return M

์ด์ „ ์Šคํฌ๋ฆฝํŠธ์™€์˜ ์ฐจ์ด์ ์€ ๋ฐ์ดํ„ฐ(flying.origins)์™€ ํ•จ์ˆ˜(flying.fly_randomly()) ๋กœ ์ฑ„์›Œ์ง„ flying ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•œ ๊ฒƒ์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด ํ…Œ์ด๋ธ”์„ ๋ฆฌํ„ดํ•ด์„œ ๋ชจ๋“ˆ์„ ์™„๋ฃŒํ•˜๊ณ , ์ด ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋‚˜๋น„์˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

flying = require "modules_example.flying"

function init(self)
        flying.fly_randomly()
end

function on_message(self, message_id, message, sender)
        if message_id == hash("fly_randomly_done") then
                flying.fly_randomly()
        end
end

์™ธ๋ถ€ ํŒŒ์ผ์„ ์š”์ฒญ(require)ํ•˜๋ฉด, ์š”์ฒญ๋œ ์Šคํฌ๋ฆฝํŠธ์˜ ๋ฆฌํ„ด๊ฐ’์„ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

flying = require "modules_example.flying"

๋ชจ๋“ˆ์ด ๋ฐ์ดํ„ฐ์™€ ๋ชจ๋“ˆ ์ฝ”๋“œ ์ „๋ถ€๋ฅผ ํฌํ•จํ•œ ํ…Œ์ด๋ธ”์„ ๋ฆฌํ„ดํ•˜๋ฉด flying ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด ํ…Œ์ด๋ธ”์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ด๋ธ” ์ด๋ฆ„์€ ์ž„์˜๋กœ ์ง€์–ด๋„ ์ƒ๊ด€ ์—†์œผ๋ฏ€๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.

banana = require "modules_example.flying"

function init(self)
        banana.fly_randomly()
end

function on_message(self, message_id, message, sender)
        if message_id == hash("fly_randomly_done") then
                banana.fly_randomly()
        end
end

์ฆ‰, ๋™์ผํ•œ ์ด๋ฆ„์„ ๊ฐ€์ง„ ๋‘ ๊ฐœ์˜ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์–ด์„œ ์„œ๋กœ ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋ช…์œผ๋กœ ๋กœ์ปฌ์— ํ• ๋‹นํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“ˆ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด์ œ ์šฐ๋ฆฌ๋Š” ์ด๋ฆ„ ์ถฉ๋Œ์„ ํ”ผํ•˜๊ณ  ๊ณต์œ ๋œ ๊ธฐ๋Šฅ์„ ์บก์Аํ™” ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Best practices

Naming conventions

๋ชจ๋“ˆ ํ…Œ์ด๋ธ”์„ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์ง€๋งŒ, public ํ•จ์ˆ˜๋‚˜ ๊ฐ’์ด ํฌํ•จ๋œ ํ…Œ์ด๋ธ”์˜ ํ‘œ์ค€ ์ด๋ฆ„์œผ๋กœ M (http://lua-users.org/wiki/ModuleDefinition ์ฐธ๊ณ )์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค. M ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋™์ผํ•œ ์ด๋ฆ„์˜ ํ•จ์ˆ˜๋กœ ๋ชจ๋“ˆ ํ…Œ์ด๋ธ”์„ ๋”ฐ๋ผํ•ด ๋ฒ„๋ฆฌ๋Š” ์‹ค์ˆ˜ ๋”ฐ์œ„๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

--- ๋ชจ๋“ˆ ์„ค๋ช…
-- @module foobar
local M = {}

--- bar ์ƒ์ˆ˜๊ฐ’ ์„ค๋ช…
-- @field BAR
local M.BAR = "bar"

local function private_function()
end

-- ๋ชจ๋“ˆ์ด ์‹ฑ๊ธ€ํ„ด์ด ์•„๋‹Œ ์ƒํƒœ(non-singleton)๋ฅผ ์œ ์ง€ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ํ˜„ ์ƒํƒœ์˜ "์ธ์Šคํ„ด์Šค"๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•จ. ๊ทธ ๋‹ค์Œ ์ด ์ธ์Šคํ„ด์Šค๋Š” ๋ชจ๋“ˆ ํ•จ์ˆ˜๋กœ ๋„˜๊ฒจ์ง
-- @foobar์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฆฌํ„ด
function M.create()
        local foobar = {
                foo = "foo"
        }
        return foobar
end

--- ์ด ํ•จ์ˆ˜์—์„œ๋Š” ๋ญ”๊ฐ€ ์ž‘์—…ํ•ฉ๋‹ˆ๋‹ค...
-- @function do_something
-- @param foobar
-- @return foo
function M.do_something(foobar)
        return foobar.foo
end

--- ์ด ํ•จ์ˆ˜์—์„œ๋„ ๋ญ”๊ฐ€ ์ž‘์—…ํ•ฉ๋‹ˆ๋‹ค...
-- @function do_something_else
-- @param foobar
-- @return foobar
function M.do_something_else(foobar)
        return M.do_something(foobar) + M.BAR
end

return M

Allow monkey patching

"๋ชฝํ‚ค ํŒจ์น˜(monkey patch)๋Š” ์›๋ณธ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๋™์  ์–ธ์–ด์˜ ๋Ÿฐํƒ€์ž„ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ํ™•์žฅํ•˜๋Š” ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค." โ€” Wikipedia

Lua๋Š” ๋™์  ์–ธ์–ด์ด๋ฏ€๋กœ ๋‚ด์žฅ๋œ ๋ชจ๋“ˆ ์ „๋ถ€๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ…Œ์ŠคํŠธ์™€ ๋””๋ฒ„๊น…์ด ์ฃผ ๋ชฉ์ ์ผ ๊ฒฝ์šฐ ๋Œ€๋‹จํžˆ ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ชฝํ‚ค ํŒจ์น˜๋Š” ๊ฐ•๋ ฅํ•œ ์ปคํ”Œ๋ง์„ ์‰ฝ๊ฒŒ ์œ ๋„ํ•˜๋ฏ€๋กœ ์ผ๋ฐ˜์ ์œผ๋กœ ์ข‹์€ ์ƒ๊ฐ์€ ์•„๋‹™๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ƒˆ ๋ชจ๋“ˆ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋ชฝํ‚ค ํŒจ์น˜๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์ปค์Šคํ…€ ๋ชจ๋“ˆ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. Lua๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ค๋‹ˆ๋‹ค.

-- mymodule.lua
local M = {}

M.foo = function()
  print('์ด๊ฒƒ์€ public ๋ชจ๋“ˆ ํ•จ์ˆ˜์ด๋‹ค.')
end

setmetatable(M, {
  __newindex = function(m, t)
	error('์œ ์ €๊ฐ€ ' .. t .. ' ์†์„ฑ์„ ๋ชจ๋“ˆ์— ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ์‹œ๋„ํ–ˆ๋‹ค!')
  end
})

return M

์œ„์˜ ํŠธ๋ฆญ์€ ์ข‹์€ ์•„์ด๋””์–ด๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ๋ชจ๋“ˆ์— ๋ฌด์—‡์„ ์‚ฌ์šฉํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ ์œ ์ €์—๊ฒŒ ๋งก๊ธฐ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Beware of locals

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ์Šคํƒ€์ผ๋กœ ๋ชจ๋“ˆ์„ ์ •์˜ํ•˜์ง€ ์•Š๊ธฐ๋กœ ํ–ˆ๋‹ค๋ฉด, local์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์กฐ์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ ์˜ˆ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. (kiki.to ์—์„œ ๋ฐœ์ทŒ):

local M = {}

local function sum(a, b)
	return a + b
end

local function mult(a, b)
	local result = 0
	for i=1,b do
		result = sum(result, a)
	end
	return result
end

M.sum = sum
M.mult = mult

return M

์ด๊ฒƒ์€ ์•„์ฃผ ๊ฐ„๋‹จํ•œ ๊ณ„์‚ฐ๊ธฐ ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. ์ด ๋ชจ๋“ˆ ํ…Œ์ด๋ธ”์ด ๋งˆ์ง€๋ง‰์— ์–ด๋–ป๊ฒŒ public ํ•จ์ˆ˜๋“ค์„ ํ• ๋‹นํ•˜๋Š”์ง€ ์ž˜ ์‚ดํŽด๋ณด์‹ญ์‹œ์˜ค. ๋˜ํ•œ local mult() ํ•จ์ˆ˜๊ฐ€ local sum() ํ•จ์ˆ˜๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€๋„ ์‚ดํŽด๋ณด์‹ญ์‹œ์˜ค. ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ์กฐ๊ธˆ ๋น ๋ฅผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์—ฌ๊ธฐ์—” ๋ฏธ๋ฌ˜ํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ค ์ด์œ ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ชจ๋“ˆ์„ ๋ชฝํ‚ค ํŒจ์น˜(monkey patch) ํ•˜๋ ค ํ•œ๋‹ค๋ฉด:

local summult = require("summult")
summult.sum = function(a,b) return 1 end
print(summult.mult(5,2))

์ด์ œ, ์žฌ์ •์˜ ๋œ ํ›„์—๋„ summult.mult(5,2) ๋Š” ์—ฌ์ „ํžˆ 10์„ ๋ฆฌํ„ด(1์„ ์˜ˆ์ƒํ–ˆ๊ฒ ์ง€๋งŒ)ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ์œ ์ €๊ฐ€ ๋ชจ๋“ˆ ํ…Œ์ด๋ธ”์—์„œ sum() ํ•จ์ˆ˜๋ฅผ ๋ณ€๊ฒฝ ํ–ˆ์ง€๋งŒ multi() ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ์—ฌ์ „ํžˆ local๊ณผ ์ˆ˜์ •๋˜์ง€ ์•Š์€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

global scope๋ฅผ ์˜ค์—ผ์‹œํ‚ค์ง€ ๋ง๊ณ  ๋‚ด๋ถ€ ์ƒํƒœ(internal state)๋ฅผ ๋…ธ์ถœ์‹œํ‚ค๊ฑฐ๋‚˜ ์ƒˆ์–ด๋‚˜์˜ค์ง€ ์•Š๊ฒŒ ํ•˜๊ธฐ

์ด ๋ชจ๋ฒ”์‚ฌ๋ก€๋Š” ๋ชจ๋“ˆ์—๋งŒ ๊ตญํ•œ๋œ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ์ „์—ญ ๋ฒ”์œ„(global scope)์—์„œ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋ฉด ์•ˆ๋˜๋Š” ์ค‘์š”์„ฑ์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์ƒ๊ธฐํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ „์—ญ ๋ฒ”์œ„์—์„œ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ช…๋ฐฑํ•œ ์œ„ํ—˜์„ฑ ์ค‘ ํ•˜๋‚˜๋Š” ๋ชจ๋“ˆ์˜ ์ƒํƒœ๊ฐ€ ๋…ธ์ถœ๋œ๋‹ค๋Š” ๊ฒƒ์ด ์žˆ์œผ๋ฉฐ ๋‹ค๋ฅธ ์œ„ํ—˜์„ฑ์œผ๋กœ๋Š” ๋™์ผํ•œ global ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋‘ ๋ชจ๋“ˆ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Defold๋Š” ๋™์ผํ•œ ์ปฌ๋ ‰์…˜์˜ ์˜ค๋ธŒ์ ํŠธ ๊ฐ„์—๋งŒ Lua context๋ฅผ ๊ณต์œ ํ•˜๋ฏ€๋กœ ์ง„์ •ํ•œ ์˜๋ฏธ์˜ ์ „์—ญ ๋ฒ”์œ„(global scope)๋Š” ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ฐœํ•˜๋Š” ๋™์•ˆ์—๋Š” global table์„ ๋ชจ๋‹ˆํ„ฐ๋ง ํ•ด์„œ global table์ด ์ˆ˜์ •๋  ๋•Œ ๋งˆ๋‹ค error() ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ž์„ธํ•œ ์ •๋ณด๋Š” Lua Wiki ํŽ˜์ด์ง€ http://lua-users.org/wiki/DetectingUndefinedVariables ์ฐธ๊ณ 

์ด ์ฝ”๋“œ๋Š” global table์„ ๋ณดํ˜ธํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

-- ์ƒˆ ์ธ๋ฑ์Šค๋กœ๋ถ€ํ„ฐ ํ…Œ์ด๋ธ”์„ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•œ ๋ชจ๋“ˆ. ์ผ๋ฐ˜์ ์œผ๋กœ global scope๋ฅผ ๋ณดํ˜ธํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋จ
-- https://gist.github.com/britzl/546d2a7e32a3d75bab45 ์—์„œ ์ตœ์‹  ๋ฒ„์ „ ๊ฐ€์ ธ์˜ค๊ธฐ
-- @module superstrict
-- @usage
--
--	-- Defold ์‚ฌ์šฉ ์˜ˆ์ œ
--	-- gameobject์™€ gui script์˜ ๋ผ์ดํ”„์‚ฌ์ดํด ํ•จ์ˆ˜๋“ค์„ ํ—ˆ์šฉํ•จ
--	-- ๋˜ํ•œ ๋ฐ์Šคํฌํƒ‘์—์„œ ๋”๋ฏธ ๊ตฌํ˜„์„ ์œ„ํ•ด facebook๊ณผ iap ๋ชจ๋“ˆ ํ• ๋‹น์„ ํ—ˆ์šฉํ•จ
--	-- whitelist๊ฐ€ ํŒจํ„ด์ด ์ผ์น˜ํ•˜๋Š”์ง€๋ฅผ ๋‹ค๋ฃจ๊ณ  ์ด ์˜ˆ์ œ์—์„œ '__' ์ ‘๋‘์–ด๊ฐ€ ์žˆ๋Š” ๋ชจ๋“  ํ•จ์ˆ˜ ๋˜ํ•œ ์ „์—ญ ๋ฒ”์œ„(global scope)์—์„œ ํ—ˆ์šฉ ๋จ
-- 	local superstrict = require("superstrict")
-- 	superstrict.lock(_G, { "go", "gui", "msg", "url", "sys", "render", "factory", "particlefx", "physics", "sound", "sprite", "image", "tilemap", "vmath", "matrix4", "vector3", "vector4", "quat", "hash", "hash_to_hex", "hashmd5", "pprint", "iap", "facebook", "push", "http", "json", "spine", "zlib", "init", "final", "update", "on_input", "on_message", "on_reload", "__*" })
--
--	-- ํ—ˆ์šฉ๋จ
--	__allowed = "abc"
--
--	-- ํ—ˆ์šฉ๋จ
--	facebook = dummy_fb
--
--	-- ํ—ˆ์šฉ๋จ
--	function init(self)
--	end
--
--	-- ์—๋Ÿฌ ๋ฐœ์ƒํ•จ
--	if foo == "bar" then
--	end
--
--	-- ์—๋Ÿฌ ๋ฐœ์ƒํ•จ
--	function global_function_meant_to_be_local()
--	end
--
local M = {}

-- ํ…Œ์ด๋ธ”๊ณผ whitelist ์ด๋ฆ„์„ ๋งคํ•‘ํ•จ
local whitelisted_names = {}

-- ์ž ๊ฒจ์ง„ ํ…Œ์ด๋ธ”์— ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ์•ก์„ธ์Šค๋ฅผ ํ•  ํ•„์š”๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ๋ˆ„๊ตฌ๋„ ์—๋Ÿฌ ํ•จ์ˆ˜๋กœ ์—‰๋ง์œผ๋กœ ๋งŒ๋“ค์ง€ ์•Š๋„๋ก ํ™•์ธํ•  ๊ฒƒ
local _error = error


--- ํ…Œ์ด๋ธ”์˜ ํ‚ค๊ฐ€ whitelist์— ์žˆ๋Š”์ง€ ์—†๋Š”์ง€ ์ฒดํฌ
-- @param t whitelist ์ด๋ฆ„์„ ์ฒดํฌํ•˜๋ ค๋Š” ํ…Œ์ด๋ธ”
-- @param n ์ฒดํฌํ•˜๋ ค๋Š” ๋ณ€์ˆ˜์˜ ์ด๋ฆ„
-- @return true n์ด t์˜ whitelist์— ํฌํ•จ๋˜์–ด ์žˆ๋‹ค๋ฉด
local function is_whitelisted(t, n)
	for _,whitelisted_name in pairs(whitelisted_names[t] or {}) do
		if n:find(whitelisted_name) then
			return true
		end
	end
	return false
end

--- ๋ณดํ˜ธ๋œ ์ƒˆ ์ธ๋ฑ์Šค
-- ์ง€์ •๋œ ์ด๋ฆ„์ด whitelist ํ…Œ์ด๋ธ”์— ์žˆ๋Š”์ง€ ์ฒดํฌํ•จ.
-- ์—†์œผ๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ์‹œํ‚ด
-- @param t ์ƒˆ ์ธ๋ฑ์Šค๊ฐ€ ์…‹ํŒ…๋œ ํ…Œ์ด๋ธ”
-- @param n ํ…Œ์ด๋ธ”์— ์…‹ํŒ…๋œ ๋ณ€์ˆ˜ ์ด๋ฆ„
-- @param v ์…‹ํŒ…๋œ ๊ฐ’
local function lock_newindex(t, n, v)
	if is_whitelisted(t, n) then
		rawset(t, n, v)
		return
	end

	_error("ํ…Œ์ด๋ธ” [" .. tostring(t) .. "] ์€ ์ž ๊ฒผ์Šต๋‹ˆ๋‹ค. '" .. n .. "'์— ๊ฐ’์„ ์“ฐ๋ ค๊ณ  ์‹œ๋„์ค‘์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์€ whitelist์— ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ local๋กœ '" .. n .. "' ์„ ์„ ์–ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.", 2)
end

--- ๋ณดํ˜ธ๋œ __index
-- ์ •์˜๋˜์ง€ ์•Š์€ ๊ฐ’์„ ์ฝ์œผ๋ ค ํ•˜๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ
-- @param t ์ƒˆ ์ธ๋ฑ์Šค๊ฐ€ ์…‹ํŒ…๋œ ํ…Œ์ด๋ธ”
-- @param n ํ…Œ์ด๋ธ”์— ์…‹ํŒ…๋œ ๋ณ€์ˆ˜ ์ด๋ฆ„
local function lock_index(t, n)
	if is_whitelisted(t, n) then
		return rawget(t, n)
	end

	_error("ํ…Œ์ด๋ธ” [" .. tostring(t) .. "] ์€ ์ž ๊ฒผ์Šต๋‹ˆ๋‹ค. ์ •์˜๋˜์ง€ ์•Š์€ ๊ฐ’ '" .. n .. "'์„ ์ฝ์œผ๋ ค ์‹œ๋„์ค‘์ž…๋‹ˆ๋‹ค.", 2)
end

--- ํ…Œ์ด๋ธ” ์ž ๊ทธ๊ธฐ. ํ…Œ์ด๋ธ”์— ์ƒˆ ๊ฐ’(ํ•จ์ˆ˜ ๋ฐ ๋ณ€์ˆ˜)์ด ํ• ๋‹น๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•จ
-- ์ผ๋ฐ˜์ ์ธ ์šฉ๋„๋กœ๋Š” global scope๋ฅผ ์‹ค์ˆ˜๋กœ ํ• ๋‹นํ•˜์ง€ ๋ชปํ•˜๊ฒŒ lock(_G) ๋ฅผ ํ˜ธ์ถœํ•ด ๋ณดํ˜ธํ•˜๋Š” ๊ฒƒ์ž„
-- @param t ์ž ๊ทธ๋ ค๋Š” ํ…Œ์ด๋ธ”
-- @param whitelist ํ…Œ์ด๋ธ”์— ํ—ˆ์šฉ๋œ ์ด๋ฆ„์˜ ๋ชฉ๋ก
function M.lock(t, whitelist)
	assert(t, "์ž ๊ทธ๋ ค๋ฉด ํ…Œ์ด๋ธ”์„ ๋„˜๊ฒจ์•ผ ํ•จ")
	whitelisted_names[t] = whitelist or {}
	local mt = getmetatable(t) or {}
	mt.__newindex = lock_newindex
	mt.__index = lock_index
	setmetatable(t, mt)
end

---
-- ํ…Œ์ด๋ธ” ์–ธ๋ฝํ•˜๊ธฐ
-- @param t ์–ธ๋ฝํ•˜๋ ค๋Š” ํ…Œ์ด๋ธ”
function M.unlock(t)
	assert(t, "์–ธ๋ฝํ•˜๋ ค๋ฉด ํ…Œ์ด๋ธ”์„ ๋„˜๊ฒจ์•ผ ํ•จ")
	local mt = getmetatable(t) or {}
	mt.__newindex = rawset
	mt.__index = rawget
	setmetatable(t, mt)
end

return M

๋˜ํ•œ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋…ธ์ถœํ•˜๋Š” ๋Œ€์‹ ์— ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๋‹ค๋ฃจ๋Š” ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๋ฉด ๋ชจ๋“ˆ์˜ ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์œผ๋ฉด์„œ ๋ชจ๋“ˆ์˜ ๋‚ด๋ถ€ ์ž‘์—…๋งŒ ๋ฆฌํŽ™ํ† ๋ง ํ•˜๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค. ์ƒํƒœ๋ฅผ ์บก์Аํ™” ํ•˜๋Š” ๊ฒƒ์€ OOP ์–ธ์–ด์—์„œ ์ผ๋ฐ˜์ ์ด์ง€๋งŒ Lua ๋ชจ๋“ˆ ๊ฐœ๋ฐœ์—์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

Stateless or stateful modules?

์ƒํƒœ๊ฐ€ ์žˆ๋Š” ๋ชจ๋“ˆ(stateful modules)์€ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜์—ฌ ๋ชจ๋“ˆ์˜ ๋ชจ๋“  ์‚ฌ์šฉ์ž ๊ฐ„์— ๊ณต์œ ๋˜๋Š” ์‹ฑ๊ธ€ํ†ค(singleton)๊ณผ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

local M = {}

-- ๋ชจ๋“ˆ์˜ ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ์ด ํ…Œ์ด๋ธ”์„ ๊ณต์œ ํ•จ
local state = {}

function M.do_something(foobar)
	table.insert(state, foobar)
end

return M

์ƒํƒœ๊ฐ€ ์—†๋Š” ๋ชจ๋“ˆ(stateless modules)์€ ์–ด๋– ํ•œ ๋‚ด๋ถ€ ์ƒํƒœ๋„ ์œ ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ๋ชจ๋“ˆ ์‚ฌ์šฉ์ž์—๊ฒŒ local์ธ ๊ฐœ๋ณ„ ํ…Œ์ด๋ธ”๋กœ ์ƒํƒœ๋ฅผ ๋…ธ์ถœ(externalize )ํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ƒํƒœ๊ฐ€ ์—†๋Š” ๋ชจ๋“ˆ๋กœ ์ ‘๊ทผํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” create() ํ˜น์€ new() ๊ฐ™์€ ๋ชจ๋“ˆ ๋‚ด์˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์— ์ข…์ข… ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋Š” ์ƒํƒœ๊ฐ€ ์ €์žฅ๋œ ํ…Œ์ด๋ธ”์„ ๋ฆฌํ„ดํ•˜๋ฉฐ, ๊ตฌํ˜„์— ๋”ฐ๋ผ์„œ ๋•Œ๋กœ๋Š” ๋ชจ๋“ˆ ํ•จ์ˆ˜ ์ž์ฒด๊ฐ€ ๋˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

state table๋งŒ ์‚ฌ์šฉํ•˜๋Š” Stateless modules

์•„๋งˆ๋„ ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ์ƒํƒœ(state)๋งŒ์„ ํฌํ•จํ•œ ์ƒˆ ํ…Œ์ด๋ธ”์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ผ ๊ฒ๋‹ˆ๋‹ค. ์ด ์ƒํƒœ(state)๋Š” state table์„ ๋‹ค๋ฃจ๋Š” ๋ชจ๋“  ํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฉ”ํ„ฐ๋กœ ๋ช…์‹œ์ ์œผ๋กœ ๋ชจ๋“ˆ๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

local M = {}

local function private_function(self, bar)
	return self.public_variable .. bar
end

function M.public_function(self, bar)
	return private_function(self, bar)
end

function M.new(foo)
	local instance = {
		public_variable = foo
	}
	return instance
end

return M

์•„๋ž˜์™€ ๊ฐ™์ด ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

local foobar = require(โ€œfoobarโ€)
local fb = foobar.new(โ€œfooโ€)
print(fb.public_variable)
print(foobar.public_function(fb, โ€œbarโ€))

metatables๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Stateless modules

Metatables๋Š” Lua์˜ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์ข‹์€ ํŠœํ† ๋ฆฌ์–ผ์€ http://nova-fusion.com/2011/06/30/lua-metatables-tutorial/ ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์ ‘๊ทผ๋ฒ•์œผ๋กœ๋Š” ํ˜ธ์ถœ ๋•Œ๋งˆ๋‹ค ๋ชจ๋“ˆ์˜ public ํ•จ์ˆ˜๋“ค๊ณผ ์ƒํƒœ๋ฅผ ํฌํ•จํ•œ ์ƒˆ ํ…Œ์ด๋ธ”์„ ๋ฆฌํ„ดํ•˜๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

local M = {}

local function private_function(self, bar)
	return self.public_variable .. bar
end

function M:public_function(bar)
	return private_function(self, bar)
end

function M.new(foo)
	local instance = {
		public_variable = foo
	}
	return setmetatable(instance, { __index = M })
end

return M

์•„๋ž˜ ๋ฐฉ๋ฒ•์œผ๋กœ ์ด ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

local foobar = require(โ€œfoobarโ€)
local fb = foobar.new(โ€œfooโ€)
print(fb.public_variable)
print(fb:public_function(โ€œbarโ€))

๋ชจ๋“ˆ์—์„œ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ณ  ํ˜ธ์ถœํ•  ๋•Œ ์ฝœ๋ก (:) ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. o:foo(x) ๊ณผ ๊ฐ™์€ ํ‘œํ˜„์‹์€ o.foo(o, x) ์˜ ๋‹ค๋ฅธ ํ‘œํ˜„์ด๋ฉฐ, ํ•จ์ˆ˜ ์„ ์–ธ์‹œ์—๋Š” ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ self๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ http://www.lua.org/pil/5.html ์ฐธ๊ณ 

Stateless modules using closures

๋ชจ๋“ˆ์„ ์ •์˜ํ•˜๋Š” ์„ธ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” Lua closures(http://www.lua.org/pil/6.1.html ์ฐธ๊ณ )๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฆฌํ„ดํ•˜๊ณ  ํด๋กœ์ €๋Š” ์ธ์Šคํ„ด์Šค์™€ private, public ๋ฐ์ดํ„ฐ์™€ ํ•จ์ˆ˜๋“ค์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” metatables๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฒ˜๋Ÿผ ์ธ์ž๊ฐ’(๋ช…์‹œ์ ์œผ๋กœ๋‚˜ ์•”์‹œ์ ์œผ๋กœ๋‚˜ ์ฝœ๋ก (:) ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š”)์œผ๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ๋„˜๊ธธ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด ๋ฐฉ๋ฒ•์€ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด "__index" metamethods ๋ฅผ ํ†ตํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ metatables์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค ๋‹ค์†Œ ๋น ๋ฆ…๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ๋‹จ์ ์€ ๊ฐ ํด๋กœ์ €๊ฐ€ ๋ฉ”์†Œ๋“œ์˜ ๋ณต์ œ๋ณธ์„ ํฌํ•จํ•˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋ชจ๊ฐ€ ํฌ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ๋‹จ์ ์€ ๊น”๋”ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ธ์Šคํ„ด์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ๋ชฝํ‚ค ํŒจ์น˜(monkey patch)ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

local M = {}

function M.new(foo)
	local instance = {
		public_variable = foo
	}

	local private_variable = ""

	local private_function = function(bar)
		return instance.public_variable .. private_variable .. bar
	end

	instance.public_function = function(bar)
		return private_function(bar)
	end

	return instance
end

return M

์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

local foobar = require(โ€œfoobarโ€)
local fb = foobar.new(โ€œfooโ€)
print(fb.public_variable)
print(fb.public_function(โ€œbarโ€))

๋ชจ๋“ˆ๊ณผ ๋ชจ๋“ˆ ํ•จ์ˆ˜๋Š” ๋ช…ํ™•ํ•œ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์ง€๊ณ  ์˜ˆ์ƒ๋Œ€๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋ชจ๋“ˆ์€ ์ฃผ๋กœ ์žฌ์‚ฌ์šฉ์„ ๋‹จ์ˆœํ™” ํ•˜๊ณ  ๋™์ž‘์„ ์บก์Аํ™” ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด ์กŒ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“ˆ์„ ์ž‘์„ฑํ•  ๋•Œ, ์˜ˆ์ƒํ•œ ๋™์ž‘์ด ๋ชจ๋“ˆ, ํ•จ์ˆ˜, ์ธ์ž์˜ ์ด๋ฆ„์ด ๋ณด์ด๋Š” ๋Œ€๋กœ ๊ฐ„๋‹จํžˆ ์ถ”๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ ๋ชจ๋“ˆ ๊ณ„์ •์˜ ํ•จ์ˆ˜ ์ด๋ฆ„์ด login(username, password) ์ด๋ผ๋ฉด ํŠน์ • ์œ ์ €์ด๋ฆ„๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ„์ •์— ๋กœ๊ทธ์ธ ํ•˜๋Š” ํ•จ์ˆ˜๋ผ๊ณ  ์ถ”๋ฆฌํ•˜๊ธฐ๊ฐ€ ์‰ฝ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“ˆ๊ณผ ๋ชจ๋“  public ํ•จ์ˆ˜๋“ค์„ ๋ฌธ์„œํ™” ํ•˜์„ธ์š”.

๋ชจ๋“ˆ ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฌธ์„œํ™” ํ•˜๋ฉด, ํ•จ์ˆ˜๋‚˜ ์ธ์ž ์ด๋ฆ„์œผ๋กœ ์ถ”์ •ํ•˜๊ธฐ ์–ด๋ ค์šด ์ •๋ณด๋ฅผ ๊ธฐ์–ตํ•ด ๋‚ด๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค. ๋งŽ์€ ๊ฒฝ์šฐ, ์งง๊ณ  ์ž˜ ์ด๋ฆ„์ง€์–ด์ง„ ํ•จ์ˆ˜๋‚˜ ์ธ์ž๋Š” ๋ชจ๋“ˆ์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๊ณ  ๋ฌด์—‡์„ ์‚ฌ์šฉํ•˜๊ณ  ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ๋ถ€ํ„ฐ ๋ฌด์—‡์„ ๊ธฐ๋Œ€ํ•˜๋Š”์ง€ ์˜ˆ์ธกํ•˜๊ธฐ ์ถฉ๋ถ„ํ•˜์ง€๋งŒ, ๋ฌธ์„œํ™”๋กœ๋Š” ๋ฐ˜ํ™˜๊ฐ’, ์ „์ œ์กฐ๊ฑด, ์‚ฌ์šฉ์˜ˆ์ œ๋ฅผ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. LDoc ํ‘œ์ค€์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์„œํ™”๋ฅผ ํ•ด๋ณด์„ธ์š”.

์ž์„ธํ•œ LDoc ๋ฌธ์„œ ํ‘œ์ค€์€ https://github.com/stevedonovan/LDoc ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.