位置表
一格 = 一个地址,上面一个名字:世界装进一个 Hash——墙,就是被占的格子。
42 秒 · 含中文字幕 · 8.7 Mo
你会学会的 7 件事
第 8 课:位置表
Regarde la leçon (42 s) : ton monde n'a pas de décor, il a une table. Qui est où — et qui ne peut pas passer.
一格 = 一个地址
Écris `case_de(x, y)` : la clé de la map pour la case (3, 4) est `"3,4"` — x, une virgule, y. Toute la case tient dans une chaîne.
安置精灵
Écris `pose(carte, x, y, nom)` qui renvoie une NOUVELLE map avec le sprite posé sur la case — l'original ne bouge jamais. Tu ranges, tu ne détruits.
格子被占了吗?
Écris `occupe?(carte, x, y)` : true si un sprite est sur cette case. On interroge l'ADRESSE — `key?` — pas la valeur : le vide n'a pas de nom.
谁遇到谁?
Écris `rencontre(carte, x, y)` : le nom du sprite sur la case — ou `nil` si elle est vide. Dans un vrai jeu, c'est ce retour qui déclenche tout : dégât, pièce, dialogue.
每秒更新六十次
Écris `tic(secondes)` : le nombre de fois où la map est relue et recalculée — 60 fois par seconde, pas une de plus. Une seconde de jeu, soixante calculs.
第 8 课:OK
Sans aide : `avance(carte, x, y, dx, dy)` — un pas vers `[x + dx, y + dy]`. Si cette case est déjà occupée (un mur, un autre sprite), le pas est IMPOSSIBLE : tu restes à `[x, y]`.
📄 备忘单
打印出来贴显示器上,就当是你自己的主意📄 备忘单 — 位置表(世界就是一个 Hash)
你的游戏没有世界,只有一张表。一个格子 = 一条地址,上面一个名字——而墙,就是被占的格子。
这张表的四个词
| 词 | 它是什么 | 例子 |
|---|---|---|
| 格子 | 一条地址 x,y |
"3,4" |
| 表 | 所有格子,一个 Hash | carte = {} |
| 心跳 | 一次更新 | 每秒 60 次 |
| 墙 | 被占的格子 | carte["5,5"] = "mur" |
一个格子 = 一条地址
def case_de(x, y)
"#{x},#{y}" # x 在前,逗号,y 在后
end
case_de(3, 4) # => "3,4"
整个格子装进一个字符串:这就是你 Hash 的键。4,3 是另一个格子。
安置精灵:只复制,绝不销毁
def pose(carte, x, y, nom)
carte.merge("#{x},#{y}" => nom) # 新 Hash,原件完好
end
pose({}, 1, 2, "joueur") # => { "1,2" => "joueur" }
merge 复制,= 毁掉。从第 6 课起规则没变过——现在用在整个世界上。
占用还是空:key? 对值
carte = { "3,4" => "joueur" }
carte.key?("3,4") # => true 地址【存在】
carte.key?("0,0") # => false 没人住那
carte["0,0"] # => nil 空没有名字
key? 告诉你格子被占了——不管值是什么。这就是游戏每秒问六十遍的问题。
谁遇到谁
def rencontre(carte, x, y)
carte["#{x},#{y}"] # 名字……或者 nil
end
rencontre(carte, 3, 4) # => "joueur"
rencontre(carte, 0, 0) # => nil
回来 nil:路上什么也没有。回来一个名字:伤害、金币、对话——全部玩法都从这个返回值开始。
每秒六十次更新
def tic(secondes)
secondes * 60 # 一秒游戏 = 重读这张表六十遍
end
tic(1) # => 60
每次心跳:重读表、移动、再比对。游戏不是在动——它在重算。
面对墙,这一步不可能
def avance(carte, x, y, dx, dy)
cible = "#{x + dx},#{y + dy}"
carte.key?(cible) ? [x, y] : [x + dx, y + dy]
end
avance({}, 2, 2, 1, 0) # => [3, 2] 格子空:我前进
avance({ "3,2" => "mur" }, 2, 2, 1, 0) # => [2, 2] 格子被占:我留下
没有物理,没有引擎的「碰撞」:一条已被占用的地址、一个 key?、一个选择。
以后别再说
「精灵撞墙了」→ 目标格已经在表里——你返回旧位置「我需要碰撞引擎」→ 你的 Hash 从第 3 课起就在干这活。
SlopCourse — 从 slop 到干净的代码。