Initial flame_lua_runtime package
This commit is contained in:
BIN
example/assets/games/ludo/assets/board.png
Normal file
BIN
example/assets/games/ludo/assets/board.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 B |
BIN
example/assets/games/ludo/assets/dice.wav
Normal file
BIN
example/assets/games/ludo/assets/dice.wav
Normal file
Binary file not shown.
BIN
example/assets/games/ludo/assets/piece_blue.png
Normal file
BIN
example/assets/games/ludo/assets/piece_blue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 B |
BIN
example/assets/games/ludo/assets/piece_red.png
Normal file
BIN
example/assets/games/ludo/assets/piece_red.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 B |
55
example/assets/games/ludo/manifest.json
Normal file
55
example/assets/games/ludo/manifest.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"gameId": "ludo",
|
||||
"name": "Lua Ludo 示例",
|
||||
"version": "0.1.0",
|
||||
"runtimeApiVersion": 1,
|
||||
"entry": "scripts/main.lua",
|
||||
"assetsBase": "assets",
|
||||
"defaultLocale": "zh-Hans",
|
||||
"supportedLocales": [
|
||||
"zh-Hans",
|
||||
"en"
|
||||
],
|
||||
"display": {
|
||||
"designWidth": 720,
|
||||
"designHeight": 720,
|
||||
"scaleMode": "fit"
|
||||
},
|
||||
"modules": {
|
||||
"runtime_ui": "runtime:runtime_ui.lua",
|
||||
"runtime_widgets": "runtime:runtime_widgets.lua",
|
||||
"runtime_commands": "runtime:runtime_commands.lua",
|
||||
"layout": "runtime:layout.lua",
|
||||
"i18n": "scripts/i18n.lua",
|
||||
"theme": "scripts/theme.lua",
|
||||
"styles": "scripts/styles.lua",
|
||||
"state": "scripts/state.lua",
|
||||
"board": "scripts/board.lua",
|
||||
"rules": "scripts/rules.lua",
|
||||
"ui": "scripts/ui.lua",
|
||||
"animation": "scripts/animation.lua"
|
||||
},
|
||||
"resources": {
|
||||
"board": {
|
||||
"type": "image",
|
||||
"path": "assets/board.png",
|
||||
"group": "board"
|
||||
},
|
||||
"piece_red": {
|
||||
"type": "image",
|
||||
"path": "assets/piece_red.png",
|
||||
"group": "pieces"
|
||||
},
|
||||
"piece_blue": {
|
||||
"type": "image",
|
||||
"path": "assets/piece_blue.png",
|
||||
"group": "pieces"
|
||||
},
|
||||
"dice": {
|
||||
"type": "audio",
|
||||
"path": "assets/dice.wav",
|
||||
"preload": "lazy",
|
||||
"group": "sfx"
|
||||
}
|
||||
}
|
||||
}
|
||||
37
example/assets/games/ludo/scripts/animation.lua
Normal file
37
example/assets/games/ludo/scripts/animation.lua
Normal file
@@ -0,0 +1,37 @@
|
||||
---@type RuntimeCommands
|
||||
local commands = runtime.import("runtime_commands")
|
||||
|
||||
local animation = {}
|
||||
|
||||
function animation.move_piece(piece_id, path)
|
||||
return commands.move_path(piece_id, path, {
|
||||
duration = 0.7,
|
||||
onComplete = "piece_move_done"
|
||||
})
|
||||
end
|
||||
|
||||
function animation.toast(text)
|
||||
return commands.toast(text)
|
||||
end
|
||||
|
||||
function animation.play_sound(name)
|
||||
return commands.play_sound(name)
|
||||
end
|
||||
|
||||
function animation.play_bgm(name, channel)
|
||||
return commands.play_bgm(name, { channel = channel or "bgm" })
|
||||
end
|
||||
|
||||
function animation.pause_bgm(channel)
|
||||
return commands.pause_bgm(channel)
|
||||
end
|
||||
|
||||
function animation.resume_bgm(channel)
|
||||
return commands.resume_bgm(channel)
|
||||
end
|
||||
|
||||
function animation.stop_bgm(channel)
|
||||
return commands.stop_bgm(channel)
|
||||
end
|
||||
|
||||
return animation
|
||||
20
example/assets/games/ludo/scripts/board.lua
Normal file
20
example/assets/games/ludo/scripts/board.lua
Normal file
@@ -0,0 +1,20 @@
|
||||
---@type BoardData
|
||||
return {
|
||||
red_home = {
|
||||
{x = 80, y = 520},
|
||||
{x = 140, y = 520}
|
||||
},
|
||||
blue_home = {
|
||||
{x = 520, y = 120},
|
||||
{x = 580, y = 120}
|
||||
},
|
||||
path = {
|
||||
{x = 120, y = 420}, {x = 180, y = 420}, {x = 240, y = 420},
|
||||
{x = 300, y = 420}, {x = 360, y = 420}, {x = 420, y = 420},
|
||||
{x = 480, y = 420}, {x = 480, y = 360}, {x = 480, y = 300},
|
||||
{x = 480, y = 240}, {x = 420, y = 240}, {x = 360, y = 240},
|
||||
{x = 300, y = 240}, {x = 240, y = 240}, {x = 180, y = 240},
|
||||
{x = 120, y = 240}, {x = 120, y = 300}, {x = 120, y = 360}
|
||||
},
|
||||
start = { red = 1, blue = 10 }
|
||||
}
|
||||
103
example/assets/games/ludo/scripts/i18n.lua
Normal file
103
example/assets/games/ludo/scripts/i18n.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
---@class RuntimeI18n
|
||||
local i18n = {}
|
||||
|
||||
local default_locale = "zh-Hans"
|
||||
local current_locale = default_locale
|
||||
|
||||
local messages = {
|
||||
["zh-Hans"] = {
|
||||
title = "Lua 飞行棋",
|
||||
roll_button = "掷骰子",
|
||||
dice_empty = "骰子: -",
|
||||
dice_value = "骰子: {value}",
|
||||
current_player = "当前玩家: {player}",
|
||||
["player.red"] = "红方",
|
||||
["player.blue"] = "蓝方",
|
||||
["toast.move_first"] = "请先移动棋子",
|
||||
["toast.no_movable_piece"] = "无可移动棋子",
|
||||
["toast.invalid_piece"] = "该棋子不能移动"
|
||||
},
|
||||
en = {
|
||||
title = "Lua Ludo",
|
||||
roll_button = "Roll",
|
||||
dice_empty = "Dice: -",
|
||||
dice_value = "Dice: {value}",
|
||||
current_player = "Current player: {player}",
|
||||
["player.red"] = "Red",
|
||||
["player.blue"] = "Blue",
|
||||
["toast.move_first"] = "Move a piece first",
|
||||
["toast.no_movable_piece"] = "No movable pieces",
|
||||
["toast.invalid_piece"] = "This piece cannot move"
|
||||
}
|
||||
}
|
||||
|
||||
---@param locale? string
|
||||
---@return string
|
||||
local function normalize_locale(locale)
|
||||
if type(locale) ~= "string" or locale == "" then
|
||||
return default_locale
|
||||
end
|
||||
locale = string.gsub(locale, "_", "-")
|
||||
if messages[locale] ~= nil then
|
||||
return locale
|
||||
end
|
||||
|
||||
local language = string.match(locale, "^([A-Za-z]+)")
|
||||
if language ~= nil and messages[language] ~= nil then
|
||||
return language
|
||||
end
|
||||
return default_locale
|
||||
end
|
||||
|
||||
---@param value string
|
||||
---@return string
|
||||
local function escape_pattern(value)
|
||||
return string.gsub(value, "([%(%)%.%%%+%-%*%?%[%]%^%$])", "%%%1")
|
||||
end
|
||||
|
||||
---@param template string
|
||||
---@param vars? table<string, string|number>
|
||||
---@return string
|
||||
local function interpolate(template, vars)
|
||||
if vars == nil then
|
||||
return template
|
||||
end
|
||||
|
||||
local result = template
|
||||
for key, value in pairs(vars) do
|
||||
result = string.gsub(result, "{" .. escape_pattern(key) .. "}", tostring(value))
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
---@param ctx? RuntimeContext
|
||||
function i18n.configure(ctx)
|
||||
local locale = nil
|
||||
if ctx ~= nil and ctx.locale ~= nil then
|
||||
locale = ctx.locale.resolved or ctx.locale.requested or ctx.locale.default
|
||||
end
|
||||
current_locale = normalize_locale(locale)
|
||||
end
|
||||
|
||||
---@return string
|
||||
function i18n.locale()
|
||||
return current_locale
|
||||
end
|
||||
|
||||
---@param key string
|
||||
---@param vars? table<string, string|number>
|
||||
---@return string
|
||||
function i18n.t(key, vars)
|
||||
local bundle = messages[current_locale] or messages[default_locale]
|
||||
local fallback = messages[default_locale]
|
||||
local value = bundle[key] or fallback[key] or key
|
||||
return interpolate(value, vars)
|
||||
end
|
||||
|
||||
---@param color PlayerColor
|
||||
---@return string
|
||||
function i18n.player(color)
|
||||
return i18n.t("player." .. color)
|
||||
end
|
||||
|
||||
return i18n
|
||||
117
example/assets/games/ludo/scripts/main.lua
Normal file
117
example/assets/games/ludo/scripts/main.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
local state = runtime.import("state")
|
||||
local rules = runtime.import("rules")
|
||||
local ui = runtime.import("ui")
|
||||
local animation = runtime.import("animation")
|
||||
local i18n = runtime.import("i18n")
|
||||
---@type RuntimeWidgets
|
||||
local widgets = runtime.import("runtime_widgets")
|
||||
local theme = runtime.import("theme")
|
||||
|
||||
widgets.configure({
|
||||
primary = theme.colors.dice_button,
|
||||
secondary = theme.colors.board,
|
||||
success = theme.colors.blue,
|
||||
overlay = "#99000000",
|
||||
surface = theme.colors.top_bar,
|
||||
surfaceAlt = theme.colors.board,
|
||||
card = theme.colors.top_bar,
|
||||
text = theme.colors.text,
|
||||
muted = "#ffcbd5e1",
|
||||
progress = theme.colors.blue,
|
||||
transparent = "#00000000"
|
||||
})
|
||||
|
||||
function smoke_test(ctx)
|
||||
i18n.configure(ctx)
|
||||
return ctx ~= nil
|
||||
and ctx.runtimeApiVersion ~= nil
|
||||
and state.current_player ~= nil
|
||||
and rules.next_player ~= nil
|
||||
and ui.create_board_nodes ~= nil
|
||||
and animation.move_piece ~= nil
|
||||
and widgets.dialog ~= nil
|
||||
end
|
||||
|
||||
function init(ctx)
|
||||
i18n.configure(ctx)
|
||||
return {
|
||||
render = { creates = ui.create_board_nodes() },
|
||||
ui = { creates = ui.create_ui_nodes() },
|
||||
commands = {}
|
||||
}
|
||||
end
|
||||
|
||||
local function handle_roll_dice()
|
||||
if state.phase ~= "waiting_roll" then
|
||||
return { commands = { animation.toast(i18n.t("toast.move_first")) } }
|
||||
end
|
||||
|
||||
state.dice = rules.next_dice()
|
||||
local movable = rules.movable_pieces()
|
||||
|
||||
if #movable == 0 then
|
||||
state.current_player = rules.next_player()
|
||||
state.phase = "waiting_roll"
|
||||
return {
|
||||
ui = { updates = ui.dice_and_turn_updates(state.dice, state.current_player) },
|
||||
render = { updates = ui.highlight_updates(rules.all_piece_ids(), false) },
|
||||
commands = { animation.toast(i18n.t("toast.no_movable_piece")) }
|
||||
}
|
||||
end
|
||||
|
||||
state.phase = "waiting_piece"
|
||||
return {
|
||||
ui = { updates = ui.dice_update(state.dice) },
|
||||
render = { updates = ui.highlight_updates(movable, true) },
|
||||
commands = { animation.play_sound("dice") }
|
||||
}
|
||||
end
|
||||
|
||||
local function handle_piece_tap(piece_id)
|
||||
if state.phase ~= "waiting_piece" then
|
||||
return {}
|
||||
end
|
||||
|
||||
local piece = state.pieces[piece_id]
|
||||
if piece == nil or piece.owner ~= state.current_player or not rules.can_move(piece, state.dice) then
|
||||
return { commands = { animation.toast(i18n.t("toast.invalid_piece")) } }
|
||||
end
|
||||
|
||||
local path = rules.calculate_path(piece, state.dice)
|
||||
rules.apply_move(piece, state.dice)
|
||||
state.phase = "animating"
|
||||
state.selected_piece = piece_id
|
||||
|
||||
return {
|
||||
render = { updates = ui.highlight_updates(rules.all_piece_ids(), false) },
|
||||
commands = { animation.move_piece(piece_id, path) }
|
||||
}
|
||||
end
|
||||
|
||||
local function handle_move_done()
|
||||
if state.dice ~= 6 then
|
||||
state.current_player = rules.next_player()
|
||||
end
|
||||
state.phase = "waiting_roll"
|
||||
state.selected_piece = nil
|
||||
|
||||
return {
|
||||
ui = { updates = ui.turn_update(state.current_player) }
|
||||
}
|
||||
end
|
||||
|
||||
function on_event(event)
|
||||
if event.handler == "roll_dice" then
|
||||
return handle_roll_dice()
|
||||
end
|
||||
|
||||
if event.handler == "piece_tap" then
|
||||
return handle_piece_tap(event.target)
|
||||
end
|
||||
|
||||
if event.handler == "piece_move_done" then
|
||||
return handle_move_done()
|
||||
end
|
||||
|
||||
return {}
|
||||
end
|
||||
88
example/assets/games/ludo/scripts/rules.lua
Normal file
88
example/assets/games/ludo/scripts/rules.lua
Normal file
@@ -0,0 +1,88 @@
|
||||
local state = runtime.import("state")
|
||||
local board = runtime.import("board")
|
||||
|
||||
local rules = {}
|
||||
|
||||
function rules.next_player()
|
||||
if state.current_player == "red" then
|
||||
return "blue"
|
||||
end
|
||||
return "red"
|
||||
end
|
||||
|
||||
function rules.next_dice()
|
||||
state.dice_index = state.dice_index + 1
|
||||
if state.dice_index > #state.dice_values then
|
||||
state.dice_index = 1
|
||||
end
|
||||
return state.dice_values[state.dice_index]
|
||||
end
|
||||
|
||||
function rules.piece_home_position(piece)
|
||||
if piece.owner == "red" then
|
||||
if piece.id == "red_1" then return board.red_home[1] end
|
||||
return board.red_home[2]
|
||||
end
|
||||
if piece.id == "blue_1" then return board.blue_home[1] end
|
||||
return board.blue_home[2]
|
||||
end
|
||||
|
||||
function rules.can_move(piece, dice)
|
||||
if piece.status == "home" then
|
||||
return dice == 6
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function rules.movable_pieces()
|
||||
local result = {}
|
||||
for id, piece in pairs(state.pieces) do
|
||||
if piece.owner == state.current_player and rules.can_move(piece, state.dice) then
|
||||
table.insert(result, id)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function rules.all_piece_ids()
|
||||
local result = {}
|
||||
for id, _ in pairs(state.pieces) do
|
||||
table.insert(result, id)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function rules.calculate_path(piece, dice)
|
||||
local path = {}
|
||||
if piece.status == "home" then
|
||||
local start_index = board.start[piece.owner]
|
||||
local pos = board.path[start_index]
|
||||
table.insert(path, {x = pos.x, y = pos.y})
|
||||
return path
|
||||
end
|
||||
|
||||
for i = 1, dice do
|
||||
local index = piece.path_index + i
|
||||
while index > #board.path do
|
||||
index = index - #board.path
|
||||
end
|
||||
local pos = board.path[index]
|
||||
table.insert(path, {x = pos.x, y = pos.y})
|
||||
end
|
||||
return path
|
||||
end
|
||||
|
||||
function rules.apply_move(piece, dice)
|
||||
if piece.status == "home" then
|
||||
piece.status = "path"
|
||||
piece.path_index = board.start[piece.owner]
|
||||
return
|
||||
end
|
||||
|
||||
piece.path_index = piece.path_index + dice
|
||||
while piece.path_index > #board.path do
|
||||
piece.path_index = piece.path_index - #board.path
|
||||
end
|
||||
end
|
||||
|
||||
return rules
|
||||
587
example/assets/games/ludo/scripts/runtime_defs.lua
Normal file
587
example/assets/games/ludo/scripts/runtime_defs.lua
Normal file
@@ -0,0 +1,587 @@
|
||||
---@meta
|
||||
--- COMMON RUNTIME TYPES SECTION.
|
||||
--- Source of truth: tool/lua_runtime_defs_common.lua
|
||||
--- After editing this common section, run:
|
||||
--- dart run tool/generate_lua_runtime_defs.dart
|
||||
|
||||
|
||||
---@alias RuntimeNodeType
|
||||
---| 'panel'
|
||||
---| 'button'
|
||||
---| 'text'
|
||||
---| 'circle'
|
||||
---| 'rect'
|
||||
---| 'line'
|
||||
---| 'progress'
|
||||
---| 'listView'
|
||||
---| 'sprite'
|
||||
---| 'image'
|
||||
---| 'spine'
|
||||
---| 'particle'
|
||||
|
||||
---@alias RuntimeAnchor
|
||||
---| 'center'
|
||||
---| 'topLeft'
|
||||
---| 'topRight'
|
||||
---| 'bottomLeft'
|
||||
---| 'bottomRight'
|
||||
|
||||
---@alias RuntimeTextAlign
|
||||
---| 'left'
|
||||
---| 'center'
|
||||
---| 'right'
|
||||
|
||||
---@alias RuntimeParticlePreset
|
||||
---| 'burst'
|
||||
---| 'trail'
|
||||
---| 'snow'
|
||||
---| 'confetti'
|
||||
|
||||
---@alias RuntimeCommandType
|
||||
---| 'move_path'
|
||||
---| 'move_to'
|
||||
---| 'fade_to'
|
||||
---| 'scale_to'
|
||||
---| 'rotate_to'
|
||||
---| 'remove_node'
|
||||
---| 'sequence'
|
||||
---| 'parallel'
|
||||
---| 'delay'
|
||||
---| 'toast'
|
||||
---| 'play_sound'
|
||||
---| 'play_bgm'
|
||||
---| 'pause_bgm'
|
||||
---| 'resume_bgm'
|
||||
---| 'stop_bgm'
|
||||
---| 'preload_resources'
|
||||
---| 'evict_resources'
|
||||
---| 'cancel_commands'
|
||||
---| 'play_spine_animation'
|
||||
---| 'copy_text'
|
||||
|
||||
---@alias RuntimeEventType
|
||||
---| 'tap'
|
||||
---| 'animation_done'
|
||||
---| 'resize'
|
||||
---| 'scroll'
|
||||
|
||||
---@alias RuntimeScaleMode
|
||||
---| 'fit'
|
||||
---| 'fill'
|
||||
---| 'stretch'
|
||||
---| 'none'
|
||||
|
||||
---@alias RuntimeLayoutAlign
|
||||
---| 'start'
|
||||
---| 'center'
|
||||
---| 'end'
|
||||
|
||||
---@alias RuntimeButtonVariant
|
||||
---| 'primary'
|
||||
---| 'secondary'
|
||||
---| 'ghost'
|
||||
|
||||
---@class (exact) RuntimeNode
|
||||
---@field id string
|
||||
---@field type RuntimeNodeType
|
||||
---@field parent? string
|
||||
---@field asset? string Normal image/sprite/spine asset key. For button nodes this is the normal-state image.
|
||||
---@field pressedAsset? string Button pressed-state image asset key.
|
||||
---@field disabledAsset? string Button disabled-state image asset key.
|
||||
---@field animation? string
|
||||
---@field skin? string
|
||||
---@field loop? boolean
|
||||
---@field text? string
|
||||
---@field x? number
|
||||
---@field y? number
|
||||
---@field width? number
|
||||
---@field height? number
|
||||
---@field paddingLeft? number
|
||||
---@field paddingTop? number
|
||||
---@field paddingRight? number
|
||||
---@field paddingBottom? number
|
||||
---@field anchor? RuntimeAnchor
|
||||
---@field layer? integer
|
||||
---@field visible? boolean
|
||||
---@field alpha? number
|
||||
---@field scale? number
|
||||
---@field rotation? number
|
||||
---@field color? string
|
||||
---@field fontSize? number
|
||||
---@field textAlign? RuntimeTextAlign
|
||||
---@field radius? number
|
||||
---@field strokeWidth? number
|
||||
---@field value? number
|
||||
---@field scrollX? number
|
||||
---@field scrollY? number
|
||||
---@field contentWidth? number
|
||||
---@field contentHeight? number
|
||||
---@field virtualized? boolean
|
||||
---@field cacheExtent? number
|
||||
---@field inertia? boolean
|
||||
---@field scrollbarThumbColor? string
|
||||
---@field scrollbarTrackColor? string
|
||||
---@field scrollbarThickness? number
|
||||
---@field scrollbarVisible? boolean
|
||||
---@field interactive? boolean
|
||||
---@field onTap? string
|
||||
---@field onScroll? string
|
||||
---@field preset? RuntimeParticlePreset
|
||||
---@field count? integer
|
||||
---@field duration? number
|
||||
---@field speedMin? number
|
||||
---@field speedMax? number
|
||||
---@field gravityX? number
|
||||
---@field gravityY? number
|
||||
---@field spread? number
|
||||
---@field colorTo? string
|
||||
---@field radiusTo? number
|
||||
---@field autoRemove? boolean
|
||||
---@field fadeOut? boolean
|
||||
|
||||
---@class (exact) RuntimeNodeProps
|
||||
---@field type? RuntimeNodeType
|
||||
---@field parent? string
|
||||
---@field asset? string Normal image/sprite/spine asset key. For button nodes this is the normal-state image.
|
||||
---@field pressedAsset? string Button pressed-state image asset key.
|
||||
---@field disabledAsset? string Button disabled-state image asset key.
|
||||
---@field animation? string
|
||||
---@field skin? string
|
||||
---@field loop? boolean
|
||||
---@field text? string
|
||||
---@field x? number
|
||||
---@field y? number
|
||||
---@field width? number
|
||||
---@field height? number
|
||||
---@field paddingLeft? number
|
||||
---@field paddingTop? number
|
||||
---@field paddingRight? number
|
||||
---@field paddingBottom? number
|
||||
---@field anchor? RuntimeAnchor
|
||||
---@field layer? integer
|
||||
---@field visible? boolean
|
||||
---@field alpha? number
|
||||
---@field scale? number
|
||||
---@field rotation? number
|
||||
---@field color? string
|
||||
---@field fontSize? number
|
||||
---@field textAlign? RuntimeTextAlign
|
||||
---@field radius? number
|
||||
---@field strokeWidth? number
|
||||
---@field value? number
|
||||
---@field scrollX? number
|
||||
---@field scrollY? number
|
||||
---@field contentWidth? number
|
||||
---@field contentHeight? number
|
||||
---@field virtualized? boolean
|
||||
---@field cacheExtent? number
|
||||
---@field inertia? boolean
|
||||
---@field scrollbarThumbColor? string
|
||||
---@field scrollbarTrackColor? string
|
||||
---@field scrollbarThickness? number
|
||||
---@field scrollbarVisible? boolean
|
||||
---@field interactive? boolean
|
||||
---@field onTap? string
|
||||
---@field onScroll? string
|
||||
---@field preset? RuntimeParticlePreset
|
||||
---@field count? integer
|
||||
---@field duration? number
|
||||
---@field speedMin? number
|
||||
---@field speedMax? number
|
||||
---@field gravityX? number
|
||||
---@field gravityY? number
|
||||
---@field spread? number
|
||||
---@field colorTo? string
|
||||
---@field radiusTo? number
|
||||
---@field autoRemove? boolean
|
||||
---@field fadeOut? boolean
|
||||
|
||||
---Helper-only fields accepted by runtime_ui/runtime_widgets. They are normalized
|
||||
---before the node/update crosses the Dart Runtime protocol boundary.
|
||||
---@class RuntimeNodeInit: RuntimeNodeProps
|
||||
---@field w? number Alias for width.
|
||||
---@field h? number Alias for height.
|
||||
---@field size? number Alias for both width and height.
|
||||
---@field handler? string Alias for onTap.
|
||||
---@field onClick? string Alias for onTap.
|
||||
|
||||
---@class (exact) RuntimeNodeUpdate
|
||||
---@field id string
|
||||
---@field props RuntimeNodeProps
|
||||
|
||||
---@class (exact) RuntimeNodeRemove
|
||||
---@field id string
|
||||
|
||||
---@class (exact) RuntimeDiffSection
|
||||
---@field creates? RuntimeNode[]
|
||||
---@field updates? RuntimeNodeUpdate[]
|
||||
---@field removes? (string|RuntimeNodeRemove)[]
|
||||
|
||||
---@class (exact) RuntimeDiff
|
||||
---@field render? RuntimeDiffSection
|
||||
---@field ui? RuntimeDiffSection
|
||||
---@field commands? RuntimeCommand[]
|
||||
|
||||
---@class (exact) RuntimeEvent
|
||||
---@field type RuntimeEventType|string
|
||||
---@field target? string
|
||||
---@field handler? string
|
||||
---@field x? number
|
||||
---@field y? number
|
||||
---@field data? table
|
||||
|
||||
---@class (exact) RuntimeCommand
|
||||
---@field type RuntimeCommandType
|
||||
---@field target? string
|
||||
---@field scope? string
|
||||
---@field id? string
|
||||
---@field group? string
|
||||
---@field commandGroup? string
|
||||
---@field onComplete? string
|
||||
---@field duration? number
|
||||
---@field commands? RuntimeCommand[]
|
||||
---@field path? RuntimePoint[]
|
||||
---@field x? number
|
||||
---@field y? number
|
||||
---@field alpha? number
|
||||
---@field scale? number
|
||||
---@field angle? number
|
||||
---@field text? string
|
||||
---@field message? string
|
||||
---@field asset? string
|
||||
---@field name? string
|
||||
---@field volume? number
|
||||
---@field channel? string
|
||||
---@field loop? boolean
|
||||
---@field failOnError? boolean
|
||||
---@field animation? string
|
||||
---@field track? integer
|
||||
---@field queue? boolean
|
||||
---@field delay? number
|
||||
|
||||
---@class (exact) RuntimeCommandOpts
|
||||
---@field id? string
|
||||
---@field group? string
|
||||
---@field commandGroup? string
|
||||
---@field scope? string
|
||||
---@field onComplete? string
|
||||
---@field duration? number
|
||||
|
||||
---@class (exact) RuntimeAudioCommandOpts: RuntimeCommandOpts
|
||||
---@field volume? number
|
||||
---@field name? string
|
||||
|
||||
---@class (exact) RuntimeBgmCommandOpts: RuntimeAudioCommandOpts
|
||||
---@field channel? string
|
||||
---@field loop? boolean
|
||||
|
||||
---@class (exact) RuntimeSpineCommandOpts: RuntimeCommandOpts
|
||||
---@field track? integer
|
||||
---@field loop? boolean
|
||||
---@field queue? boolean
|
||||
---@field delay? number
|
||||
|
||||
---@class (exact) RuntimeResourceCommandOpts: RuntimeCommandOpts
|
||||
---@field failOnError? boolean
|
||||
|
||||
---@class (exact) RuntimePoint
|
||||
---@field x number
|
||||
---@field y number
|
||||
|
||||
---@class (exact) RuntimeLocaleContext
|
||||
---@field requested string
|
||||
---@field resolved string
|
||||
---@field default string
|
||||
---@field supported string[]
|
||||
---@field languageCode string
|
||||
---@field scriptCode? string
|
||||
---@field countryCode? string
|
||||
|
||||
---@class (exact) RuntimeScreenContext
|
||||
---@field width number
|
||||
---@field height number
|
||||
|
||||
---@class (exact) RuntimeDesignContext
|
||||
---@field width number
|
||||
---@field height number
|
||||
|
||||
---@class (exact) RuntimeViewportContext
|
||||
---@field x number
|
||||
---@field y number
|
||||
---@field width number
|
||||
---@field height number
|
||||
---@field scaleX number
|
||||
---@field scaleY number
|
||||
---@field scaleMode RuntimeScaleMode|string
|
||||
|
||||
---@class (exact) RuntimeContext
|
||||
---@field screen RuntimeScreenContext
|
||||
---@field design RuntimeDesignContext
|
||||
---@field viewport RuntimeViewportContext
|
||||
---@field seed integer
|
||||
---@field runtimeApiVersion integer
|
||||
---@field gameId string
|
||||
---@field gameVersion string
|
||||
---@field locale? RuntimeLocaleContext
|
||||
|
||||
---@class RuntimeUi
|
||||
---@field style fun(base?: RuntimeNodeProps, opts?: RuntimeNodeProps): RuntimeNodeProps
|
||||
---@field with_parent fun(parent: string, opts?: RuntimeNodeProps): RuntimeNodeProps
|
||||
---@field node fun(node_type: RuntimeNodeType, id: string, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field panel fun(id: string, x: number|RuntimeNodeInit, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field rect fun(id: string, x: number|RuntimeNodeInit, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field circle fun(id: string, x: number|RuntimeNodeInit, y?: number, size?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field line fun(id: string, x: number|RuntimeNodeInit, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field progress fun(id: string, x: number|RuntimeNodeInit, y?: number, width?: number, height?: number, value?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field particle fun(id: string, x: number|RuntimeNodeInit, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field text fun(id: string, text: string|RuntimeNodeInit, x?: number, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field button fun(id: string, text: string|RuntimeNodeInit, x?: number, y?: number, width?: number, height?: number, handler?: string, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field list_view fun(id: string, x: number|RuntimeNodeInit, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field image fun(id: string, asset: string|RuntimeNodeInit, x?: number, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field sprite fun(id: string, asset: string|RuntimeNodeInit, x?: number, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field spine fun(id: string, asset: string|RuntimeNodeInit, x?: number, y?: number, width?: number, height?: number, animation?: string, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field update fun(id: string, props: RuntimeNodeInit): RuntimeNodeUpdate
|
||||
---@field text_update fun(id: string, text: string): RuntimeNodeUpdate
|
||||
---@field visible_update fun(id: string, visible: boolean): RuntimeNodeUpdate
|
||||
---@field alpha_update fun(id: string, alpha: number): RuntimeNodeUpdate
|
||||
---@field scale_update fun(id: string, scale: number): RuntimeNodeUpdate
|
||||
---@field position_update fun(id: string, x: number, y: number): RuntimeNodeUpdate
|
||||
---@field size_update fun(id: string, width: number, height: number): RuntimeNodeUpdate
|
||||
---@field transform_update fun(id: string, x: number, y: number, scale: number, rotation: number): RuntimeNodeUpdate
|
||||
---@field batch_update fun(ids: string[], props: RuntimeNodeInit): RuntimeNodeUpdate[]
|
||||
---@field append fun(nodes: RuntimeNode[], node: RuntimeNode): RuntimeNode[]
|
||||
---@field append_all fun(nodes: RuntimeNode[], extra_nodes: RuntimeNode[]): RuntimeNode[]
|
||||
|
||||
---@class (exact) RuntimeDialogButton
|
||||
---@field id? string
|
||||
---@field text string
|
||||
---@field handler string
|
||||
---@field color? string
|
||||
|
||||
---@class (exact) RuntimeDialogOpts
|
||||
---@field screenWidth? number
|
||||
---@field screenHeight? number
|
||||
---@field overlay? boolean
|
||||
---@field overlayColor? string
|
||||
---@field blockInput? boolean
|
||||
---@field layer? integer
|
||||
---@field color? string
|
||||
---@field radius? number
|
||||
---@field panelStyle? RuntimeNodeProps
|
||||
---@field titleColor? string
|
||||
---@field titleSize? number
|
||||
---@field titleStyle? RuntimeNodeProps
|
||||
---@field messageColor? string
|
||||
---@field messageSize? number
|
||||
---@field messageStyle? RuntimeNodeProps
|
||||
---@field buttons? RuntimeDialogButton[]
|
||||
---@field buttonGap? number
|
||||
---@field buttonStyle? RuntimeNodeProps
|
||||
|
||||
---@class RuntimeLabeledProgressOpts: RuntimeNodeInit
|
||||
---@field labelHeight? number
|
||||
---@field labelStyle? RuntimeNodeProps
|
||||
|
||||
---@class RuntimePillOpts: RuntimeNodeInit
|
||||
---@field panelStyle? RuntimeNodeProps
|
||||
---@field textStyle? RuntimeNodeProps
|
||||
|
||||
---@class RuntimeTextButtonOpts: RuntimeNodeInit
|
||||
---@field variant? RuntimeButtonVariant
|
||||
|
||||
---@class RuntimeListItemOpts: RuntimeTextButtonOpts
|
||||
---@field selected? boolean
|
||||
---@field activeColor? string
|
||||
---@field inactiveColor? string
|
||||
|
||||
---@class RuntimeTabItem
|
||||
---@field id? string
|
||||
---@field key? string
|
||||
---@field text string
|
||||
---@field handler? string
|
||||
---@field selected? boolean
|
||||
|
||||
---@class RuntimeTabsOpts: RuntimeNodeInit
|
||||
---@field tabs? RuntimeTabItem[]
|
||||
---@field selected? string
|
||||
---@field gap? number
|
||||
---@field itemWidth? number
|
||||
---@field itemHeight? number
|
||||
---@field activeColor? string
|
||||
---@field inactiveColor? string
|
||||
---@field buttonStyle? RuntimeNodeProps
|
||||
|
||||
---@class RuntimeActionItem
|
||||
---@field id? string
|
||||
---@field text string
|
||||
---@field handler? string
|
||||
---@field visible? boolean
|
||||
---@field color? string
|
||||
---@field style? RuntimeNodeProps
|
||||
|
||||
---@class RuntimeActionRowOpts: RuntimeNodeInit
|
||||
---@field actions? RuntimeActionItem[]
|
||||
---@field gap? number
|
||||
---@field itemWidth? number
|
||||
---@field itemHeight? number
|
||||
---@field buttonStyle? RuntimeNodeProps
|
||||
|
||||
---@class RuntimePanelHeaderOpts: RuntimeNodeInit
|
||||
---@field eyebrow? string
|
||||
---@field title string
|
||||
---@field summary? string
|
||||
---@field gap? number
|
||||
---@field eyebrowId? string
|
||||
---@field titleId? string
|
||||
---@field summaryId? string
|
||||
---@field eyebrowHeight? number
|
||||
---@field titleHeight? number
|
||||
---@field summaryHeight? number
|
||||
---@field eyebrowStyle? RuntimeNodeProps
|
||||
---@field titleStyle? RuntimeNodeProps
|
||||
---@field summaryStyle? RuntimeNodeProps
|
||||
|
||||
---@class RuntimeWidgetTheme
|
||||
---@field primary? string
|
||||
---@field secondary? string
|
||||
---@field success? string
|
||||
---@field overlay? string
|
||||
---@field surface? string
|
||||
---@field surfaceAlt? string
|
||||
---@field card? string
|
||||
---@field text? string
|
||||
---@field muted? string
|
||||
---@field progress? string
|
||||
---@field transparent? string
|
||||
|
||||
---@class RuntimeWidgets
|
||||
---@field configure fun(tokens?: RuntimeWidgetTheme): RuntimeWidgets
|
||||
---@field label fun(id: string, text: string|RuntimeNodeInit, x?: number, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field section_title fun(id: string, text: string|RuntimeNodeInit, x?: number, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field pill fun(id: string, text: string|RuntimePillOpts, x?: number, y?: number, width?: number, height?: number, opts?: RuntimePillOpts): RuntimeNode[]
|
||||
---@field text_button fun(id: string, text: string|RuntimeTextButtonOpts, x?: number, y?: number, width?: number, height?: number, handler?: string, opts?: RuntimeTextButtonOpts): RuntimeNode
|
||||
---@field list_item fun(id: string, text: string|RuntimeListItemOpts, x?: number, y?: number, width?: number, height?: number, handler?: string, opts?: RuntimeListItemOpts): RuntimeNode
|
||||
---@field tabs fun(id: string, tabs: RuntimeTabItem[]|RuntimeTabsOpts, opts?: RuntimeTabsOpts): RuntimeNode[]
|
||||
---@field action_row fun(id: string, actions: RuntimeActionItem[]|RuntimeActionRowOpts, opts?: RuntimeActionRowOpts): RuntimeNode[]
|
||||
---@field panel_header fun(id: string, opts: RuntimePanelHeaderOpts): RuntimeNode[]
|
||||
---@field overlay fun(id: string, width: number|RuntimeNodeInit, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field card fun(id: string, x: number|RuntimeNodeInit, y?: number, width?: number, height?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field progress_bar fun(id: string, x: number|RuntimeNodeInit, y?: number, width?: number, height?: number, value?: number, opts?: RuntimeNodeInit): RuntimeNode
|
||||
---@field labeled_progress fun(id: string, label: string, x: number, y: number, width: number, height: number, value: number, opts?: RuntimeLabeledProgressOpts): RuntimeNode[]
|
||||
---@field button_row fun(parent: string, id: string, buttons: RuntimeDialogButton[], x: number, y: number, width: number, height: number, gap?: number, opts?: RuntimeNodeProps): RuntimeNode[]
|
||||
---@field dialog fun(id: string, title: string, message: string, x: number, y: number, width: number, height: number, opts?: RuntimeDialogOpts): RuntimeNode[]
|
||||
|
||||
---@class (exact) RuntimeLayoutItem
|
||||
---@field node RuntimeNode
|
||||
---@field marginLeft? number
|
||||
---@field marginRight? number
|
||||
---@field marginTop? number
|
||||
---@field marginBottom? number
|
||||
|
||||
---@class RuntimeLayoutItemOpts
|
||||
---@field margin? number
|
||||
---@field mx? number
|
||||
---@field my? number
|
||||
---@field ml? number
|
||||
---@field mr? number
|
||||
---@field mt? number
|
||||
---@field mb? number
|
||||
---@field marginLeft? number
|
||||
---@field marginRight? number
|
||||
---@field marginTop? number
|
||||
---@field marginBottom? number
|
||||
|
||||
---@class RuntimeLinearLayoutOpts
|
||||
---@field x? number
|
||||
---@field y? number
|
||||
---@field width? number
|
||||
---@field height? number
|
||||
---@field gap? number
|
||||
---@field align? RuntimeLayoutAlign
|
||||
---@field padding? number
|
||||
---@field paddingX? number
|
||||
---@field paddingY? number
|
||||
---@field px? number
|
||||
---@field py? number
|
||||
---@field paddingLeft? number
|
||||
---@field paddingTop? number
|
||||
|
||||
---@class RuntimeBoxLayoutOpts: RuntimeLinearLayoutOpts
|
||||
---@field rows? integer
|
||||
---@field columns? integer
|
||||
---@field cols? integer
|
||||
---@field cellWidth? number
|
||||
---@field cellHeight? number
|
||||
---@field cellW? number
|
||||
---@field cellH? number
|
||||
---@field gapX? number
|
||||
---@field gapY? number
|
||||
---@field valign? RuntimeLayoutAlign
|
||||
|
||||
---@class RuntimeLayout
|
||||
---@field item fun(node: RuntimeNode, opts?: RuntimeLayoutItemOpts): RuntimeLayoutItem
|
||||
---@field local_position fun(origin: RuntimePoint, position: RuntimePoint): RuntimePoint
|
||||
---@field row fun(parent?: string, items: (RuntimeNode|RuntimeLayoutItem)[], opts?: RuntimeLinearLayoutOpts): RuntimeNode[]
|
||||
---@field column fun(parent?: string, items: (RuntimeNode|RuntimeLayoutItem)[], opts?: RuntimeLinearLayoutOpts): RuntimeNode[]
|
||||
---@field stack fun(parent?: string, items: (RuntimeNode|RuntimeLayoutItem)[], opts?: RuntimeLinearLayoutOpts): RuntimeNode[]
|
||||
---@field box fun(parent?: string, items: (RuntimeNode|RuntimeLayoutItem)[], opts?: RuntimeBoxLayoutOpts): RuntimeNode[]
|
||||
|
||||
---@class RuntimeCommands
|
||||
---@field toast fun(text: string, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field copy_text fun(text: string, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field delay fun(duration: number, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field sequence fun(items: RuntimeCommand[], opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field parallel fun(items: RuntimeCommand[], opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field move_path fun(target: string, path: RuntimePoint[], opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field move_to fun(target: string, x: number, y: number, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field fade_to fun(target: string, alpha: number, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field scale_to fun(target: string, scale: number, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field rotate_to fun(target: string, angle: number, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field remove_node fun(target: string, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field play_spine_animation fun(target: string, animation: string, opts?: RuntimeSpineCommandOpts): RuntimeCommand
|
||||
---@field play_sound fun(asset: string, opts?: RuntimeAudioCommandOpts): RuntimeCommand
|
||||
---@field play_bgm fun(asset: string, opts?: RuntimeBgmCommandOpts): RuntimeCommand
|
||||
---@field pause_bgm fun(channel?: string, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field resume_bgm fun(channel?: string, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field stop_bgm fun(channel?: string, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field preload_group fun(group: string, opts?: RuntimeResourceCommandOpts): RuntimeCommand
|
||||
---@field evict_group fun(group: string, opts?: RuntimeCommandOpts): RuntimeCommand
|
||||
---@field cancel_id fun(id: string): RuntimeCommand
|
||||
---@field cancel_group fun(group: string): RuntimeCommand
|
||||
---@field cancel_scope fun(scope: string): RuntimeCommand
|
||||
|
||||
---@class RuntimeImportApi
|
||||
---@field import fun(moduleName: string): table
|
||||
|
||||
---@type RuntimeImportApi
|
||||
runtime = runtime
|
||||
|
||||
---@alias PlayerColor 'red'|'blue'
|
||||
---@alias GamePhase 'waiting_roll'|'waiting_piece'|'animating'
|
||||
---@alias PieceStatus 'home'|'path'|'finished'
|
||||
|
||||
---@class (exact) PieceState
|
||||
---@field id string
|
||||
---@field owner PlayerColor
|
||||
---@field path_index integer
|
||||
---@field status PieceStatus
|
||||
|
||||
---@class (exact) LudoState
|
||||
---@field current_player PlayerColor
|
||||
---@field phase GamePhase
|
||||
---@field dice_index integer
|
||||
---@field dice_values integer[]
|
||||
---@field dice? integer
|
||||
---@field selected_piece? string
|
||||
---@field players PlayerColor[]
|
||||
---@field pieces table<string, PieceState>
|
||||
|
||||
---@class (exact) BoardPoint
|
||||
---@field x number
|
||||
---@field y number
|
||||
|
||||
---@class (exact) BoardData
|
||||
---@field red_home BoardPoint[]
|
||||
---@field blue_home BoardPoint[]
|
||||
---@field path BoardPoint[]
|
||||
---@field start table<PlayerColor, integer>
|
||||
15
example/assets/games/ludo/scripts/state.lua
Normal file
15
example/assets/games/ludo/scripts/state.lua
Normal file
@@ -0,0 +1,15 @@
|
||||
---@type LudoState
|
||||
return {
|
||||
current_player = "red",
|
||||
phase = "waiting_roll",
|
||||
dice_index = 0,
|
||||
dice_values = {6, 3, 5, 2, 6, 4},
|
||||
selected_piece = nil,
|
||||
players = {"red", "blue"},
|
||||
pieces = {
|
||||
red_1 = { id = "red_1", owner = "red", path_index = 0, status = "home" },
|
||||
red_2 = { id = "red_2", owner = "red", path_index = 0, status = "home" },
|
||||
blue_1 = { id = "blue_1", owner = "blue", path_index = 0, status = "home" },
|
||||
blue_2 = { id = "blue_2", owner = "blue", path_index = 0, status = "home" }
|
||||
}
|
||||
}
|
||||
80
example/assets/games/ludo/scripts/styles.lua
Normal file
80
example/assets/games/ludo/scripts/styles.lua
Normal file
@@ -0,0 +1,80 @@
|
||||
local theme = runtime.import("theme")
|
||||
|
||||
local colors = theme.colors
|
||||
local styles = {}
|
||||
|
||||
styles.layers = {
|
||||
background = 0,
|
||||
board = 1,
|
||||
board_content = 2,
|
||||
piece = 10,
|
||||
hud = 100,
|
||||
hud_content = 101
|
||||
}
|
||||
|
||||
styles.board_panel = {
|
||||
color = colors.board,
|
||||
layer = styles.layers.background
|
||||
}
|
||||
|
||||
styles.board_title = {
|
||||
fontSize = 24,
|
||||
color = colors.text,
|
||||
layer = styles.layers.board_content
|
||||
}
|
||||
|
||||
styles.red_home = {
|
||||
color = colors.red_home,
|
||||
layer = styles.layers.board
|
||||
}
|
||||
|
||||
styles.blue_home = {
|
||||
color = colors.blue_home,
|
||||
layer = styles.layers.board
|
||||
}
|
||||
|
||||
styles.path_cell = {
|
||||
anchor = "center",
|
||||
color = colors.path_cell,
|
||||
layer = styles.layers.board_content
|
||||
}
|
||||
|
||||
styles.top_bar = {
|
||||
color = colors.top_bar,
|
||||
layer = styles.layers.hud
|
||||
}
|
||||
|
||||
styles.hud_text = {
|
||||
fontSize = 22,
|
||||
color = colors.text,
|
||||
layer = styles.layers.hud_content
|
||||
}
|
||||
|
||||
styles.dice_button = {
|
||||
color = colors.dice_button,
|
||||
fontSize = 20,
|
||||
layer = styles.layers.hud_content
|
||||
}
|
||||
|
||||
styles.piece_highlight = {
|
||||
scale = 1.25,
|
||||
alpha = 1
|
||||
}
|
||||
|
||||
styles.piece_normal = {
|
||||
scale = 1,
|
||||
alpha = 0.95
|
||||
}
|
||||
|
||||
function styles.piece(owner)
|
||||
return {
|
||||
anchor = "center",
|
||||
asset = "piece_" .. owner,
|
||||
color = colors[owner],
|
||||
layer = styles.layers.piece,
|
||||
interactive = true,
|
||||
onTap = "piece_tap"
|
||||
}
|
||||
end
|
||||
|
||||
return styles
|
||||
18
example/assets/games/ludo/scripts/theme.lua
Normal file
18
example/assets/games/ludo/scripts/theme.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
local i18n = runtime.import("i18n")
|
||||
|
||||
return {
|
||||
title = function()
|
||||
return i18n.t("title")
|
||||
end,
|
||||
colors = {
|
||||
red = "#ef4444",
|
||||
blue = "#3b82f6",
|
||||
top_bar = "#020617",
|
||||
dice_button = "#2563eb",
|
||||
board = "#1e293b",
|
||||
red_home = "#7f1d1d",
|
||||
blue_home = "#1e3a8a",
|
||||
path_cell = "#f8fafc",
|
||||
text = "#ffffff"
|
||||
}
|
||||
}
|
||||
74
example/assets/games/ludo/scripts/ui.lua
Normal file
74
example/assets/games/ludo/scripts/ui.lua
Normal file
@@ -0,0 +1,74 @@
|
||||
---@type RuntimeUi
|
||||
local runtime_ui = runtime.import("runtime_ui")
|
||||
---@type RuntimeLayout
|
||||
local layout = runtime.import("layout")
|
||||
local theme = runtime.import("theme")
|
||||
local i18n = runtime.import("i18n")
|
||||
local styles = runtime.import("styles")
|
||||
local state = runtime.import("state")
|
||||
local board = runtime.import("board")
|
||||
local rules = runtime.import("rules")
|
||||
|
||||
local ui = {}
|
||||
local board_origin = { x = 40, y = 90 }
|
||||
|
||||
function ui.highlight_updates(ids, enabled)
|
||||
return runtime_ui.batch_update(ids, enabled and styles.piece_highlight or styles.piece_normal)
|
||||
end
|
||||
|
||||
function ui.create_board_nodes()
|
||||
local nodes = {
|
||||
runtime_ui.sprite("board_panel", "board", 40, 90, 640, 520, styles.board_panel),
|
||||
runtime_ui.text("board_title", theme.title(), 240, 15, 180, 40, runtime_ui.with_parent("board_panel", styles.board_title)),
|
||||
runtime_ui.panel("red_home", 20, 390, 130, 90, runtime_ui.with_parent("board_panel", styles.red_home)),
|
||||
runtime_ui.panel("blue_home", 460, -10, 130, 90, runtime_ui.with_parent("board_panel", styles.blue_home))
|
||||
}
|
||||
|
||||
for index, cell in ipairs(board.path) do
|
||||
local pos = layout.local_position(board_origin, cell)
|
||||
runtime_ui.append(nodes, runtime_ui.circle("cell_" .. tostring(index), pos.x, pos.y, 28, runtime_ui.with_parent("board_panel", styles.path_cell)))
|
||||
end
|
||||
|
||||
for id, piece in pairs(state.pieces) do
|
||||
local pos = rules.piece_home_position(piece)
|
||||
runtime_ui.append(nodes, runtime_ui.circle(id, pos.x, pos.y, 44, styles.piece(piece.owner)))
|
||||
end
|
||||
|
||||
return nodes
|
||||
end
|
||||
|
||||
function ui.create_ui_nodes()
|
||||
local hud_items = layout.row("top_bar", {
|
||||
runtime_ui.text("turn_text", i18n.t("current_player", { player = i18n.player(state.current_player) }), 0, 0, 230, 32, styles.hud_text),
|
||||
runtime_ui.text("dice_text", i18n.t("dice_empty"), 0, 0, 120, 32, styles.hud_text),
|
||||
layout.item(
|
||||
runtime_ui.button("dice_button", i18n.t("roll_button"), 0, 0, 130, 48, "roll_dice", styles.dice_button),
|
||||
{ marginLeft = 134 }
|
||||
)
|
||||
}, {
|
||||
x = 24,
|
||||
height = 76,
|
||||
gap = 16,
|
||||
align = "center"
|
||||
})
|
||||
|
||||
local nodes = { runtime_ui.panel("top_bar", 0, 0, 720, 76, styles.top_bar) }
|
||||
return runtime_ui.append_all(nodes, hud_items)
|
||||
end
|
||||
|
||||
function ui.dice_and_turn_updates(dice, current_player)
|
||||
return {
|
||||
runtime_ui.text_update("dice_text", i18n.t("dice_value", { value = dice })),
|
||||
runtime_ui.text_update("turn_text", i18n.t("current_player", { player = i18n.player(current_player) }))
|
||||
}
|
||||
end
|
||||
|
||||
function ui.dice_update(dice)
|
||||
return { runtime_ui.text_update("dice_text", i18n.t("dice_value", { value = dice })) }
|
||||
end
|
||||
|
||||
function ui.turn_update(current_player)
|
||||
return { runtime_ui.text_update("turn_text", i18n.t("current_player", { player = i18n.player(current_player) })) }
|
||||
end
|
||||
|
||||
return ui
|
||||
Reference in New Issue
Block a user