上个月,我用Unity做了一个打砖块单机游戏。规则很简单,屏幕下方一块挡板,控制它接住弹跳的小球,把上方密密麻麻的砖块全部砸碎就算过关。说实话,我从来没写过游戏代码,只是看过几篇教程,但就是想试试。
我打开Unity Hub,建了个2D项目,版本选了2022.3 LTS,因为别人说长期支持版稳定。场景里首先要三样东西:挡板、小球、砖块。挡板用Unity自带的精灵方块,拉成宽2.4、高0.2的长条,放在屏幕底部。小球是个直径0.3的圆形精灵,刚体组件里把重力设成0,这样它只靠速度和碰撞移动。砖块先做成一排,再复制出50个,分成5行10列,每行颜色不同,顺便用来区分血量。
写代码才是重头戏。我建了个C#脚本控制挡板,用键盘左右箭头移动,速度每秒8个单位。为了不让挡板飞出屏幕,我在Update函数里加了Mathf.Clamp,把x轴限制在-7.5到7.5之间。小球一开始贴在挡板上,按空格键才发射,初速度每秒6个单位,方向固定45度。小球碰到砖块时,砖块要消失,我在砖块上挂了另一个脚本,用OnCollisionEnter2D检测碰撞,每次碰撞让砖块的局部血量减1。第一行砖块血量为3,第二行2,后面都是1,打光就调用Destroy(gameObject)删掉它。
我以为一切顺利,问题跟着就来了。小球发射后,如果角度太水平,会在左右两堵墙之间来回弹,根本碰不到砖块。这是经典的死球现象。解决办法是限制小球的最小垂直速度,每帧检查刚体的velocity.y绝对值,如果小于0.5,就把它提到0.6,保持原方向。
紧接着是另一个坑。砖块排列太密,小球速度稍微一快就会穿透过去。Unity默认的碰撞检测对高速物体不灵敏,我在小球的刚体组件里把Collision Detection设成Continuous,砖块和挡板保持Discrete。这样穿透几率明显下降,但没完全消除。干脆把小球最大速度限制在每秒12个单位,超过就直接缩放回9。

到第二天,游戏勉强能玩了。但手感很怪,挡板移动有点飘。我怀疑是Input.GetAxis自带的平滑处理,导致响应延迟。改成直接用Input.GetKeyRaw判断左右箭头,单独处理,挡板就变得干脆利落。同时把速度从8提到10,又不至于太快。
测试过程中我记了一些数据。总共玩了23局,平均一局能打掉43个砖块,最高分那次打满50个,用时2分18秒。穿透问题只遇到一次,球从挡板边缘擦过,碰撞体重叠了不到0.01单位。这个概率太低,我暂时没修。
后来我加了点小细节。挡板击中球时,根据接触点离挡板中心的距离改变反弹角度。拿碰撞点坐标算出相对位置,映射到-60度到60度之间,球的绝对速度不变,但方向可控。这个功能让手感提升了一大截。
音效方面,我从Unity商店找了个免费的AudioClip包,一个击中砖块的短音,一个挡板反弹音,一个游戏结束音。背景音乐没加,找不到合适的,干脆保持安静。音效文件加起来200多KB,不占空间。
整个项目花了9个晚上,每天晚上两小时左右。所有脚本加起来不到300行,挡板控制40行,球控制60行,砖块逻辑30行,剩下是UI显示和通用功能。UI用了简单Canvas,显示得分和剩余砖块数,字体用内置的Arial。
最终打包成Windows可执行文件,大小37MB,因为引擎本身占了不少空间。窗口分辨率960x540,没做全屏,因为我喜欢边调试边改。我的笔记本和台式机都跑了一遍,帧率稳定在60,没有明显卡顿。
做这个小游戏最大的收获,是明白游戏看起来简单,背后全是细节。那个角度控制,我以为反弹就行,实际得自己写逻辑。物理引擎也不是永远可靠,需要手动补漏洞。如果你也想做个游戏,建议从这种小项目开始,别一上来就想做大型RPG。
现在这个项目还留在我电脑里,偶尔打开玩两局,看看自己写的代码,会觉得挺有意思。也许将来我会再加几关,换个皮肤,但至少现在,它是一个能运行、完整的小游戏。