Roguelike
对象、Hash、Set、YAML、AI、回合:六块砖,一座地牢——外加抹掉一切的死亡。这是你的配方。
42 秒 · 含中文字幕 · 8.5 Mo
你会学会的 7 件事
第 9 课:Roguelike
Regarde la leçon (42 s) : l'histoire d'un genre né d'un détail — puis la recette complète, brique par brique. Tu as déjà tout ce qu'il faut.
第 1 块砖:对象——英雄
Écris la classe `Heros` : `initialize(pv)` qui range les points de vie, et une lecture `pv`. Un seul chiffre décide de ta vie — le reste est du confort.
第 2 块砖:地牢——数组的数组
Écris `donjon(lignes, colonnes)` : un tableau de tableaux rempli de `"."` — la case vide. Une grille qui dépend des dimensions reçues, jamais une taille en dur.
第 3 块砖:战利品——剑不拿两次
Écris `ramasse(objets)` qui renvoie un `Set` : les objets uniques du butin. `require "set"` en haut, et les doublons tombent tout seuls.
第 4 块砖:存档——一个文件,一个 YAML
Écris `sauvegarde(etat)` : l'état du héros en YAML (`pv: 20`…). Le roguelike sauvegarde tout au même endroit — et la mort le relit pour l'effacer.
第 5 块砖:怪物——朝你走一步
Écris `chasse(pos, cible)` : le monstre avance d'UNE case vers sa cible — l'axe X d'abord, l'axe Y ensuite (avec `<=>`). Pas de diagonale : un axe à la fois, comme les fantômes.
第 9 课:OK
Sans aide : `tour(carte, x, y, dx, dy)` — le tour complet. Case libre → renvoie `[x + dx, y + dy]` · case `"mur"` → tu restes `[x, y]` · case `"monstre"` → `:combat`.
📄 备忘单
打印出来贴显示器上,就当是你自己的主意📄 备忘单 — Roguelike(你的配方)
1980 年,Rogue 跑在绿色终端里:每局都是新地牢,死亡抹掉一切。整个流派装进六块砖——而你全都有。
历史,三行
| 年份 | 发生了什么 | 带来了什么 |
|---|---|---|
| 1980 | 绿色终端上的 Rogue | 程序生成的地牢 + 永久死亡 |
| 80 年代 | NetHack、ADOM… | 同一配方,更深 |
| 今天 | 成千上万的 roguelike | 你的配方 — 第 1 到 9 课 |
奠基的那点:关卡不是关卡,是生成器。 你不画地牢——你写下造它的规则。
配方:6 块砖 = 6 课
| 砖 | 课 | 那行代码 |
|---|---|---|
| 英雄(状态) | 1 — 对象 | initialize + 读取器 |
| 存档(文件) | 2 — 格式 | to_yaml |
| 地牢(网格) | 3 + 8 — 容器与表 | Array.new + 格子 x,y |
| 战利品(不重复) | 3 — Set | Set.new(objets) |
| 怪物(AI) | 5 — 四个幽灵 | 一步,一个轴 |
| 回合(规则) | 7 + 8 — 移动与碰撞 | case/when |
第 1 块砖 — 英雄(对象)
class Heros
def initialize(pv)
@pv = pv
end
def pv
@pv
end
end
Heros.new(20).pv # => 20
英雄的命是存起来的状态,绝不是全局变量。
第 2 块砖 — 地牢(数组的数组)
def donjon(lignes, colonnes)
Array.new(lignes) { Array.new(colonnes, ".") }
end
donjon(2, 3) # => [[".", ".", "."], [".", ".", "."]]
空格子是 "."——我的会变成 #,你的随你。
第 3 块砖 — 战利品(Set)+ 存档(YAML)
Set.new(["epee", "epee", "potion"]) # => #<Set: {"epee", "potion"}>
{ "pv" => 20, "x" => 3 }.to_yaml # => "---\npv: 20\nx: 3\n"
拒绝重复的背包,装进文件的一局——格式与容器,别无其他。
第 4 块砖 — 怪物:AI 之前的 AI
def chasse(pos, cible)
dx = cible[0] <=> pos[0]
dy = cible[1] <=> pos[1]
dx != 0 ? [pos[0] + dx, pos[1]] : [pos[0], pos[1] + dy]
end
chasse([5, 5], [5, 2]) # => [5, 4]
没有轨迹计算,没有机器学习:每回合一步,一次一个轴。 (Pac-Man,也是 1980——第 5 课。)
第 5 块砖 — 回合:全部玩法在一个 case 里
def tour(carte, x, y, dx, dy)
cible = "#{x + dx},#{y + dy}"
case carte[cible]
when "mur" then [x, y] # 面对墙:我留下
when "monstre" then :combat # 面对敌人:我打
else [x + dx, y + dy] # 空格:我前进
end
end
每回合读一次 Hash——墙、怪物、宝物:同一个问题,同一条地址。
永久死亡(这个流派的悖论)
File.write("partie.yaml", sauvegarde(etat)) # 存档
File.delete("partie.yaml") # 死了 → 一切重来
难度来自被抹掉的东西,不是加进去的。
以后别再说
「我需要引擎 / 地牢生成器」→ 一条填满数组的规则「怪物 AI」→ 距离上的一个if,1980 年就这样「roguelike 太复杂」→ 六块砖,早写好了,就在这门课里。
SlopCourse — 从 slop 到干净的代码。