戰(zhàn):教你寫一個(gè)人狗大作戰(zhàn)回合制小游戲)
如果一個(gè)小游戲能讓人對(duì) Python 的興趣直接拉滿那它一定同時(shí)做到了三件事能運(yùn)行、能看懂、能改著玩。很多初學(xué) Python 的人都會(huì)卡在同一步語法看了兩三遍書上例題也做完了但一到自己寫程序就不知道從哪下手。如果你也處在這樣的階段本文要拆解的「人狗大作戰(zhàn)」小游戲會(huì)是一個(gè)很好的突破口。它不需要圖形界面不需要安裝龐大的第三方框架只用 Python 自帶的語法和標(biāo)準(zhǔn)庫就能寫出一款完整的回合制戰(zhàn)斗游戲。這篇教程會(huì)從零開始完整走一遍環(huán)境安裝、游戲設(shè)計(jì)、代碼實(shí)現(xiàn)、運(yùn)行驗(yàn)證、打包 exe 的流程。最終你拿到的不只是一段能跑的代碼而是把 Python 入門階段的核心語法全部串起來的一次項(xiàng)目實(shí)踐。全文代碼均可直接復(fù)制運(yùn)行建議一邊讀一邊在本地敲一遍。1. 為什么推薦用游戲項(xiàng)目來入門 Python1.1 游戲項(xiàng)目能覆蓋完整的語法鏈很多人學(xué) Python 會(huì)遇到一個(gè)典型困境語法書看懂了合上書卻寫不出東西。原因很簡單知識(shí)點(diǎn)是零散的缺少一個(gè)能把它們串起來的實(shí)際場景。游戲項(xiàng)目恰好是最合適的場景之一。它不涉及復(fù)雜的業(yè)務(wù)邏輯卻能逼著你把變量、類型、條件判斷、循環(huán)、函數(shù)、類、模塊導(dǎo)入全部用起來。以「人狗大作戰(zhàn)」為例雖然它只是一個(gè)運(yùn)行在命令行里的小游戲但天然包含這些編程要素編程要素在游戲中的作用變量與類型保存角色當(dāng)前血量、攻擊力、防御力條件判斷判斷玩家輸入、判斷角色是否存活while 循環(huán)讓戰(zhàn)斗輪次持續(xù)進(jìn)行直到某一方倒下函數(shù)把攻擊、防御、吃藥、顯示狀態(tài)等行為封裝起來類與對(duì)象用類來描述玩家和野狗兩個(gè)角色random 模塊生成隨機(jī)傷害和暴擊效果輸入輸出通過 input() 和 print() 完成交互一個(gè)項(xiàng)目把這些全部跑通比單獨(dú)背十遍語法都有效。這也是為什么我一直建議初學(xué)者盡早做一個(gè)完整的小項(xiàng)目而不是在練習(xí)題里打轉(zhuǎn)。1.2 人狗大作戰(zhàn)到底怎么玩「人狗大作戰(zhàn)」是純文本回合制小游戲。場景很簡單一天晚上你走在回家的小路上突然從路邊躥出一只野狗擋在面前。你現(xiàn)在有兩個(gè)選擇跟它打一架或者找機(jī)會(huì)逃跑。戰(zhàn)斗采用回合制每回合玩家先行動(dòng)野狗再行動(dòng)。玩家有四種指令攻擊對(duì)野狗造成傷害傷害值在基礎(chǔ)攻擊力上下浮動(dòng)。防御減少本回合受到的傷害適合血量較低時(shí)使用。使用藥水恢復(fù)一定生命值藥水?dāng)?shù)量有限需要省著用。逃跑有一定成功率失敗時(shí)會(huì)白白消耗一回合。野狗的設(shè)計(jì)上加入了一個(gè)小機(jī)制它有 15% 的概率觸發(fā)暴擊暴擊傷害提升 1.5 倍。這樣一來戰(zhàn)斗就有了隨機(jī)性和緊張感不會(huì)變成簡單的“你一刀我一刀”。順便說一句這只是游戲設(shè)定?,F(xiàn)實(shí)中遇到無主動(dòng)物請(qǐng)不要嘗試戰(zhàn)斗保持距離并及時(shí)向物業(yè)或相關(guān)部門求助。1.3 為什么這個(gè)項(xiàng)目適合作為第一個(gè)完整代碼整個(gè)項(xiàng)目核心代碼只有一百多行正好處于“不會(huì)因?yàn)樘L而看不下去”的區(qū)間。同時(shí)它是一個(gè)完整可運(yùn)行的程序運(yùn)行之后能看到真實(shí)的交互反饋這對(duì)新手來說是很強(qiáng)的正反饋。寫完以后還能打包發(fā)給朋友讓對(duì)方也運(yùn)行一把。這種“我的代碼真的能玩”的成就感往往就是興趣持續(xù)升溫的來源。這個(gè)項(xiàng)目的擴(kuò)展性也很強(qiáng)想加技能就加技能列表想加關(guān)卡就做關(guān)卡循環(huán)想做圖形界面可以用 pygame 或 tkinter 重寫。后面第 7 節(jié)會(huì)專門討論擴(kuò)展方向。2. 環(huán)境準(zhǔn)備把 Python 跑起來不管之前有沒有接觸過 Python先把運(yùn)行環(huán)境準(zhǔn)備好。這一步如果沒做好后面所有代碼都跑不起來。2.1 Python 安裝三步走第一步打開 Python 官方網(wǎng)站 python.org進(jìn)入 Downloads 頁面選擇對(duì)應(yīng)操作系統(tǒng)的版本下載。Windows 用戶下載 Windows installer 格式的安裝包即可macOS 和 Linux 用戶也有對(duì)應(yīng)的安裝包或包管理器方式。這里要特別提醒 Windows 用戶一個(gè)關(guān)鍵細(xì)節(jié)安裝界面出現(xiàn)后第一步一定要勾選最下方的“Add Python to PATH”然后再點(diǎn) Install Now。這個(gè)選項(xiàng)會(huì)把 Python 自動(dòng)加入系統(tǒng)環(huán)境變量。很多新手遇到的“python 不是內(nèi)部或外部命令”報(bào)錯(cuò)基本都是因?yàn)檫@里沒有勾選。第二步等待安裝完成然后驗(yàn)證安裝結(jié)果。按 Win R輸入 cmd 回車打開命令行輸入python --version如果看到類似Python 3.12.x的輸出說明安裝成功。如果提示找不到 python可以嘗試python3命令或者檢查環(huán)境變量配置。第三步可選檢查 pip 是否可用。pip 是 Python 的包管理工具后面打包 exe 時(shí)會(huì)用到。輸入pip --version能看到版本號(hào)說明 pip 正常。2.2 開發(fā)工具選擇Python 安裝完成后還需要一個(gè)寫代碼的工具。這里給出三種選擇你可以根據(jù)情況挑一個(gè)IDLEPython 自帶的編輯器安裝完就有適合零基礎(chǔ)讀者不需要額外配置。缺點(diǎn)是代碼提示和調(diào)試功能較弱。VS Code免費(fèi)開源配合 Python 擴(kuò)展后體驗(yàn)很好是目前非常主流的選擇。選它的話記得在擴(kuò)展市場搜索“Python”安裝微軟官方發(fā)布的擴(kuò)展。PyCharmJetBrains 出品的專業(yè) Python IDE社區(qū)版免費(fèi)功能全面適合打算長期深入 Python 開發(fā)的讀者。缺點(diǎn)是啟動(dòng)相對(duì)較重。不管選哪個(gè)工具本質(zhì)都是編寫一個(gè) .py 文件再用 Python 解釋器運(yùn)行。工具只是輔助不要在選擇工具上糾結(jié)太久。這里補(bǔ)充一個(gè) VS Code 的常見配置點(diǎn)打開一個(gè) .py 文件后VS Code 會(huì)在右下角提示選擇解釋器需要選到剛才安裝的 Python 版本右上角的運(yùn)行按鈕才能正確執(zhí)行當(dāng)前文件。2.3 項(xiàng)目目錄結(jié)構(gòu)為了方便管理先新建一個(gè)項(xiàng)目文件夾名字可以叫 human_dog_game。整個(gè)項(xiàng)目只需要一個(gè)核心 Python 文件human_dog_game/ ├── main.py # 游戲主程序 ├── README.md # 項(xiàng)目說明可選 └── requirements.txt # 依賴清單本項(xiàng)目為空main.py 就是要寫的全部代碼。README.md 可以記錄游戲玩法和運(yùn)行方式養(yǎng)成寫說明文檔的習(xí)慣在以后接手真實(shí)項(xiàng)目時(shí)會(huì)有很大幫助。3. 游戲設(shè)計(jì)先拆解再寫代碼寫代碼之前先把游戲邏輯拆清楚。這一步看起來不產(chǎn)生代碼但它決定了代碼寫出來后好不好改、好不好擴(kuò)展。3.1 核心規(guī)則說明「人狗大作戰(zhàn)」的完整規(guī)則可以濃縮成下面幾條玩家和野狗各有生命值HP、攻擊力attack、防御力defense三個(gè)基礎(chǔ)屬性。每回合玩家先行動(dòng)選擇攻擊、防御、吃藥或逃跑之一。玩家行動(dòng)結(jié)束后如果野狗存活野狗發(fā)起攻擊。受到攻擊時(shí)先計(jì)算本次傷害再減去目標(biāo)防御力得到實(shí)際扣血量。任何一方 HP 降到 0或者玩家逃跑成功戰(zhàn)斗結(jié)束。這個(gè)規(guī)則足夠簡單又留有變化空間。野狗的暴擊機(jī)制本質(zhì)上就是在傷害計(jì)算上加了一個(gè)隨機(jī)系數(shù)。以后想增加閃避、技能冷卻、多段攻擊都可以按同樣的思路擴(kuò)展。3.2 數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)用類來描述角色是最直接的方式。類可以把屬性和行為封裝在一起代碼讀起來很清楚。游戲里有兩個(gè)角色玩家和野狗。它們屬性不同、行為不完全一樣但本質(zhì)上都是“有血量、能造成傷害、能承受傷害”的角色。所以可以先定義一個(gè)Character基類把公共邏輯放進(jìn)去再由Player和Dog繼承并擴(kuò)展。Character維護(hù) name、max_hp、hp、attack、defense 屬性提供 is_alive()、take_damage()、attack_target() 三個(gè)方法。Player繼承 Character額外增加 potions 屬性和 use_potion() 方法。Dog繼承 Character額外增加 level 屬性根據(jù)等級(jí)動(dòng)態(tài)計(jì)算屬性。這樣設(shè)計(jì)的好處是以后想加 Boss 角色只需要繼承 Character再擴(kuò)展方法即可戰(zhàn)斗主邏輯基本不用動(dòng)。3.3 戰(zhàn)斗流程梳理整個(gè)游戲的流程可以概括成下面的順序開始 ↓ 初始化玩家和野狗 ↓ 循環(huán)判斷雙方是否都存活 ↓ 顯示雙方狀態(tài) ↓ 玩家選擇行動(dòng) ├─ 逃跑成功 → 結(jié)束 ├─ 攻擊 → 計(jì)算傷害 ├─ 防御 → 標(biāo)記本回合減傷 └─ 吃藥 → 恢復(fù)血量 ↓ 野狗行動(dòng)根據(jù)玩家是否防御計(jì)算實(shí)際傷害 ↓ 回到循環(huán)開頭 ↓ 有一方死亡或逃跑成功 → 輸出結(jié)果這個(gè)流程就是 main() 函數(shù)的大綱。先把流程列出來再對(duì)應(yīng)寫代碼思路會(huì)清晰很多。4. 完整代碼實(shí)現(xiàn)下面進(jìn)入正題。為了方便閱讀我會(huì)先分段解釋關(guān)鍵代碼最后再給一份完整可復(fù)制的 main.py。4.1 導(dǎo)入模塊與定義角色基類游戲需要用到 random 模塊生成隨機(jī)數(shù)time 模塊在輸出之間加一點(diǎn)延遲讓戰(zhàn)斗過程更有節(jié)奏感。然后是 Character 基類。初始化方法接收名字、最大生命值、攻擊力、防御力四個(gè)參數(shù)。max_hp 單獨(dú)保存一份方便吃藥回血時(shí)判斷上限。import random import time class Character: 角色基類包含所有角色共有的屬性和行為 def __init__(self, name, hp, attack, defense): self.name name self.max_hp hp self.hp hp self.attack attack self.defense defense def is_alive(self): 判斷角色是否存活 return self.hp 0 def take_damage(self, damage): 承受傷害返回實(shí)際扣血量 actual_damage max(0, damage - self.defense) self.hp - actual_damage if self.hp 0: self.hp 0 return actual_damage def attack_target(self, target): 攻擊目標(biāo)傷害在基礎(chǔ)攻擊力 80%~120% 之間浮動(dòng) damage random.randint(int(self.attack * 0.8), int(self.attack * 1.2)) return target.take_damage(damage)這里有一個(gè)容易忽略的細(xì)節(jié)take_damage 中使用了max(0, damage - self.defense)防止防御力高于傷害時(shí)出現(xiàn)“被打還回血”的邏輯錯(cuò)誤。這是典型的邊界條件處理真實(shí)項(xiàng)目中到處都會(huì)遇到。4.2 定義玩家類和野狗類玩家類繼承 Character額外增加藥水?dāng)?shù)量 potions。使用藥水時(shí)恢復(fù) 30 點(diǎn)生命值但不能超過最大生命值。野狗類同樣繼承 Character構(gòu)造時(shí)根據(jù) level 動(dòng)態(tài)計(jì)算屬性等級(jí)越高越難打。class Player(Character): 玩家類 def __init__(self): super().__init__(勇敢的你, 100, 15, 3) self.potions 3 def use_potion(self): 使用藥水恢復(fù)生命值返回實(shí)際恢復(fù)量 if self.potions 0: return 0 heal 30 before self.hp self.hp min(self.max_hp, self.hp heal) self.potions - 1 return self.hp - before class Dog(Character): 野狗類等級(jí)越高屬性越強(qiáng) def __init__(self, level1): name f兇猛的野狗等級(jí){level} hp 60 level * 10 attack 10 level * 2 defense 1 level super().__init__(name, hp, attack, defense) self.level level這里用了min(self.max_hp, self.hp heal)來限制回復(fù)上限。如果不做這一步角色可能會(huì)通過吃藥把血量加到超過最大值游戲數(shù)值就會(huì)亂掉。4.3 實(shí)現(xiàn)戰(zhàn)斗界面與玩家行動(dòng)接下來是兩個(gè)輔助函數(shù)。show_status 負(fù)責(zé)在回合開始前打印雙方狀態(tài)。player_turn 負(fù)責(zé)接收玩家輸入并執(zhí)行行動(dòng)最后返回一個(gè)字符串標(biāo)記本回合行為供野狗攻擊時(shí)判斷是否需要減傷。def show_status(player, dog): 打印雙方當(dāng)前狀態(tài) print( * 40) print(f【{player.name}】 HP: {player.hp}/{player.max_hp} 藥水: {player.potions}) print(f【{dog.name}】 HP: {dog.hp}/{dog.max_hp}) print( * 40) def player_turn(player, dog): 處理玩家回合返回本回合行為標(biāo)記 print(\n你打算怎么辦) print(1. 攻擊) print(2. 防御) print(3. 使用藥水) print(4. 逃跑) while True: choice input(請(qǐng)輸入數(shù)字 1-4).strip() if choice 1: damage player.attack_target(dog) print(f你揮拳出擊對(duì){dog.name}造成 {damage} 點(diǎn)傷害) return attack if choice 2: print(你壓低身體擺出防御姿態(tài)。) return defend if choice 3: heal player.use_potion() if heal 0: print(f你喝下一瓶藥水恢復(fù) {heal} 點(diǎn)生命值) else: print(你的藥水已經(jīng)用完了) return potion if choice 4: return run print(輸入無效請(qǐng)重新選擇。)這里用input().strip()而不是直接使用 input()是為了去掉用戶輸入時(shí)誤敲的空格。真實(shí)項(xiàng)目中處理用戶輸入時(shí)這個(gè)習(xí)慣也很實(shí)用。4.4 實(shí)現(xiàn)野狗攻擊邏輯野狗攻擊時(shí)有 15% 的概率觸發(fā)暴擊傷害提升 1.5 倍。如果玩家本回合選擇了防御最終傷害先削減 60%只承受 40%。def dog_turn(dog, player, player_choice): 處理野狗回合 if random.random() 0.15: print(f{dog.name} 眼睛發(fā)紅發(fā)動(dòng)暴擊) damage int(dog.attack * 1.5) else: damage dog.attack if player_choice defend: damage int(damage * 0.4) print(你的防御姿態(tài)減輕了傷害) actual player.take_damage(damage) print(f{dog.name} 撲向你造成 {actual} 點(diǎn)傷害)暴擊概率用random.random()實(shí)現(xiàn)它返回 0 到 1 之間的浮點(diǎn)數(shù)。小于 0.15 就觸發(fā)暴擊這樣寫非常直觀。4.5 編寫主程序 main()主程序把前面的模塊串起來。初始化玩家和一只等級(jí)為 1 的野狗進(jìn)入 while 循環(huán)只要雙方都存活就繼續(xù)。玩家選擇逃跑時(shí)有 50% 成功率失敗則野狗繼續(xù)攻擊。def main(): print(歡迎來到『人狗大作戰(zhàn)』!) print(你走在回家的小路上突然一只野狗從草叢里躥