JavaFX 實戰:從零打造一個功能豐富的英文“劊子手”(Hangman)游戲

大家好!今天我們要挑戰一個經典的單詞猜謎游戲——“劊子手”(Hangman),并使用 JavaFX 這個強大的 GUI 工具包來賦予它現代化的交互體驗。這個項目不僅有趣,而且是學習和實踐 JavaFX 核心概念的絕佳途徑,涵蓋了布局管理、自定義繪制、事件處理、狀態管理等多個方面。

我們將構建的這個版本不僅僅是基礎功能,還包含了:

  • 單詞分類選擇: 增加游戲的可玩性和重玩價值。
  • 圖形化絞刑架: 使用 Canvas 動態繪制小人被“吊起”的過程,提供直觀的視覺反饋。
  • 屏幕虛擬鍵盤: 提供界面內交互,更適合觸屏或純鼠標操作。
  • 清晰的狀態反饋: 實時顯示猜測進度、錯誤次數、猜錯的字母等。

無論你是想系統學習 JavaFX,還是尋找一個有一定復雜度的練手項目,這篇文章都將為你提供詳細的實現步驟和深入的技術解析。

一、 設計藍圖:游戲規則與界面構思

在動手編碼前,清晰的設計是成功的關鍵。

游戲規則核心:

  1. 選詞: 程序從預設的單詞庫(按分類)中隨機選擇一個秘密單詞。
  2. 顯示: 單詞以隱藏形式(如下劃線 _)展示給玩家,非字母字符(如空格、連字符)直接顯示。
  3. 猜測: 玩家通過點擊虛擬鍵盤上的字母進行猜測。
  4. 反饋:
    • 猜對: 單詞中所有對應的下劃線被替換為正確的字母。
    • 猜錯: 錯誤次數增加,并在畫布上繪制“小人”的一部分。猜錯的字母會被記錄并顯示。
  5. 勝負條件:
    • 勝利: 在錯誤次數達到上限前,猜出所有字母。
    • 失敗: 錯誤次數達到上限(通常是6次,對應小人的6個部分),游戲結束,顯示答案。
  6. 重玩: 提供“新游戲”功能。

界面布局規劃 (BorderPane):

  • 頂部 (Top): 使用 VBox 放置單詞分類選擇 ComboBox 和一個主要的 Label (statusLabel) 用于顯示游戲提示信息。
  • 左側 (Left): 使用 VBox 放置 Canvas (hangmanCanvas) 用于繪制絞刑架和小人。
  • 中部 (Center): 使用 VBox 放置核心信息:隱藏的單詞 (wordLabel)、錯誤次數統計 (errorsLabel)、猜錯的字母列表 (wrongGuessesLabel) 以及“新游戲”按鈕 (newGameButton)。
  • 底部 (Bottom): 使用 TilePane (keyboardPane) 自動排列 A-Z 的字母按鈕,形成虛擬鍵盤。
    在這里插入圖片描述

二、 JavaFX 實現深度剖析

現在,讓我們深入代碼,逐一解析關鍵技術的實現。

1. 項目基礎與狀態管理

我們創建 HangmanGameFX_EN 類繼承自 Application。核心的游戲狀態由以下成員變量維護:

private Map<String, List<String>> wordCategories = new HashMap<>(); // 單詞庫
private String currentCategory = "Animals"; // 當前分類
private String secretWord;         // 秘密單詞 (大寫)
private StringBuilder displayedWord; // 顯示給玩家的單詞 (帶下劃線)
private int errors;                // 當前錯誤次數
private Set<Character> guessedLetters; // 已猜字母集合 (高效去重)
private boolean gameOver;          // 游戲結束標志
// ... UI 元素引用 ...
private Map<Character, Button> keyboardButtons = new HashMap<>(); // 鍵盤按鈕引用
  • wordCategories: 使用 Map 存儲分類和對應的 List<String>,結構清晰。
  • displayedWord: 使用 StringBuilder 而非 String,因為需要頻繁修改其中的字符(替換下劃線),StringBuilder 性能更好。
  • guessedLetters: 使用 Set<Character> 存儲已猜字母,利用 Set 的特性可以快速判斷一個字母是否已被猜過(contains 操作效率高)。
  • keyboardButtons: 使用 Map<Character, Button> 存儲虛擬鍵盤上每個字母按鈕的引用,鍵是字母本身,值是對應的 Button 對象。這使得我們可以通過字母快速找到并禁用對應的按鈕。
2. 構建動態用戶界面

UI 的構建被拆分到各個 create...Pane() 方法中。

  • 分類選擇 (createTopPane): ComboBox<String> 控件綁定 wordCategories 的鍵集。通過 setOnAction 監聽選擇變化,一旦改變,就更新 currentCategory 并調用 initializeGame() 開始基于新分類的游戲。
  • 單詞顯示 (createCenterPane): wordLabel 使用等寬字體 (Monospaced),確保每個下劃線 _ 占用的寬度一致,視覺效果更好。
  • 虛擬鍵盤 (createKeyboardPane):
    • 使用 TilePane 是個巧妙的選擇。它會自動將子節點(按鈕)排列成網格狀,只需設置 setPrefColumns(期望的列數)和間距 (setHgap, setVgap),布局非常方便。
    • 循環創建 A-Z 按鈕,為每個按鈕設置 setOnAction,調用 handleGuess(letter) 并傳入對應的字母。同時,將按鈕存入 keyboardButtons Map。
3. Canvas 繪圖:動態的絞刑架

這是游戲最具視覺特色的部分。

  • 設置 (createHangmanPane): 創建 Canvas 并獲取其 GraphicsContext (gc)。設置線條寬度和顏色。
  • 繪制絞刑架 (drawGallows): 在游戲初始化時調用,使用 gc.strokeLine() 繪制幾條直線構成基本的絞刑架結構。坐標計算基于 CANVAS_WIDTHCANVAS_HEIGHT 的比例,使得圖形能適應畫布大小。
  • 繪制小人 (drawHangmanPart): 這個方法根據傳入的 errorCount (1-6) 繪制小人的一個新部分(頭、身體、四肢)。使用 switch 語句,每個 case 對應一個錯誤階段,調用 gc.strokeOval() 畫頭,gc.strokeLine() 畫身體和四肢。坐標同樣是相對計算的。
  • 清空畫布 (clearCanvas): 在每次開始新游戲時,需要調用 gc.clearRect() 清除上一次繪制的內容。
// 在 drawHangmanPart(int errorCount) 中
gc.setStroke(HANGMAN_COLOR); // 確保顏色正確
switch (errorCount) {case 1: // Headgc.strokeOval(headX - headRadius, headY - headRadius, headRadius * 2, headRadius * 2);break;case 2: // Bodygc.strokeLine(headX, bodyStartY, headX, bodyEndY);break;// ... case 3, 4, 5, 6 for arms and legs ...
}
4. 核心游戲邏輯:處理猜測 (handleGuess)

這是響應玩家點擊鍵盤按鈕的核心方法,邏輯嚴謹性至關重要:

private void handleGuess(char letter) {// 1. 狀態檢查: 游戲是否結束?字母是否已猜過?if (gameOver) return;letter = Character.toUpperCase(letter); // 統一轉大寫if (guessedLetters.contains(letter)) {// ... (提示已猜過) ...return;}// 2. 更新狀態: 添加到已猜集合,禁用對應按鈕guessedLetters.add(letter);keyboardButtons.get(letter).setDisable(true);// 3. 檢查猜測是否正確boolean found = false;for (int i = 0; i < secretWord.length(); i++) {if (secretWord.charAt(i) == letter) {// 關鍵:更新 displayedWord 中對應位置的下劃線int displayIndex = i * 2; // 乘以2是因為每個字符后有空格if (displayIndex < displayedWord.length()) {displayedWord.setCharAt(displayIndex, letter);}found = true;}}// 4. 更新單詞顯示 UIwordLabel.setText(displayedWord.toString());// 5. 根據猜測結果更新狀態和反饋if (found) {// ... (提示猜對,更新狀態標簽顏色) ...if (checkWin()) endGame(true); // 檢查是否勝利} else {errors++;// ... (更新錯誤標簽,繪制小人部分,更新猜錯字母列表,提示猜錯) ...if (checkLoss()) endGame(false); // 檢查是否失敗}
}

關鍵點解析:

  • 狀態優先檢查: 首先判斷游戲是否結束以及字母是否已猜,避免無效操作。
  • 狀態更新原子性: 將字母加入 guessedLetters 和禁用按鈕緊密關聯。
  • displayedWord 更新: 遍歷 secretWord,找到匹配字母后,計算其在 displayedWord 中的正確索引(考慮到空格,是 i * 2)并替換下劃線。這是保證單詞正確顯示的核心。
  • 分支處理: 清晰地分為 found (猜對) 和 else (猜錯) 兩個分支,分別處理 UI 反饋、狀態更新(errors++)和勝負檢查。
5. 勝負判斷與游戲結束
  • checkWin() 實現非常簡潔,只要 displayedWord 中不再包含 _,就意味著所有字母都已猜出,玩家獲勝。
  • checkLoss() 同樣簡單,只要 errors 達到 MAX_ERRORS,玩家失敗。
  • endGame(boolean won) 負責游戲結束時的收尾工作:設置 gameOver 標志,禁用所有鍵盤按鈕和分類選擇,并根據 won 參數顯示最終的勝利或失敗信息(失敗時揭示答案)。
6. 游戲初始化與重置 (initializeGame)

提供良好的“再來一局”體驗很重要。initializeGame 方法做了所有必要的重置工作:

  • 重置錯誤次數、已猜字母集合、gameOver 標志。
  • 調用 chooseNewWord() 獲取新單詞。
  • 重新生成帶下劃線的 displayedWord
  • 重置所有 UI 元素到初始狀態(標簽文本、畫布、鍵盤按鈕可用性)。

三、 總結與展望

通過這個 Hangman 項目,我們不僅實現了一個經典游戲,更重要的是,我們深入實踐了 JavaFX 的許多核心功能:

  • 布局系統: BorderPane, VBox, HBox, TilePane 的組合使用。
  • 控件交互: Button, Label, ComboBox 的事件處理和狀態更新。
  • 自定義繪圖: 利用 CanvasGraphicsContext 實現動態圖形繪制。
  • 狀態管理: 通過成員變量和枚舉(雖然此版本未使用枚舉,但概念相通)清晰地管理游戲進程。
  • 數據結構應用: Map 用于單詞庫和按鈕引用,Set 用于高效存儲已猜字母,StringBuilder 用于高效構建顯示單詞。

這個項目也為進一步探索留下了空間:

  • 美化與主題: 應用 CSS 打造更個性化的外觀。
  • 動畫效果: 為小人繪制、字母顯示等添加過渡動畫。
  • 音效反饋: 增加點擊、猜對、猜錯、游戲結束的音效。
  • 單詞庫管理: 從文件加載單詞,甚至允許用戶添加自定義單詞或分類。
  • 更智能的提示: 例如提供一個“提示”按鈕,隨機顯示一個未猜中的字母(并計為一次錯誤)。

希望這篇詳細的開發日志能幫助你理解使用 JavaFX 構建交互式應用的具體過程,并激發你動手嘗試和創造的熱情。Happy coding!


附注: 上述代碼片段是說明性的,完整的可運行代碼文前資源文件中的java完整示例。確保你的開發環境已正確配置 JavaFX。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/77930.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/77930.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/77930.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【自我介紹前端界面分享】附源碼

我用夸克網盤分享了「800套HTML模板」&#xff0c;鏈接&#xff1a;https://pan.quark.cn/s/a205a794552c <!DOCTYPE HTML> <html> <head> <title>Miniport</title> <meta http-equiv"content-type" content&q…

安寶特分享|AR智能裝備賦能企業效率躍升

AR裝備開啟智能培訓新時代 在智能制造與數字化轉型浪潮下&#xff0c;傳統培訓體系正面臨深度重構。安寶特基于工業級AR智能終端打造的培訓系統&#xff0c;可助力企業構建智慧培訓新生態。 AR技術在不同領域的助力 01遠程指導方面 相較于傳統視頻教學的單向輸出模式&#x…

今日html筆記

原手寫筆記 ------------------------------------------------------------------------------------------------------- 關于超鏈接的使用 <a href"https://www.luogu.com.cn/" target"_blank">//href屬性指定了超鏈接的目標地址,即當用戶點擊超…

【人工智能】Ollama 負載均衡革命:多用戶大模型服務的高效調度與優化

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 在 多用戶大模型推理 場景下,負載均衡 是確保高并發、低延遲的關鍵挑戰。本文以 Ollama(一個流行的本地大模型運行框架)為例,深入探討 …

線上救急-AWS限頻

線上救急-AWS限頻 問題 在一個天氣炎熱的下午&#xff0c;我正喝著可口可樂&#xff0c;悠閑地看著Cursor生成代碼&#xff0c;忽然各大群聊中出現了加急?全體的消息&#xff0c;當時就心里一咯噔&#xff0c;點開一看&#xff0c;果然&#xff0c;線上服務出問題&#xff0…

Maven 項目中引入本地 JAR 包

在日常開發過程中&#xff0c;我們有時會遇到一些未上傳到 Maven 中央倉庫或公司私有倉庫的 JAR 包&#xff0c;比如第三方提供的 SDK 或自己編譯的庫。這時候&#xff0c;我們就需要將這些 JAR 包手動引入到 Maven 項目中。本文將介紹兩種常見方式&#xff1a;將 JAR 安裝到本…

解鎖webpack:對html、css、js及圖片資源的抽離打包處理

面試被問到webpack&#xff0c;可別只知道說 HtmlWebpackPlugin 了哇。 前期準備 安裝依賴 npm init -y npm install webpack webpack-cli --save-dev配置打包命令 // package.json {"scripts": {// ... 其他配置信息"build": "webpack --mode pr…

SpringBoot整合SSE,基于okhttp

一、引入依賴 <dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.10.0</version> </dependency> <dependency><groupId>com.squareup.okhttp3</groupId><…

【哈希表】1399. 統計最大組的數目

1399. 統計最大組的數目 - 力扣&#xff08;LeetCode&#xff09; 給你一個整數 n 。請你先求出從 1 到 n 的每個整數 10 進制表示下的數位和&#xff08;每一位上的數字相加&#xff09;&#xff0c;然后把數位和相等的數字放到同一個組中。 請你統計每個組中的數字數目&…

手動實現LinkedList

前言 大家好&#xff0c;我是Maybe。最近在學習數據結構中的鏈表&#xff0c;自己手動實現了一個LinkedList。我想與大家分享一下。 思維導圖 代碼部分 package Constant;public class constant {public static final String INDEX_IS_WRONG"輸入的下標不合法"; }p…

如何檢查瀏覽器是否啟用了WebGL2.0硬件加速

一:WebGL Inspector使用 打開 Chrome 或 Edge(推薦使用 Chromium 內核瀏覽器)。 安裝插件: ?? Spector.js on Chrome Web Store 安裝完成后,在瀏覽器工具欄看到綠色的 S 圖標 二:捕獲 WebGL 渲染幀 打開你要分析的 Web3D 網站(比如 https://3dviewer.net)。 點擊瀏…

“時間”,在數據處理中的真身——弼馬溫一般『無所不能』(DeepSeek)

電子表格時間處理真理&#xff1a;數值存儲最瘦身&#xff0c;真身闖關通四海。 筆記模板由python腳本于2025-04-23 22:25:59創建&#xff0c;本篇筆記適合喜歡在電子表格中探求時間格式的coder翻閱。 【學習的細節是歡悅的歷程】 博客的核心價值&#xff1a;在于輸出思考與經驗…

AXOP39062: 25MHz軌到軌輸入輸出雙通道運算放大器

AXOP39062是用于低壓應用(1.5V~5.5V)的雙通道運算放大器&#xff0c;具有軌到軌的輸入輸出工作范圍&#xff0c;非常適合需要小尺寸、大容性負載驅動能力的低壓應用。產品具有25MHz的增益帶寬&#xff0c;具有優異的噪聲性能和極低的失真度。 主要特性 軌到軌的輸入輸出范圍低…

基于大模型的胃食管反流病全周期預測與診療方案研究

目錄 一、引言 1.1 研究背景與意義 1.2 研究目的與創新點 二、胃食管反流病概述 2.1 疾病定義與分類 2.2 流行病學特征 2.3 發病機制 三、大模型技術原理與應用基礎 3.1 大模型簡介 3.2 適用于胃食管反流病預測的大模型類型 3.3 數據收集與預處理 四、大模型在胃食…

西門子S7-200SMART 控制Profinet閉環步進MD-4250-PN (1)電機及專欄介紹

一、前言 本系列是我繼 《西門子S7-1200PLC 控制步進電機 MD-4240-PN》系列專欄后&#xff0c;新開的一篇專欄。 系列的主題圍繞 S7-200SMART Profinet閉環步進(MD-4250-PN) 觸摸屏的硬件&#xff0c;預計作四篇文章&#xff0c;分別為&#xff1a;專欄介紹、硬件介紹、PLC…

bedtools coverage 獲取每個位置的測序深度

1.bedtools 文檔 $ bedtools --version bedtools v2.31.1coverage Compute the coverage over defined intervals. Usage:bedtools coverage [OPTIONS] -a <FILE> \-b <FILE1, FILE2, ..., FILEN>(or):coverageBed [OPTIONS] -a <FILE> \-b <FILE1,…

反向代理和DDNS的區別是什么?

反向代理&#xff08;Reverse Proxy&#xff09;和動態域名解析&#xff08;DDNS&#xff0c;Dynamic Domain Name System&#xff09;是兩種不同的網絡技術&#xff0c;雖然它們都與外部訪問內部服務相關&#xff0c;但解決的問題和應用場景完全不同。具體區別如下&#xff1a…

縮放點積注意力

Scaled Dot-Product Attention 論文地址 https://arxiv.org/pdf/1706.03762 注意力機制介紹 縮放點積注意力是Transformer模型的核心組件&#xff0c;用于計算序列中不同位置之間的關聯程度。其核心思想是通過查詢向量&#xff08;query&#xff09;和鍵向量&#xff08;key&am…

可吸收聚合物:醫療科技與綠色未來的交匯點

可吸收聚合物&#xff08;Biodegradable Polymers&#xff09;作為生物醫學工程的核心材料&#xff0c;正引領一場從“金屬/塑料植入物”到“智能降解材料”的范式轉移。根據QYResearch&#xff08;恒州博智&#xff09;預測&#xff0c;2031年全球可吸收聚合物市場銷售額將突破…

房地產項目績效考核管理制度與績效提升

房地產項目績效考核管理制度的核心目的是通過合理的績效考核機制&#xff0c;提升項目的整體運作效率&#xff0c;并鼓勵項目團隊成員的積極性。該制度適用于所有房地產項目部工作人員&#xff0c;涵蓋了項目經理和項目成員的考核。考核的主要內容包括項目經理和項目部成員的工…