尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

带你认识老派编程语言:Delphi 2007 复刻童年《坦克大战》

发布时间:2026/9/28 18:08:11

资讯中心
01
ARTICLE

带你认识老派编程语言:Delphi 2007 复刻童年《坦克大战》

带你认识老派编程语言:Delphi 2007 复刻童年《坦克大战》
先扯点这门语言的历史。因为作为一个新生代的程序员对此语言多半是不了解甚至没听说过的。1995 年Borland 推出 Delphi 1.0首席架构师是传奇人物 Anders Hejlsberg就是后来跑去微软搞出 C# 和 TypeScript 的那位。当年的 Delphi 是带着VB 杀手的名号出道的编译成原生机器码快得飞起、VCL 组件拖完就能跑、数据库开发体验吊打一众对手风头一度盖过 Visual Basic。整个 90 年代末到 2000 年代初它在中国企业级开发里是绝对的王者——进销存、医院系统、银行前端、各类 MIS几乎半壁江山都是 Delphi 写的2002 年的 Delphi 7 至今被很多老程序员封为神版本。但辉煌之后就是下坡路.NET 和 Java 生态崛起Anders 被微软挖走Borland 经营失策开发工具部门几经转手CodeGear → EmbarcaderoDelphi 的市场份额一路萎缩到 2010 年前后在国内基本淡出了主流视野。然而它没有死——无数当年用 Delphi 写的企业系统至今还在银行、医院、工厂里跑着而维护这些系统的程序员比如我就成了这门语言活着的证明。在维护公司客户的一套老 Delphi 代码时天天和 VCL、TQuery 这些老伙计打交道。某天迭代完一个需求突然冒出一个念头既然目前天天写这套东西为什么不干脆用它做点让自己快乐的项目于是就有了这个用 Delphi 2007 复刻的联机坦克大战。没有游戏引擎、没有多线程库整个游戏核心只有一个 2589 行的 MainForm.pas却实现了双人联机对战、AI 寻路、A* 算法、地图编辑器一整套东西。本文把开发过程里的设计思路逐模块拆给大家看也顺便聊聊这门过气了的语言为什么至今依然好使。目录一、项目概览二、开发环境与技术选型三、整体架构一个窗体就是一个游戏引擎四、游戏循环十几个 TTimer 的排班表五、AI 设计普通 AI 三板斧BOSS 坦克真会 A*5.1 普通坦克三层决策5.2 BOSS 坦克递归式 A* 寻路六、联机同步教科书级的瘦客户端方案6.1 两条通道各司其职6.2 控制信令手搓的 VK_ 协议6.3 状态快照一个 record 打包整个战场七、渲染GDI 双缓冲 摄像机跟随八、地图编辑器九、踩坑实录老技术栈教会我的事十、总结一、项目概览项目目录结构非常清爽典型的三件套Source/—— 游戏主工程TankWar.dpr约 3400 行 Pascal 代码MapEditer/—— 独立的地图编辑器工程用来生成 .map 地图文件Bin/—— 编译产物和两张示例地图Map1.map、Map2.map。主工程一共 7 个单元分工如下单元职责MainForm.pas游戏主窗体几乎全部游戏逻辑都在这里2589 行Unit_CreateGame.pas创建游戏选地图、开房间Unit_JoinGame.pas加入游戏输入 IP 连接主机Unit_Chat.pas联机聊天窗口Unit_SelectMap.pas地图选择TankWar_TLB.pas类型库拖控件自动生成的UnitAppface.pas皮肤库相关说个开发中的小事故MainForm.pas 的中文注释曾在一次文件转码中全军覆没2500 多个汉字变成了清一色的?号。痛定思痛后我把所有源码固定用 GBK 保存并纳入版本管理才没让惨剧重演。写 Delphi 的朋友大概率都懂这种痛——这也是我后来给客户代码做维护时格外谨慎的原因。二、开发环境与技术选型先看工程配置TankWar.dproj编译器DCC32工程文件版本 7.0即 Delphi 2007GUI 框架经典 VCL网络双栈混搭 ——ScktComp的 TServerSocket / TClientSocketTCP Indy 9 的 IdUDPServer / IdUDPClientUDP IdIcmpClientPing 测延迟绘图纯 GDITPaintBox TBitmap 手绘没有 DirectX / OpenGL音效MMSystemWindows API 层面的播放 Sound.RES 资源文件游戏循环十几个 TTimer 排班上岗一个真正的线程都没有。这套选型放到今天看处处是反面教材但我要为它说句话对一个下班后凭兴趣写的小游戏VCL 的成熟度、Delphi 编译器的速度、组件拖完就能跑的开发体验正是当年它能统治 Windows 桌面开发半壁江山的原因。整个项目从搭框架到能联机对战实际编码时间并不长——这就是 RAD 的含金量。三、整体架构一个窗体就是一个游戏引擎整个游戏没有独立的 Game 类Tfrm_Main就是引擎。我用一组 record 定义了全部游戏状态几个自己比较得意的设计点坦克是圆形的。不用矩形 AABB全部用GetDistance两点距离做圆形碰撞检测半径 20 像素左右。这个偷懒的做法在这类网格游戏里意外地好用每辆坦克自带一张 25×25 的寻路缓存表。PathValues 直接长在 record 里6 辆坦克就是 6 份独立寻路状态简单粗暴但有效Steps 字段是 AI 的节拍器。各种 AI 逻辑用Steps mod 40 0、Steps mod 200 0这类条件触发相当于给不同 AI 事件设置了不同的心跳周期。四、游戏循环十几个 TTimer 的排班表没有 while(True) 主循环游戏被拆成了十几个定时器协程TTimer职责YellowTankMoveThread黄方玩家坦克移动节拍驱动GreenTankMoveThread绿方玩家坦克移动AutoFireThreadAI 坦克自动开火TankCreateThread / WaitForCreateThread坦克出生动画与排队WaitForDisappearThread爆炸消失动画DataSendThread / DataReciveThread联机状态收发DrawScreenThread画面重绘RefreshLabelThreadHUD 刷新比分、存活数CheckGameInforThread胜负判定CalculateDelayThread网络延迟计算单机模式下键盘中断直接改状态TTimer 们按各自周期推着状态走——本质上还是状态 帧驱动只是每一帧被拆到了不同频率的定时器里。为什么不用真线程因为 VCL 控件只能主线程摸TTimer 反而是最安全、零锁、零同步原语的选择。代价是帧率受 Windows 定时器精度限制约 15.6ms逻辑周期不可能精确——但对坦克大战这个量级的游戏完全够用。五、AI 设计普通 AI 三板斧BOSS 坦克真会 A*5.1 普通坦克三层决策AutoTankControl里普通 AI 的决策优先级是贴边逃生撞到地图边界就按随机概率Random(31) 分三档反向转向避让/避墙发现别的坦克或不可通行格子Kind 2/3/5/6/7 的砖墙、铁墙、水、草丛挡路就朝反方向转向AIChangeAspectA索敌追击Kind 3 的坦克每 200 步判断一次朝距离更近的玩家转向AIChangeAspectB。5.2 BOSS 坦克递归式 A* 寻路Kind 4 的 BOSS 坦克每 100 步重建一次路径场。核心的SearchPath是一个递归实现的四方向最短路搜索严格说这是记忆化递归搜索类似 Dijkstra 场 flood但它干了 A* 该干的活算出全图每格到目标的代价然后 BOSS 每一步都朝代价最小的邻格走BossChangeAspect。一个有意思的细节是转向平滑处理——当新旧朝向发生 90 度转弯时代码会把坦克坐标吸附到 40 像素网格中线上防止斜穿墙角。21×21 的小地图喂这个递归毫无压力2007 年的家用机都跑得飞快。六、联机同步教科书级的瘦客户端方案这是整个项目我自己最满意的部分。架构是经典的主机权威 状态广播主机Server运行全部游戏逻辑是唯一的状态权威客户端Client基本只做渲染和输入转发收到什么画什么。6.1 两条通道各司其职通道协议内容TServerSocket / TClientSocketTCP控制信令 聊天文本IdUDPServer / IdUDPClientUDP键盘输入上行 战场快照下行6.2 控制信令手搓的 VK_ 协议TCP 上跑了一套自定义文本协议全部以VK_前缀命名和 Windows 虚拟键码 VK_ 撞个满怀算是写代码时的小恶趣味信令含义VK_MAP_LOADED客户端地图收到了VK_BEGI / VK_NEXT_BEGIN主机开始游戏VK_CONN连接确认VK_WINS / VK_LOSE胜 / 负VK_PAUS / VK_RECO暂停 / 恢复VK_ERROR主机出错VK_BLA1开火音效同步VK_TESTUDP 通道测试客户端按键后根本不处理移动直接IdUDPClient.Send(VK_UP)把键码原样发给主机6.3 状态快照一个 record 打包整个战场主机端DataSendThread定时把整个战场状态打包进一个巨型 record 广播客户端DecodeBuffer收到后逐字段拷贝回本地状态数组下一帧 DrawScreen 直接画。地图格被摧毁这种增量信息靠Pos Kind两个字段捎带。整包大约 700 字节按 TTimer 周期广播局域网里丝般顺滑。延迟显示用 IdIcmpClient 直接 Ping 主机实现简单诚实。后来我意识到这套TCP 信令 UDP 快照 主机权威的三分结构其实就是今天多人游戏同步的标准答案——只是当年的实现粗糙现在的实现精致骨架是一模一样的。七、渲染GDI 双缓冲 摄像机跟随地图是 21×21 网格每格 40 像素整张地图 840×840而游戏窗口小于地图所以做了一个小小的摄像机系统LoadMap把 .map 文件读进 21×21 的字节数组DrawLowerMapGrids/DrawUpperMapGrids分别绘制地面层水、地面和可遮挡层砖、铁、草丛所有元素先画到一张 840×840 的离屏 TBitmap 上双缓冲防闪烁ChangeScreenPos实现摄像机跟随当玩家坦克离屏幕边缘小于5×Radius且继续朝该方向移动时镜头跟着平移——就是现在游戏里常见的 camera dead-zone 手法最后DrawScreen把离屏位图按 ScreenPosition 裁剪贴到 GameBox 上。坦克的四个朝向不是旋转生成的而是老老实实各画了一张ProcessBitmap负责载入时预处理。八、地图编辑器MapEditer是个独立的 Delphi 工程用来可视化摆放 21×21 网格里的各种格子砖墙、铁墙、水、草丛等 7 种 Kind保存为 .map 文件。联机时主机把整个TMap21×21 441 字节通过 TCP 一把发给客户端客户端校验Size Sizeof(TMap)后载入并回VK_MAP_LOADED——用 record 的内存长度做包完整性校验简单有效。九、踩坑实录老技术栈教会我的事开发过程也是踩坑过程几处非常有代表性的问题写出来给同样在维护 Delphi 老项目的兄弟避坑编码是 Delphi 项目的头号地雷中文注释在转码中全部变?的教训前面说过了。现在我的原则是老代码不乱转码要转先备份TServerSocket 已废弃Delphi 2007 里 ScktComp 已被标记 deprecated官方推荐 Indy。项目里我两个都用了TCP 走 ScktComp、UDP 走 Indy如果是新项目建议直接全 Indy 或 System.Net.SocketSleep(1000) 卡死主线程开局动画我直接在主线程 Sleep 一秒整个 UI 冻结——自己写着爽但放在正式代码里肯定要被同事喷递归寻路无深度限制SearchPath是纯递归靠 TriedPos 数组防死循环最坏情况栈深度与地图格数同阶。还好地图只有 441 格地图再大就得改成显式队列魔法数字的债格子 Kind 的 2/3/5/6/7、坦克 Kind 1~4、坐标偏移 20/40 全是裸数字。注释被毁之后这些魔法数字成了最难读的部分——这也是我后来在客户代码里坚持见到裸数字就补枚举的原因。十、总结写这个小项目最初只是突发奇想写完却发现收获比预期大情怀层面坦克大战是童年Delphi 是饭碗用饭碗复刻童年快乐加倍架构层面用最少的抽象一个窗体 一组 record 一堆 TTimer实现了一个功能完备的联机游戏证明了窗体即引擎在 VCL 时代完全可行也让我更理解了自己维护的那套客户老代码当年的设计语境技术层面TCP 信令 UDP 快照 主机权威的同步骨架至今未过时手搓记忆化寻路也让我重新捡回了被现成算法库惯坏的基本功工作层面踩过的编码坑、废弃组件坑反过来提升了我在公司老代码维护上的警觉性——副业项目反哺主业这是最大的意外收获。如果有人想在 Delphi 上做类似的小游戏我建议的入手顺序是先用 TTimer 搭出帧驱动骨架再用 record 把游戏状态定死最后才加网络和 AI——顺序反了会很痛苦。项目开源地址如果你也维护着一套 Delphi 老代码或者也想用过时的技术做点让自己快乐的东西欢迎评论区交流。觉得有收获的话点赞 收藏再走。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。