血迹
关于本教程
本教程是免费且开源的,所有代码均使用 MIT 许可证 - 因此您可以随意使用它。 我希望您会喜欢本教程,并制作出色的游戏!
如果您喜欢这个教程并希望我继续写作,请考虑支持我的 Patreon。
我们的角色过着“杀人流浪汉 (murder-hobo)”的生活,随意掠夺和杀戮 - 因此,原始的地牢开始变得像停尸房 (charnel house) 也就很合理了。 这也为我们进入未来的章节搭建了桥梁,在未来的章节中,我们将开始向游戏中添加一些粒子和视觉效果(以 ASCII/CP437 格式)。
存储血液
瓦片 (Tile) 要么有血迹,要么没有,因此将它们作为“集合 (set)”附加到地图是有意义的。 因此,在 map.rs
的顶部,我们将包含一个新的存储类型 - HashSet
:
#![allow(unused)] fn main() { use std::collections::HashSet; }
在地图定义中,我们将包含一个 usize
(用于表示瓦片索引)类型的 HashSet
用于血液:
#![allow(unused)] fn main() { #[derive(Default, Serialize, Deserialize, Clone)] pub struct Map { pub tiles : Vec<TileType>, pub rooms : Vec<Rect>, pub width : i32, pub height : i32, pub revealed_tiles : Vec<bool>, pub visible_tiles : Vec<bool>, pub blocked : Vec<bool>, pub depth : i32, pub bloodstains : HashSet<usize>, #[serde(skip_serializing)] #[serde(skip_deserializing)] pub tile_content : Vec<Vec<Entity>> } }
在新地图生成器中,我们将初始化它:
#![allow(unused)] fn main() { let mut map = Map{ tiles : vec![TileType::Wall; MAPCOUNT], rooms : Vec::new(), width : MAPWIDTH as i32, height: MAPHEIGHT as i32, revealed_tiles : vec![false; MAPCOUNT], visible_tiles : vec![false; MAPCOUNT], blocked : vec![false; MAPCOUNT], tile_content : vec![Vec::new(); MAPCOUNT], depth: new_depth, bloodstains: HashSet::new() }; }
渲染血液
我们将通过将瓦片背景更改为深红色来指示血迹。 我们不想让效果太“引人注目”,也不想隐藏瓦片内容 - 因此这应该足够了。 我们也不会显示视觉范围之外的血液,以保持低调。 在 map.rs
中,渲染部分现在看起来像这样:
#![allow(unused)] fn main() { if map.revealed_tiles[idx] { let glyph; let mut fg; let mut bg = RGB::from_f32(0., 0., 0.); match tile { TileType::Floor => { glyph = rltk::to_cp437('.'); fg = RGB::from_f32(0.0, 0.5, 0.5); } TileType::Wall => { glyph = wall_glyph(&*map, x, y); fg = RGB::from_f32(0., 1.0, 0.); } TileType::DownStairs => { glyph = rltk::to_cp437('>'); fg = RGB::from_f32(0., 1.0, 1.0); } } if map.bloodstains.contains(&idx) { bg = RGB::from_f32(0.75, 0., 0.); } if !map.visible_tiles[idx] { fg = fg.to_greyscale(); bg = RGB::from_f32(0., 0., 0.); // 不显示视觉范围外的污渍 } ctx.set(x, y, fg, bg, glyph); } }
为血腥之神献血 (Blood for the blood god)
现在我们需要向场景中添加血液! 每当有人在瓦片中受到伤害时,我们都会将该瓦片标记为血腥的。 我们将调整 damage_system.rs
中的 DamageSystem
以设置血迹:
#![allow(unused)] fn main() { impl<'a> System<'a> for DamageSystem { type SystemData = ( WriteStorage<'a, CombatStats>, WriteStorage<'a, SufferDamage>, ReadStorage<'a, Position>, WriteExpect<'a, Map>, Entities<'a> ); fn run(&mut self, data : Self::SystemData) { let (mut stats, mut damage, positions, mut map, entities) = data; for (entity, mut stats, damage) in (&entities, &mut stats, &damage).join() { stats.hp -= damage.amount.iter().sum::<i32>(); let pos = positions.get(entity); if let Some(pos) = pos { let idx = map.xy_idx(pos.x, pos.y); map.bloodstains.insert(idx); } } damage.clear(); } } }
如果您 cargo run
运行您的项目,地图将开始显示战斗的迹象!
本章的源代码可以在这里找到
在您的浏览器中使用 WebAssembly 运行本章的示例(需要 WebGL2)
版权 (Copyright) (C) 2019, Herbert Wolverson。