以Visual Basic製作乒乓球遊戲

(2005年 3月4月)
 
  大二時一起作報告的回憶.
 
 
 乒乓球遊戲「DILS PingPong」,對面是電腦的藍色球拍,以動畫般的GIF圖片呈現;下方是使用者的紅色球拍;
 
 白色的小球是乒乓球,以VB的外形控制項來表現。
 
 
 使用者控球的方法:
 
 1. 以游標的「垂直速度」,來決定打出球的「遠近」與「弧度」。
 
 2. 以游標的「水平速度」,來決定打出球的「方向」和「角度」。
 
 3. 以游標的「移動速率」,來決定打出的「球的速率」。
 
 
 背景圖片、和「DILS PingPong」、「TKU-DILS.Edu」字樣經PhotoImpact修改。左上角的白色文字顯示比賽的狀況和雙方的比數。
 
 遊戲可以讓玩家容易地去控制球的速率、方向、和遠近,練習之後容易地就可以打出左右變線、或長短變線的戰術玩法。
 
 
 1 表單的大小
 
 表單即視窗;有的使用者的螢幕大小為600乘800(像素),為了顧及這些使用者,所以表單的大小最大不超過600乘800(像素),即12000乘9000(tip)。所以我們的表單大小設定為12000乘9000(tip)。
 
 Form1.Width = 12000: Form1.Height = 9000
 
 
 2 球桌
 
 利用PhotoImpact可以方便地得到我們想要的球桌圖,接下來將球桌圖設為表單的背景即可。
 先將球桌圖命名為DilsPingpong.jpg,再將它放入picture資料夾,再將picture資料夾與遊戲程式放在同一層即可。
 
 Form1.Picture = LoadPicture(“picture/DilsPingpong.jpg”)
 
 為了防止使用者任意調整表單的大小,所以將表單的框線設為固定。
 
 Form1.BorderStyle = 1
 
 
 3 測量游標的速度
 
 為了讓玩家能夠以最簡單的方法靈活地控制乒乓球,所以我們規劃球的運動的根據,如下:
 
 (1) 以滑鼠的垂直速度(y方向)決定打出的球的遠近。
 (2) 以打出的球的遠近決定球的拋物線運動路徑的弧度。
 (3) 以滑鼠的水平速度(x方向)決定球打出的角度。
 (4) 以滑鼠的移動速率((x^2 + y^2)^(1/2))決定打出的球的速率。
 
 基於以上四點,所以我們必須測量游標的速度。
 
 為了隨時知道游標移動的速度,所以我們必須隨時知道游標在表單上的坐標位置。利用表單的MouseMove事件即可得知游標的xy坐標位置。
 
 Private Sub Form_MouseMove(Button As Integer, Shift As Integer, Xinform As Single, Yinform As Single)
 
  接下來將游標的x坐標與y坐標分別存入X1prct(0)與Y1prct(0)變數中。
 
     X1pRct(0) = Xinimg1prct
      Y1pRct(0) = Yinimg1prct
  End Sub 
 
 接下來產生一個計時器在表單上,命名為tmr1pRctVct(意即timer 1p Racket Vector),並將tmr1pRctVct.interval設為100(即每0.1秒執行一次)。
 
 tmr1pRctVct.Interval = 100
 tmr1pRctVct.Enabled = True
 
 宣告一個tmr1pRctVct計時器的計數變數,命名為Ttmr1prctvct,在計時器啟動的時候,Ttmr1prctvct的值會在1與2之間切換。
 
 Private Sub tmr1pRctVct_Timer()
     Ttmr1prctvct = Abs(Ttmr1prctvct – 3)
    ’計數變數的值每0.1秒切換為1或2
     If Ttmr1prctvct = 1 Then    ’當計數變數為1的時候,就將游標的坐標值存入X1pRctVct(1)與Y1pRctVct(1)之中
         X1pRct(1) = X1pRct(0): Y1pRct(1) = Y1pRct(0)
     ElseIf Ttmr1prctvct = 2 Then
    ’當計數變數為2的時候,就將游標的坐標值存入X1pRctVct(2)與Y1pRctVct(2)之中
         X1pRct(2) = X1pRct(0): Y1pRct(2) = Y1pRct(0)
     End If
     If Ttmr1prctvct = 1 Then
    ’如果 tmrrckvctT=1,亦即rckX(1)為游標的新X位置,而rckX(2)為游標的舊X位置
         Vx1prct = X1pRct(1) – X1pRct(2): Vy1prct = Y1pRct(1) – Y1pRct(2)    ’目前游標的X方向的速度為游標的新X坐標 – 舊X坐標
     ElseIf Ttmr1prctvct = 2 Then
         Vx1prct = X1pRct(2) – X1pRct(1): Vy1prct = Y1pRct(2) – Y1pRct(1)
     End If
 End Sub
 
 意即,我們用三組變數來儲存游標的坐標值;X1pRct(0)即最新的坐標;計數變數每0.1秒切換為1或2,
 當計數變數為1時則將坐標值存入X1pRct(1),當計數變數為2時則將坐標值存入X1pRct(2)。
 意即當計數變數為1時則X1pRct(1)為新坐標,X1pRct(2)為舊坐標,反之亦然。
 那麼游標目前的速度就是他在這0.1秒裡面的位移量, 所以游標的新坐標 – 舊坐標即可代表游標目前的速度。
 
 
 4 球拍圖
   
  
 
 
 5 球拍的移動
 
 要讓球拍的圖隨著游標移動,須先將球拍圖設成image的背景,
 
 Image.Picture = LoadPicture(“picture/racketA/racketA.105.jpg”)
 
 再讓image隨著游標移動。
 
 當球拍圖隨著游標移動,而球拍圖的中心點總是置於游標底下時,此時游標就不是在表單上移動了,而變成在球拍圖上移動;
 亦即,MouseMove事件是發生在球拍圖(image)上而不是表單上。將我們想要移動的球拍命名為image1pRct(意即image 1P Racket)則程式碼如下:
 
 Private Sub img1pRct_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)    
     img1pRct.Move X – img1prRct.Width / 2 + img1pRct.Left, Y – img1pRct.Top / 2 + img1pRct.Top
 End Sub
 
 「游標移到的位置」減去「寬或長的一半」再加上當時球拍圖的(左上角)坐標,即可使球拍圖的中心點隨著游標移動。
 
 
 6 球第一段彈跳的拋物線路徑模擬
 
 首先要能畫出球的拋物線路徑。
 
 球的路徑是立體的拋物線;把拋物線畫在yz平面上可以簡化方程式;所以我們需要一個虛擬的z軸,需要一個三維的坐標系;
 為了避免和表單的二維坐標系的名稱相混淆,我們分別將其命名為u軸, v軸,與w軸。
 左圖為球運動路徑所需要的三維坐標系,右圖為表單的xy平面坐標系。為了方便,我們將表單的坐標原點設在背景球桌圖的桌子中間。
 
 在vw平面上的拋物線方程式為「w^2 = 4cv」,利用這個方程式,我們只要先設定好c的值與w的範圍,便可以得到三維的拋物線曲線。
 
 w0 = 2000        ’設定w的範圍
 c = 500        ’設定焦距
 For w = -w0 To w0
     u = 0
        ’在vw平面上u值恆為0
     v = Int(w ^ 2 / 4 / c)
 Next w
 
 注意其w的範圍(w0)越大,意即其線段在w軸上的投影越長,則其線段的長度越長;w的範圍越小,則拋物線的線段長度越短。
 c為焦距,c越大則拋物線越平直,c越小則拋物線的彎曲幅度越大。
 
 但目前這是三維的拋物線段,若要畫在二維的表單上須先將其坐標值轉換成二維的坐標值才能輸出在表單,
 亦即,須將虛擬的w坐標值轉換成x與y的形式。
 
 w0 = 2000
 c = 500
 angle = pi * 1 / 4
 Dx = 1000: Dy = -2000
 For w = -w0 To w0
     u = 0
     v = Int(w ^ 2 / 4 / c)
     x = u + Cos(angle) + Dx
     y = v – Sin(angle) + Dy
     Pset (x, y)
 Next w
 
 新加上的Dx和Dy變數可以控制此拋物線段在表單上的位移;如此,只要我們預先設好w0、c、angle、Dx、Dy,
 即可控制此拋物線段的長度、弧度、方向、橫坐標位置、與縱坐標位置,即任意地得到我們想要的三維拋物線段。
 
 
 7 球的拋物線路徑實作
 
 現在我們已經有了球(外形控制項)、與球的運動路線; 將程式的迴圈改成會自動執行的計時器
 利用這個計時器tmrBall,即可讓球以某速率沿著我們設定的路線移動。
 
 
 8 球的拋物線路徑範本
 
 當球由近處彈向遠處時,我們假設其第二段彈跳的拋物線焦距不變,而其路線看起來變短(變矮)。
 我們已經設定第一段彈跳的拋物線其在w軸上的w範圍為由-w0至w0,現在第二段彈跳的拋物線其w的範圍我們就設定命名為由-w1至w1;
 現在假設w1 = 7/8 * w0。意即球的第二段彈跳的拋物線,其實是複製第一段的彈跳拋物線,再和第一段的路線接在一起。如圖。
 左圖為第一段彈跳的拋物線路線。中圖為在第一段拋物線中複製較短的第二段彈跳拋物線;
 將w = w0代入第一段的拋物線方程式,得到的x與y,即為第一段拋物線的終點在表單上的位置(即第二段拋物線的起點在表單上的位置);
 將w = -w1代入第一段的拋物線方程式,得到的x與y,即為第二段拋物線的起點在第一段拋物線上的位置;
 將「第二段拋物線的起點在表單上的位置」減去「第二段拋物線的起點在第一段拋物線上的位置」即得一位移向量D。
 見右圖,將複製的第二段拋物線位移D即可使兩段拋物線相接起來。
 依此方法類推,即可得到第三段與第四段的拋物線路徑。
 將各變數的名稱改成較不易混淆、特定的長名稱,即得乒乓球四段拋物線彈跳的程式。
 
 
 9 界內與界外
 
 利用表單的MouseMove事件即可得知桌子各點的坐標;如下圖,
 利用這些坐標我們可以求出各條直線的方程式;將乒乓球落點的坐標代入這些方程式(不等式),
 我們即可得知此落點是落在對方或我方桌子、是觸網或者是出界。
 
 將前述的路徑範本程式的「產生第二段起點(即球第一段彈跳的終點)」的部份用「Do…Loop」迴圈包起來,並在Do之後加上條件判斷:
 「如果球的落點將會在對方桌子界內的話」,則才讓這個球路發出去,否則則產生一新的球路,直到滿足條件為止;
 如此,運用在電腦的回球上,我們即可讓電腦的回球隨機而且不出界。
 
 
 心得
 
   這次的VB真的是覺得很難做,比起其他組別我覺得乒乓球真的難做很多。我有試做一個簡易型的乒乓球,真的是超級難做的,而且bug一堆,剛開始做碰 撞和拋物線時就搞半天,我想還要多多加油。而且,實習課的作業,我也只做好井字遊戲、終極密碼、剪刀石頭布,而五子棋到現都還沒搞定,判斷輸贏的連線不知道要怎麼設,做了半天還是無法D bug。其實我對於VB也不是完全沒興趣,可能是因為跟電腦有關係吧,比較起來,西編才真的是會讓人想自殺的鬼東西,就算認真去念也不知道在學什麼。以前我真的是花太少時間去寫VB了,以至於現在光想一個迴圈就要想半天,如果再這樣下去,真的有點擔心大三上的資料庫會掛掉耶。不過最近是有寫出一點心得了,深深的體會到,VB是真的要常寫,不然死到臨頭要趕真的是會寫不出來的。 by 振維
 
   在製作過程中我發現組長太強了,每天都有新進度完成,寫法又高深莫測,實在不是我這種平民老百姓可以趕得上的呀!這份作業讓我知道還有很多東西要精進的,一樣都是從大二開始學習、一樣的老師教、一樣一天24小時,為什麼他可以做到這樣而我卻不行呢,他也花了很多時間教大家,一個一個步驟的解釋,讓我覺得這有點不像是在做作業,反而像是另外開一個班內班,請一個小老師來教一個小班級,所以我總是認為,修老師的課會有非常多的學習機會,尤其是在寫作業的時候,學習東西是不可以紙上談兵的,很多事情也是要親身經歷過才會明白,這真的是一個相當充實的作業,雖然還有很多地方不了解,但是我會找同學請教弄懂。有了這次的經驗,組長表示下次的作業就要全靠我們自己來完成了,這次也算是一個幫大家打基礎的過程吧,而下次就會是另一個實戰經驗囉! by 小冰
 
   我們這組作的VB小遊戲是乒乓球,感覺一點也不像是小遊戲。然後我們有去文學院週本系展覽看過學長姐的作品,不過我們覺得那種不是我們想要作的作品,所以就決定要作真正的乒乓球。我們先找網路上的適合我們使用的桌球圖,還有球拍。然後接下來是最重要的部分,程式碼部分。我們先把可能會用到的還有必須用到的球路與路徑先想好,然後在一起討論要如何做,不過關於這個部分,我們僅能找出問題所在而不能解決問題,而這份作業我們花了將近2個禮拜才將雛型給完成,可見此遊戲是非常的不容易。然後接下來1禮拜是改進作品的階段,我們有像球拍移動的問題,隨機發球的問題,圖片閃爍問題,開始與結尾的問題,以及音效的插入後開檔的問題等。在詢問老師及助教還有自我摸索下,克服了許多的問題,已經能讓此作品更臻於完美,不過最還是留下了一些無法修改的缺點,像學校的顯示器就不能正常的玩等。經由這次的作業,讓我們覺得有些事真的作的比想的還難上許多,也許我們可以簡單說出一個路徑來執行球拍的軌跡,但是要作出這個軌跡,卻要花上大半天的測試與模擬。學好VB沒有其他法門,就是不斷的作,不斷的嘗試新做法,抱持著沒有解不出的問題,一定都能迎刃而解的。現在想想,覺得我實在太過於依賴吳同學了,我希望在依賴他的同時,要能夠想想如何去效訪他學VB的精神,我相信我最後也是可以做到像他一樣的。 by 永祥
 
   一開始看到老師給我們這組的題目”乒乓球”,我當場傻眼,我不禁懷疑自己真的有辦法完成這種複雜的遊戲嗎?所以我一度想把遊戲做成較簡單的板球,但是在我同組的同學的反對下,我們還是開始著手於乒乓球的遊戲製作,當然途中遇到很多問題,光是一開始的版面設計就讓我們忙昏了頭,找了幾十張桌球拍、球桌還有球場的背景圖,從中挑選最好的組合,雖然畫面沒有問題了,但是我們的球拍在移動中會不斷的閃爍,所以我們只好放棄原本設計在不同位置,就會改變球拍的角度的這項功能,才稍稍改善了球拍閃爍的問題。但這樣也只完成我們作業的一些皮毛,我們為設計球如何立體的移動而大傷腦筋,想破了頭還是想不出方法,後來想到用三維坐標轉化成二維坐標的辦法。原本我們只想做出幾種球路,讓電腦隨機選一種球路來回球,但是這樣太單調了,所以我們算出球桌的範圍的直線不等式,讓電腦不管怎麼回球都在界內,還有為設計出讓球拍移動的遠近決定球的速度跟距離,甚至到遊戲結束動畫。種種突破真的都是我們始料未及的。我們後來有體會出一句話「當你千方百計的在解決一個問題的時候,那個問題終將不再是個問題。」大概是這種執著讓我們完成了幾乎不可能的任務吧! by 尚遠
 
   大約有一個月的時間,我們的心力都花在這上面,日以繼夜的。想當初還在研究球要怎麼print、要怎麼反彈、怎麼在平面上照拋物線彈跳,後來突破性地想出三維坐標系等,回想起來覺得我們走了很遠。而且也整個重做過,本來畫的圖讓球拍比較少空間活動,而且本來是用鍵盤玩的,約有十種固定的球路,還有變化球喔,而且本來的計時器有十幾個。我們重做時在網路上抓到三個乒乓球的遊戲,其中一個檔很大,作得很漂亮,而且全是3D的。另一個不錯的是用flash作的,流暢感很好而且覺得AI很不錯。當初想說只要我們的作品有這些遊戲的幾分之一就很了不起了。而其實這些遊戲都有共同的缺點,就是球拍控球困難,很難去控制乒乓球的左右與球的速度,更別說遠近或落點了。現在我們自信的是,我們的作品可以讓玩家能容易地去控制球的速率、方向、遠近,練習之後很容易地就可以打出左右變線或長短變線的戰術玩法。最後的收穫是我們不曾想過的。還有,我對同學很吹毛求疵,例如振維畫的桌子圖我就讓他重作了十幾次…,大家這陣子都辛苦了。這個作品是大家趕出來的,最後趕工的幾天真是廢寢忘食,昏天黑地,百感交集。 by 政毅
 
     於2005年3月4月
 
 
 
 一開始時用小畫家畫好的圖
 
 —
 変わり続きけるこの時代に
 変わらない愛があるなら
本篇發表於 library and information studies。將永久鏈結加入書籤。

發表留言