Python | OpenCV 專案:天堂私服遊戲輔助(三)YOLOv8 怪物偵測整合
📑 目錄
⚠️ 免責聲明
本文章內容僅供學術研究與電腦視覺技術學習之用途,所有程式碼與技術說明均以教育目的為出發點。
- 本文作者不提供任何形式的輔助程式販售、散佈或商業服務。
- 本文所有範例程式僅限在自行架設的私有伺服器環境中測試,不得用於任何正式營運的線上遊戲伺服器。
- 使用遊戲輔助程式可能違反個別遊戲的使用者條款,並導致帳號封鎖、法律責任等後果,讀者須自行承擔一切相關風險與責任。
- 本文技術內容若被用於任何違法或損害他人利益之行為,作者概不負責。
- 私有伺服器的架設與使用涉及遊戲著作權相關法律問題,讀者應自行評估所在地區的法規,並確認於合法範圍內使用。
📚 前言
在上一篇 (二)自動補藥 中,我們完成了自動補藥功能,並透過 PostMessage 讓補藥熱鍵即使在背景也能送進目標視窗。
本篇加入 YOLOv8 怪物偵測,核心挑戰在於:YOLO 推論本身耗時,若直接塞進 Thread 1 會拖慢血量偵測的更新速率。解法是新增 Worker Thread 2 專門跑 YOLO,兩個執行緒透過 queue.Queue 溝通。
系列總覽:
| 篇次 | 主題 |
|---|---|
| 一 | 主程式 GUI 框架與 HP/MP 血量監控 |
| 二 | 自動補藥 |
| 本篇(三) | YOLOv8 怪物偵測整合 |
| 四(最終篇) | 目標優先序選擇 |
🎯 本篇目標
- 建立
detector.py:封裝 YOLOv8 推論,並提供 live(畫 bbox) 與 grid(扁平菱形小地圖) 兩種預覽模式 - 新增 Thread 2(
detection_loop)專跑 YOLO,Thread 1 透過frame_q = queue.Queue(maxsize=2)丟舊幀給它,保證推論永遠跑最新畫面 - UI 加入「怪物偵測設定」面板與即時預覽區塊,checkbox 與「🔄 載入模型」都可執行中熱切換
window_capture.py內建HUD_PCT_BY_SIZE查表自動判定 ROI;附錄提供calibrate_game_roi.py讓你擴充新解析度
🗂️ 本篇新增檔案
1 | lineage_assistant/ |
🛠️ 套件安裝
1 | pip install ultralytics pillow |
pywin32、opencv-python、numpy在前兩篇已安裝,不需要重複裝。
📁 模型檔案從哪來
本篇用到的 models/lineage_detector.pt,就是我們在 天堂私服 YOLOv8 物件偵測實戰 中一路從「私服截圖蒐集 → LabelImg 標記 → YOLOv8 訓練」產出的那顆 runs/detect/lineage_detector/weights/best.pt。
只要把它複製或搬到專案的 models/ 目錄下即可:
1 | lineage_assistant/ |
若你還沒訓練過自己的模型,請先回去看上一篇把訓練流程跑完。也可以先拿
yolov8s.pt官方預訓練權重接上來驗證整條管線通不通,只是偵測結果會是 COCO 類別(person、car…)而非怪物。
🗺️ 遊戲畫面 ROI 查表
天堂視窗並不是「拍到什麼都拿來算」:標題列、聊天框、小地圖、上方 HUD 這些區塊都不是真正的世界畫面,拿去推座標會錯。所以要把真正的遊戲畫面在整個視窗內的矩形切出來。
好消息是:Lineage 的內部解析度只有幾個固定選項(400×300、800×600、1200×900…),而且每種解析度配上相同的 Windows 標題列後,擷取到的視窗尺寸跟 HUD 佔比都是固定的。所以作法是:
- 作者私下用小工具對每種解析度量一次 HUD 佔比
- 把結果寫成查表常數放進
window_capture.py - 程式啟動後依
capture_window實際抓到的視窗大小查表,直接選對應HUD_PCT
讀者不用自己校準 —— 除非你的遊戲解析度不在表內,才需要回去跑附錄的 calibrate_game_roi.py 補一筆。
window_capture.py 新增常數與函式
1 | # window_capture.py 底部新增(本篇新增) |
兩個
TILES_PER_HALF_*是遊戲常數(不會因視窗大小而變);換不同客戶端或視角縮放才需要改。
怎麼量 8 / 10? 在遊戲裡把一個不動的地標(例如怪物或 NPC)放在人物正右方一格,往正左方走到地標剛好在畫面右邊界為止,走的格數 +1 就是水平半徑;垂直半徑同理(放正下方、往正上方走)。作者實測 Lineage 預設視角:水平 8、垂直 10。
附錄:新增解析度用的 calibrate_game_roi.py
HUD_PCT_BY_SIZE 沒涵蓋到你的解析度時才需要,流程:選取視窗 → 擷取一幀 → cv2.selectROI 框出「真正的遊戲畫面」→ 換算成四邊百分比印出來,複製一個 key-value 對貼進 HUD_PCT_BY_SIZE 就行。
點此展開 calibrate_game_roi.py 完整程式碼
1 | # calibrate_game_roi.py |

圖:執行 calibrate_game_roi.py,點擊遊戲視窗後拖曳框出真正的遊戲畫面範圍,程式即印出可貼進 HUD_PCT_BY_SIZE 的 key-value 對
💻 偵測模組:detector.py
Detector 有兩個預覽模式:
mode="live":沿用原本的annotate,在原畫面上畫 bbox(適合調 conf、debug 誤判)mode="grid":呼叫render_grid,把偵測結果投影到以角色為中心的扁平等角菱形格(左右 ±8、上下 ±10,對應遊戲實際可視範圍;適合運行中快速看怪物相對方位)
格子地圖的核心是等角(isometric)逆變換。天堂視角旋轉 45°,世界座標東向對應畫面右上,所以把偵測中心的像素偏移 (dx, dy) 換成世界格座標:
1 | tw, th = get_tile_px(...) # = roi_w/16, roi_h/20(水平半徑 8、垂直半徑 10) |
四捨五入即為格子座標。判斷是否在視野內不是用方形 |wx|≤N、|wy|≤N,而是用菱形:|wx+wy| ≤ 16(對應螢幕 ±8 格寬)且 |wy-wx| ≤ 20(對應螢幕 ±10 格高)。格子地圖也只畫這塊菱形裡的 cell,整個小地圖就會跟遊戲畫面一樣扁、佔用空間也小很多。
⚠️
tw和th分母不同(16 vs 20):Lineage 的螢幕可視範圍是左右 8 格、上下 10 格,所以每格在螢幕上是扁的(DW:DH ≈ 2.3:1,不是標準 iso 2:1)。把th當rh/16算會讓上下方向的偵測位置偏掉。
1 | # detector.py |
💻 執行緒架構(本篇)
1 | Worker Thread 1 (monitor_loop) |
💻 主程式:main.py(第三篇版本)

圖:雙執行緒架構,Thread 1 擷取畫面傳入 frame_q,Thread 2 跑 YOLOv8 推論後把 detections / preview 寫回 SharedState,主執行緒每 200ms 更新 tkinter 預覽視窗
⚠️ 注意事項
🧵 執行緒與熱切換
frame_q(maxsize=2)丟舊幀:佇列滿就先get_nowait()丟最舊一幀再放新幀,Thread 2 永遠跑最新畫面、不因推論慢而累積延遲。- 三種熱切換皆下一幀生效、不用停啟:(1)
啟用怪物偵測checkbox 改detector.enabled;(2)「🔄 載入」新建Detector(...)原子指派給self.detector,Thread 2 透過lambda: self.detector下一輪自動吃新模型;(3)conf滑桿由_poll每 200ms 寫回detector.conf。 - 載模型失敗不會崩潰:
_load_detector用 try/except 包住,路徑錯或檔案損毀只寫日誌、保留上一顆模型,監控與補藥照常運作;啟動時找不到預設模型只記 log,勾 checkbox 會提醒先按「🔄 載入」。
❓️ 新手常踩的雷
ImageTk.PhotoImage必須保留參考:存到self._tk_img才不會被 Python GC 回收,否則預覽 Label 會變空白。- worker 掛掉要讓 UI 知道:兩條 worker 都用
try/finally+try/except吞例外;_poll偵測到都掛了會把 ▶/■ 切回「啟動」並在日誌提示。
🗺️ ROI 與格子地圖座標
- 查表 key 是「含標題列的視窗尺寸」:
capture_window抓到整個視窗(含標題列與邊框),所以 key 比遊戲內部解析度大 ~2×27 像素。若解析度不在表內,_pick_hud會找面積最接近的當 fallback,但角標可能對不準 —— 建議跑calibrate_game_roi.py補一筆。 - Lineage 的 tile 是扁的:
get_tile_px回傳(roi_w/16, roi_h/20),分母不同(螢幕寬裝得下 16 個 tile-width、高只裝得下 20 個 tile-height,DW:DH ≈ 2.3:1)。若把th也寫成rh/16,上下方向的偵測位置會偏掉。 - 偵測與繪製都用菱形視野:
|wx+wy| ≤ 16且|wy-wx| ≤ 20,對應螢幕上左右 ±8、上下 ±10 的可視範圍;超出菱形的偵測結果忽略、超出菱形的空格不畫。
🎯 結語
本篇完成了最核心的多執行緒分工:Thread 1 負責螢幕擷取與補藥,Thread 2 負責 YOLO 推論,主執行緒只做 UI,中間用 frame_q 與 SharedState 解耦。
下一篇將加入 (四)目標優先序選擇,讓 Thread 2 在眾多偵測結果中挑出最優先攻擊的目標,並在預覽視窗中用紅框標記它。
📖 如在學習過程中遇到疑問,或是想了解更多相關主題,建議回顧一下 Python | OpenCV 系列導讀,掌握完整的章節目錄,方便快速找到你需要的內容。
註:以上參考了
Ultralytics YOLOv8 官方文件
Pillow ImageTk 文件
Python queue.Queue 文件
tkinter ttk.Combobox