Initial flame_lua_runtime package
This commit is contained in:
22
example/assets/games/flight/manifest.json
Normal file
22
example/assets/games/flight/manifest.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"gameId": "flight",
|
||||
"name": "Lua 飞行棋基础版",
|
||||
"version": "0.1.0",
|
||||
"runtimeApiVersion": 1,
|
||||
"entry": "scripts/main.lua",
|
||||
"assetsBase": "assets",
|
||||
"modules": {
|
||||
"runtime_ui": "runtime:runtime_ui.lua",
|
||||
"runtime_widgets": "runtime:runtime_widgets.lua",
|
||||
"runtime_commands": "runtime:runtime_commands.lua",
|
||||
"layout": "runtime:layout.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": {}
|
||||
}
|
||||
17
example/assets/games/flight/scripts/animation.lua
Normal file
17
example/assets/games/flight/scripts/animation.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
---@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.55,
|
||||
onComplete = "piece_move_done"
|
||||
})
|
||||
end
|
||||
|
||||
function animation.toast(text)
|
||||
return commands.toast(text)
|
||||
end
|
||||
|
||||
return animation
|
||||
91
example/assets/games/flight/scripts/board.lua
Normal file
91
example/assets/games/flight/scripts/board.lua
Normal file
@@ -0,0 +1,91 @@
|
||||
local board = {
|
||||
route_length = 40,
|
||||
finish_progress = 40,
|
||||
start = {
|
||||
red = 1,
|
||||
yellow = 11,
|
||||
blue = 21,
|
||||
green = 31
|
||||
},
|
||||
homes = {
|
||||
red = {
|
||||
{ x = 92, y = 132 },
|
||||
{ x = 142, y = 132 }
|
||||
},
|
||||
yellow = {
|
||||
{ x = 518, y = 132 },
|
||||
{ x = 568, y = 132 }
|
||||
},
|
||||
blue = {
|
||||
{ x = 518, y = 548 },
|
||||
{ x = 568, y = 548 }
|
||||
},
|
||||
green = {
|
||||
{ x = 92, y = 548 },
|
||||
{ x = 142, y = 548 }
|
||||
}
|
||||
},
|
||||
finish = {
|
||||
red = {
|
||||
{ x = 290, y = 330 },
|
||||
{ x = 250, y = 330 }
|
||||
},
|
||||
yellow = {
|
||||
{ x = 350, y = 330 },
|
||||
{ x = 390, y = 330 }
|
||||
},
|
||||
blue = {
|
||||
{ x = 350, y = 390 },
|
||||
{ x = 390, y = 390 }
|
||||
},
|
||||
green = {
|
||||
{ x = 290, y = 390 },
|
||||
{ x = 250, y = 390 }
|
||||
}
|
||||
},
|
||||
route = {}
|
||||
}
|
||||
|
||||
local function add(x, y)
|
||||
table.insert(board.route, { x = x, y = y })
|
||||
end
|
||||
|
||||
for i = 0, 9 do add(200 + i * 32, 104) end
|
||||
for i = 0, 9 do add(520, 136 + i * 32) end
|
||||
for i = 0, 9 do add(488 - i * 32, 456) end
|
||||
for i = 0, 9 do add(168, 424 - i * 32) end
|
||||
|
||||
function board.home_position(piece)
|
||||
local index = piece.id:sub(-1) == "2" and 2 or 1
|
||||
return board.homes[piece.owner][index]
|
||||
end
|
||||
|
||||
function board.finish_position(piece)
|
||||
local index = piece.id:sub(-1) == "2" and 2 or 1
|
||||
return board.finish[piece.owner][index]
|
||||
end
|
||||
|
||||
function board.route_index(owner, progress)
|
||||
local start = board.start[owner]
|
||||
local index = start + progress - 1
|
||||
while index > board.route_length do
|
||||
index = index - board.route_length
|
||||
end
|
||||
return index
|
||||
end
|
||||
|
||||
function board.route_position(owner, progress)
|
||||
return board.route[board.route_index(owner, progress)]
|
||||
end
|
||||
|
||||
function board.position(piece)
|
||||
if piece.status == "home" then
|
||||
return board.home_position(piece)
|
||||
end
|
||||
if piece.status == "finished" then
|
||||
return board.finish_position(piece)
|
||||
end
|
||||
return board.route_position(piece.owner, piece.progress)
|
||||
end
|
||||
|
||||
return board
|
||||
154
example/assets/games/flight/scripts/main.lua
Normal file
154
example/assets/games/flight/scripts/main.lua
Normal file
@@ -0,0 +1,154 @@
|
||||
local state = runtime.import("state")
|
||||
local rules = runtime.import("rules")
|
||||
local ui = runtime.import("ui")
|
||||
local animation = runtime.import("animation")
|
||||
---@type RuntimeWidgets
|
||||
local widgets = runtime.import("runtime_widgets")
|
||||
local theme = runtime.import("theme")
|
||||
|
||||
widgets.configure({
|
||||
primary = theme.colors.dice_button,
|
||||
secondary = theme.colors.board_inner,
|
||||
success = theme.colors.green,
|
||||
overlay = "#99000000",
|
||||
surface = theme.colors.top_bar,
|
||||
surfaceAlt = theme.colors.board_inner,
|
||||
card = theme.colors.top_bar,
|
||||
text = theme.colors.text,
|
||||
muted = theme.colors.muted_text,
|
||||
progress = theme.colors.green,
|
||||
transparent = "#00000000"
|
||||
})
|
||||
|
||||
function smoke_test(ctx)
|
||||
return ctx ~= nil
|
||||
and ctx.runtimeApiVersion ~= nil
|
||||
and state.current_player ~= nil
|
||||
and rules.plan_move ~= nil
|
||||
and ui.create_board_nodes ~= nil
|
||||
and animation.move_piece ~= nil
|
||||
and widgets.dialog ~= nil
|
||||
end
|
||||
|
||||
function init(ctx)
|
||||
return {
|
||||
render = { creates = ui.create_board_nodes() },
|
||||
ui = { creates = ui.create_ui_nodes() },
|
||||
commands = {}
|
||||
}
|
||||
end
|
||||
|
||||
local function handle_roll_dice()
|
||||
if state.phase == "game_over" then
|
||||
return { commands = { animation.toast("游戏已结束") } }
|
||||
end
|
||||
|
||||
if state.phase ~= "waiting_roll" then
|
||||
return { commands = { animation.toast("请先完成当前移动") } }
|
||||
end
|
||||
|
||||
state.dice = rules.next_dice()
|
||||
local movable = rules.movable_pieces()
|
||||
|
||||
if #movable == 0 then
|
||||
local message = state.current_player .. " 无可移动飞机"
|
||||
if state.dice ~= 6 then
|
||||
state.current_player = rules.next_player()
|
||||
end
|
||||
state.phase = "waiting_roll"
|
||||
return {
|
||||
ui = { updates = ui.dice_and_status_updates() },
|
||||
render = { updates = ui.highlight_updates(rules.all_piece_ids(), false) },
|
||||
commands = { animation.toast(message) }
|
||||
}
|
||||
end
|
||||
|
||||
state.phase = "waiting_piece"
|
||||
return {
|
||||
ui = { updates = ui.dice_and_status_updates() },
|
||||
render = { updates = ui.highlight_updates(movable, true) }
|
||||
}
|
||||
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("该飞机不能移动") } }
|
||||
end
|
||||
|
||||
local plan = rules.plan_move(piece, state.dice)
|
||||
state.phase = "animating"
|
||||
state.selected_piece = piece_id
|
||||
state.pending_move = plan
|
||||
|
||||
return {
|
||||
ui = { updates = ui.dice_and_status_updates() },
|
||||
render = { updates = ui.highlight_updates(rules.all_piece_ids(), false) },
|
||||
commands = { animation.move_piece(piece_id, plan.path) }
|
||||
}
|
||||
end
|
||||
|
||||
local function handle_move_done()
|
||||
local plan = state.pending_move
|
||||
if plan == nil then
|
||||
state.phase = "waiting_roll"
|
||||
return { ui = { updates = ui.dice_and_status_updates() } }
|
||||
end
|
||||
|
||||
rules.commit_move(plan)
|
||||
local moved_piece = state.pieces[plan.piece_id]
|
||||
local updates = ui.piece_position_updates(plan.captures)
|
||||
table.insert(updates, ui.piece_position_update(plan.piece_id))
|
||||
|
||||
local messages = {}
|
||||
if #plan.captures > 0 then
|
||||
table.insert(messages, "撞回 " .. tostring(#plan.captures) .. " 架飞机")
|
||||
end
|
||||
|
||||
if rules.player_finished(moved_piece.owner) then
|
||||
state.winner = moved_piece.owner
|
||||
state.phase = "game_over"
|
||||
table.insert(messages, moved_piece.owner .. " 获胜")
|
||||
else
|
||||
if state.dice ~= 6 then
|
||||
state.current_player = rules.next_player()
|
||||
else
|
||||
table.insert(messages, "掷出 6,额外回合")
|
||||
end
|
||||
state.phase = "waiting_roll"
|
||||
end
|
||||
|
||||
state.selected_piece = nil
|
||||
state.pending_move = nil
|
||||
|
||||
local commands = {}
|
||||
if #messages > 0 then
|
||||
commands = { animation.toast(table.concat(messages, ";")) }
|
||||
end
|
||||
|
||||
return {
|
||||
ui = { updates = ui.dice_and_status_updates() },
|
||||
render = { updates = updates },
|
||||
commands = commands
|
||||
}
|
||||
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
|
||||
153
example/assets/games/flight/scripts/rules.lua
Normal file
153
example/assets/games/flight/scripts/rules.lua
Normal file
@@ -0,0 +1,153 @@
|
||||
local state = runtime.import("state")
|
||||
local board = runtime.import("board")
|
||||
|
||||
local rules = {}
|
||||
|
||||
local function piece_index(piece_id)
|
||||
return piece_id:sub(-1) == "2" and 2 or 1
|
||||
end
|
||||
|
||||
function rules.next_player()
|
||||
for index, player in ipairs(state.players) do
|
||||
if player == state.current_player then
|
||||
local next_index = index + 1
|
||||
if next_index > #state.players then
|
||||
next_index = 1
|
||||
end
|
||||
return state.players[next_index]
|
||||
end
|
||||
end
|
||||
return state.players[1]
|
||||
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.can_move(piece, dice)
|
||||
if piece == nil or piece.status == "finished" then
|
||||
return false
|
||||
end
|
||||
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.piece_position(piece)
|
||||
return board.position(piece)
|
||||
end
|
||||
|
||||
function rules.plan_move(piece, dice)
|
||||
local path = {}
|
||||
local final_status = "route"
|
||||
local final_progress = piece.progress
|
||||
|
||||
if piece.status == "home" then
|
||||
final_progress = 1
|
||||
table.insert(path, board.route_position(piece.owner, final_progress))
|
||||
else
|
||||
for step = 1, dice do
|
||||
local progress = piece.progress + step
|
||||
if progress >= board.finish_progress then
|
||||
final_status = "finished"
|
||||
final_progress = board.finish_progress
|
||||
table.insert(path, board.finish_position(piece))
|
||||
break
|
||||
end
|
||||
table.insert(path, board.route_position(piece.owner, progress))
|
||||
final_progress = progress
|
||||
end
|
||||
end
|
||||
|
||||
local captures = {}
|
||||
if final_status == "route" then
|
||||
local landing_index = board.route_index(piece.owner, final_progress)
|
||||
for id, other in pairs(state.pieces) do
|
||||
if id ~= piece.id and other.owner ~= piece.owner and other.status == "route" then
|
||||
if board.route_index(other.owner, other.progress) == landing_index then
|
||||
table.insert(captures, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
piece_id = piece.id,
|
||||
final_status = final_status,
|
||||
final_progress = final_progress,
|
||||
path = path,
|
||||
captures = captures
|
||||
}
|
||||
end
|
||||
|
||||
function rules.commit_move(plan)
|
||||
local piece = state.pieces[plan.piece_id]
|
||||
piece.status = plan.final_status
|
||||
piece.progress = plan.final_progress
|
||||
|
||||
for _, captured_id in ipairs(plan.captures) do
|
||||
local captured = state.pieces[captured_id]
|
||||
captured.status = "home"
|
||||
captured.progress = 0
|
||||
end
|
||||
end
|
||||
|
||||
function rules.player_finished(owner)
|
||||
for _, piece in pairs(state.pieces) do
|
||||
if piece.owner == owner and piece.status ~= "finished" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function rules.status_text()
|
||||
if state.winner ~= nil then
|
||||
return "胜利者: " .. state.winner
|
||||
end
|
||||
if state.phase == "waiting_roll" then
|
||||
return "请 " .. state.current_player .. " 掷骰子"
|
||||
end
|
||||
if state.phase == "waiting_piece" then
|
||||
return "请选择 " .. state.current_player .. " 的飞机"
|
||||
end
|
||||
if state.phase == "animating" then
|
||||
return "飞机移动中..."
|
||||
end
|
||||
return "准备中"
|
||||
end
|
||||
|
||||
function rules.piece_label(piece)
|
||||
if piece.status == "home" then
|
||||
return "待飞"
|
||||
end
|
||||
if piece.status == "finished" then
|
||||
return "到达"
|
||||
end
|
||||
return tostring(piece.progress)
|
||||
end
|
||||
|
||||
return rules
|
||||
589
example/assets/games/flight/scripts/runtime_defs.lua
Normal file
589
example/assets/games/flight/scripts/runtime_defs.lua
Normal file
@@ -0,0 +1,589 @@
|
||||
---@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'|'yellow'|'blue'|'green'
|
||||
---@alias GamePhase 'waiting_roll'|'waiting_piece'|'animating'|'game_over'
|
||||
---@alias PieceStatus 'home'|'route'|'finished'
|
||||
|
||||
---@class (exact) PieceState
|
||||
---@field id string
|
||||
---@field owner PlayerColor
|
||||
---@field progress 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 pending_move? table
|
||||
---@field winner? PlayerColor
|
||||
---@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>
|
||||
22
example/assets/games/flight/scripts/state.lua
Normal file
22
example/assets/games/flight/scripts/state.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
---@type table
|
||||
return {
|
||||
players = { "red", "yellow", "blue", "green" },
|
||||
current_player = "red",
|
||||
phase = "waiting_roll",
|
||||
dice_index = 0,
|
||||
dice_values = { 6, 3, 4, 6, 2, 5, 1, 6, 4, 2, 6, 5 },
|
||||
dice = nil,
|
||||
selected_piece = nil,
|
||||
pending_move = nil,
|
||||
winner = nil,
|
||||
pieces = {
|
||||
red_1 = { id = "red_1", owner = "red", status = "home", progress = 0 },
|
||||
red_2 = { id = "red_2", owner = "red", status = "home", progress = 0 },
|
||||
yellow_1 = { id = "yellow_1", owner = "yellow", status = "home", progress = 0 },
|
||||
yellow_2 = { id = "yellow_2", owner = "yellow", status = "home", progress = 0 },
|
||||
blue_1 = { id = "blue_1", owner = "blue", status = "home", progress = 0 },
|
||||
blue_2 = { id = "blue_2", owner = "blue", status = "home", progress = 0 },
|
||||
green_1 = { id = "green_1", owner = "green", status = "home", progress = 0 },
|
||||
green_2 = { id = "green_2", owner = "green", status = "home", progress = 0 }
|
||||
}
|
||||
}
|
||||
81
example/assets/games/flight/scripts/styles.lua
Normal file
81
example/assets/games/flight/scripts/styles.lua
Normal file
@@ -0,0 +1,81 @@
|
||||
local theme = runtime.import("theme")
|
||||
local colors = theme.colors
|
||||
local styles = {}
|
||||
|
||||
styles.layers = {
|
||||
board = 1,
|
||||
cell = 2,
|
||||
home = 3,
|
||||
plane = 10,
|
||||
hud = 100,
|
||||
hud_content = 101
|
||||
}
|
||||
|
||||
styles.board = {
|
||||
color = colors.board,
|
||||
layer = styles.layers.board
|
||||
}
|
||||
|
||||
styles.center = {
|
||||
color = colors.board_inner,
|
||||
layer = styles.layers.board
|
||||
}
|
||||
|
||||
styles.route_cell = {
|
||||
anchor = "center",
|
||||
color = colors.route_cell,
|
||||
layer = styles.layers.cell
|
||||
}
|
||||
|
||||
styles.home_panel = function(owner)
|
||||
return {
|
||||
color = colors[owner .. "_home"],
|
||||
layer = styles.layers.home
|
||||
}
|
||||
end
|
||||
|
||||
styles.hud = {
|
||||
color = colors.top_bar,
|
||||
layer = styles.layers.hud
|
||||
}
|
||||
|
||||
styles.hud_text = {
|
||||
fontSize = 20,
|
||||
color = colors.text,
|
||||
layer = styles.layers.hud_content
|
||||
}
|
||||
|
||||
styles.small_text = {
|
||||
fontSize = 14,
|
||||
color = colors.muted_text,
|
||||
layer = styles.layers.hud_content
|
||||
}
|
||||
|
||||
styles.dice_button = {
|
||||
color = colors.dice_button,
|
||||
fontSize = 20,
|
||||
layer = styles.layers.hud_content
|
||||
}
|
||||
|
||||
styles.plane = function(owner)
|
||||
return {
|
||||
anchor = "center",
|
||||
color = colors[owner],
|
||||
layer = styles.layers.plane,
|
||||
interactive = true,
|
||||
onTap = "piece_tap",
|
||||
alpha = 0.95
|
||||
}
|
||||
end
|
||||
|
||||
styles.plane_highlight = {
|
||||
scale = 1.25,
|
||||
alpha = 1
|
||||
}
|
||||
|
||||
styles.plane_normal = {
|
||||
scale = 1,
|
||||
alpha = 0.95
|
||||
}
|
||||
|
||||
return styles
|
||||
22
example/assets/games/flight/scripts/theme.lua
Normal file
22
example/assets/games/flight/scripts/theme.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
return {
|
||||
title = "Lua 飞行棋",
|
||||
colors = {
|
||||
background = "#0f172a",
|
||||
board = "#1e293b",
|
||||
board_inner = "#334155",
|
||||
route_cell = "#f8fafc",
|
||||
route_text = "#0f172a",
|
||||
top_bar = "#020617",
|
||||
dice_button = "#2563eb",
|
||||
text = "#ffffff",
|
||||
muted_text = "#cbd5e1",
|
||||
red = "#ef4444",
|
||||
yellow = "#eab308",
|
||||
blue = "#3b82f6",
|
||||
green = "#22c55e",
|
||||
red_home = "#7f1d1d",
|
||||
yellow_home = "#713f12",
|
||||
blue_home = "#1e3a8a",
|
||||
green_home = "#14532d"
|
||||
}
|
||||
}
|
||||
130
example/assets/games/flight/scripts/ui.lua
Normal file
130
example/assets/games/flight/scripts/ui.lua
Normal file
@@ -0,0 +1,130 @@
|
||||
---@type RuntimeUi
|
||||
local runtime_ui = runtime.import("runtime_ui")
|
||||
---@type RuntimeLayout
|
||||
local layout = runtime.import("layout")
|
||||
local theme = runtime.import("theme")
|
||||
local styles = runtime.import("styles")
|
||||
local state = runtime.import("state")
|
||||
local board = runtime.import("board")
|
||||
local rules = runtime.import("rules")
|
||||
|
||||
local ui = {}
|
||||
|
||||
local function color_name(owner)
|
||||
if owner == "red" then return "红" end
|
||||
if owner == "yellow" then return "黄" end
|
||||
if owner == "blue" then return "蓝" end
|
||||
if owner == "green" then return "绿" end
|
||||
return owner
|
||||
end
|
||||
|
||||
local function piece_size(piece)
|
||||
if piece.status == "finished" then
|
||||
return 30
|
||||
end
|
||||
return 34
|
||||
end
|
||||
|
||||
function ui.highlight_updates(ids, enabled)
|
||||
return runtime_ui.batch_update(ids, enabled and styles.plane_highlight or styles.plane_normal)
|
||||
end
|
||||
|
||||
function ui.piece_position_update(piece_id)
|
||||
local piece = state.pieces[piece_id]
|
||||
local pos = rules.piece_position(piece)
|
||||
return runtime_ui.update(piece_id, {
|
||||
x = pos.x,
|
||||
y = pos.y,
|
||||
width = piece_size(piece),
|
||||
height = piece_size(piece),
|
||||
scale = 1,
|
||||
alpha = 0.95
|
||||
})
|
||||
end
|
||||
|
||||
function ui.piece_position_updates(ids)
|
||||
local updates = {}
|
||||
for _, id in ipairs(ids) do
|
||||
table.insert(updates, ui.piece_position_update(id))
|
||||
end
|
||||
return updates
|
||||
end
|
||||
|
||||
function ui.all_piece_position_updates()
|
||||
return ui.piece_position_updates(rules.all_piece_ids())
|
||||
end
|
||||
|
||||
function ui.create_board_nodes()
|
||||
local nodes = {
|
||||
runtime_ui.panel("board_panel", 28, 82, 664, 610, styles.board),
|
||||
runtime_ui.panel("center_airport", 252, 292, 168, 136, styles.center),
|
||||
runtime_ui.text("board_title", theme.title, 268, 318, 140, 32, styles.hud_text),
|
||||
runtime_ui.text("board_tip", "掷 6 起飞 · 撞子回家 · 全部到达获胜", 206, 360, 320, 28, styles.small_text),
|
||||
runtime_ui.panel("home_red", 62, 98, 128, 92, styles.home_panel("red")),
|
||||
runtime_ui.panel("home_yellow", 498, 98, 128, 92, styles.home_panel("yellow")),
|
||||
runtime_ui.panel("home_blue", 498, 516, 128, 92, styles.home_panel("blue")),
|
||||
runtime_ui.panel("home_green", 62, 516, 128, 92, styles.home_panel("green")),
|
||||
runtime_ui.text("label_red", "红方", 96, 102, 60, 24, styles.small_text),
|
||||
runtime_ui.text("label_yellow", "黄方", 532, 102, 60, 24, styles.small_text),
|
||||
runtime_ui.text("label_blue", "蓝方", 532, 520, 60, 24, styles.small_text),
|
||||
runtime_ui.text("label_green", "绿方", 96, 520, 60, 24, styles.small_text)
|
||||
}
|
||||
|
||||
for index, cell in ipairs(board.route) do
|
||||
runtime_ui.append(nodes, runtime_ui.circle("route_" .. tostring(index), cell.x, cell.y, 24, styles.route_cell))
|
||||
end
|
||||
|
||||
for _, owner in ipairs(state.players) do
|
||||
local start = board.route[board.start[owner]]
|
||||
runtime_ui.append(nodes, runtime_ui.text("start_" .. owner, color_name(owner), start.x - 14, start.y - 14, 36, 24, {
|
||||
fontSize = 14,
|
||||
color = theme.colors[owner],
|
||||
layer = styles.layers.cell + 1
|
||||
}))
|
||||
end
|
||||
|
||||
for id, piece in pairs(state.pieces) do
|
||||
local pos = rules.piece_position(piece)
|
||||
runtime_ui.append(nodes, runtime_ui.circle(id, pos.x, pos.y, piece_size(piece), styles.plane(piece.owner)))
|
||||
end
|
||||
|
||||
return nodes
|
||||
end
|
||||
|
||||
function ui.create_ui_nodes()
|
||||
local hud_items = layout.row("top_bar", {
|
||||
runtime_ui.text("turn_text", "当前: 红方", 0, 0, 120, 32, styles.hud_text),
|
||||
runtime_ui.text("dice_text", "骰子: -", 0, 0, 100, 32, styles.hud_text),
|
||||
runtime_ui.text("status_text", rules.status_text(), 0, 0, 260, 32, styles.hud_text),
|
||||
layout.item(
|
||||
runtime_ui.button("dice_button", "掷骰子", 0, 0, 120, 48, "roll_dice", styles.dice_button),
|
||||
{ marginLeft = 18 }
|
||||
)
|
||||
}, {
|
||||
x = 24,
|
||||
height = 76,
|
||||
gap = 16,
|
||||
align = "center"
|
||||
})
|
||||
|
||||
local nodes = { runtime_ui.panel("top_bar", 0, 0, 720, 76, styles.hud) }
|
||||
return runtime_ui.append_all(nodes, hud_items)
|
||||
end
|
||||
|
||||
function ui.turn_name(owner)
|
||||
return "当前: " .. color_name(owner) .. "方"
|
||||
end
|
||||
|
||||
function ui.dice_and_status_updates()
|
||||
return {
|
||||
runtime_ui.text_update("dice_text", "骰子: " .. tostring(state.dice or "-")),
|
||||
runtime_ui.text_update("turn_text", ui.turn_name(state.current_player)),
|
||||
runtime_ui.text_update("status_text", rules.status_text())
|
||||
}
|
||||
end
|
||||
|
||||
function ui.status_update()
|
||||
return { runtime_ui.text_update("status_text", rules.status_text()) }
|
||||
end
|
||||
|
||||
return ui
|
||||
Reference in New Issue
Block a user