Message passing - kuimoani/defold GitHub Wiki

Message passing

๋ฉ”์„ธ์ง€ ์ „๋‹ฌ์€ ์˜ค๋ธŒ์ ํŠธ๊ฐ„ ์ข…์†์„ฑ์„ ๋งŒ๋“ค์ง€ ์•Š์œผ๋ฉด์„œ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” Defold์˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ด ๋งค๋‰ด์–ผ์€ ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๋ฉฐ ๊ฒŒ์ž„์˜ค๋ธŒ์ ํŠธ, ์ปดํฌ๋„ŒํŠธ, ์ปฌ๋ ‰์…˜์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ง€์‹์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ์„ค๋ช…ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

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

Defold์˜ Lua ํ†ตํ•ฉ(integration)์€ Java, C++, C# ๊ฐ™์ด ์ƒ์†์„ ์‚ฌ์šฉํ•œ ํด๋ž˜์Šค ๊ตฌ์กฐ๋กœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋“ฏ์ด ๊ฐ์ฒด์ง€ํ–ฅ์„ ์ œ๊ณตํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  Defold๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ๊ฐ์ฒด ์ง€ํ–ฅ ์„ค๊ณ„๋กœ Lua์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค:

  • ์˜ค๋ธŒ์ ํŠธ๊ฐ„ ํ†ต์‹ ์„ ์œ„ํ•œ ๋ฉ”์„ธ์ง€ ์ „๋‹ฌ(Message passing)
  • ๋ชจ๋“  ์˜ค๋ธŒ์ ํŠธ๋Š” ์ž์ฒด์ ์ธ ๋‚ด๋ถ€ ์ƒํƒœ์™€ ์ œ์–ด ๊ฐ€๋Šฅํ•œ ์ž์ฒด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ€์ง. "self" ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด์„œ ๊ฐ€๋Šฅํ•จ
  • ๊ธฐ์กด ์˜ค๋ธŒ์ ํŠธ์— ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฉ”์„ธ์ง€์— ์–ด๋–ป๊ฒŒ ์‘๋‹ตํ• ์ง€๋Š” ์ฝ”๋“œ์— ๋”ฐ๋ผ ๋‹ค๋ฆ„. on_message() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ํŠน์ • ๋ฉ”์„ธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉด ์•„๋ฌด ์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š์Œ

Addressing and URLs

Defold์˜ ๋ชจ๋“  ์˜ค๋ธŒ์ ํŠธ๋Š” URL(Uniform Resource Locator)์„ ํ†ตํ•ด ๊ณ ์œ ํ•œ ์ฃผ์†Œ๊ฐ€ ์ง€์ •๋ฉ๋‹ˆ๋‹ค. ์ด ์ฃผ์†Œ๋Š” ์ปดํŒŒ์ผ์‹œ์— ์„ค์ •๋˜๋ฉฐ ์˜ค๋ธŒ์ ํŠธ์˜ ์ˆ˜๋ช…์ด ์ง€์†๋˜๋Š” ๋™์•ˆ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์ฆ‰ ์˜ค๋ธŒ์ ํŠธ์— ์ฃผ์†Œ๋ฅผ ์ง€์ •ํ•˜๋ฉด ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์กด์žฌํ•˜๋Š” ๋™์•ˆ์€ ์œ ํšจํ•œ ์ƒํƒœ๋กœ ์œ ์ง€๋˜๋ฏ€๋กœ ์ €์žฅ๋œ ์˜ค๋ธŒ์ ํŠธ์˜ ์ฐธ์กฐ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

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

  • ์˜์›… ์บ๋ฆญํ„ฐ์™€ ์  ์บ๋ฆญํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ๋ ˆ๋ฒจ ์ปฌ๋ ‰์…˜
  • ๊ทธ๋ฆฌ๊ณ  ์˜จ-์Šคํฌ๋ฆฐ(on-screen) ์ธํ„ฐํŽ˜์ด์Šค

์—ฌ๊ธฐ์— ์ด๋ฅผ ์œ„ํ•œ ์ผ๋ฐ˜์ ์ธ ๊ตฌ์กฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

Message passing structure

์ด ๊ฒŒ์ž„์˜ ๊ตฌ์„ฑ์€:

  • id๊ฐ€ "main"๊ณผ "level"์ธ ๋‘ ๊ฐœ์˜ ์ปฌ๋ ‰์…˜ . "level"์€ "main" ์•ˆ์— ์žˆ์Œ
  • id๊ฐ€ "hero"์™€ "enemy"์™€ "interface"์ธ ์„ธ ๊ฐœ์˜ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ
  • "interface"๋Š” "main" ์•ˆ์— ์žˆ์Œ
  • "hero"์™€ "enemy"๋Š” "level" ์•ˆ์— ์žˆ์Œ
  • ์˜ˆ์ œ์˜ ๊ฐ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋Š” ๋‘ ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Œ
    • "hero"์™€ "enemy" ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋Š” "brain"์ด๋ผ๋Š” ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ์™€ "body"๋ผ๋Š” ์Šคํ”„๋ผ์ดํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Œ
    • "interface" ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋Š” "control"์ด๋ผ๋Š” ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ์™€ "gui"๋ผ๋Š” GUI์ปดํฌ๋„ŒํŠธ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Œ
    • "interface"์˜ "gui"์ปดํฌ๋„ŒํŠธ๋Š” GUI์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ฒจ๋ถ€๋˜์–ด ์žˆ์Œ

๊ฒŒ์ž„ ์ปจํ…์ธ  ์ค‘ ์ผ๋ถ€๋Š” ํ”„๋กœ์ ํŠธ์˜ ํŠน์ • ํŒŒ์ผ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ปฌ๋ ‰์…˜์€ ํ•ญ์ƒ ํŒŒ์ผ์— ์ €์žฅ๋˜๋ฏ€๋กœ "main" ์ปฌ๋ ‰์…˜๊ณผ "level"์ปฌ๋ ‰์…˜ ํŒŒ์ผ์ด ์ ์–ด๋„ ํ•œ ๊ฐœ์”ฉ์€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ๋ณ„๋กœ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๊ฒƒ์€ ํŒŒ์ผ์˜ ์ด๋ฆ„๊ณผ ํ”„๋กœ์ ํŠธ ํด๋”์—์„œ์˜ ํŒŒ์ผ ์œ„์น˜๋Š” ์ „ํ˜€ ๊ด€๋ จ์ด ์—†๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ซ๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์†Œ ์ง€์ •์„ ์œ„ํ•ด ์ค‘์š”ํ•œ ๋‘ ๊ฐ€์ง€ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  1. id๋ฅผ ๋ฌด์—‡์œผ๋กœ ์ง€์—ˆ๋Š”๊ฐ€
  2. ์–ด๋–ค ์ปฌ๋ ‰์…˜์— ๋„ฃ์—ˆ๋Š”๊ฐ€

๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ ํ˜น์€ ์ปฌ๋ ‰์…˜์„ ๋ฐฐ์น˜ํ•˜๋ฉด Defold ์—๋””ํ„ฐ๋Š” ํ˜„์žฌ ์ปฌ๋ ‰์…˜์—์„œ ๊ณ ์œ ํ•œ ์•„์ด๋””๋ฅผ ์ž๋™์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ด๋ฆ„์€ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—๋””ํ„ฐ๋Š” id๋ฅผ ์ถ”์ ํ•ด์„œ ์ด๋ฆ„์ด ์ถฉ๋Œํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ฐ•์ œ๋กœ ์ด๋ฆ„ ์ถฉ๋Œ์„ ๋‚˜๊ฒŒ ํ•˜๋ฉด Defold ์—๋””ํ„ฐ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ์ฃผ์†Œ๋“ค์€ ๊ฒŒ์ž„ ์‹คํ–‰์ค‘์˜ ๊ฐ ๋ฉ”์„ธ์ง€ ๋ฐœ์‹ ์ž์™€ ์ˆ˜์‹ ์ž๋ฅผ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•˜๋Š” URL๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. URL์€ 3๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์œผ๋ฉฐ ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

"[socket:][path][#fragment]"

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ์— ์ด๋Ÿฌํ•œ URL ์ปดํฌ๋„ŒํŠธ๋Š” ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋‚˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€๋ช…ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๊ธด ํ•˜์ง€๋งŒ ์ด ํ˜•์‹์€ ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.

socket

๋ฐœ์‹ ์ž ํ˜น์€ ์ˆ˜์‹ ์ž๊ฐ€ ์กด์žฌํ•˜๋Š” "world"๋ฅผ ์‹๋ณ„ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ปฌ๋ ‰์…˜ ํ”„๋ก์‹œ(Collection proxy)๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ๋งค์šฐ ์ค‘์š”ํ•˜๋ฉฐ ๋™์ ์œผ๋กœ ๋ถˆ๋Ÿฌ์šด ์ปฌ๋ ‰์…˜์„ ์‹๋ณ„ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

path

URL์˜ ์ด ๋ถ€๋ถ„์€ ์ผ๋ฐ˜์ ์œผ๋กœ ํƒ€๊ฒŸ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ์ „์ฒด id๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

fragment

์ง€์ •๋œ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ ๋‚ด์˜ ํƒ€๊ฒŸ ์ปดํฌ๋„ŒํŠธ์˜ id์ž…๋‹ˆ๋‹ค.

์œ„์—์„œ "hero" ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ์Šคํฌ๋ฆฝํŠธ์— ๋Œ€ํ•œ ์ „์ฒด URL์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค:

main:/level/hero#brain

๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

-- "enemy"์˜ ์Šคํฌ๋ฆฝํŠธ๋กœ "hello" ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋ƒ„
msg.post("main:/level/enemy#brain", "hello")

์•Œ ์ˆ˜ ์—†๋Š” ์ˆ˜์‹ ์ž์—๊ฒŒ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ด๋ฉด, Defold๋Š” ์ฝ˜์†”์ฐฝ์— ์—๋Ÿฌ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

ERROR:GAMEOBJECT: Instance '/level/enemy' could not be found when dispatching message 'hello' sent from default:/level/hero#brain

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ์—” ์œ„ ์ฒ˜๋Ÿผ ์ „์ฒด URL์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ถˆํ•„์š”ํ•˜๋ฉฐ ๋„ˆ๋ฌด ๊ตฌ์ฒด์ ์ž…๋‹ˆ๋‹ค. ๋Œ€์‹ ์— ์ƒ˜ํ”Œ ๊ฒŒ์ž„์„ ํ†ตํ•ด ์–ด๋–ป๊ฒŒ ๋ฉ”์„ธ์ง€๋ฅผ ์จ์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์•ฝ 3๊ฐ€์ง€์˜ ์ผ๋ฐ˜์ ์ธ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค:

Message passing

Message 1

"knock" ๋ฉ”์„ธ์ง€๊ฐ€ "hero" ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ "enemy" ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. ์ด ๋‘ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์ปฌ๋ ‰์…˜ ๊ณ„์ธต๊ตฌ์กฐ์ƒ ๋™์ผํ•œ ์œ„์น˜์— ์žˆ๋‹ค๋ฉด URL์˜ socket ๋ถ€๋ถ„("world", root, main collection ๋“ฑ๋“ฑ)๋„ ๋™์ผํ•˜๋ฏ€๋กœ ์ด ๋ถ€๋ถ„์„ ์ƒ๋žตํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

-- "hero"์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ "enemy"์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ "knock" ์ „์†กํ•˜๊ธฐ
msg.post("/level/enemy#brain", "knock")

URL์˜ socket๋ถ€๋ถ„์„ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด, ์ด ๋ฉ”์„ธ์ง€๋Š” ๋ฐœ์‹ ์ž๊ฐ€ ๋™์ผํ•œ socket์˜ ์ˆ˜์‹ ์ž์—๊ฒŒ ์ „์†ก๋˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค. Defold๋Š” URL์˜ path ๋ถ€๋ถ„์—์„œ๋„ id์˜ ์ผ๋ถ€๋ฅผ ์ƒ๋žต ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. "/"๋กœ ์‹œ์ž‘ํ•˜๋Š” path๋Š” ์ ˆ๋Œ€๊ฒฝ๋กœ์ด๋ฉฐ ํ•ญ์ƒ socket(์ผ๋ฐ˜์ ์œผ๋กœ main collection)์˜ root์—์„œ๋ถ€ํ„ฐ ์‹œ์ž‘๋˜์–ด ์˜ค๋ธŒ์ ํŠธ์˜ id๊ฐ€ ๋‚˜ํƒ€๋‚  ๋•Œ ๊นŒ์ง€ ์™„์ „ํžˆ ๊ณ„์ธต์ ์ธ ์ „์ฒด ๊ฒฝ๋กœ(path)๋กœ ์จ์•ผ ํ•ฉ๋‹ˆ๋‹ค. "hero"์™€ "enemy"์˜ id๊ฐ€ ๊ฐ๊ฐ "/level/hero"์™€ "/level/enemy" ์ด๊ธฐ ๋•Œ๋ฌธ์— "/level"์„ ์ƒ๋žตํ•˜์—ฌ ์ƒ๋Œ€์  ํ˜น์€ ๋ถ€๋ถ„์ ์ธ id๋ฅผ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

-- "hero"์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ "enemy"์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ "knock" ์ „์†กํ•˜๊ธฐ
msg.post("enemy#brain", "knock")

์•ž๋ถ€๋ถ„์— "/"๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ "/enemy#brain" ์ฒ˜๋Ÿผ ์“ฐ์ง€ ์•Š๋„๋ก ์ฃผ์˜ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋งจ ์•ž์— "/"๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด "main" ์ปฌ๋ ‰์…˜์˜ root์—์„œ "enemy"๋ผ๋Š” ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ฐพ์•„๋ณด๋ ค ํ•˜๊ฒ ์ง€๋งŒ root์— ์ด๋Ÿฐ ์˜ค๋ธŒ์ ํŠธ๋Š” ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ž, ์ด์ œ๋Š” URL์˜ fragment ๋ถ€๋ถ„์„ ์ƒ๋žตํ•˜๋ฉด ๋ฌด์Šจ์ผ์ด ๋ฐœ์ƒํ• ๊นŒ์š”?

-- "hero"์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ "enemy"๋กœ "knock" ์ „์†กํ•˜๊ธฐ
msg.post("enemy", "knock")

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

Message 2

"increase_score" ๋ฉ”์„ธ์ง€๋Š” "hero" ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ "interface" ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.

-- "hero"์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ "interface"์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ "increase_score"๋ฅผ ๋ณด๋ƒ„
msg.post("/interface#controller", "increase_score")

์œ„ ์ผ€์ด์Šค์—์„œ๋Š” ์ƒ๋Œ€(relative)๊ฒฝ๋กœ์˜ id๋ฅผ ์“ธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. "hero"์˜ ๊ด€์ ์—์„œ ๋ณผ ๋•Œ ์ ˆ๋Œ€(absolute)์ ์ด๊ณ  ์™„์ „ํ•œ full id("../interface" ์ฒ˜๋Ÿผ ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ฐ™์€ ํ‘œ๊ธฐ๋ฒ•์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ "interface"์˜ ์Šคํฌ๋ฆฝํŠธ ์ชฝ์—์„œ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ์ƒ๋Œ€๊ฒฝ๋กœ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:

-- "interface"์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ "hero"์˜ ์Šคํฌ๋ฆฝํŠธ๋กœ "increase_score_response"๋ฅผ ๋ณด๋ƒ„
msg.post("level/hero#brain", "increase_score_response")

๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ์•ž์ชฝ์˜ "/"๊ฐ€ ์ƒ๋žต๋œ ๊ฒƒ์— ์ฃผ๋ชฉํ•˜์‹ญ์‹œ์˜ค. ์ƒ๋Œ€๊ฒฝ๋กœ์˜ id๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐœ์‹ ์ž์™€ ์ˆ˜์‹ ์ž๋Š” ์ปฌ๋ ‰์…˜ ๊ณ„์ธต์˜ ๋ชจ๋“  ์œ„์น˜์—์„œ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์˜ค๋ธŒ์ ํŠธ๋‚˜ ์˜ค๋ธŒ์ ํŠธ ๊ณ„์ธต์„ ์—ฌ๋Ÿฌ๋ฒˆ ์ธ์Šคํ„ด์Šคํ™” ํ•˜๊ฑฐ๋‚˜ ๋™์ ์œผ๋กœ ์Šคํฐํ•  ํ•„์š”๊ฐ€ ์žˆ์„ ๋•Œ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Message 3

"update_minimap" ๋ฉ”์„ธ์ง€๋Š” "enemy" ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋กœ๋ถ€ํ„ฐ "interface" ๊ฒŒ์ž„์˜ค๋ธŒ์ ํŠธ์˜ "gui" ์Šคํฌ๋ฆฝํŠธ๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.

-- "enemy"์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ "interface"์˜ GUI ์Šคํฌ๋ฆฝํŠธ๋กœ "update_minimap"๋ฅผ ์ „์†กํ•จ
msg.post("/interface#gui", "update_minimap")

์—ฌ๊ธฐ๋Š” ์ƒ๋Œ€๊ฒฝ๋กœ๋กœ URL์„ ์“ธ ์ˆ˜ ์—†๋Š” ๋˜ ๋‹ค๋ฅธ ์ผ€์ด์Šค์ž…๋‹ˆ๋‹ค. ๋Œ€์‹  "interface" ์˜ค๋ธŒ์ ํŠธ์˜ full id๋ฅผ ์จ์„œ ์ด ๋ฉ”์„ธ์ง€๋ฅผ "gui" ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฝํŠธ์™€ GUI์ปดํฌ๋„ŒํŠธ๋Š” Lua์Šคํฌ๋ฆฝํŠธ์™€ ๊ด€๋ จ๋œ ์œ ์ผํ•œ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ ์ปดํฌ๋„ŒํŠธ์ด๋ฉฐ ์ž„์˜์˜ ๋ฉ”์„ธ์ง€์— ๋ฐ˜์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. GUI์Šคํฌ๋ฆฝํŠธ๋Š” GUI์”ฌ์—๋งŒ ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•˜๋Š”๊ฒƒ์„ ๊ธฐ์–ตํ•˜์„ธ์š”. GUI์Šคํฌ๋ฆฝํŠธ์™€ ๋‹ค๋ฅธ ์Šคํฌ๋ฆฝํŠธ๊ฐ„์˜ ๋ฉ”์„ธ์ง€ ์†ก์ˆ˜์‹ ์€ ๋‹ค๋ฅธ ์˜ค๋ธŒ์ ํŠธ๊ฐ„ ์†ก์ˆ˜์‹  ๋ฐฉ์‹๊ณผ ์™„์ „ํžˆ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

Shorthands (์•ฝ์นญ)

์šฐ๋ฆฌ๋Š” ๋ฉ”์„ธ์ง€๋ฅผ ์ž‘์„ฑํ•  ๋•Œ URL์—์„œ ๋ถˆํ•„์š”ํ•œ ์ •๋ณด๋Š” ์ƒ๋žตํ•˜๋Š”๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ๊ฐ€๋Šฅํ•œ์ง€ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ Defold๋Š” ๋‘ ๊ฐ€์ง€ ํŽธ๋ฆฌํ•œ ์•ฝ์นญ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

"." ํ˜„์žฌ ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” URL ์•ฝ์นญ

"#" ํ˜„์žฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” URL ์•ฝ์นญ

์˜ˆ๋ฅผ ๋“ค์–ด:

-- ์ด ๊ฒŒ์ž„์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์ž…๋ ฅ ํฌ์ปค์Šค๋ฅผ ์–ป๋„๋ก ํ•˜์ž
msg.post(".", "acquire_input_focus")
-- ์ด ์Šคํฌ๋ฆฝํŠธ๋กœ "reset" ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋ƒ„
msg.post("#", "reset")

A concrete example (๊ตฌ์ฒด์ ์ธ ์˜ˆ์ œ)

๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค. ๋‹น์‹ ์˜ ๊ฒŒ์ž„์— ์Šคํƒฏ(์ฒด๋ ฅ, ์ ์ˆ˜, ๋ณ„์  ๋ณด๋„ˆ์Šค ๋“ฑ) ๊ฐ™์ด ํ™”๋ฉด์— ๋ณด์—ฌ์•ผํ•  ์š”์†Œ๋“ค์ด ์žˆ๋Š” HUD๊ฐ€ ์žˆ์œผ๋ฉฐ, ์ด HUD๋Š” "hud"๋ผ๋Š” ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๋กœ ์ œ์–ด๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ด…์‹œ๋‹ค.

HUD

์šฐ๋ฆฌ๋Š” ์ฒด๋ ฅ์„ ์ฆ๊ฐ ์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด ์ž‘์—…์„ "hud" ์˜ค๋ธŒ์ ํŠธ์˜ ์Šคํฌ๋ฆฝํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ด์„œ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

msg.post("hud#script", "increase_health")

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด id (ํ˜น์€ name)์ด "increase_health"์ธ ๋ฉ”์„ธ์ง€๋ฅผ "hud" ์˜ค๋ธŒ์ ํŠธ์˜ "script"๋ผ๋Š” ์ˆ˜์‹ ์ž ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฒŒ์‹œ(post)ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. Defold๋Š” ๋‹ค์Œ๋ฒˆ ๋ฉ”์„ธ์ง€๊ฐ€ ๋ฐœ์†ก(dispatch)๋˜๋ฉด ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐฐ๋‹ฌํ•˜๋ฉฐ, ์ด๋Š” ํ˜„์žฌ ํ”„๋ ˆ์ž„ ๋‚ด์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ ๋ฉ”์„ธ์ง€๋ฅผ ์‘๋‹ต ๋ฐ›์œผ๋ฉด ๋ฉ‹์ง„ ๋ฐฉ์‹์œผ๋กœ ์ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ "hud" ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

-- file: hud.script

function on_message(self, message_id, message, sender)
	if message_id == hash("increase_health") then
		-- ํ•˜ํŠธ 1๊ฐœ๋ฅผ ์‚๊นŒ๋ป”์ฉํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜์œผ๋กœ HUD์— ์ถ”๊ฐ€ํ•ด ๋ณด์ž.
		โ€ฆ
	end
end

Message data

msg.post()์˜ ํ•จ์ˆ˜ ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

msg.post(receiver, message_id[, message])

์šฐ๋ฆฌ๋Š” ํŽธ์˜์ƒ HUD์˜ ๋ชจ๋“  ์ •๋ณด๋ฅผ ํ•œ๋ฒˆ์— ์…‹ํŒ…ํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ ๊ฐœ์˜ ๋ฉ”์„ธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฉ”์„ธ์ง€์˜ ์ด๋ฆ„์„ "set_stats"๋กœ ์ •ํ•˜๊ณ  ๋ฉ”์„ธ์ง€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์ฒจ๋ถ€ํ•ฉ๋‹ˆ๋‹ค:

-- ๋ฉ”์„ธ์ง€๋กœ table ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ธฐ
msg.post("hud#script", "set_stats", { score = 100, stars = 2, health = 4 })

์ด ํ˜ธ์ถœ์€ ์ถ”๊ฐ€์ ์ธ ๋ฐ์ดํ„ฐ์™€ ํ•จ๊ป˜ ๋ฉ”์„ธ์ง€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ธ์ˆ˜๋Š” ์„ ํƒ์ ์ด๋ฉฐ ์ค‘๊ด„ํ˜ธ ์•ˆ์—์„œ ํ‚ค-๊ฐ’ ์Œ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ Lua ํ…Œ์ด๋ธ”์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ์˜ ๋ชจ๋“  ์ž๋ฃŒํ˜•์˜ ๋ฐ์ดํ„ฐ๊ฐ€ Lua ํ…Œ์ด๋ธ” ๋ฉ”์„ธ์ง€์— ํฌํ•จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ˆซ์žํ˜•, ๋ฌธ์ž์—ดํ˜•, ๋ถˆ๋ฆฐํ˜•, URL, ํ•ด์‰ฌ, ์ค‘์ฒฉ ํ…Œ์ด๋ธ” ๋ชจ๋‘ ์ „๋‹ฌ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํ•จ์ˆ˜(function) ํƒ€์ž…์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

-- Send table data containing a nested table
local invtable = { sword = true, shield = true, bow = true, arrows = 9 }
local msgdata = { score = 100, stars = 2, health = 4, inventory = invtable }
msg.post("hud#script", "set_stats", msgdata)

๋ฉ”์„ธ์ง€ ํŒŒ๋ผ๋ฏธํ„ฐ ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ์—๋Š” ์—„๊ฒฉํ•œ ์ œํ•œ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ œํ•œ์€ 2kb ๊นŒ์ง€์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ํ…Œ์ด๋ธ”์ด ์†Œ๋ชจํ•˜๋Š” ์ •ํ™•ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์ด์ฆˆ๋ฅผ ์•Œ์•„๋‚ด๋Š” ๋ฐฉ๋ฒ•์€ ์—†์ง€๋งŒ, collectgarbage("count") ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ด๋ธ”์— ๊ฐ’์„ ์‚ฝ์ž…ํ•˜๊ธฐ ์ „ํ›„๋ฅผ ๋”ฐ์ ธ์„œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ธก์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

on_message()

on_message() ํ•จ์ˆ˜๋Š” 3๊ฐœ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. (๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ ์ž์‹ ์˜ ์ฐธ์กฐ๋ฅผ ํฌํ•จํ•˜๋Š” "self"์™€๋Š” ๋ณ„๊ฐœ๋กœ)

message_id

๋ฉ”์„ธ์ง€์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. ์ด ์ด๋ฆ„์€ ํ•ด์‰ฌ(hash)๋ฉ๋‹ˆ๋‹ค.

message

๋ฉ”์„ธ์ง€์˜ ๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Lua ํ…Œ์ด๋ธ”์ž…๋‹ˆ๋‹ค.

sender

๋ฐœ์‹ ์ž์˜ ์ „์ฒด URL์ž…๋‹ˆ๋‹ค.

function on_message(self, message_id, message, sender)
    -- message id ์ถœ๋ ฅํ•˜๊ธฐ
    print(message_id)
    -- message data ์ถœ๋ ฅํ•˜๊ธฐ (ํ…Œ์ด๋ธ”์ด๋ผ pprint๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€!)
    pprint(message)
    -- sender ์ถœ๋ ฅํ•˜๊ธฐ
    print(sender)
end

์œ„ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ์ฝ˜์†”์ฐฝ์— ์•„๋ž˜ ๋‚ด์šฉ์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค:

DEBUG:SCRIPT: hash: [set_stats]
DEBUG:SCRIPT:
{
  health = 4,
  stars = 2,
  score = 100,
}
DEBUG:SCRIPT: url: [main:/game_controller#script]

๋‹ค์Œ์€ "hud" ๊ฒŒ์ž„ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ "set_stats"๋ฅผ ๊ฐ„๋‹จํžˆ ๊ตฌํ˜„ํ–ˆ๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:

function init(self)
        -- ํ•˜ํŠธ10๊ฐœ ๋ณ„10๊ฐœ๋กœ GUI ๋…ธ๋“œ๋ฅผ ๋ณต์ œํ•จ
        self.heart_nodes = {}
        self.star_nodes = {}
        local heart_node = gui.get_node("heart")
        local star_node = gui.get_node("star")

        -- ์‰ฝ๊ฒŒ ์–ต์„ธ์Šค ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ํ…Œ์ด๋ธ”์— ์ €์žฅํ•จ
        table.insert(self.heart_nodes, heart_node)
        -- ๋…ธ๋“œ๊ฐ€ ๋น„ํ™œ์„ฑํ™” ๋œ ์ฑ„๋กœ ์‹œ์ž‘ํ•จ
        gui.set_enabled(heart_node, false)

        for i = 1, 9 do
                local clone = gui.clone(heart_node)
                local pos = gui.get_position(heart_node)
                pos.x = pos.x + i * 32
                gui.set_position(clone, pos)
                table.insert(self.heart_nodes, clone)
                gui.set_enabled(clone, false)
        end
        table.insert(self.star_nodes, star_node)
        gui.set_enabled(star_node, false)
        for i = 1, 9 do
                local clone = gui.clone(star_node)
                local pos = gui.get_position(star_node)
                pos.x = pos.x + i * 32
                gui.set_position(clone, pos)
                table.insert(self.star_nodes, clone)
                gui.set_enabled(clone, false)
        end
end

function on_message(self, message_id, message, sender)
        if message_id == hash("set_stats") then
                -- ์ ์ˆ˜ GUI๋…ธ๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ
                gui.set_text(gui.get_node("score"), message.score)
                -- ํ•˜ํŠธ ๋…ธ๋“œ์˜ ์ˆ˜๋งŒํผ ํ™œ์„ฑํ™”
                for i = 1, message.health do
                        gui.set_enabled(self.heart_nodes[i], true)
                end
                -- ๋ณ„ ๋…ธ๋“œ์˜ ์ˆ˜๋งŒํผ ํ™œ์„ฑํ™”
                for i = 1, message.stars do
                        gui.set_enabled(self.star_nodes[i], true)
                end
        end
end

Child-parent vs. collection-object hierarchies (๋ถ€๋ชจ-์ž์‹ ๊ณ„์ธต๊ตฌ์กฐ์™€ ์ปฌ๋ ‰์…˜-์˜ค๋ธŒ์ ํŠธ ๊ณ„์ธต๊ตฌ์กฐ ๋น„๊ตํ•˜๊ธฐ)

์šฐ๋ฆฌ๋Š” ๊ฒฝ๋กœ(path)๋ฅผ ํ†ตํ•œ ์˜ค๋ธŒ์ ํŠธ ์ฃผ์†Œ ์ง€์ •์ด Defold์—์„œ ์ •์ (static)์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ์•˜์œผ๋ฉฐ ์ด๋Š” ๊ฒŒ์ž„ ๋กœ์ง์„ ์ฝ”๋”ฉํ•  ๋•Œ ํ•ญ์ƒ ์˜ค๋ธŒ์ ํŠธ id์˜ ๋ฌด๊ฒฐ์„ฑ์„ ์‹ ๋ขฐํ•ด๋„ ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋ธŒ์ ํŠธ๊ฐ„์˜ ๋ถ€๋ชจ-์ž์‹ ๊ณ„์ธต๊ตฌ์กฐ๋Š” ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€ํ˜•(transformations)์— ๋ฐ˜์‘ํ•˜๋Š”์ง€ ์˜ํ–ฅ์„ ์ฃผ๋Š” ๋™์ ์ธ ๊ด€๊ณ„(dynamic relation)์ž…๋‹ˆ๋‹ค. ์˜ค๋ธŒ์ ํŠธ์— ์ ์šฉ๋˜๋Š” ๋ชจ๋“  ๋ณ€ํ˜•์€ ์ด ์˜ค๋ธŒ์ ํŠธ์˜ ์ž์‹๋“ค์—๊ฒŒ๋„ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. "set_parent" ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์œผ๋กœ ๋Ÿฐํƒ€์ž„์‹œ ์˜ค๋ธŒ์ ํŠธ ๋ถ€๋ชจ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

local parent = go.get_id("tree")
msg.post(".", "set_parent", { parent_id = parent })

๋ถ€๋ชจ-์ž์‹ ๊ณ„์ธต๊ตฌ์กฐ๋Š” ์—๋””ํ„ฐ์—์„œ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ ์—ฌ์ „ํžˆ ๋™์ ์ธ (dynamic) ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ•˜ํŠธ๊ฐ€ ๋‹ฌ๋ฆฐ ๋‚˜๋ฌด๋ฅผ ๋งŒ๋“ค์–ด ๋ด…์‹œ๋‹ค. ์ด๋Š” "tree" ์˜ค๋ธŒ์ ํŠธ์™€ ๋ช‡ ๊ฐœ์˜ "heart" ์˜ค๋ธŒ์ ํŠธ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋‚˜๋ฌด๊ฐ€ ์‚ด์•„๊ฐ€๋Š”๋ฐ ํ•„์š”ํ•œ "pot"๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ์„  ์ด ์˜ค๋ธŒ์ ํŠธ๋“ค์„ ๋ถ€๋ชจ์™€ ์ž์‹๊ด€๊ณ„๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด "hearttree"๋ผ๊ณ  ๋ถˆ๋ฆฌ์šฐ๋Š” ์ปฌ๋ ‰์…˜์— ์˜ค๋ธŒ์ ํŠธ๋“ค์„ ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ "heart" ์˜ค๋ธŒ์ ํŠธ๋ฅผ "tree" ์˜ค๋ธŒ์ ํŠธ์— ๋“œ๋ž˜๊ทธ ํ•˜์—ฌ ๊ฐ„๋‹จํžˆ ์ž์‹๊ฐ์ฒด๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Heart tree

๋‚˜๋ฌด์— ํ•˜ํŠธ ์ž์‹๋“ค์„ ๋งŒ๋“ฌ์œผ๋กœ์จ, ๋งˆ์น˜ ๋‚˜๋ฌด ์˜ค๋ธŒ์ ํŠธ์˜ ์ผ๋ถ€๋ถ„์ธ ๊ฒƒ ์ฒ˜๋Ÿผ ๋‚˜๋ฌด์— ์ฃผ๋Š” ๋ชจ๋“  ๋ณ€ํ˜•์ด ํ•˜ํŠธ๋“ค์—๊ฒŒ ์˜ํ–ฅ์„ ์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‚˜๋ฌด๋ฅผ ์•ž๋’ค๋กœ ์›€์ง์ด๊ฒŒ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฉด ํ•˜ํŠธ๋“ค๋„ ๋”ฐ๋ผ์„œ ์›€์ง์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

"hearttree" ์ปฌ๋ ‰์…˜ ๋‚ด์˜ ํ•˜ํŠธ ์˜ค๋ธŒ์ ํŠธ์— ๋Œ€ํ•œ ๊ฒฝ๋กœ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์„ค์ •ํ•œ ๋™์ ์ธ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„์— ์˜ํ•ด ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

/hearttree/heart1 ("/hearttree/tree/heart1"๊ฐ€ ์•„๋‹˜) /hearttree/heart2 /hearttree/heart3 /hearttree/heart4

๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋Š” ์ปฌ๋ ‰์…˜ ๊ณ„์ธต๊ตฌ์กฐ ๋‚ด์˜ ์˜ค๋ธŒ์ ํŠธ ์ฃผ์†Œ์™€ ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋Š” ๊ฒฐ์ฝ” ์˜ค๋ธŒ์ ํŠธ์˜ URL์— ๋ฐ˜์˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Advanced topics

Constructing URLs

๋“œ๋ฌผ๊ธด ํ•˜์ง€๋งŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ URL ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด์•ผํ•  ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿด ๋• ์•„๋ž˜์™€ ๊ฐ™์ด ํ•˜์„ธ์š”:

local my_url = msg.url()
my_url.socket = "main" -- ์œ ํšจํ•œ ์ด๋ฆ„์œผ๋กœ ์ง€์ •ํ•˜๊ธฐ
my_url.path = hash("/hearttree/tree") -- ๋ฌธ์ž์—ด์ด๋‚˜ ํ•ด์‰ฌ๋กœ ์ง€์ •ํ•˜๊ธฐ
my_url.fragment = "script" -- ๋ฌธ์ž์—ด์ด๋‚˜ ํ•ด์‰ฌ๋กœ ์ง€์ •ํ•˜๊ธฐ
msg.post(my_url, "grow")

URL ๋ฐ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์กฐ์‚ฌํ•ด๋ณด๋ฉด:

print(my_url) --> url: [main:/hearttree/tree#script]
print(my_url.socket) --> 786443 (internal numeric value)
print(my_url.path) --> hash: [/hearttree/tree]
print(my_url.fragment) --> hash: [script]

System sockets

Defold๋Š” ์—”์ง„์˜ ํŠน์ • ์„œ๋ธŒ ์‹œ์Šคํ…œ๊ณผ ํ†ต์‹ ํ•˜๊ธฐ ์œ„ํ•ด URL์˜ socket ๋ถ€๋ถ„์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค:

  1. @physics:
  2. @render:
  3. @system:

path๋‚˜ fragment ๋ถ€๋ถ„์€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋ƒ„์œผ๋กœ์จ ์‹œ์Šคํ…œ ํ”„๋กœํŒŒ์ผ๋Ÿฌ๋ฅผ ํ† ๊ธ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 msg.post("@system:", "toggle_profile")

Collection Proxies

Defold๊ฐ€ ์‹œ์ž‘๋˜๋ฉด ๊ฒŒ์ž„ ํ”„๋กœ์ ํŠธ ์…‹ํŒ…์ฐฝ์˜ "bootstrap" ์•„๋ž˜์˜ "main_collection" ํ•ญ๋ชฉ์— ์ง€์ •๋œ ์ปฌ๋ ‰์…˜์„ ์ž๋™์œผ๋กœ ๋กœ๋“œํ•˜๊ณ  ์ดˆ๊ธฐํ™” ํ•ฉ๋‹ˆ๋‹ค.

๋ณ„๋„์˜ ์ปฌ๋ ‰์…˜์— ๊ฐ๊ธฐ ๋‹ค๋ฅธ ๊ฒŒ์ž„ ๋ ˆ๋ฒจ์„ ์œ ์ง€ํ•ด์•ผ ํ•˜๋Š” ๋“ฑ, ์„œ๋กœ ๋‹ค๋ฅธ ์ปฌ๋ ‰์…˜์„ ๋™์ ์œผ๋กœ ๋ถˆ๋Ÿฌ์™€์•ผํ•  ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Defold๋Š” ๋™์ ์œผ๋กœ ๋กœ๋“œ๋˜๋Š” ์ปฌ๋ ‰์…˜์„ ์œ„ํ•ด ์ปฌ๋ ‰์…˜ ํ”„๋ก์‹œ(Collection Proxy) ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ๊ฐ€ ์ปฌ๋ ‰์…˜ ํ”„๋ก์‹œ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  "level"์ด๋ผ๊ณ  ๋ช…๋ช…๋œ ๋ช‡๋ช‡ ์ปฌ๋ ‰์…˜์„ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์…‹ํŒ…ํ•œ๋‹ค๋ฉด, ์ด ํ”„๋ก์‹œ์—๊ฒŒ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์œผ๋กœ ์ปฌ๋ ‰์…˜์„ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Proxy

msg.post("/loader#levelproxy", "load")

์ปฌ๋ ‰์…˜์ด ๋กœ๋“œ๋˜๋ฉด ๋ฉ”์„ธ์ง€๋ฅผ ๋Œ๋ ค๋ฐ›๊ณ  ์ดˆ๊ธฐํ™” ์ž‘์—… ๋ฐ ๋‹ค๋ฅธ ์ตœ์ƒ์œ„ ์ปฌ๋ ‰์…˜์œผ๋กœ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function on_message(self, message_id, message, sender)
    if message_id == hash("proxy_loaded") then
        -- ์ปฌ๋ ‰์…˜์ด ๋กœ๋“œ๋˜์—ˆ๊ณ  ํ™œ์„ฑํ™”๋ฅผ ํ•ด๋ณด์ž
        msg.post(sender, "enable")
        -- ๋กœ๋“œ๋œ ์ปฌ๋ ‰์…˜์˜ ์•„๋ฌด๋‚˜์—๊ฒŒ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ด๋ณด์ž
        msg.post("level:/gamemaster#script", "wake_up")
    end
end

์ด์™€ ๊ฐ™์ด ์ตœ์ƒ์œ„ ์ปฌ๋ ‰์…˜ ๊ฐ„์— ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ด๋ฉด, URL์˜ socket ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํƒ€๊ฒŸ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์ƒ์ฃผํ•˜๋Š” ์ปฌ๋ ‰์…˜์„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ž์„ธํ•œ ์„ค๋ช…์€ Collection proxy ๋ฌธ์„œ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Message chains

๊ฒŒ์‹œ๋œ ๋ฉ”์„ธ์ง€๋“ค์ด ๋””์ŠคํŒจ์น˜๋˜๊ณ  ์ˆ˜์‹ ์ž์˜ on_message()๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด, ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ๋‹ด์•„ ๋˜ ์ƒˆ ๋ฉ”์„ธ์ง€๋ฅผ ๊ฒŒ์‹œํ•˜์—ฌ ์ฃผ๊ฑฐ๋‹ˆ ๋ฐ›๊ฑฐ๋‹ˆ ํ•˜๋Š” ๊ฒƒ์€ ์ผ๋ฐ˜์ ์ธ ๊ฐœ๋ฐœ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ์—”์ง„์ด ๋””์ŠคํŒจ์น˜ ํ•ด์•ผํ•˜๋Š” ๊ธด ๋ฉ”์„ธ์ง€ ์ฒด์ธ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์–ธ์ œ ๋ฐœ์ƒํ• ๊นŒ์š”?

์งง๊ฒŒ ๋Œ€๋‹ตํ•˜์ž๋ฉด ์ด ๋””์ŠคํŒจ์น˜๋Š” ์ฆ‰์‹œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ฒŒ์ž„์—”์ง„์€ ๋ฉ”์„ธ์ง€๋“ค์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ณ  ๋‹น์‹ ์ด ์ƒˆ ๋ฉ”์„ธ์ง€๋ฅผ ๊ฒŒ์‹œํ•˜์—ฌ ํ๋ฅผ ๊ณ„์† ์ฑ„์šฐ๋”๋ผ๋„ ๋ฉ”์„ธ์ง€ ํ๊ฐ€ ๋น„์›Œ์งˆ ๋•Œ๊นŒ์ง€ ๊ณ„์† ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฒŒ์ž„์—”์ง„์ด ๋ฉ”์„ธ์ง€ํ๋ฅผ ๋น„์šธ ์ˆ˜ ์žˆ๋Š” ํšŸ์ˆ˜๋Š” ์ œํ•œ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ธด ๋ฉ”์„ธ์ง€ ์ฒด์ธ์„ ํ•œ ํ”„๋ ˆ์ž„ ๋‚ด์—์„œ ํšจ๊ณผ์ ์œผ๋กœ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ update() ์‚ฌ์ด์— ์—”์ง„์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋””์ŠคํŒจ์น˜ ์ˆ˜๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋˜๋Š”์ง€ ์‰ฝ๊ฒŒ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function init(self)
        -- ์˜ค๋ธŒ์ ํŠธ ์ดˆ๊ธฐํ™” ๋™์•ˆ ๊ธด ๋ฉ”์„ธ์ง€ ์ฒด์ธ์„ ์‹œ์ž‘ํ•ด ๋ณผ๊นŒ๋‚˜
        -- ๊ทธ๋ฆฌ๊ณ  update()๋งˆ๋‹ค ์ˆซ์ž๋ฅผ ์ฆ๊ฐ€ํ•˜์ž
        print("INIT")
        msg.post("#", "msg")
        self.updates = 0
        self.count = 0
end

function update(self, dt)
        if self.updates < 5 then
                self.updates = self.updates + 1
                print("UPDATE " .. self.updates)
                print(self.count .. " ํšŒ ๋””์ŠคํŒจ์น˜ ๋จ.")
                self.count = 0
        end
end

function on_message(self, message_id, message, sender)
        if message_id == hash("msg") then
                self.count = self.count + 1
                msg.post("#", "msg")
        end
end

์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜ ์ฒ˜๋Ÿผ ์ถœ๋ ฅ ๋ฉ๋‹ˆ๋‹ค:

DEBUG:SCRIPT: INIT
INFO:ENGINE: Defold Engine 1.2.36 (5b5af21)
DEBUG:SCRIPT: UPDATE 1
DEBUG:SCRIPT: 10 ํšŒ ๋””์ŠคํŒจ์น˜ ๋จ.
DEBUG:SCRIPT: UPDATE 2
DEBUG:SCRIPT: 75 ํšŒ ๋””์ŠคํŒจ์น˜ ๋จ.
DEBUG:SCRIPT: UPDATE 3
DEBUG:SCRIPT: 75 ํšŒ ๋””์ŠคํŒจ์น˜ ๋จ.
DEBUG:SCRIPT: UPDATE 4
DEBUG:SCRIPT: 75 ํšŒ ๋””์ŠคํŒจ์น˜ ๋จ.
DEBUG:SCRIPT: UPDATE 5
DEBUG:SCRIPT: 75 ํšŒ ๋””์ŠคํŒจ์น˜ ๋จ.

์ด ๋ฒ„์ „์˜ Defold ์—”์ง„์€ init()๊ณผ ์ฒซ update() ํ˜ธ์ถœ ์‚ฌ์ด์— 10ํšŒ์˜ ๋ฉ”์„ธ์ง€ ํ ๋””์ŠคํŒจ์น˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋งค update() ๋งˆ๋‹ค 75ํšŒ์˜ ๋ฉ”์„ธ์ง€๊ฐ€ ์ˆ˜ํ–‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค.