📝 应用描述
Galaga 风格的夜蔷城堡 2D 文本射击小游戏,守住裂隙并完成刘烨与夏冉的故事。
📋 详细信息
| 应用ID |
night_rose_galaga |
| 名称 |
夜蔷裂隙防御战 |
| 版本 |
v1 |
| 文件大小 |
4 KB |
| 上传时间 |
2026-07-29 20:51:28 |
| 状态 |
✅ 已启用 |
💡 界面预览 (main.lua)
📄 Lua 源码
local W = 9
local H = 6
local phase = "intro"
local player_x = 5
local lives = 3
local score = 0
local wave = 1
local energy = 2
local turn = 0
local shield = false
local enemies = {}
local boss_hp = 0
local ending_shown = false
local story_intro = table.concat({
"【夜蔷城堡·主厅】",
"刘烨在陌生的古堡中醒来,夏冉站在回廊尽头。",
"祖父从裂隙另一头来电:狼人群正在冲门,夜蔷城堡是连接表界与里界的节点。",
"夏冉教他打开脑中的“现实重构”模块。",
"这一次,防御术被重构成一架银星战机。你要在天亮前守住五道裂隙。"
}, "\n")
local story_win = table.concat({
"【终章·裂隙闭合】",
"裂隙之眼在银星炮火中崩解,夜蔷城堡上空第一次出现真正的黎明。",
"夏冉收起短刃,轻声说:'你祖父没有选错人。'",
"刘烨看着掌心逐渐熄灭的数据流,终于明白自己不是被困在城堡里,而是接过了一座城的守夜。",
"表界与里界的门重新合拢。狼人退入黑暗,夜蔷花在晨光里盛开。",
"故事完结:刘烨成为新一任渡梦者,夏冉与他共同守护夜蔷节点。"
}, "\n")
local function wave_title()
if wave == 1 then
return "第一波:铁栅门前的狼影"
elseif wave == 2 then
return "第二波:中庭上空的裂隙虫群"
elseif wave == 3 then
return "第三波:钟楼坠落的黑羽"
elseif wave == 4 then
return "第四波:祖父留下的旧防线"
else
return "最终战:裂隙之眼"
end
end
local function story_for_wave()
if wave == 1 then
return "夏冉:'别怕,银星炮会回应你的意志。先把正门守住。'"
elseif wave == 2 then
return "刘烨追到中庭,裂隙虫群像旧电视雪花一样扑来。"
elseif wave == 3 then
return "钟楼破碎,黑羽怪从夜空俯冲。夏冉提醒你:'别让它们贴近核心。'"
elseif wave == 4 then
return "祖父的声音从通讯器里响起:'小烨,最后一道旧防线交给你了。'"
else
return "裂隙睁开巨大的眼睛。只要击碎它,夜蔷城堡就能迎来黎明。"
end
end
local function add_enemy(x, y, hp, mark)
enemies[#enemies + 1] = { x = x, y = y, hp = hp, mark = mark }
end
local function spawn_wave()
enemies = {}
turn = 0
shield = false
energy = energy + 1
if energy > 4 then
energy = 4
end
if wave == 1 then
add_enemy(3, 1, 1, "w")
add_enemy(5, 1, 1, "w")
add_enemy(7, 1, 1, "w")
elseif wave == 2 then
add_enemy(2, 1, 1, "x")
add_enemy(4, 1, 1, "x")
add_enemy(6, 1, 1, "x")
add_enemy(8, 1, 1, "x")
elseif wave == 3 then
add_enemy(1, 1, 1, "v")
add_enemy(3, 2, 1, "v")
add_enemy(5, 1, 1, "v")
add_enemy(7, 2, 1, "v")
add_enemy(9, 1, 1, "v")
elseif wave == 4 then
add_enemy(2, 1, 2, "W")
add_enemy(5, 1, 2, "W")
add_enemy(8, 1, 2, "W")
else
boss_hp = 7
add_enemy(3, 1, 1, "e")
add_enemy(7, 1, 1, "e")
end
end
local function cell_at(x, y)
if y == H and x == player_x then
return "A"
end
if wave >= 5 and y == 1 and x >= 4 and x <= 6 and boss_hp > 0 then
return "O"
end
local i
for i = 1, #enemies do
if enemies[i].x == x and enemies[i].y == y then
return enemies[i].mark
end
end
return "."
end
local function build_grid()
local lines = {}
local y
for y = 1, H do
local row = {}
local x
for x = 1, W do
row[#row + 1] = cell_at(x, y)
end
lines[#lines + 1] = table.concat(row, " ")
end
return table.concat(lines, "\n")
end
local function render(message)
local status = "章节:" .. wave_title() ..
"\n生命:" .. tostring(lives) ..
" 能量:" .. tostring(energy) ..
" 分数:" .. tostring(score)
if wave >= 5 then
status = status .. " 裂隙之眼:" .. tostring(boss_hp)
else
status = status .. " 敌人:" .. tostring(#enemies)
end
if shield then
status = status .. "\n状态:概念墙已展开,下一次伤害会被抵消。"
else
status = status .. "\n状态:银星战机待命。"
end
app.set_text("story", story_for_wave())
app.set_text("status", status)
app.set_text("field", build_grid())
app.set_text("message", message or "操作:左右移动,发射银星,阻止敌群触底。")
end
local function show_intro()
phase = "intro"
app.set_text("story", story_intro)
app.set_text("status", "玩法:Galaga 风格回合制 2D 射击\n目标:清除四波敌群,并击败最终 Boss“裂隙之眼”。")
app.set_text("field", ". . . O . O . . .\n. . . . . . . . .\n. w . w . w . w .\n. . . . . . . . .\n. . . . . . . . .\n. . . . A . . . .")
app.set_text("message", "点击“剧情/开始”进入夜蔷裂隙防御战。")
end
local function show_ending()
phase = "ending"
ending_shown = true
app.set_text("story", story_win)
app.set_text("status", "通关完成\n最终分数:" .. tostring(score) .. "\n结局:夜蔷黎明")
app.set_text("field", ". . . . * . . . .\n. . * . . . * . .\n. . . \\ | / . . .\n* . . - ☼ - . . *\n. . . / | \\ . . .\n. . . . A . . . .")
app.set_text("message", "你守住了夜蔷节点。点击“重新开始”可以再次挑战。")
end
local function game_over()
phase = "over"
app.set_text("story", "【坏结局·城堡失守】\n裂隙吞没中庭,夏冉把刘烨推出门外。通讯器里只剩祖父的杂音。\n但渡梦印没有熄灭,只要重新开始,故事仍能改写。")
app.set_text("status", "挑战失败\n最终分数:" .. tostring(score))
app.set_text("field", "x x x x x x x x x\nx . . . O . . . x\nx . . O O O . . x\nx . . . O . . . x\nx x x x x x x x x\n. . . . A . . . .")
app.set_text("message", "点击“重新开始”再守一次夜蔷城堡。")
end
local function reset_game()
phase = "intro"
player_x = 5
lives = 3
score = 0
wave = 1
energy = 2
turn = 0
shield = false
boss_hp = 0
ending_shown = false
enemies = {}
show_intro()
end
local function start_game()
phase = "play"
player_x = 5
lives = 3
score = 0
wave = 1
energy = 2
ending_shown = false
spawn_wave()
render("现实重构完成:银星战机上线。夏冉在城墙上为你掩护。")
end
local function next_wave()
wave = wave + 1
if wave > 5 then
show_ending()
else
spawn_wave()
render("裂隙震动,新的敌群出现。\n" .. story_for_wave())
end
end
local function hit_player(reason)
if shield then
shield = false
app.toast("概念墙挡下了攻击")
return "概念墙挡下了" .. reason
end
lives = lives - 1
if lives <= 0 then
game_over()
return "生命耗尽"
end
return reason .. ",生命 -1"
end
local function enemy_step()
turn = turn + 1
local note = ""
if wave >= 5 and boss_hp > 0 and turn % 3 == 0 then
if player_x >= 4 and player_x <= 6 then
note = hit_player("裂隙之眼的凝视命中银星战机")
else
note = "裂隙之眼扫射中路,你及时避开。"
end
end
if phase ~= "play" then
return note
end
if turn % 2 == 0 then
local i
for i = #enemies, 1, -1 do
enemies[i].y = enemies[i].y + 1
if enemies[i].y >= H then
local reason = "敌人突破底线"
table.remove(enemies, i)
note = hit_player(reason)
if phase ~= "play" then
return note
end
end
end
end
return note
end
local function clear_if_done(message)
if phase ~= "play" then
return
end
if wave >= 5 and boss_hp <= 0 then
score = score + 50
show_ending()
return
end
if #enemies == 0 and wave < 5 then
score = score + 10
next_wave()
return
end
render(message)
end
local function move_left()
if phase ~= "play" then
app.toast("先点击“剧情/开始”")
return
end
if player_x > 1 then
player_x = player_x - 1
end
local note = enemy_step()
clear_if_done(note ~= "" and note or "银星战机左移。")
end
local function move_right()
if phase ~= "play" then
app.toast("先点击“剧情/开始”")
return
end
if player_x < W then
player_x = player_x + 1
end
local note = enemy_step()
clear_if_done(note ~= "" and note or "银星战机右移。")
end
local function fire()
if phase ~= "play" then
app.toast("先点击“剧情/开始”")
return
end
local hit_index = 0
local best_y = H + 1
local i
for i = 1, #enemies do
if enemies[i].x == player_x and enemies[i].y < best_y then
hit_index = i
best_y = enemies[i].y
end
end
local message = ""
if hit_index > 0 then
enemies[hit_index].hp = enemies[hit_index].hp - 1
if enemies[hit_index].hp <= 0 then
table.remove(enemies, hit_index)
score = score + 5
message = "银星命中,敌机碎成黑色花瓣。"
else
score = score + 2
message = "银星击中重甲狼人,还需要一次命中。"
end
elseif wave >= 5 and player_x >= 4 and player_x <= 6 and boss_hp > 0 then
boss_hp = boss_hp - 1
score = score + 8
message = "银星穿透瞳孔,裂隙之眼 HP -1。"
else
message = "银星划过夜空,没有命中目标。"
end
if phase == "play" then
local note = enemy_step()
if note ~= "" then
message = message .. "\n" .. note
end
end
clear_if_done(message)
end
local function guard()
if phase ~= "play" then
app.toast("先点击“剧情/开始”")
return
end
if energy <= 0 then
app.toast("能量不足")
return
end
energy = energy - 1
shield = true
local note = enemy_step()
clear_if_done(note ~= "" and note or "你展开概念墙,下一次伤害将被抵消。")
end
local function story_button()
if phase == "intro" then
start_game()
elseif phase == "play" then
render(story_for_wave())
elseif phase == "ending" and ending_shown then
app.toast("故事已经完结:夜蔷黎明")
else
show_intro()
end
end
return ui.page({
title = "夜蔷裂隙防御战",
children = {
ui.text({
text = "夜蔷裂隙防御战",
size = 22,
center = true,
color = "#D86B8A",
margin = 8
}),
ui.text({
id = "story",
text = story_intro,
size = 14,
color = "#5F6470",
margin = 8
}),
ui.text({
id = "status",
text = "玩法:Galaga 风格回合制 2D 射击\n目标:清除四波敌群,并击败最终 Boss“裂隙之眼”。",
size = 14,
color = "#2F4858",
margin = 8
}),
ui.text({
id = "field",
text = ". . . O . O . . .\n. . . . . . . . .\n. w . w . w . w .\n. . . . . . . . .\n. . . . . . . . .\n. . . . A . . . .",
size = 18,
color = "#101820",
center = true,
margin = 8
}),
ui.text({
id = "message",
text = "点击“剧情/开始”进入夜蔷裂隙防御战。",
size = 14,
color = "#8A3D5A",
margin = 8
}),
ui.list({
children = {
ui.button({
text = "剧情 / 开始",
on_click = function()
story_button()
end
}),
ui.button({
text = "← 左移",
on_click = function()
move_left()
end
}),
ui.button({
text = "发射银星",
on_click = function()
fire()
end
}),
ui.button({
text = "右移 →",
on_click = function()
move_right()
end
}),
ui.button({
text = "构筑护盾",
on_click = function()
guard()
end
}),
ui.button({
text = "重新开始",
on_click = function()
reset_game()
end
})
}
})
}
})