技术博客:从零到一,我如何用纯前端做出一款「点球大战」小游戏
技术博客:从零到一,我如何用纯前端做出一款「点球大战」小游戏
作者:Eddygit
项目仓库:football-game
文章分类:前端实践 / 游戏开发 / 华为云开发者训练营作品
一、技术路线
这款「点球大战 · Penalty Kick」是一个单文件、零依赖、纯前端的小游戏。整个项目只有两个文件:index.html(内嵌 HTML + CSS + JavaScript)和 README.md。选择这条路线的理由很直接:
- 零门槛运行:不需要构建工具、不需要服务器,双击浏览器就能玩,最适合作为训练营/教学场景的演示作品。
- Canvas 2D 足够:游戏场景是绿茵场、球门、足球、守门员,属于 2D 矢量绘制范畴,
<canvas>的 2D 上下文完全够用,无需引入 Three.js 等重型库。 - 状态机驱动:游戏流程较长(瞄准 → 射门 → 守门员扑救 → 电脑射门 → 结算),用清晰的阶段状态机管理,比零散的 if/else 更容易维护。
技术栈可一句话概括:HTML + CSS + Canvas 2D + requestAnimationFrame + 状态机。
二、技术心得
1. 状态机是游戏的主心骨
我把整局游戏拆成几个阶段:
aim(瞄准) → shoot(玩家射门动画) → flash(定格) → saveSelect(玩家守门选择) → cpuShoot(电脑射门) → gameOver(结算)
每个阶段只做自己的事,阶段切换是唯一改变游戏行为的地方。这个设计让代码心智负担很小:写「玩家射门」时完全不关心「电脑射门」的逻辑,各阶段互不干扰。
踩过的坑:JavaScript 的 setTimeout 回调很容易串台——比如玩家快速按两次射门,上一个动画还没结束,新的回调又触发了。我的解法是引入「局代数」S.gen,每次进入新阶段就自增,回调执行前先检查 gen 是否还是当前局代,不是就直接丢弃。这是我在实战中觉得最值的一个小技巧。
2. 命中判定:覆盖区碰撞模型
射门命中的核心问题是「守门员有没有扑到球」。我没有用复杂的物理引擎,而是用一个覆盖区模型:
- 守门员有一个扑救覆盖半径
KEEPER_COVER = 62; - 球到达门线时,如果球的落点
x与守门员扑救中心gx的距离小于该半径,就判定「扑出」; - 慢速球(力度 < 50)覆盖半径还会 +14,模拟「球速慢更容易被扑到」的真实感;
- 贴门柱射门则单独做「中柱」边界判定。
这个模型把复杂的碰撞检测简化为一次距离比较,效果却足够「像真的」,性价比非常高。
3. 动画:requestAnimationFrame + 缓动函数
球的飞行、守门员的飞扑都用 requestAnimationFrame 逐帧驱动,配合 easeOutQuad 缓动让运动「由快变慢」,比线性运动更有质感。守门员扑救时我做了骨骼倾斜 + 手臂伸展的细节,只是几行坐标变换,画面生动度提升明显。
4. AI 博弈的平衡
守门员的扑救是「62% 概率预判玩家瞄准方向 + 随机猜边」,这样既不会让玩家觉得「AI 永远猜中」而挫败,也不会太笨。扑救重心只取左/中/右三档,避免了无限细分的判定复杂度。
三、实战经验
开发流程上的收获
这次我用的是华为云 CodeArts 智能体 + ACP 协议的协作方式:我先用自然语言描述需求(玩法、视觉、约束),AI 生成完整代码并自我验证(HTML 结构检查、JS 语法 node --check、HTTP 200 探测),我再做人工验收。最大的感受是:
- 需求描述越具体,产出越接近预期:我把「命中判定模型」「守门员扑救概率」「射门力度阈值」都写进 prompt,AI 生成的逻辑几乎不需要返工;
- AI 自测 + 人工复核要结合:AI 会做静态检查,但「手感」这种东西只有人玩过才知道,所以最终一定要自己跑起来玩两局。
上云与发布流程
作品完成后,我把它推到了 GitCode 仓库(Eddygit/football-game),并通过华为云开发者训练营的「作品展览馆」流程投稿:解析 IAM Domain → 生成 STS 临时凭证 → 启动本地服务 → 生成封面/简介/详情 zip → 选择训练营 → 发布。这条路把「本地写好代码」到「作品上架展示」串成了一条自动化流水线,对独立开发者很友好。
四、存在问题与优化空间
诚实地说,这个作品还远不完美:
- 玩法深度有限:目前射门是「鼠标瞄准 + 力度滑杆」,没有「助跑/方向键拉弧线」等进阶操作;守门员扑救也只有三档方向。后续可以加入射门蓄力条、弧线球(香蕉球)轨迹、搓射/挑射等技巧球。
- 没有音效:进球、扑救、哨声都是静默的。用
Web Audio API合成简单音效(甚至不需要音频文件)可以极大提升沉浸感。 - 没有移动端适配:目前是桌面鼠标交互,触屏上瞄准/拖拽体验一般。优化方向是加入 touch 事件、响应式画布缩放。
- AI 可以更聪明:现在的守门员是「概率预判」,可以升级为记录玩家历史射门习惯、动态调整扑救倾向(类似简单强化学习),让 AI 会「学习」。
- 可玩性扩展:可以增加难度分级、世界杯淘汰赛模式、多人轮流罚球、排行分数等,让游戏从「demo」向「可传播的小产品」进化。
- 工程化:单文件适合展示,但代码已经 700+ 行,继续加功能会变臃肿;下一步可以拆分为模块(用 ES Module)或引入 Vite 做构建。
五、总结
这个作品体量不大,但「麻雀虽小五脏俱全」:状态机、动画循环、碰撞检测、简单 AI、记分与结算,几乎覆盖了 2D 小游戏开发的全部基础命题。对初学者来说,它是一个很好的第一课:用最少的工具,做出一件能玩、能分享、能上架展览馆的完整作品。
如果你也想做点什么,我的建议是:先做一个能跑的最小版本,再一点点加细节。游戏开发的乐趣,就在那句「再来一局」里。
- 点赞
- 收藏
- 关注作者
评论(0)