端午划龙舟 — 用 Pygame 做了一款打字竞速游戏
端午节到了,突发奇想用 Python + Pygame 做了一款划龙舟游戏。
用键盘敲字母来划船,和电脑 AI 在河道上比谁先到终点。
代码、音乐、图片全由 AI 辅助完成。
游戏效果
主界面,游戏功能有单人模式 和 人机对战模式

单人游戏

游戏失败

双人游戏,ai玩家会自动网上划船,你得追赶上它,不然游戏失败。

游戏简介
《龙舟划船》是一款打字竞速游戏。玩家通过快速准确地敲出屏幕上显示的字母序列来驱动龙舟前进,在规定时间内划完 840 米(游戏内距离单位)即为胜利。
游戏提供两种模式:
- 单人模式 — 独自挑战,在 60 秒内抵达终点
- 人机对战 — AI 对手自动打字,两条船同场竞技
核心玩法
- 屏幕上方显示一组 5 位随机英文字母(如
a k f j d) - 键盘敲对当前高亮的字母 → 船向前划 +4 距离,船身向前俯仰,船尾溅出水花粒子
- 敲完整组字母 → 额外奖励 +8 距离,刷新下一组
- 敲错字母 → 罚停 0.7 秒,船上闪烁红色,这段时间按键无效
- 游戏限时 60 秒,倒计时最后 10 秒闪烁警告
- 底部进度条实时显示距离百分比
- 船身带 2° 正弦波浪浮沉,划桨时改为 6° 快速俯仰模拟发力
模式详解
单人模式
单人模式的逻辑简单直接:玩家独自与 60 秒倒计时赛跑。
- 起跑:从菜单按 Enter/Space 或点击"单人游戏"按钮进入
- 过程:纯靠自己手速,没有对手干扰,也没有外部加速/减速
- 目标:在倒计时归零前累积到 840 距离
- 胜利:达到目标 → 显示胜利画面"你赢了!",播放胜利音效
- 失败:倒计时归零 → 显示"游戏结束!",显示最终进度百分比,播放失败音效
- 重开:按 Enter 或 Space 返回菜单
设计要点:单人是熟悉机制的训练场。由于没有对手压力,玩家可以专注于字母定位和节奏感培养。840 的目标 ÷ 每次操作 +4 = 210 次正确击键,按单人平均 350-400 次/分钟的手速计算,理论上 32-36 秒就能完成,留出了容错空间。
人机对战
人机对战是游戏的核心体验。两条龙舟同屏竞速,AI 自动打字,视觉差距实时反映谁领先。
- 起跑:按
2键或点击"人机对战"按钮进入 - 布局:
- 玩家龙舟在右侧(60% 画面宽度处),AI 龙舟在左侧(40% 画面宽度处)
- 船上方各有标签"玩 家"和"电 脑"
- 背景河流跟随玩家进度滚动,AI 的垂直位置反映它的领先差距
- AI 打字逻辑(详见技术要点部分):
- AI 每 0.45 秒自动敲一个字母,间隔加上随机扰动 ±0.12 秒
- 93% 准确率 — 7% 概率敲错字母(自身罚停 0.7 秒)
- 橡筋追赶:AI 领先时减速、落后时加速,差距调节因子 ±0.15 秒
- 结算:时间归零时比较双方完成的字母组数
- 玩家组数 > AI → “玩家获胜!”
- 玩家组数 < AI → “电脑获胜!”
- 组数相同 → “平局!”
设计要点:AI 故意被设计成"虽强但能赢"。基础速度与人类中高水平相当,橡筋机制保证落后可以追回来,7% 的随机失误让比赛结果不那么机械。AI 领先时船升起的高度可视化地提醒玩家"再不加速就输了"。
两种模式对比
| 特性 | 单人模式 | 人机对战 |
|---|---|---|
| 对手 | 倒计时 | AI 对手 |
| 胜负条件 | 840 距离 | 字母组数 pk |
| 画面焦点 | 单船 | 双船并排 |
| 紧张感 | 中(与时间赛跑) | 高(与对手赛跑) |
| AI 追赶机制 | — | 橡筋 + 随机失误 |
| 适合场景 | 热身 / 练手速 | 核心竞技 |
架构设计
项目采用分层架构,代码按职责分为 8 个模块:
龙舟划船/
├── audio/ # 音效(AI 生成)
│ ├── bg.wav # 背景音乐
│ ├── effect.wav # 划桨音效
│ ├── win.wav # 胜利音效
│ └── lose.wav # 失败音效
├── images/ # 图片(AI 生成)
│ ├── bg.png # 河道背景
│ ├── 1.png / 2.png # 龙舟划桨两帧动画
└── src/ # 源代码(AI 编写)
├── config.py # 常量配置层 — 屏幕/颜色/游戏参数
├── assets.py # 资源加载层 — 图片/音效/字体/屏幕
├── state.py # 数据逻辑层 — 状态字典/序列生成/按键处理
├── input_handler.py # 输入映射层 — 键盘编码 → 字母
├── particles.py # 粒子系统 — 船尾水花效果
├── renderer.py # 渲染表现层 — 背景/船/HUD/菜单/结算
└── main.py # 入口控制层 — 游戏循环/事件分发
各层职责
| 模块 | 职责 |
|---|---|
config.py | 所有数字参数集中管理:屏幕尺寸、颜色、游戏时长、AI 速度等 |
assets.py | 初始化 Pygame,加载图片、音效、字体;模块级别全局引用 |
state.py | 游戏状态字典的创建与更新;字母序列生成;正确/错误按键处理 |
input_handler.py | 两种键盘映射方案(keycode + scancode),兼容不同键盘布局 |
particles.py | 简单的粒子类,每次划桨在船尾生成 6 颗水花 |
renderer.py | 所有绘制逻辑:背景、船、HUD、菜单、胜负画面 |
main.py | 主循环:处理事件 → 更新状态 → 渲染画面 |
技术要点
背景河流滚动
河道图片 bg.png 等比放大 1.5 倍后居中裁切,总可滚动高度达 1908 像素。玩家距离进度通过平滑插值映射为背景纵向偏移:
target = -int(BG_MAX_SCROLL * (1.0 - prog))
g["scroll_y"] += (target - g["scroll_y"]) * 0.08
0.08 的 lerp 因子让画面跟随节奏平滑过渡,没有突兀跳跃。在人机对战中也保持以玩家进度为基准滚动,确保玩家视线始终稳定。
人机对战 — 橡筋追赶
AI 对手并非固定速度,而是加入了橡筋效应:
diff = g["ai_dist"] - g["dist"]
rb = diff / GOAL_DIST * 0.35
interval = AI_TYPING_INTERVAL + clamp(rb, -0.15, 0.15)
AI 领先越多打字越慢,落后越多打字越快。0.15 秒的 clamp 极限防止 AI 极端变速。配合 93% 的随机准确率,每局比赛的胜负悬念一直保持到最后几秒。
双船视觉逻辑
- 玩家船固定在屏幕底部,始终可见
- AI 船以进度差
max(0, ai_prog - p_prog)为单位向上偏移,偏移范围 800 像素 - AI 领先 100% 进度 → 船升到顶;AI 落后 → 与玩家船平齐
- 这种设计确保视觉差距就是实际的进度差距,不会产生"明明领先但船在后面"的误解
动画与粒子
| 效果 | 实现方式 |
|---|---|
| 船身浮沉 | sin(elapsed * 2.5) 振幅 2px,模拟水流 |
| 划桨俯仰 | sin(elapsed * 16) 振幅 6px,持续到 row_timer 归零(0.15s) |
| 船桨动画 | row_timer > 0 时两帧交替切换(0.15s/帧) |
| 水花粒子 | 正确击键时在船尾生成 6 个 Splash 粒子,随机方向扩散,0.6s 后淡出消失 |
| AI 水花 | AI 正确击键时同步生成 AI 船尾水花 |
| 错误闪烁 | 按键错误时船身叠加半透明红色遮罩,0.15s 后消退 |
| 罚停遮罩 | 罚停期间叠加灰色遮罩,表示船被定住 |
菜单与状态切换
- 游戏启动 → 菜单画面(黑色淡入覆盖),显示中文标题和两个按钮
- 按钮支持鼠标点击和键盘快捷键
- 比赛结束 → 半透明黑色遮罩 + 结果文字 + 提示"按 Enter/Space 返回菜单"
- 所有 HUD 元素(计时器、进度条、字母序列、调试信息)在菜单状态时完全隐藏,只在比赛中显示
输入兼容
支持 TEXTINPUT 事件和 KEYDOWN 两种输入通道,并加入 60ms 去抖,确保中英文输入法切换时不出双发。键盘映射同时维护 keycode 和 scancode 两套映射表,适配不同键盘布局。
AI 辅助开发
本项目所有要素均由 AI 辅助生成:
- 代码:使用 Claude(Anthropic)通过自然语言对话生成完整代码,包括架构设计、重构、功能迭代
- 图片:河道背景和龙舟两帧动画使用 AI 图像生成工具产出
- 音效:划桨音效、背景音乐、胜负音效均由 AI 音乐生成工具制作
开发过程完全是"用嘴写代码"——通过对话式交互,从零开始迭代出完整的游戏。
运行方式
# 进入项目目录
cd 龙舟划船/
# 运行游戏
python src/main.py
依赖:pygame 库(pip install pygame)。
源码下载github
我将这个龙舟游戏整合到我的python小游戏合集里面,希望大家可以自行下载修改 拥抱欢乐!!
python小游戏合集下载链接在此
总结
这是一次很有意思的尝试:用 AI 从零生成一个完整的游戏项目。从最初的功能原型,到分层架构重构,再到人机对战和视觉调优,全程通过自然语言对话完成。
端午节,龙舟赛,键盘做桨,代码为舟。祝大家端午安康!

476

被折叠的 条评论
为什么被折叠?



