想象一下,你的英雄安雅(Anya)正在地下城里冒险。她需要记住身边最近的敌人叫什么名字,才能精准地挥剑攻击。如果她的脑子里没有"格子"来装这个名字,每走一步就忘了刚才看到的怪物——那可就糟糕啦!在编程的世界里,变量(Variable)就是我们给英雄准备的"记忆格子",让程序能够记住信息、使用信息、甚至改变信息。
在编程中,变量是一个可以存储数据的命名容器。你可以把数据"放进去",之后随时取出来使用。就像冒险者的背包里有很多口袋,每个口袋都贴了一个标签——"金币"口袋里装金币数量,"血量"口袋里装当前生命值,"敌人"口袋里装最近一个怪物的名字。
在 Python 中,创建变量非常简单,只需要给它起个名字,然后用等号 = 把值"放进去":
# 创建变量并赋值 gold = 0 # 变量 gold 里装了数字 0 health = 100 # 变量 health 里装了数字 100 enemy = "Kratt" # 变量 enemy 里装了字符串 "Kratt"
换一种角度理解:变量就是一个代号或者符号,它代表了某个具体的数据。当你在代码中写 enemy,计算机会自动去找它对应的值——也许是 "Kratt",也许下一秒就变成了 "Grul"。这就像在学校里老师叫你的名字,你代表你自己;在游戏里"最近的敌人"这个代号,在不同时刻可能代表不同的怪物。
变量最重要的特性就是:值可以变。如果一个值永远不变,我们通常称它为常量(后面会讲到)。变量之所以叫"变量"(Variable),就是因为 Variable 这个词本身的意思就是"可变的"。
还有一种更精确的比喻方式:变量像一个标签(name tag),而不是盒子。你把标签贴到一个物品上,这个标签就"指向"那个物品。当你撕下标签贴到另一个物品上时,标签指向的东西就变了,但标签的名字没变。
在 Python 中这种理解尤为重要。当你写:
enemy = "Kratt" enemy = "Grul"
你并没有"修改" Kratt 变成了 Grul——你只是把 enemy 这个标签从 "Kratt" 身上撕下来,重新贴到了 "Grul" 身上。原来的 "Kratt" 字符串还在内存里(只是没有标签指向它了)。
你可能会问:"我直接写 hero.attack("Kratt") 不就好了吗?为什么还要多此一举弄个变量?" 好问题!让我们来看看没有变量时会遇到的窘境:
场景一:敌人名字未知。在很多关卡中,敌人不止一个,而且它们的名字你事先不知道。你没法直接写 hero.attack("???")。你需要英雄用眼睛"看"一下最近的敌人是谁,把这个信息记下来(存到变量里),然后再攻击。
场景二:信息会变化。英雄塔林(Talin)在循环中一遍又一遍地寻找最近的敌人。第一圈最近的是 Kratt,攻击它;第二圈最近的变成了 Grul,再攻击它。如果不用变量来动态保存"当前最近的敌人",你就没法灵活应对不断变化的战场。
场景三:避免重复。如果某个值在代码中出现了很多次,把它存入变量可以让你只需要修改一个地方就更新全部。这对大型程序来说非常重要。
hero.findNearestEnemy() 是英雄的"侦察"方法,它返回最近的敌人对象。你必须把返回值存到变量里才能使用它!
为了帮助你更好地理解变量,这里整理了几种常见的类比:
| 类比 | 变量是什么 | 值是什么 | 要点 |
|---|---|---|---|
| 🗃️ 鞋盒 | 贴着标签的盒子 | 盒子里的东西 | 内容可以换,标签名不变 |
| 🏷️ 名牌 | 贴在物品上的标签 | 标签指向的物品 | 标签可以撕下来贴到别处 |
| 📱 通讯录 | 联系人名字 | 电话号码 | 名字不变,号码可以更新 |
| 🧪 实验变量 | 温度、浓度等名称 | 具体的数值 | 实验中可以改变的量 |
| 📌 便利贴 | 便利贴上写的名字 | 便利贴贴在的物品 | 把便利贴从一个物品移到另一个 |
在数学课上你可能见过 x + 5 = 10 这样的表达式,其中 x 就是变量。编程中的变量概念与此类似,但有一个巨大差异:数学里的 = 表示"等于"(一种关系),而编程里的 = 表示"赋值"(一个动作)。这个区别非常重要,我们在 4.2.3 会详细讲解。
了解了变量是什么之后,最关键的操作就是赋值(Assignment)——把一个值"塞进"变量里。赋值是编程中最基础、最高频的操作之一。每次你写 x = 5,你就在做赋值。
Python 中赋值语句的基本格式是:
变量名 = 值
等号 = 在这里是赋值运算符(assignment operator)。它的含义是:把右边的值,交给左边的变量来保管。
让我们看看英雄安雅在关卡中怎么用赋值:
# 安雅把敌人信息存入变量 enemy = hero.findNearestEnemy() # 现在 enemy 这个变量里装的是最近的敌人对象 hero.attack(enemy) # 用变量 enemy 作为参数传给 attack 方法
赋值的执行顺序很重要:计算机先计算等号右边的值,然后再把结果存到左边的变量。所以 enemy = hero.findNearestEnemy() 的执行过程是:先调用 hero.findNearestEnemy() 得到一个结果(比如一只叫 Kratt 的食人魔),然后把这个结果存到 enemy 变量中。
变量的值不是"刻在石头上"的,它可以随时被更新!当你给一个已有的变量赋一个新值时,旧值就被丢弃了,变量现在指向新值。
health = 100 # 英雄初始血量 100 health = 80 # 被怪物打了!血量变成 80 health = 80 + 20 # 喝了药水!血量恢复到 100
在游戏循环中,这种重新赋值非常常见。每一帧(tick),英雄都需要重新侦察最近的敌人,因为敌人在移动,最近的那个可能已经换了:
while True: enemy = hero.findNearestEnemy() # 每一轮都重新赋值 if enemy: hero.attack(enemy)
每次循环执行到 enemy = hero.findNearestEnemy(),变量 enemy 都会被更新为此刻最新的最近敌人。这就是"重新赋值"的力量——让你的程序能实时响应变化。
很多初学者会混淆编程中的 = 和数学中的 =。让我们彻底搞清楚这两者的区别:
表示"等于",是一种对称关系。x = 5 和 5 = x 是一样的意思。
它表达一个事实:x 的值等于 5。
表示"赋值",是一个有方向的动作。x = 5 合法(把 5 存入 x)。5 = x 非法!你不能把东西存入数字 5。
一个经典的例子能让区别更明显:
x = 5 x = x + 1 # 在数学里这是矛盾的(x 不能等于 x+1) # 但在编程里完全合法!意思是:取出 x 当前的值(5), # 加上 1 得到 6,然后把 6 重新存回 x
执行完后,x 的值从 5 变成了 6。这在编程里叫做"自增",超级常用!
= 是赋值(把右边的值存到左边的变量),而 == 才是"等于"的比较运算符。写代码时千万不要搞混!
给变量起名字可是一门大学问!一个好的变量名能让代码一目了然,而一个糟糕的名字会让代码读起来像天书。在 CodeCombat 中,当你看到 enemy = hero.findNearestEnemy(),一眼就知道这个变量存的是敌人。如果写成 a = hero.findNearestEnemy()……谁知道 a 是什么呢?
Python 对变量名有严格的语法要求。如果违反了这些规则,程序直接报错:
| 规则 | 正确示例 | 错误示例 | 说明 |
|---|---|---|---|
| 只能包含字母、数字、下划线 | enemy_1 | enemy-1 | 减号、空格、特殊符号都不行 |
| 不能以数字开头 | level2_boss | 2nd_enemy | 开头必须是字母或下划线 |
| 不能使用保留字 | my_class | class | while、if、for、True 等都不能用 |
| 区分大小写 | Enemy ≠ enemy | — | 大小写不同就是不同变量 |
# ✅ 合法的变量名 enemy = "Kratt" nearest_enemy = hero.findNearestEnemy() _health = 100 level2Boss = "Brak" # ❌ 非法的变量名(会报错) # 2enemy = "Kratt" # 数字开头 # my-enemy = "Kratt" # 含有减号 # while = "Kratt" # 保留字
除了语法层面的"硬规则",还有一些约定俗成的"软规则",虽然不遵守不会报错,但会让你的代码更专业、更易读:
1. 使用有意义的名字。变量名应该能告诉读者"这里存了什么"。enemy 比 e 好,nearest_enemy 比 ne 好。想象六个月后你再看自己的代码,你能看懂 ne 是什么吗?
2. 使用蛇形命名法(snake_case)。Python 社区的惯例是:用小写字母,单词之间用下划线分隔。比如 nearest_enemy、total_gold、max_health。(Java 和 JavaScript 则习惯用驼峰命名法 nearestEnemy,不同语言有不同风格。)
3. 不要太长也不要太短。一个字母的变量名(如 x)通常只用在很小的范围内。太长的名字(如 the_nearest_enemy_that_i_need_to_attack)则冗余。2-3 个词的组合通常刚刚好。
4. 避免使用容易混淆的名字。不要用 l(小写 L)和 1(数字一)、O(大写 O)和 0(数字零)这类容易看花眼的字符作为变量名。
让我们用一个实际的 CodeCombat 场景来感受好坏命名的差异:
while True: a = hero.findNearestEnemy() if a: hero.attack(a) b = hero.findNearestItem() if b: hero.moveXY(b.pos.x, b.pos.y)
while True: enemy = hero.findNearestEnemy() if enemy: hero.attack(enemy) item = hero.findNearestItem() if item: hero.moveXY(item.pos.x, item.pos.y)
两段代码的功能完全一样,但右边的版本让人一眼就能看懂每个变量存的是什么。在实际开发中,"代码首先是写给人看的,其次才是让机器执行的"。好的命名就是好的文档!
list、str、int、print 等。虽然用了不会报错,但会覆盖(shadowing)原有的内置功能,导致难以发现的 bug。
变量可以存各种各样的数据,但这些数据并不都是同一类"东西"。数字和文字是不同类型的数据,就像背包里的金币和信件是不同类型的物品一样。Python 中常见的数据类型有以下几种:
| 数据类型 | Python 名 | 描述 | 示例 |
|---|---|---|---|
| 整数 | int | 没有小数点的数字 | 42, -7, 0 |
| 浮点数 | float | 有小数点的数字 | 3.14, 0.5, -2.8 |
| 字符串 | str | 由引号包裹的文本 | "Anya", 'hello' |
| 布尔值 | bool | 只有两个值:真/假 | True, False |
| 对象 | 各种类 | 复杂的数据结构 | 英雄、敌人、物品 |
| 空值 | None | 表示"什么都没有" | None |
在 CodeCombat 中,你会频繁接触到这些类型。让我们看安雅在一个关卡中用到的各种变量:
# 整数 int — 坐标、生命值 x_pos = 34 y_pos = 20 # 浮点数 float — 距离 distance = 12.5 # 字符串 str — 名字、类型 hero_name = "Anya" build_type = "fence" # 布尔值 bool — 条件判断 is_alive = True # 对象 — findNearestEnemy 返回的是一个敌人对象 enemy = hero.findNearestEnemy() # None — 当没有敌人时,findNearestEnemy 返回 None enemy = hero.findNearestEnemy() # 如果没敌人,enemy 就是 None
Python 是一门动态类型(dynamically typed)语言。这意味着你不需要提前声明变量的类型,而且同一个变量可以在不同时刻存储不同类型的值:
x = 42 # 此时 x 是 int x = "hello" # 此时 x 变成了 str x = True # 此时 x 又变成了 bool
虽然 Python 允许这样做,但在实际编程中,频繁改变变量的数据类型是不好的习惯。这会让代码变得混乱难懂。一个叫 enemy 的变量最好始终存敌人对象(或 None),而不是突然变成一个数字。
与 Python 不同,有些语言(如 Java、C++)是静态类型语言,你必须在创建变量时就声明它的类型:
// Java 示例(对比用,不需要在 CodeCombat 中写) int health = 100; // 声明 health 是 int 类型 String name = "Anya"; // 声明 name 是 String 类型 // health = "hello"; // ❌ 报错!不能把字符串存入 int 变量
type() 函数来查看一个变量的数据类型。比如 type(enemy) 会告诉你 enemy 当前存的是什么类型的数据。不过在游戏关卡中一般不需要这么做,了解即可。
在前面的单元中我们学过方法(method)是对象能执行的动作。有些方法不仅执行动作,还会返回一个结果给你。这个结果叫做返回值(return value)。变量在这里的作用就是"接住"这个返回值,就像你抛出一个飞盘,需要有人接住它一样。
方法可以分为两大类:
只做事不返回值的方法:比如 hero.moveRight()、hero.attack(enemy)。它们执行了一个动作(移动、攻击),但不给你任何"答案"。
做事并返回结果的方法:比如 hero.findNearestEnemy()。它执行了一个动作(扫描周围),并且返回一个结果(最近的敌人对象)。你需要用变量来接收这个结果。
# 不需要接收返回值的方法 hero.moveXY(20, 30) # 英雄移动到 (20,30),没有返回值需要保存 # 需要用变量接收返回值的方法 enemy = hero.findNearestEnemy() # 返回值是最近的敌人对象 item = hero.findNearestItem() # 返回值是最近的物品对象
如果你调用了一个有返回值的方法,却不用变量接收,那返回值就"飘走了"——你没法使用它。这就像有人告诉你最近的敌人叫 Kratt,但你转头就忘了。
hero.findNearestEnemy() 是 CodeCombat 中最重要的返回值方法之一。让我们深入了解它:
功能:扫描英雄周围的视野范围,找到距离最近的敌人。
返回值:如果找到了敌人,返回该敌人对象(包含名字、位置、血量等信息);如果没有敌人在视野内,返回 None。
为什么需要变量:因为你接下来想要对这个敌人"做点什么"(比如攻击它),你需要一个名字来指代它。
# 塔林(Talin)使用 findNearestEnemy 的完整流程 enemy = hero.findNearestEnemy() # 第1步:侦察并记住 if enemy: # 第2步:检查是否找到了敌人 hero.attack(enemy) # 第3步:攻击!
注意第2步的 if enemy:——这是一个非常重要的安全检查。如果场上没有敌人,findNearestEnemy() 返回 None。如果你对 None 调用 attack(),程序就会报错。所以我们先检查 enemy 是否有值(不是 None),再去攻击。
除了 findNearestEnemy(),CodeCombat 中还有许多返回值方法,它们都需要变量来接收结果:
| 方法 | 返回值类型 | 描述 |
|---|---|---|
hero.findNearestEnemy() | 对象 或 None | 最近的敌人 |
hero.findNearestItem() | 对象 或 None | 最近的物品(宝石、药水等) |
hero.findNearestFriend() | 对象 或 None | 最近的友方单位 |
hero.findEnemies() | 列表 (list) | 所有可见敌人的列表 |
hero.findItems() | 列表 (list) | 所有可见物品的列表 |
hero.distanceTo(target) | float | 到目标的距离 |
hero.isReady("skill") | bool | 技能是否冷却完毕 |
让我们看一个综合使用多个返回值方法的例子:
# 安雅的综合战斗循环 while True: enemy = hero.findNearestEnemy() if enemy: distance = hero.distanceTo(enemy) if distance < 10: hero.attack(enemy) item = hero.findNearestItem() if item: hero.moveXY(item.pos.x, item.pos.y)
变量 = 来接住它!
变量和循环是一对绝佳搭档!在循环中,变量可以被不断更新,帮助程序追踪变化的状态。就像英雄塔林在巡逻时需要不断刷新"最近敌人"的信息一样,循环中的变量让你的代码有了"实时更新"的超能力。
在 while True 循环中更新变量是 CodeCombat 最常见的模式。每一次循环(每一个"tick"),英雄重新观察环境,更新变量中的信息,然后基于最新信息做出决策:
# 塔林的巡逻模式 while True: # 每次循环都重新侦察 → 变量被更新 enemy = hero.findNearestEnemy() # 基于最新的变量值做决策 if enemy: hero.attack(enemy) hero.attack(enemy) # 攻击两次确保击杀
为什么要在循环内部更新变量?因为如果你把 enemy = hero.findNearestEnemy() 写在循环外面,那 enemy 永远是开始时找到的那一个敌人。即使那个敌人已经被击败了,变量也不会自动更新——你的英雄会对着一堆骨灰空挥剑!
计数器(counter)是一种特殊用途的变量,专门用来计数。它通常在循环外初始化为 0,每次循环满足某个条件时加 1:
# 安雅数自己消灭了多少敌人 kill_count = 0 # 计数器初始化为 0(循环外) while True: enemy = hero.findNearestEnemy() if enemy: hero.attack(enemy) hero.attack(enemy) kill_count = kill_count + 1 # 每消灭一个,计数加1 hero.say("已消灭 " + str(kill_count) + " 个敌人!")
kill_count = kill_count + 1 这行代码的意思是:取出 kill_count 的当前值,加上 1,然后把新值存回 kill_count。这正是我们在 4.2.3 讨论的"编程中的 = 不是数学等号"的体现。
kill_count += 1,效果和 kill_count = kill_count + 1 完全一样。类似地,还有 -=、*=、/= 等运算符。
累加器(accumulator)和计数器类似,但它不一定是每次加 1,而是可能加上不同的值。比如英雄收集金币,每枚金币的价值不同:
# 塔林收集金币并追踪总金额 total_gold = 0 # 累加器初始化 while True: item = hero.findNearestItem() if item: hero.moveXY(item.pos.x, item.pos.y) total_gold += item.value # 加上这枚金币的价值 hero.say("当前金币总额: " + str(total_gold))
累加器模式非常实用,在很多关卡中你需要"攒够"一定金币才能购买装备或建造建筑。通过累加器变量,你可以随时知道自己攒了多少钱,然后在达到目标时做出相应的行动。
并非所有值都需要变化。有时候你需要一个"永远不变"的值——比如游戏地图的宽度、一个固定的坐标位置、或者某个阈值。这就是常量(Constant)的用武之地。
常量是指在程序运行过程中值保持不变的量。与变量(可以被重新赋值)不同,常量一旦设定就不应该再修改。
为什么要用常量?原因有两个。第一,可读性:FENCE_X = 40 比到处写数字 40 好得多——读代码的人一看就知道 40 是栅栏的 X 坐标。第二,可维护性:如果栅栏位置需要调整,你只需要修改常量定义的那一处,所有用到它的地方都会自动更新。
在 CodeCombat 中,典型的常量使用场景包括固定的建造位置、移动目标点、或者触发条件的阈值:
# 定义常量(建造位置和金币阈值) FENCE_X = 40 FENCE_Y = 52 GOLD_THRESHOLD = 25 # 在代码中使用常量 while True: item = hero.findNearestItem() if item: hero.moveXY(item.pos.x, item.pos.y) if hero.gold >= GOLD_THRESHOLD: hero.buildXY("fence", FENCE_X, FENCE_Y)
Python 本身没有语法级别的"常量"——你没法真正禁止重新赋值。但程序员有一个约定俗成的规矩:用全大写字母加下划线来命名常量。
# 常量用全大写 + 下划线(约定俗成) MAX_HEALTH = 200 SPAWN_X = 14 SPAWN_Y = 36 PI = 3.14159 # 变量用小写 + 下划线(普通变量) current_health = 200 enemy_count = 0
当其他程序员(包括未来的你自己)看到全大写的名字时,就知道"这是一个不应该被修改的值"。虽然从技术上你可以修改它,但这违反了团队约定,会让代码变得不可预测。
const 关键字声明常量(尝试修改会报错),Java 中用 final 关键字。Python 选择相信程序员的自觉性——看到全大写,就别改它!
在某些 CodeCombat 关卡中,英雄不仅要战斗,还要建造!buildXY 是一个强大的方法,让英雄在指定坐标处建造各种结构。这个方法完美展示了变量的实用价值——通过变量,你可以灵活控制建造的类型和位置。
buildXY 方法需要三个参数:要建造的东西的类型(字符串)、建造位置的 X 坐标(数字)和 Y 坐标(数字)。
hero.buildXY("fence", 40, 52) # 参数1: "fence" → 建造类型(字符串) # 参数2: 40 → X 坐标(数字) # 参数3: 52 → Y 坐标(数字)
常见的可建造物品包括:
| 类型字符串 | 建造物 | 用途 |
|---|---|---|
"fence" | 栅栏 | 阻挡敌人前进 |
"fire-trap" | 火焰陷阱 | 对经过的敌人造成伤害 |
"decoy" | 诱饵 | 吸引敌人注意力 |
"bear-trap" | 捕兽夹 | 定住敌人 |
buildXY 的参数完全可以用变量来提供。这让你的代码更灵活、更易修改:
# 使用变量控制建造——安雅的防线布置 build_type = "fence" build_x = 40 build_y = 52 hero.buildXY(build_type, build_x, build_y) # 如果要改位置或类型,只需要修改变量值 build_type = "fire-trap" build_y = 20 hero.buildXY(build_type, build_x, build_y)
更高级的用法是结合循环和条件判断——根据敌人出现的方向来决定建造什么类型的防御:
# 塔林根据敌人位置动态建造防御 while True: enemy = hero.findNearestEnemy() if enemy: if enemy.pos.x < 30: # 敌人从左边来,在左通道建栅栏 hero.buildXY("fence", 25, 34) else: # 敌人从右边来,在右通道放陷阱 hero.buildXY("fire-trap", 55, 34)
让我们看一个完整的关卡策略——收集金币然后建造防御设施:
# 关卡策略:先攒钱,再建造 # 常量定义 GOLD_NEEDED = 25 DECOY_X = 40 DECOY_Y = 52 # 第一阶段:收集金币直到够用 while hero.gold < GOLD_NEEDED: item = hero.findNearestItem() if item: hero.moveXY(item.pos.x, item.pos.y) # 第二阶段:建造诱饵 hero.buildXY("decoy", DECOY_X, DECOY_Y) # 第三阶段:躲到安全位置 hero.moveXY(20, 52)
buildXY 会失败。所以在建造之前,通常需要先收集足够的金币。你可以用 hero.gold 属性来检查当前金币数量。
学了这么多关于变量的知识,是时候把它们组合起来,在真实的关卡中大展身手了!下面是几个关卡的实战代码,展示变量在不同场景中的应用。
在这个关卡中,英雄需要知道敌人的"真名"才能攻击它。你需要把敌人的名字存入变量,然后传给 attack 方法:
# True Names 关卡 — 安雅通过变量记住敌人名字 enemy1 = "Treg" hero.attack(enemy1) hero.attack(enemy1) enemy2 = "Brak" hero.attack(enemy2) hero.attack(enemy2)
这个关卡中敌人不止一个,你不知道它们的名字,需要用 findNearestEnemy() 来动态查找:
# Known Enemy 关卡 — 塔林动态寻敌并攻击 while True: enemy = hero.findNearestEnemy() if enemy: hero.attack(enemy) hero.attack(enemy)
这个关卡完美结合了变量、循环和 buildXY:
# Bait and Switch 关卡 — 安雅的策略 # 第一步:收集 25 金币 while hero.gold < 25: item = hero.findNearestItem() if item: hero.moveXY(item.pos.x, item.pos.y) # 第二步:建造诱饵 hero.buildXY("decoy", 40, 52) # 第三步:躲起来! hero.moveXY(20, 52)
# 综合防御关卡 — 塔林建造多道防线 TRAP_COST = 20 while True: # 收集金币 item = hero.findNearestItem() if item: hero.moveXY(item.pos.x, item.pos.y) # 够钱就建造 if hero.gold >= TRAP_COST: enemy = hero.findNearestEnemy() if enemy: # 在敌人前方建造陷阱 hero.buildXY("fire-trap", enemy.pos.x, enemy.pos.y)
当你的代码出了问题,变量往往是排查的关键。以下是一些实用的调试技巧:
不确定变量里存了什么?让英雄"说出来":
enemy = hero.findNearestEnemy() hero.say(enemy) # 英雄会说出 enemy 变量的内容 hero.say(hero.gold) # 英雄会说出当前金币数
如果 findNearestEnemy() 没找到敌人,返回的是 None。对 None 调用任何方法都会报错。永远在使用变量前检查它是否为 None:
enemy = hero.findNearestEnemy() if enemy: # 这行相当于 if enemy != None: hero.attack(enemy) # 确认有敌人才攻击
如果你在循环内部定义了一个变量,在循环外部可能无法访问它(虽然 Python 的作用域规则比较宽松,但养成好习惯很重要)。把需要在循环外使用的变量在循环外初始化。
确认你的 findNearestEnemy() 是在循环内部被调用的,而不是只在开头调用了一次。
以下是初学者使用变量时最常犯的错误,以及如何修复它们:
| 错误 | 错误代码 | 正确代码 | 原因 |
|---|---|---|---|
| 忘记赋值就使用变量 | hero.attack(enemy) |
enemy = hero.findNearestEnemy() |
enemy 未定义会报 NameError |
| 不检查 None | enemy = hero.findNearestEnemy() |
enemy = hero.findNearestEnemy() |
没有敌人时 enemy 为 None |
| 字符串忘加引号 | enemy = Kratt |
enemy = "Kratt" |
不加引号 Python 把 Kratt 当成变量名 |
| 侦察不在循环内 | enemy = hero.findNearestEnemy() |
while True: |
变量永远不更新 |
让我们把本单元学到的所有语法知识整理到一起,方便你随时查阅:
| 概念 | 语法 | 示例 | 说明 |
|---|---|---|---|
| 创建变量 | 变量名 = 值 | gold = 0 | 等号是赋值运算符 |
| 重新赋值 | 变量名 = 新值 | gold = 50 | 旧值被覆盖 |
| 接收返回值 | 变量 = 方法() | enemy = hero.findNearestEnemy() | 方法的结果存入变量 |
| 自增 | 变量 = 变量 + 数值 | count = count + 1 | 或简写 count += 1 |
| 变量作参数 | 方法(变量) | hero.attack(enemy) | 变量值作为参数传入 |
| 常量 | ALL_CAPS = 值 | MAX_HP = 200 | 全大写表示不应修改 |
| 建造 | hero.buildXY(类型, x, y) | hero.buildXY("fence", 40, 52) | 三个参数:类型+坐标 |
| None 检查 | if 变量: | if enemy: | 确保变量不是 None |
| 访问属性 | 变量.属性 | enemy.pos.x | 获取对象中的数据 |
# 完整语法示范 — 一个完整关卡的结构 # 1. 定义常量 BUILD_COST = 25 BUILD_TYPE = "fence" # 2. 初始化变量 kill_count = 0 # 3. 主循环 while True: # 4. 更新变量(侦察) enemy = hero.findNearestEnemy() item = hero.findNearestItem() # 5. 条件判断 + 使用变量 if enemy: hero.attack(enemy) kill_count += 1 elif item: hero.moveXY(item.pos.x, item.pos.y) # 6. 使用常量作为条件 if hero.gold >= BUILD_COST: hero.buildXY(BUILD_TYPE, 40, 34)
恭喜你完成了 Unit 4 的学习!让我们来回顾一下这个单元中你掌握的超级技能:
变量是什么:变量是存储数据的命名容器,像贴着标签的盒子或便利贴一样。变量名指向一个值,而这个值是可以改变的。
赋值操作:使用 = 赋值运算符将值存入变量。计算机先计算右边的表达式,再将结果存到左边的变量中。编程中的 = 不是数学里的"等于",而是一个有方向的动作。
命名规则:变量名只能包含字母、数字和下划线,不能以数字开头,不能使用保留字。好的命名应该有意义、使用蛇形命名法、长度适中。
数据类型:变量可以存储 int、float、str、bool、对象和 None 等不同类型的数据。Python 是动态类型语言,不需要提前声明变量类型。
返回值:有些方法会返回一个值(如 findNearestEnemy()),你需要用变量接收这个返回值才能使用它。使用前记得检查是否为 None。
变量与循环:在循环中更新变量可以让程序实时响应变化。计数器和累加器是两种常见的循环中使用变量的模式。
常量:值不会改变的量用全大写命名,便于识别和维护。
buildXY:使用变量控制建造类型和坐标,让代码更灵活。建造前需要收集足够的金币。
| 核心概念 | 关键知识 | 对应章节 |
|---|---|---|
| 变量概念 | 命名容器,存储可变数据 | 4.1 |
| 赋值操作 | = 是赋值运算符,从右到左执行 | 4.2 |
| 命名规则 | snake_case,有意义,避免保留字 | 4.3 |
| 数据类型 | int, float, str, bool, 对象, None | 4.4 |
| 返回值 | 用变量接收方法返回值,检查 None | 4.5 |
| 循环中的变量 | 计数器、累加器、实时更新 | 4.6 |
| 常量 | 全大写命名,值不应改变 | 4.7 |
| buildXY | hero.buildXY(类型, x, y),需要金币 | 4.8 |
安雅已经学会了用变量记住敌人信息,塔林也掌握了动态建造防御的技能。
下一站:第五单元——更复杂的条件与策略,让英雄做出更聪明的决策!⚔️
CodeCombat 编程知识 · 计算机科学入门(暗影地牢):第四单元
CodeCombat教研团队