表單大戰 10 週年

十年前的 3/4,「表單大戰」誕生了。

於師大附中電算社,展出至少四屆成發(2010~2013)、以及三屆資訊營 Visual Basic 課程的展示作品(2010~2012)的表單大戰,今年終於十歲啦!!

因此,我在此宣佈,表單大戰 10 週年計畫,正式展開!

Visual Basic 再戰十年

主要項目如下:

  1. 表單大戰正式開源!請參考: https://github.com/dwy6626/FormWar
    (若要參考 2013 成發展出的版本,可以從 tag 選 v1.3.1.2
  2. 發表 v1.4.5.3 版更新:
    下載點
    • Code 大幅簡化(減少 copy paste)
    • 更厲害的表單分身
    • 更多移動方式
    • 更多的攻擊方式!

所以關於表單大戰

我於 2010 年在師大附中電算社用 VB 實作的小程式,而他是一個以 Visual Basic 2008 (VB)寫成的小遊戲(也因為是 VB 所以是 Windows only)。

簡單來說,就是使用滑鼠追逐奔跑的 Windows Form(表單)的小遊戲。

表單,其實就是 Windows Form 的 Form 的中文直譯,比較接近現在常用的「視窗」的意思。(後來 Google 表單出現之後,表單這個名詞更常被拿去當作一個需要填寫內容回答問題並送出的線上文件。但是此表單並非彼表單)

表單大戰」可以說是我人生第一個自主 Side Project(?)。當時是師大附中電算社高一的我,在社團主要學的是 VB(畢竟當時是第一次接觸程式語言的小孩,對於能夠馬上做出 GUI 程式的比較感興趣。)也因此自己照著社團指導老師李啟龍老師寫的「Visual Basic 2008 程式設計 16 堂特訓」開始跟著範例慢慢跑。

而當時書中有一個範例程式,是使用滑鼠點選表單,表單就會跑到別的位置。經過一陣腦補之後就成了現在的樣子了。

還記得發布時最陽春的第一版,一點開程式就是一個 Windows Form (表單)在畫面上奔跑,玩家要用滑鼠去點表單上面的數字,每點一次數字就會 -1,當數字歸零時就結束了。而當數字變小,表單也不會就乖乖讓你點,會放出各種招式妨礙玩家。因為要用滑鼠一直追擊表單,如果沒點好就會不小心點到桌面上各種捷徑(高中生的惡趣味十足)。

form war game play

後來新的版本才出現了背景計時、主選單、難度選擇等 Features,版本號也往前推進,因為熟練(?)的玩家數量增加,因此出了個超級難的「不可能的任務」難度,連作者都花了 9 分鐘才全破,自虐意味十足。

但是這樣自己創造新遊戲然後給自己玩,應該也算是我一直以來的興趣,從最初的 LF2 改版研究了好幾年,出了一版「YDW-LF2」,主打劇情模式,但是平衡炸裂,畢竟是小學生作品(也因為是太久之前,檔案備份我也不存在了,消失的童年,真可惜)。之後是紅色警戒 2 的改版,在素材網搜集素材、利用規則 INI 編寫屬性及 AI 等,然後再做來自己挑戰…。也許就是這樣的成長歷程,才會有「表單大戰」的誕生吧?

Icon

表單大戰 Icon

表單大戰」的 Icon 其實是由「Message Box 攻擊!」時會出現的警示符號與錯誤符號組成,參考「終極動員令二:泰伯倫之日」的 Icon 排列組成:

終極動員令二:泰伯倫之日,圖片取自網路

為什麼會有十週年計畫

因為最近在幫實驗室寫互動實驗程式的 GUI,因此就想參考一下以前自己是怎麼寫的,把高中的舊 Code 從雲端全部挖了出來。

結果 Code 一片慘不忍賭,各種複製貼上,才想到我當時根本沒有學過真正的物件導向,也沒有 Class 和 Function 的概念,原本還想說搞不好可以當自己的作品集,可是這種程度如果放上 GitHub 根本給人笑 QQ。當時也沒有用 Git 進行版控,所以就會有各種不同版本的資料夾,於是決定就趁這個機會花點時間整理一下。

所有的舊 Project 中最具代表性的當然就是這篇的主角「表單大戰」了,因此就成了我第一個開刀的目標,剛好今年又是第一版發行的十週年,因此就有了這個突發奇想的計畫。

例如說這個片段,是控制表單移動的部分:

Randomize()
If Val(Label1.Text) < 15 Then
    If Me.Location.X < 800 And Me.Location.Y < 600 And x_add = True And y_add = True Then
        Me.SetDesktopLocation(Me.Location.X + Int(Rnd() * 50) + 10, Me.Location.Y + Int(Rnd() * 50) + 10)
    ElseIf Me.Location.X > 50 And Me.Location.Y < 600 And x_add = False And y_add = True Then
        Me.SetDesktopLocation(Me.Location.X - Int(Rnd() * 50) + 10, Me.Location.Y + Int(Rnd() * 50) + 10)
    ElseIf Me.Location.X > 50 And Me.Location.Y > 50 And x_add = False And y_add = False Then
        Me.SetDesktopLocation(Me.Location.X - Int(Rnd() * 50) + 10, Me.Location.Y - Int(Rnd() * 50) + 10)
    ElseIf Me.Location.X < 800 And Me.Location.Y > 50 And x_add = True And y_add = False Then
        Me.SetDesktopLocation(Me.Location.X + Int(Rnd() * 50) + 10, Me.Location.Y - Int(Rnd() * 50) + 10)
    End If
Else
    If Me.Location.X < 800 And Me.Location.Y < 600 And x_add = True And y_add = True Then
        Me.SetDesktopLocation(Me.Location.X + Int(Rnd() * 50), Me.Location.Y + Int(Rnd() * 50))
    ElseIf Me.Location.X > 50 And Me.Location.Y < 600 And x_add = False And y_add = True Then
        Me.SetDesktopLocation(Me.Location.X - Int(Rnd() * 50), Me.Location.Y + Int(Rnd() * 50))
    ElseIf Me.Location.X > 50 And Me.Location.Y > 50 And x_add = False And y_add = False Then
        Me.SetDesktopLocation(Me.Location.X - Int(Rnd() * 50), Me.Location.Y - Int(Rnd() * 50))
    ElseIf Me.Location.X < 800 And Me.Location.Y > 50 And x_add = True And y_add = False Then
        Me.SetDesktopLocation(Me.Location.X + Int(Rnd() * 50), Me.Location.Y - Int(Rnd() * 50))
    End If
End If
If Me.Location.X > 800 And x_add = True Then
    x_add = False
ElseIf Me.Location.Y > 600 And y_add = True Then
    y_add = False
ElseIf Me.Location.Y < 50 And y_add = False Then
    y_add = True
ElseIf Me.Location.X < 50 And x_add = False Then
    x_add = True
End If

就是相當冗長又充滿複製貼上的代碼,而且每個分身表單都有這麼一段。因此這次的一項工程,就是把分身表單的 Code 集中起來,每次召喚分身都從同一個物件 New 一個新的出來而不是直接寫很多份 Code。

而經過一些簡單的修改之後,這段 Code 變成:

Public Sub FormMove(ByRef form)
    Randomize()
    form.SetDesktopLocation(
        form.Location.X + form.x_sign * SpeedScale,
        form.Location.Y + form.y_sign * SpeedScale
    )
    If form.Location.X + form.Size.Width > screenw And form.x_sign = 1 Then
        form.x_sign = -1
    End If
    If form.Location.Y + form.Size.Height > screenh And form.y_sign = 1 Then
        form.y_sign = -1
    End If
    If form.Location.Y < 0 And form.y_sign = -1 Then
        form.y_sign = 1
    End If
    If form.Location.X < 0 And form.x_sign = -1 Then
        form.x_sign = 1
    End If
End Sub

然後讓分身與本尊都來調用這個 Function:

FormMove(Me)

原本的數字 15 以下會加速的設定,就可以改成另外去修改 SpeedScale 這個變數:

If Val(Label1.Text) < levelSpeedUp Then  '這邊設定成 15
    SpeedScale *= 1.5
End If

維護起來容易很多。(雖然我以後也不一定會繼續來維護了…XD)

其實有更好的寫法,利用繼承的方式共同繼承自一個基礎的表單類別,然後把 FormMove 寫成 Method,不過因為工程浩大,錢不夠多(誤),因此就沒有這樣改了。

小結

結論就是這是一個作者自嗨的 Side Project 以及自嗨的十週年計畫,希望大家能夠真的因為這個小遊戲得到一點娛樂,也希望沒有螢幕鍵盤滑鼠因為這個程式受到傷害(?)。

FormWar Playing