基于Java Swing的禁忌岛桌面游戏

  • 模板大小:2.05M
  • 浏览次数:4次
  • 最后更新:2026-05-19
立即下载 查看演示

注意:IT技能网提供的所有源代码或模板仅供学习交流使用。

基于Java Swing的禁忌岛桌面游戏

禁忌岛(Forbidden Island)桌游数字化实现系统介绍

一、项目概述

本项目是对经典合作型桌游《禁忌岛》的完整数字化复刻,采用纯 Java 语言开发,基于 Java Swing 构建图形用户界面,支持 2~4 名玩家本地多人协作游玩。游戏完整还原了原版规则:玩家需在小岛持续沉没的压迫下,分工合作收集四件神圣宝藏,并于直升机停机坪集合起飞,方可取得胜利。


二、整体架构设计

系统整体采用 分层架构 + 观察者模式 的设计思路,核心分为三层:

┌─────────────────────────────────────────────┐
│              UI 层(Java Swing)             │
│  ForbiddenIslandFrame / GamePanel / Tile    │
│  OperatePanel / PlayerPanel / WaterMeter    │
└──────────────────┬──────────────────────────┘
                   │  事件触发 / 渲染刷新
┌──────────────────▼──────────────────────────┐
│           控制层(MVC Controller)           │
│  GameController(按钮监听 / 动作分发)       │
│  GameListener(全局鼠标/键盘监听)           │
└──────────────────┬──────────────────────────┘
                   │  状态读写
┌──────────────────▼──────────────────────────┐
│              数据层(Game Engine)           │
│  ForbiddenIslandGame(回合状态机)           │
│  ElementEngine(游戏元素管理)               │
│  TileBoard / Deck / Adventurer 等           │
└─────────────────────────────────────────────┘

核心引擎双轨设计

引擎 职责
元素引擎 ElementEngine 管理所有游戏数据:牌堆、地图、角色、卡牌选择等
渲染引擎 RenderingEngine 统一调度各 UI 子模块(6个渲染器)的刷新

两引擎完全解耦:控制层调用 ElementEngine 修改状态后,再调用 RenderingEngine.getXxxRendering().update() 触发对应 UI 刷新,实现数据与视图的分离。


三、核心技术实现

3.1 回合状态机(ForbiddenIslandGame

游戏回合由一个静态状态机全局管理,通过若干状态变量驱动整个游戏流程:

private static int roundNum;        // 当前回合玩家索引
private static int actionCount;     // 本回合已用行动数(上限3)
private static boolean stage23Done; // 是否已完成阶段2、3(抽牌/沉没)
private static boolean need2save;   // 是否有玩家落水待救援
private static boolean inFakeRound; // 是否处于"虚拟回合"

回合流程分三个阶段

  1. 阶段1:当前玩家执行最多 3 个动作(移动/加固/传卡/捕宝等)
  2. 阶段2:抽取 2 张宝藏卡,处理"水位上升"特殊卡
  3. 阶段3:按当前水位抽取相应数量的洪水卡,沉没对应地块

3.2 “虚拟回合”(Fake Round)机制

这是本系统中最具代表性的核心设计之一。当出现以下场景时,系统需要临时"插入"一个不消耗正常回合的操作窗口:

  • 玩家落水:地块完全沉没,其上的玩家需立刻游向邻近格,此时插入虚拟回合,限定该玩家最多移动 2 步
  • 传牌手牌超限:接收方满 5 张手牌时,临时切换至接收方让其先弃牌
  • 信使/导航员特殊能力:需临时切换操控目标玩家

实现方式是将真实状态快照存储在 fakeRoundNum / fakeActionCount 中,处理完成后还原:

// 进入虚拟回合
ForbiddenIslandGame.setFakeRoundNum(currentRound); // 保存当前回合
ForbiddenIslandGame.setFakeActionCount(actionCount);
ForbiddenIslandGame.setRoundNum(targetPlayer);      // 切换控制权
ForbiddenIslandGame.setActionCount(2);              // 限制行动数

// 虚拟回合结束后恢复
ForbiddenIslandGame.setRoundNum(fakeRoundNum);
ForbiddenIslandGame.setActionCount(fakeActionCount);

3.3 地图系统的坐标双向映射

游戏地图为 6×6 网格,但实际可用格子仅 24 个(菱形分布),其余 12 个为空白占位格。Map 工具类维护两张 HashMap 实现 O(1) 的双向查询:

// 编号 → [行, 列] 坐标
HashMap<Integer, int[]> coordinatesMatcher;

// "[行, 列]"字符串 → 编号
HashMap<String, Integer> numberMatcher;

TileBoard 在初始化时将 24 个地块编号(1~24)随机洗牌后按此坐标布置,保证每局地图随机性。


3.4 多态角色系统

所有角色继承自抽象类 Adventurer,通过多态实现差异化技能:

角色 特殊技能实现方式
潜水员(Diver) 落水后可移动至距离最近的任意存在格(欧氏距离最短格集合)
探索者(Explorer) canNormalMove() 中允许斜对角方向移动及加固
飞行员(Pilot) 可移动到地图上任意存在格,不受邻接限制
工程师(Engineer) shoreUpCount 计数器,每回合首次加固后额外获得一次免费加固机会
信使(Messenger) 传牌时跳过"同格限制"检查,可跨格传牌
导航员(Navigator) 借助虚拟回合机制,临时切换控制其他玩家移动

落水后的游泳检测对探索者专门处理了斜向格:

boolean upLeft   = isExplorer && x>0 && y>0 && board.getTile(x-1,y-1).isExist();
boolean upRight  = isExplorer && x>0 && y<5 && board.getTile(x-1,y+1).isExist();
boolean downLeft = isExplorer && x<5 && y>0 && board.getTile(x+1,y-1).isExist();
boolean downRight= isExplorer && x<5 && y<5 && board.getTile(x+1,y+1).isExist();
return up || down || left || right || upLeft || upRight || downLeft || downRight;

3.5 牌堆系统(Deck 模板 + 两类子类)

Deck 抽象基类统一管理"牌堆"与"弃牌堆",两个子类各自扩展:

FloodDeck(洪水牌堆)

  • 初始发 6 张固定数量,之后按水位计动态决定每回合抽牌数
  • 触发"水位上升"卡时,将弃牌堆洗牌后置顶(putBack2Top()),提升后续洪水频率
  • 地块永久沉没时调用 removeFloodCard() 将对应洪水牌踢出牌池,确保已沉没地块不再被抽到

TreasureDeck(宝藏牌堆)

  • 管理 28 张宝藏卡(20 张宝物卡 + 3 张直升机卡 + 2 张沙袋卡 + 3 张水位升卡)
  • 发初始手牌时过滤"水位上升"卡(getNoRiseCards()),保证初始手牌合法

3.6 渲染引擎(分模块渲染 + 统一接口)

所有 UI 子模块实现统一接口:

interface IRendering {
    void update();  // 刷新界面
    void finish();  // 游戏结束时禁用所有控件
}

RenderingEngine 作为单例容器持有 6 个渲染器实例:

渲染器 负责区域
TileRendering 游戏地图格子
FloodRendering 洪水卡牌展示区
PlayerRendering 玩家手牌与状态面板
TreasureRendering 宝藏卡牌展示区
WaterMeterRendering 水位计
ControllersRendering 操作按钮区

控制层按需精确刷新对应模块,避免全量重绘,提升界面响应效率。


3.7 胜负判定

失败条件(任一触发):

  • 任意宝藏的两块神殿均沉没且该宝藏未被收集(isShrinesFlooded()
  • 玩家落水后无任何邻接可移动格(无路可逃)

胜利条件(同时满足):

  • 所有玩家集合于直升机停机坪(Tile #14)
  • 4 件宝藏全部收集完毕
  • 至少持有 1 张直升机起飞卡(编号 20/21/22)

四、测试支持

项目引入 JUnit 4.13.1 进行单元测试,并包含 hamcrest-core-1.3.jar 断言增强库,对各游戏逻辑单元的正确性提供了测试保障。


五、技术栈汇总

技术/组件 版本 用途
Java SE 8+ 核心开发语言
Java Swing JDK 内置 GUI 框架(JFrame/JPanel/JButton 等)
JUnit 4.13.1 单元测试
Hamcrest 1.3 测试断言增强
Collections.shuffle JDK 内置 地图/牌堆随机洗牌

六、包结构总览

com.forbidden.island
├── Application.java                  # 程序入口
├── ForbiddenIslandGame.java          # 回合状态机(核心逻辑)
├── adventurer/                       # 角色模块
│   ├── Adventurer.java               # 角色抽象基类
│   ├── Diver / Engineer / Explorer   # 各角色具体实现
│   ├── Messenger / Navigator / Pilot
├── cards/                            # 牌堆模块
│   ├── Deck.java                     # 牌堆抽象基类
│   ├── FloodDeck.java                # 洪水牌堆
│   └── TreasureDeck.java             # 宝藏牌堆
├── enums/                            # 枚举定义
│   ├── TileStatus.java               # 地块状态(正常/淹没/沉没)
│   └── TreasureFigurines.java        # 宝藏雕像类型
├── listener/                         # 控制层
│   ├── GameController.java           # 按钮事件分发
│   └── GameListener.java             # 全局事件监听
├── ui/                               # 视图层
│   ├── ElementEngine.java            # 元素引擎
│   ├── TileBoard.java                # 游戏地图
│   ├── Tile.java                     # 地块单元
│   ├── WaterMeter.java               # 水位计
│   ├── handler/                      # 渲染子模块
│   │   ├── IRendering.java           # 渲染接口
│   │   ├── RenderingEngine.java      # 渲染引擎(统一管理)
│   │   └── TileRendering / FloodRendering / ...
└── utils/                            # 工具类
    ├── Map.java                      # 坐标双向映射
    ├── ImageUtil.java                # 图片加载工具
    ├── Constant.java                 # 全局常量
    └── LogUtil.java                  # 控制台日志

本系统完整实现了《禁忌岛》的全部规则,通过状态机驱动回合流程虚拟回合处理复杂中断多态角色封装差异化技能双引擎解耦数据与视图,工程结构清晰,扩展性良好。

相关推荐