追求神乎其技的程式设计之道(一)

来源:百度文库 编辑:神马文学网 时间:2024/04/29 08:04:30

追求神乎其技的程式设计之道(一)


最近有读者问到我学写程式的方法和经验,让我一下掉入时光隧道回想起当初用VB写出自己第一个游戏时的成就感,但当初没料到的是我真的就此迷上了电脑和写程式的快感,不知不觉也过了10年的光阴…。在这篇文章中,我想写出我对程式设计的看法和我一路学习上来的歷程和经验。写程式是一条无止境的道路,不只是科学和工程,更是一种艺术。而我还在追求「神乎其技」的半路上,虽然还有很多要学的,但我也希望能让初学者更容易看清楚这条路是什么样子,避免陷入盲目追求新技术的死巷中。

一切的开始

如果是从DOS时代开始玩电脑的玩家,应该都知道当初DOS有两个内建的QBASIC小游戏:贪食蛇和猩猩丢香蕉。这两个小游戏是许多人儿时共同的回忆,我还记得我国小时曾有几堂电脑课,当时老师在台上叽哩瓜啦的不知道在教什么,而台下每台电脑都是贪食蛇或丢香蕉的画面(老师对不起,其实我就是带头做乱的罪魁祸首…)。

微软把这两个QBASIC游戏附在DOS内对我产生了莫大的影响,那是我第一次发现到原来QBASIC和不只是像PE2能打打字而已,QBASIC竟然能把一堆看起来像咒语的文字变成游戏!幸运的是我家刚好有本第三波的QBASIC入门书,没事我就自己拿起来翻着看,虽然当时太小,即使把整本都看完了还是搞不懂贪食蛇是怎么写出来的,但也误打误撞知道了原来这就是程式设计,原来我能直接把贪食蛇档案内的一个数字改掉就能有几百条命可以死,原来学写程式就能做出电脑游戏…。对小孩子而言,知道这些事就像告诉他魔术师袖子里的秘密一样,我一天到晚兴奋地要老爸带我去书局看电脑书,彷彿真的可以搞懂电脑萤幕背后的一切魔法一样,我也梦想着有一天能写出自己的游戏。但当时我没想到的是,我还真的花了十几年的时间在探索电脑的魔法…。

MUD与黑白棋

升上国中后,家里装了一台28.8kbps的modem,当时的internet还没完全成形,在没有Google的时代internet是没什么价值的。当时的modem最常被我拿来上一些拨接式的BBS,那时候的拨接BBS站台还不少,最棒的是还能从站上抓到很多软体和各式各样的教学文章,像是如何用组合语言写电脑病毒,如何破解大富翁2之类的文章。这些文章对当时的我就像武林密籍一样,虽然没办法完全看懂,但我也是从中得到很多零碎的概念,像是16进位的换算、组合语言、中断向量、常驻程式….。

在国二时,我还不小心迷上当时一个超热门的MUD – 万王之王(KK),每天放学回家都急着连上线,让家里电话整晚都忙线中,玩到每个月电话费都是上千元,搞得我妈数次警告要把modem收起来再也不让我上网了。(还好她没真的这么做,不然我现在就没办法写这篇文章了。)

MUD是现在MMORPG的纯文字版,整个虚拟世界都用文字描述,并且只要用telnet就可以连上去玩了。但内行的玩家都知道,玩MUD应该要用zMud或是UNIX下的tintin++,因为这两个软体可以设定所谓的trigger,侦测到某些事件的发生,就能自动採取事先指定好的动作。因为一切的讯息都是由文字呈现,所以侦测事件非常简单,只要看看有没有特定字串出现就可以了;而要做特定的动作也很简单,就是送出文字指令而已。(眼尖的人一定会发现,这其实就是现在MMORPG外挂的最原始形式。)严格说起来,zMud是我首次写「实用程式」的平台,我学会透过trigger在MUD的世界中写自动化的机器人,自动在迷宫中游走,自动换装备打怪练功..。这时的我突然体会到,会写程式真是太棒了,我在MUD中简直跟神一样。其实当时我也不过只会用最基本的变数、if、迴圈而已,但透过在虚拟世界中写机器人的练习,让我的逻辑思考概念有飞快的进步,也给我了非常强烈的动力想好好学一个正统的程式语言。

升上国三后,很幸运的透过推荐甄试提早上了台中一中,升学压力解除后,老师和父母就完全不管我要干麻了。这时我终于有了一段完整的时间可以好好的再把BASIC重新学过,无奈的是在我国三时QBASIC已经快灭绝了,取而代之的是Windows上的Visual Basic,我只好硬着头皮买本新书来从头学起VB。当时我看的是王国荣的VB 5入门书,整本书有六七百页吧,比我国三所有课本叠起来都还厚,现在想想小时候真的有点不知天高地厚竟然相信自己能看完这么厚的砖头书。那时候我每天上课就带着这本砖头去学校,这样看了几个礼拜下来,没想到我这时突然都看得懂了,很多原本不知道有什么用途的概念突然都相互连结起来了。(多亏了在MUD里的训练!)就这样,某天突然有种打通任督二脉的感觉,我发现我全搞懂了,迴圈、阵列、Windows GUI控制项、去背贴图…,我突然想通要怎么用程式语言写出游戏了。

从那之后,每天回家就是打开VB写程式,我想写个黑白棋来检验自己的想法,我把自己知道的所有概念都放进去,有GUI元件、有贴图、有动画、有音效..,这是我第一个完整的程式,从头到尾每一行都是自己写出来的。(以现在的眼光来说只能说是一个期末project规模的小程式,但对当时的我可是意义非凡)

这个黑白棋让我印象最深的其实是debug的痛苦经验。我花了一个礼拜把程式的核心部分完成,但在吃子的时候却跑出一个不明的bug会打乱整个盘面。为了找这个bug,我又花了一个礼拜,每天从早到晚都在想哪里写错了,后来慢慢trace了好久,才发现竟然只是一个变数忘了归零!!!

这种bug很常见,不过只是programmer最容易犯的无心之过之一,但这件事对我的影响非常大,它让我花了很长时间在想以后要怎么避免犯同样的错。我后来才知道一个普通的programmer和厉害的programmer从这里就会分出高下:普通programmer犯了这种错会觉得很平常,并提醒自己下次别再这么笨了,但实际上不久后一定又会再犯同样的错;厉害的programmer会反省自己写程式的方法,并改变原有的方法或习惯来避免以后再度产生同样的bug。

古老的程式设计教材(尤其是C语言),都说要把变数宣告在函式的一开头,并且因为变数宣告完还得经过初始化,所以很多人习惯是在函式开头宣告并初始化所有变数。这不是错的,可是,这其实就是会导致bug的元兇。
因为变数在开头就被初始化,这样在真正要用到它的时候就能直接拿来用,但是如果这个变数需要被归零(也就是重新初始化)并在迴圈中重复利用,就很容易会忘记要再多做这一步。(在多层迴圈中更容易发生)

我为这个bug苦恼了几天,后来才意识到这是coding style的问题,只要改变宣告变数的习惯,就能避免犯这种错误。如果一开始就在迴圈内宣告并给定变数的初始值,而不是在函式开头宣告,就不会有这种bug跑出来了。有了这个经验后,我归纳出一个原则:「永远在变数需要被用到的最内层区块才宣告并初始化该变数。」这种原则很重要,我日后一直放在心里,它也帮助我避免掉未来再犯同样错误的可能。(事实上,我后来再写了十年的程式,再也没有比这更痛苦更长久的debug经验了…)