城市一夜
关于本教程
本教程是免费且开源的,所有代码均使用 MIT 许可证 - 因此您可以随意使用。我希望您喜欢本教程,并制作出色的游戏!
如果您喜欢这个教程并希望我继续写作,请考虑支持我的 Patreon。
游戏的下一关是一个黑暗精灵城市。设计文档在细节上有些简略,但这是我们所知道的:
- 它最终通向一个前往深渊的传送门。
- 黑暗精灵天生好斗,尔虞我诈,应该表现得像那样。
- 黑暗精灵城市出奇地像城市,只是位于地下深处。
- 光照将非常重要。
生成一个基础城市
map_builders/mod.rs
中的 level_builder
函数控制为给定关卡调用哪个地图算法。为新的地图类型添加一个占位符条目:
#![allow(unused)] fn main() { pub fn level_builder(new_depth: i32, width: i32, height: i32) -> BuilderChain { rltk::console::log(format!("Depth: {}", new_depth)); match new_depth { 1 => town_builder(new_depth, width, height), 2 => forest_builder(new_depth, width, height), 3 => limestone_cavern_builder(new_depth, width, height), 4 => limestone_deep_cavern_builder(new_depth, width, height), 5 => limestone_transition_builder(new_depth, width, height), 6 => dwarf_fort_builder(new_depth, width, height), 7 => mushroom_entrance(new_depth, width, height), 8 => mushroom_builder(new_depth, width, height), 9 => mushroom_exit(new_depth, width, height), 10 => dark_elf_city(new_depth, width, height), _ => random_builder(new_depth, width, height) } } }
在同一文件的顶部,为新的 builder 模块添加导入:
#![allow(unused)] fn main() { mod dark_elves; use dark_elves::*; }
并创建新的 map_builders/dark_elves.rs
文件,并在其中放置一个占位符 builder:
#![allow(unused)] fn main() { use super::{BuilderChain, XStart, YStart, AreaStartingPosition, CullUnreachable, VoronoiSpawning, AreaEndingPosition, XEnd, YEnd, BspInteriorBuilder }; pub fn dark_elf_city(new_depth: i32, width: i32, height: i32) -> BuilderChain { println!("Dark elf builder"); // 黑暗精灵生成器 let mut chain = BuilderChain::new(new_depth, width, height, "Dark Elven City"); chain.start_with(BspInteriorBuilder::new()); chain.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER)); chain.with(CullUnreachable::new()); chain.with(AreaStartingPosition::new(XStart::RIGHT, YStart::CENTER)); chain.with(AreaEndingPosition::new(XEnd::LEFT, YEnd::CENTER)); chain.with(VoronoiSpawning::new()); chain } }
这创建了一个完全不像城市的地图(只是一个 bsp 内部地图)——但这是一个好的开始。我选择这个作为基础 builder,因为它不浪费任何空间。我喜欢想象这座城市是一个巨大的相互连接的房间组成的迷宫,较贫穷的精灵住在危险的地方(顶部)。因此,我们将在这一层填充相对“正常”的黑暗精灵和他们的奴隶。
添加一些黑暗精灵
如果我们只是想在到处放置黑暗精灵,那么只需在 spawns.json
的 spawn_table
部分添加一行即可:
{ "name": "Dark Elf", "weight": 10, "min_depth": 10, "max_depth": 11 }
那样太无聊了,所以我们不那样做。我们的黑暗精灵分为 Arbat 氏族、Barbo 氏族 和 Cirro 氏族(A、B、C,明白了吗?)。由于 YALA 护身符的深渊影响,他们内部充满了可怕的争斗和战争!我们稍后会担心区分氏族,现在让我们先创建一些条目,提供三组互相憎恨的黑暗精灵。
在 spawns.json
的 factions
部分,创建三个新的派系:
{ "name" : "DarkElfA", "responses" : { "Default" : "attack", "DarkElfA" : "ignore", "DarkElfB" : "attack", "DarkElfC" : "attack" } },
{ "name" : "DarkElfB", "responses" : { "Default" : "attack", "DarkElfB" : "ignore", "DarkElfA" : "attack", "DarkElfC" : "attack" } },
{ "name" : "DarkElfC", "responses" : { "Default" : "attack", "DarkElfC" : "ignore", "DarkElfA" : "attack", "DarkElfB" : "attack" } }
请注意他们如何忽略自己的氏族,并攻击其他氏族。这是制造战区的关键!我们的派系系统已经支持交战团体——我们只是没有广泛使用它。现在找到 mobs
部分,并将“Dark Elf”复制三次——每个派系一次:
{
"name" : "Arbat Dark Elf",
"renderable": {
"glyph" : "e",
"fg" : "#FF0000",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "random_waypoint",
"attributes" : {},
"equipped" : [ "Hand Crossbow", "Scimitar", "Buckler", "Drow Chain", "Drow Leggings", "Drow Boots" ],
"faction" : "DarkElfA",
"gold" : "3d6",
"level" : 6
},
{
"name" : "Barbo Dark Elf",
"renderable": {
"glyph" : "e",
"fg" : "#FF0000",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "random_waypoint",
"attributes" : {},
"equipped" : [ "Hand Crossbow", "Scimitar", "Buckler", "Drow Chain", "Drow Leggings", "Drow Boots" ],
"faction" : "DarkElfB",
"gold" : "3d6",
"level" : 6
},
{
"name" : "Cirro Dark Elf",
"renderable": {
"glyph" : "e",
"fg" : "#FF0000",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "random_waypoint",
"attributes" : {},
"equipped" : [ "Hand Crossbow", "Scimitar", "Buckler", "Drow Chain", "Drow Leggings", "Drow Boots" ],
"faction" : "DarkElfC",
"gold" : "3d6",
"level" : 6
},
在 spawn 表中,我们希望它们出现在 10 级:
{ "name" : "Arbat Dark Elf", "weight": 10, "min_depth": 10, "max_depth": 11 },
{ "name" : "Barbo Dark Elf", "weight": 10, "min_depth": 10, "max_depth": 11 },
{ "name" : "Cirro Dark Elf", "weight": 10, "min_depth": 10, "max_depth": 11 }
如果你现在 cargo run
,并作弊下到 10 层(我建议使用上帝模式和传送)——你会发现自己身处三个氏族之间的战区之中。到处都是战斗,他们只会在互相残杀的间隙停下来谋杀玩家。这里有大量的混乱——混沌之神会感到自豪的。
氏族区分
让所有氏族都一模一样有点无聊。基本的“Dark Elf”可以保持不变,但让我们添加一些特色,使氏族 感觉 与众不同。
Arbat 氏族
我们将首先使 Arbat 氏族变成不同的颜色——更浅的红色。将他们的 Dark Elf 的 “fg” 属性替换为 #FFAAAA
——一种粉红色。我们也将拿走他们的弩。他们是一个以近战为主的氏族。将 Scimitar
替换为 Scimitar +1
。修改后的 Arbat Dark Elf
看起来像这样:
{
"name" : "Arbat Dark Elf",
"renderable": {
"glyph" : "e",
"fg" : "#FFAAAA",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "random_waypoint",
"attributes" : {},
"equipped" : [ "Scimitar +1", "Buckler", "Drow Chain", "Drow Leggings", "Drow Boots" ],
"faction" : "DarkElfA",
"gold" : "3d6",
"level" : 6
},
我们也给他们一些首领——更强大的战士:
{
"name" : "Arbat Dark Elf Leader",
"renderable": {
"glyph" : "E",
"fg" : "#FFAAAA",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "random_waypoint",
"attributes" : {},
"equipped" : [ "Scimitar +2", "Buckler +1", "Drow Chain", "Drow Leggings", "Drow Boots" ],
"faction" : "DarkElfA",
"gold" : "3d6",
"level" : 7
},
他们也应该得到一些兽人奴隶:
{
"name" : "Arbat Orc Slave",
"renderable": {
"glyph" : "o",
"fg" : "#FFAAAA",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "static",
"attributes" : {},
"faction" : "DarkElfA",
"gold" : "1d8"
},
最后,将这些放入 spawn 表:
{ "name" : "Arbat Dark Elf", "weight": 10, "min_depth": 10, "max_depth": 11 },
{ "name" : "Arbat Dark Elf Leader", "weight": 7, "min_depth": 10, "max_depth": 11 },
{ "name" : "Arbat Orc Slave", "weight": 14, "min_depth": 10, "max_depth": 11 },
他们可能会后悔专注于近战,但我们不太关心他们的健康!
Barbo 氏族
相反,我们将使 Barbo 氏族非常侧重于远程武器——并且更加稀有,因为那样非常危险。我们还将给他们一把匕首而不是弯刀,并将他们的颜色改为橙色:
{
"name" : "Barbo Dark Elf",
"renderable": {
"glyph" : "e",
"fg" : "#FF9900",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "random_waypoint",
"attributes" : {},
"equipped" : [ "Hand Crossbow +1", "Dagger", "Buckler", "Drow Chain", "Drow Leggings", "Drow Boots" ],
"faction" : "DarkElfB",
"gold" : "3d6",
"level" : 6
},
他们也得到一些奴隶——这次是地精,带有远程武器:
{
"name" : "Barbo Goblin Archer",
"renderable": {
"glyph" : "g",
"fg" : "#FF9900",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "static",
"attributes" : {},
"faction" : "Cave Goblins",
"gold" : "1d6",
"equipped" : [ "Shortbow", "Leather Armor", "Leather Boots" ]
},
最后,更新 spawns 表以包含它们:
{ "name" : "Barbo Dark Elf", "weight": 9, "min_depth": 10, "max_depth": 11 },
{ "name" : "Barbo Goblin Archer", "weight": 13, "min_depth": 10, "max_depth": 11 },
Cirro 氏族
我们将使 Cirro 氏族强大而稀有。基本的 Cirro Dark Elf 看起来像这样:
{
"name" : "Cirro Dark Elf",
"renderable": {
"glyph" : "e",
"fg" : "#FF00FF",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "random_waypoint",
"attributes" : {},
"equipped" : [ "Hand Crossbow", "Scimitar", "Buckler", "Drow Chain", "Drow Leggings", "Drow Boots" ],
"faction" : "DarkElfC",
"gold" : "3d6",
"level" : 7
},
我们还将给他们首领——可以网住你的女祭司:
{
"name" : "Cirro Dark Priestess",
"renderable": {
"glyph" : "E",
"fg" : "#FF00FF",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 8,
"movement" : "random_waypoint",
"attributes" : {},
"equipped" : [ "Hand Crossbow", "Scimitar", "Buckler", "Drow Chain", "Drow Leggings", "Drow Boots" ],
"faction" : "DarkElfC",
"gold" : "3d6",
"level" : 8,
"abilities" : [
{ "spell" : "Web", "chance" : 0.2, "range" : 6.0, "min_range" : 3.0 }
]
},
我们不给他们奴隶,而是给他们蜘蛛:
{
"name" : "Cirro Spider",
"level" : 3,
"attributes" : {},
"renderable": {
"glyph" : "s",
"fg" : "#FF00FF",
"bg" : "#000000",
"order" : 1
},
"blocks_tile" : true,
"vision_range" : 6,
"movement" : "static",
"natural" : {
"armor_class" : 12,
"attacks" : [
{ "name" : "bite", "hit_bonus" : 1, "damage" : "1d12" }
]
},
"abilities" : [
{ "spell" : "Web", "chance" : 0.2, "range" : 6.0, "min_range" : 3.0 }
],
"faction" : "DarkElfC"
},
这也需要更新 spawn 表:
{ "name" : "Cirro Dark Elf", "weight": 7, "min_depth": 10, "max_depth": 11 },
{ "name" : "Cirro Dark Priestess", "weight": 6, "min_depth": 10, "max_depth": 11 },
{ "name" : "Cirro Spider", "weight": 10, "min_depth": 10, "max_depth": 11 }
如果你现在 cargo run
该项目,你会发现黑暗精灵正在互相残杀——并且呈现出良好的多样性。
总结
这是一个简短的章节:因为大多数先决条件已经编写完成。这对整个引擎来说是一个好兆头:我们现在可以构建非常不同风格的关卡,而无需编写太多新代码。在下一章中,我们将进一步深入黑暗精灵城市——尝试创建一个更开放的城市关卡。混乱将继续!
本章的源代码可以在这里找到
在您的浏览器中使用 web assembly 运行本章的示例 (需要 WebGL2)
版权 (C) 2019, Herbert Wolverson.