0%

硬编码功能列表

这里列出 Luanti 引擎里写死、无法被模组自定义的功能。
长期目标是把这些都改成可配置,但目前暂时改不了。


游戏玩法

血量与伤害

  • 坠落伤害计算公式是写死的
  • 伤害方块固定 1 秒掉一次血,不能改间隔
  • 氧气机制写死:
    • 每 2 秒掉一次氧气或溺水伤害
    • 每 0.5 秒恢复一次氧气
  • 受伤时的屏幕变红效果时长固定
  • 受伤时的屏幕震动固定

物品

  • 工具挖掘速度公式写死(只能改参数,不能改公式)
  • 工具耐久损耗公式写死
  • 所有物品都能指向方块,无法关闭
  • range=0 不生效,因为在方块内部依然能指向

玩家

  • 所有相机模式永远可用,无法禁用或强制

画面表现

  • 受伤屏幕闪红
  • 受伤屏幕震动
  • 太阳光带轻微黄色
  • 黑暗带轻微蓝色
  • 光照曲线固定(每个亮度等级的显示效果)
  • 全局光色固定
  • 物品 3D 展示模型:角度、旋转写死
  • inventory_image 只支持 2D 图
  • 挖掘粒子的数量、大小、生命周期写死
  • 手持物品/空手的画面表现几乎不能自定义

HUD 界面

  • 聊天窗口位置不能被模组移动
  • 状态提示文字(如“已开启飞行模式”)不能移动或隐藏
  • Formspec 样式大量写死,无法自定义:
    • 滚动条
    • 下拉框
    • 选中文本高亮色
    • 文字阴影

控制按键

  • 鼠标滚轮固定切换快捷栏,无法改绑其他功能

可以接受的硬编码(没问题)

  • Esc 键 = 暂停/退出
  • 调试界面内容(但可选择显示多少)
  • WASD / 摇杆移动

引擎限制

这一页列出 Luanti 引擎目前存在的各种限制,也可以看作是未来的“愿望清单”。
另见:硬编码功能列表(引擎里写死、无法轻易修改的行为)。


在客户端运行代码

  • 模组默认只在服务端运行,不在客户端运行。
  • 虽然有客户端模组 API(CSM),但功能非常有限,且需要玩家手动安装。
  • SSCSM(服务端下发客户端模组) 理论上能解决这个问题,但目前并未完整实现

检测自定义按键

脚本 API 无法检测任意按键
你只能使用 get_player_control() 里已有的固定按键。
只有 Aux1 键可以勉强拿来做自定义功能。


动态修改方块纹理

  • 你可以用 param2 给方块改色,但不能直接修改方块本身的纹理
  • 想要切换纹理,必须注册多个不同纹理的方块,然后在游戏里互换方块实现。

授权许可

很多基于 Luanti 开发的游戏出现在了安卓应用商店,这些大多属于修改版(分支)
如果你要发布自己的游戏,必须遵守 LGPL 开源协议,不然就是侵权。


遵守协议的核心要求

Luanti 引擎和 Minetest Game 均使用 LGPL 2.1+ 自由软件许可证
以下是你必须做到的事情:

  1. 必须公开源码

    • 如果你修改了引擎或游戏,必须提供你修改后的完整源码
    • 没修改也要提供官方原版源码链接
    • 源码必须同样以 LGPL 2.1+ 或兼容协议发布
  2. 不能删除版权声明
    任何地方都不能删掉原作者与社区的版权信息。

  3. 必须说明你做了哪些修改
    重大改动要明确写出来。

  4. 禁止闭源代码与 LGPL 代码混写
    不能把开源和私有代码锁死在一起。

  5. 必须在下载页/游戏内显示署名
    示例署名(直接抄):

    1
    2
    3
    本应用使用 Luanti 引擎(及 Minetest Game)
    版权 2010-2018 Perttu Ahola 及贡献者
    基于 LGPLv2.1+ 协议授权

源码链接放哪里?

  • 应用商店介绍页
  • 官网
  • 游戏内** credits(致谢)页面**
  • 主菜单(强烈建议放)

如果我用了闭源库/广告SDK?

⚠️ 严禁混编!

  • 闭源代码(广告、统计、付费SDK)不能和 LGPL 代码耦合
  • 用户必须能替换掉 LGPL 部分继续使用你的软件
  • 你必须提供替换编译方法
  • 闭源代码不能阻碍用户调试/修改 LGPL 部分
  • 必须显眼声明使用了 Luanti 引擎

简单说:
你要把引擎当纯库调用,Java 层全部重写,不能动引擎核心。


发现侵权盗版怎么办?

如果你看到有人盗用 Luanti 代码、不公开源码、乱改协议

  1. 先检查它是否公布源码、是否标注 LGPL
  2. 确认侵权后,联系 celeron55
  3. 或去 Luanti IRC 频道举报
  4. 论坛有专门帖子记录安卓盗版分支,你可以补充

绝对不要做这些事!

  • ❌ 不要网暴、挂人、发动攻击
  • ❌ 不要破解、炸服、搞破坏
  • ❌ 不要自己去骂侵权作者
  • ❌ 不要私下对抗

私下报复只会造成舆论反转,让侵权者反而占据优势。
全部交给官方团队处理!

L‑System 自动种树教程

Luanti 内置两种树:

  1. 简单小树(原版 MTG 那种)
  2. L‑System 智能大树(用公式自动生成复杂树形)

L‑System 树用 core.spawn_tree 生成,靠一个 treedef 表格完全定义。


核心原理:海龟绘图(Turtle Graphics)

你可以把它当成一只会画图的笔(海龟)

  • 移动
  • 旋转
  • 放方块(树干/树叶/果实)

移动指令

符号作用
G抬笔前进(不放方块)
F落笔前进(放树枝)
f落笔前进(放树叶)
T落笔前进(只放树干)
R落笔前进(放果实)

旋转指令

符号作用
+向右转(偏航)
-向左转(偏航)
&向下低头
^向上抬头
/向右滚转
*向左滚转

海龟初始朝上


公理(Axiom)

就是起始指令串,海龟从这行命令开始执行。

例子:

  • 公理 TTTT → 垂直向上长 4 格树干
  • 公理 TTTTT&TTTTT&TTTTT&TTTTT + 角度 90° → 画出一个正方形

栈(保存/恢复状态)

符号作用
[保存当前位置+方向
]读档回到保存点

用来长分叉

例子:
TTTTT[^TTTTT][&TTTTT] + 60° → 直接长成 Y 字形树


L‑System 基础:替换规则

A/B/C/D 会被递归替换成对应规则,直到达到最大迭代次数。

符号作用
A替换成规则 A
B替换成规则 B
C替换成规则 C
D替换成规则 D

举个栗子:Y 形分形树

公理:TTTTTA
规则 A:[^TTTTTA][&TTTTTA]

迭代 3 次后,就会变成一棵超级分叉树,顶端有 8 个分叉。


概率替换(随机树形)

小写 a/b/c/d 有概率触发,让树长得自然不重复:

符号概率
a90% 执行 A
b80% 执行 B
c70% 执行 C
d60% 执行 D

L‑System 树实例(直接复制可用)

巨型枯灌木

1
2
3
4
5
6
7
8
9
10
11
treedef={
axiom = "A/A/A/A/A/A/A/A/A/A/A/A",
rules_a = "[B+B+B+B]",
rules_b = "[FFFFFFFFFF]",
trunk = "mapgen_tree",
angle = 30,
iterations = 1,
random_level = 0,
trunk_type = "single",
thin_branches = true
}

苹果树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
treedef = {
axiom="FFFFFAFFBF",
rules_a="[&&&FFFFF&&FFFF][&&&++++FFFFF&&FFFF][&&&----FFFFF&&FFFF]",
rules_b="[&&&++FFFFF&&FFFF][&&&--FFFFF&&FFFF][&&&------FFFFF&&FFFF]",
trunk="mapgen_tree",
leaves="mapgen_leaves",
angle=30,
iterations=2,
random_level=0,
trunk_type="single",
thin_branches=true,
fruit_chance=10,
fruit="mapgen_apple",
}

金合欢树(Acacia)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
treedef={
axiom="FFFFFFccccA",
rules_a = "[B]//[B]//[B]//[B]",
rules_b = "&TTTT&TT^^G&&----GGGGGG++GGG++"
.."fffffffGG++G++"
.."Gffffffff--G--"
.."ffffffffG++G++"
.."fffffffff--G--"
.."fffffffff++G++"
.."fffffffff--G--"
.."ffffffffG++G++"
.."Gffffffff--G--"
.."fffffffGG"
.."^^G&&----GGGGGGG++GGGGGG++"
.."ffffGGG++G++"
.."GGfffff--G--"
.."ffffffG++G++"
.."fffffff--G--"
.."ffffffG++G++"
.."GGfffff--G--"
.."ffffGGG",
rules_c = "/",
trunk="default:acacia_tree",
leaves="default:acacia_leaves",
angle=45,
iterations=3,
random_level=0,
trunk_type="single",
thin_branches=true,
}

保持世界兼容

如果你的游戏或模组已经稳定、有很多玩家在玩,尽量保持对旧世界的兼容非常重要!
不然玩家升级后会出现未知方块、贴图错误、数据崩坏,直接炸档。


别名(Aliases)

方块和物品都支持名称别名,可以把旧的内部名称映射到新名称。

最简单的用法:

1
core.register_alias('mymod:旧物品名', 'mymod:新物品名')

批量重命名/重构模组命名空间时超好用:

1
2
3
4
5
for _, item in ipairs({
"stone", "cobble", "dirt", "grass"
}) do
core.register_alias('旧模组名:'..item, '新模组名:'..item)
end

加载块修正器(LBM)

LBM = Loading Block Modifier
用于在地图块加载时自动对方块执行修复逻辑,适合处理复杂升级,比如:

  • 更新方块的界面(formspec)
  • 修复元数据(meta)
  • 升级方块状态

示例:升级方块表单到 v2 版本

1
2
3
4
5
6
7
8
9
10
11
12
13
core.register_lbm({
label = "把酷炫方块的UI升级到v2",
name = "mymod:update_formspec_coolblock_v2",
nodenames = {"mymod:coolblock"},
run_at_every_load = false, -- 只跑一次
action = function(pos, node)
local meta = core.get_meta(pos)
if meta:get_int('form_ver') < 2 then
meta:set_int('form_ver', 2)
meta:set_string('formspec', get_coolblock_formspec())
end
end
})

空手(手)

空手是 Luanti 里最基础的“工具”,可以挖方块、打人,不同游戏效果会不一样。空手就是你啥也不拿时的默认状态。


隐形的“空手机制”

  • 你拿着非工具物品(比如石头)时,效果 = 空手
  • 用不对口的工具挖方块(比如用镐挖泥土),速度 = 空手,且不掉耐久
  • 只要能徒手挖的方块,都会按空手速度计算

Minetest Game 里的空手

空手能挖一些软方块,但速度很慢:
沙子、泥土、木头、树叶、玻璃等都能徒手挖。

空手属性:

  • 攻击间隔:0.9 秒
  • 伤害:1 点生命值(0.5 颗心)
  • 指向距离:4 格

常用挖掘速度(徒手)

  • 泥土、沙子:0.70 秒
  • 苹果树叶、草块:0.40 秒
  • 苹果树树干:3.50 秒
  • 苹果木木板:2.0 秒

创造模式下的空手

在 MTG 创造模式里,空手直接超神

  • 指向距离拉到 10 格
  • 伤害提升到 10 点(5 颗心)
  • 几乎能秒挖所有方块
  • 挖掘速度大幅加快

你的第一个生物

这篇教程带你从零做一只简单的攻击型怪物,名字叫 Bloblet(小绿团)
教程会教你实体(entity)基础用法——凡是比方块更“能动”的东西,全都靠实体实现。

前提:你已经有一个基础模组 mymod,要编辑 mymod/init.lua
版本要求:Luanti 5.5.0 及以上

阅读全文 »

分组(Groups)

分组是 Luanti 里方块、物品、工具的核心分类机制。
任何东西都可以属于一个或多个分组,也可以不属于任何分组。
分组主要用于:合成配方、伤害计算、挖掘时间,以及各种游戏逻辑。


小提示

下面这些是 Minetest Game 默认分组,其他游戏/模组可能会魔改,不一定通用。


用于合成配方的普通分组

  • wood:木头类
  • stone:石头、圆石、石砖、沙漠石、沙漠石砖
  • sand:沙子、沙漠沙
  • flora:花(蒲公英、玫瑰、郁金香等)+ 小型植物
  • leaves:树叶

决定伤害与挖掘时间的分组

  • oddly_breakable_by_hand:徒手就能挖掉
  • crumbly:松软类(泥土、沙子)→ 铲子最快
  • cracky:坚硬类(石头类)→ 最快
  • choppy:可砍断类(树、木板)→ 最快
  • fleshy:生物/玩家血肉类 → 伤害最高
  • snappy:易剪断类(树叶、植物、线、薄金属)→ 剑可挖,但掉耐久快
  • explody:极易被炸飞

特殊分组(节选)

  • dig_immediate:瞬间挖掘
  • soil:土壤组,树苗能在上面生长

游戏主题重实现

主菜单里负责背景、标题栏等主题的逻辑,默认是用 mm_game_theme(在 game_theme.lua 里)实现的。
如果你只是想给所有页面统一用一张背景 + 一个标题图,完全没必要去啃这套复杂逻辑。


mm_game_theme 到底干了啥?

它本质就是封装调用了这个核心函数:
core.set_background
用来设置:背景、顶部标题、底部栏、覆盖层。

函数用法:

1
core.set_background(类型, 图片路径, 是否平铺, 最小尺寸)
  • type:background(背景)、overlay(覆盖层)、header(顶部标题)、footer(底部)
  • tile:是否平铺(只对背景有效)
  • minsize:平铺前最小缩放尺寸

极简重写示例(直接抄就能用)

下面是来自 Voxelmanip Classic 的超简方案,
直接替换掉 mm_game_theme,实现静态背景 + 固定标题

1
2
3
4
5
6
7
8
-- 设置顶部标题
core.set_background('header', defaulttexturedir .. "menu_header.png")

-- 设置主背景
core.set_background('background', defaulttexturedir .. "menu_bg.png")

-- 关闭云层动画
core.set_clouds(false)

把这段代码放进 init_globals() 函数里
直接删掉原来调用 mm_game_theme 的代码就行。

脱离 ContentDB 分发游戏

这篇教你不依赖官方商店,把你的 Luanti 游戏打包成独立客户端发布。
前提:你得会从源码编译 Luanti。

Luanti 引擎本身没有官方一键导出功能,游戏默认都走 ContentDB、在游戏内安装。但因为 Luanti 是自由软件,你可以fork 引擎 → 改头换面 → 绑定你的游戏 → 独立发布

阅读全文 »