㈠ 怎麼用vb製作俄羅斯方塊游戲啊,簡單點的。
visual basic繼承了basic語言易學易用的特點,特別適合於初學者學習windows系統編程。隨著21世紀信息社會的到來,計算機在人們的工作和生活中的深入,要求我們越來越多地與計算機打交道,為了使用戶在繁忙的日程工作中得到放鬆,於是出現了各種各樣的休閑軟體,如聊天工具,游戲等等。於是我們小組著手設計開始一個這樣的游戲軟體。通過這學期來Visual Basic的學習,我初步掌握了Visual Basic語言的最基本的知識,於是在牛榮和李鵬等老師的指導下動手用Visual Basic編寫俄羅斯方塊游戲。
我們之所以選擇開發俄羅斯方塊游戲,無可爭議,《俄羅斯方塊》是有史以來最偉大的游戲之一。 在曾經發布過的所有游戲中,《俄羅斯方塊》還被認為是僅有的一個能夠真正吸引廣泛人群的作品。誰能說清楚,迄今為止人們究竟花了多少萬個小時在這個游戲上?也許這些時間本來可以被花在更具生產力的活動上。某些批評家也許會聲稱,《俄羅斯方塊》要比過去二十年間出現的任何東西都要浪費人們的時間。至於我們,則要欣然提名它為GameSpot評選出的歷史上最偉大游戲之一。
為了懷念經典,也為了能夠給大多的計算機用戶在工作之餘找到一個休閑、娛樂的一個方式,我們小組開始著手用VB語言開發一個經典的俄羅斯方塊游戲。
工程概況
2.1 項目名稱
俄羅斯方塊游戲
2.2 設計平台
VB 全稱Visual Basic,它是以Basic語言作為其基本語言的一種可視化編程工具。
Vb是microsoft公司於1991年退出的windows應用程序開發工具visual意思是「可視化的」。在它剛推出來時,自身還存在一些缺陷,功能也相對少一些。但是經過多年的開發研究。最近microsoft公司又推出了VB6.0版本
VB6.0運行環境:硬體,要求486以上的處理器、16MB以上內存,50MB 以上的硬碟,cd-rom驅動器,滑鼠。軟體:要求windows 95以上版本。
2.3程序設計思想
游戲是用來給大家娛樂的,所以要能在使用的過程中給大家帶來快樂,消除大家的疲勞,所以我們在游戲中添加了漂亮的場景和動聽的音樂,設置了過關升級的功能,激發大家的娛樂激情。
從游戲的基本玩法出發,主要就是俄羅斯方塊的形狀和旋轉,我們在設計中在一個圖片框中構造了一個4*4的網狀小塊,由這些小塊組合成新的形狀,每四個小塊連接在一起就可以構造出一種造型,因此我們總共設計了7中造型,每種造型又可以通過旋轉而變化出2到4種形狀,利用隨機函數在一個欲覽窗體中提前展示形狀供用戶參考,然後將展示的形狀復制到游戲窗體中進行擺放,在游戲窗體中用戶就可以使用鍵盤的方向鍵來控制方塊的運動,然後利用遞歸語句對每一行進行判斷,如果有某行的方塊是滿的,則消除這行的方塊,並且使上面的方塊自由下落,其中,方塊向下的速度是有時鍾控制項控制的,在游戲中,用戶也可以使用向下鍵加快下落速度,定義一個變數,對消除的函數進行記錄,最後就可以得出用戶的分數,用if 語句對分數判斷,達到一定的積分就可以升級到下一個檔次。
俄羅斯方塊游戲設計的主要步驟為以下10個方面:
(1)游戲界面的設計。
(2)俄羅斯方塊的造型。
(3)俄羅斯方塊的旋轉。
(4)俄羅斯方塊的運動情況(包括向左,向右和向下)。
(5)俄羅斯方塊的自動消行功能。
(6)游戲級別的自由選擇。
(7)游戲速度的自由選擇。
(8)游戲得分的計算。
(9)游戲菜單選項的設計及功能實現。
(10)游戲的背景音樂及特效。
2.4運用的控制項和主要對象
我們在設計過程中主要用到的控制項有:command控制項,image控制項,picture控制項,label控制項,timer控制項,text控制項,windows media player控制項等等。
2.5主要實現的功能
我們開發的俄羅斯方塊游戲,主要實現了以下幾種功能:
1.可以靈活控制方塊在圖形框中運動。
2.游戲過程中方塊可以自由旋轉。
3.當某一行的方塊排列滿時,將自動將這一行方塊消除,然後將上面所有方塊向下移動,可以支持連續消行。
4.游戲前可以選擇游戲的速度和游戲的等級,游戲速度既為方塊下落速度,游戲等級為初始游戲時在基層隨機生成一定行數的無規律方塊,生成的行數由你來選擇,每行至少產生5個以上的無規律方塊,這樣增加了游戲難度,對於游戲高手來說,無疑不是一個新的挑戰。
5.游戲的得分支持積分,並且按照公式:
得分 = 原來分數+ 100 * (2 ^ 同時消除的行數-1)
這樣,你同一時間消除的行數越多,你的得分也就越高,當游戲積分到了一定時可以自動升級,這個升級指速度升級。
6.游戲中提供了一個漂亮的場景和動聽的音樂,給你帶來無限激情。
2.6開發人員
由於這次課程設計所選的題目太復雜,而時間又比較緊張,指導老師建議和同學分工完成。我們小組成員包括組長孫磊周,副組長鄒海星,此游戲由我們兩個人共同開發而成。
正文
3.1游戲設計的具體實現
在我們兩個人共同努力下,此次設計,終於能夠圓滿完成。由於時間的緊促,在設計中,也許會有一些考慮不周之處,但其功能已經能夠滿足大多用戶的需求,相信假以時日,一定能做出一個更經典,更完美的俄羅斯方塊游戲,下面我們將對每一步的具體如何實現展示給大家。
3.1.1游戲界面的設計和背景音樂及特效的實現
俄羅斯方塊游戲主要由兩個界面構成,登陸界面和開始游戲界面,在登陸界面中我們可以首先看到聖誕節的晚上飄梅花的場景,梅花從窗體頂部做函數曲線的下落運動,在窗體中定義一個Image控制項組,在通用中定義梅花X坐標變數動態數組,Y坐標變數動態數組,步距X的變數動態數組,步距Y的變數動態數組,以及振幅變數動態數組。然後在窗體form_load中可以定義梅花的數量,利用隨機函數產生隨機的梅花坐標,步距和振幅,Image控制項在運行時候就調用梅花圖片,Image控制項就可以由時鍾控制項控制下落速度,可以自由調節,梅花按snow(i).Left = xp(i) + am(i) * Sin(dx(i))函數在做縱向的正玄函數軌跡運動,豎直方向上為自由下落運動,,有am(i)來控制梅花的左右移動振幅。因此,我們就可以看到一個梅花在空中自由飄舞的畫面了。
背景畫面是用photoshop軟體處理的漂亮圖案,原本畫面中的動畫效果都是由Image控制項製作的,還有點擊進入游戲的按鈕是由Label控制項實現的,因為Image控制項沒有置前置後功能,不能將下雪的場景體現完整性,所以將這些圖案全部放在背景上,不影響雪花飄落的效果,當點擊畫面的時候一樣可以進入游戲界面。
游戲的背景音樂是由一段代碼調用系統播放器Windows Player播放背景音樂,由於本次設計主要是針對游戲如何設計的,所以在這里就不對播放背景音樂的功能做介紹了。
3.1.2俄羅斯方塊的造型
相信朋友們都玩過俄羅斯方塊,對這個游戲的玩法和方塊形狀都比較熟悉。我們這個游戲只選擇了最基本的7中造型,包括長條型,正方型,正S型,反S型,正7型,反7型,T型。如果需要我們可以添加更多的造型。將游戲界面的游戲區圖片框分割成10*20的小塊,每個小塊放置一個command控制項,預覽區圖片框按同樣比例分割成4*4的小塊,同樣有command控制項構成,我們可以把預覽區圖片框看作是從游戲區圖片框中選取的一個部分,游戲區的小方塊編號和欲覽區編號如下圖:
0 1 2 3 4 5 6 7 8 9
… … … … … … … … … …
… … … … … … … … … …
90 91 92 93 94 95 96 97 98 99
3 4 5 6
13 14 15 16
23 24 25 26
33 34 35 36
游戲區編號 欲覽區編號
利用Select將方塊的7中造型列出,比如長條型的設計,在欲覽區中分別有3.4.5.6和5.15.25.35四個方塊構成兩中形態,用數組為:
m(0) = 3: m(1) = 4: m(2) = 5: m(3) = 6: situation2 = 0
m(0) = 5: m(1) = 15: m(2) = 25: m(3) = 35: situation2 = 1
將它的形狀編號為0和1,在後面方便調用,其他的方塊造型同樣的方法。
3.1.3俄羅斯方塊的旋轉
俄羅斯方塊的旋轉主要將方塊的位置加以變換得到的,例如上述範例,長條型有兩中樣式,根據小方塊的編號變動來實現整個造型的旋轉,比如:
If n(0) - 18 >= 2 And n(3) + 9 <= 198 Then
If cmdfang(n(0) - 18).Visible = False And _
cmdfang(n(1) - 9).Visible = False And _
cmdfang(n(3) + 9).Visible = False Then
hidefang 0
n(0) = n(0) - 18
n(1) = n(1) - 9
n(3) = n(3) + 9
showfang 0
situation = 1
End If
End If
方塊的造型在旋轉的時候存在一個公式,當然首先要判斷是否滿足旋轉的要求,以上是一個長條型由橫著變成豎立狀態的旋轉,我們以它的造型中的第三個小方塊n(3)為中心旋轉,這樣,在開始運動的時候,長條形要發生旋轉最少要運動到第三行,才能由橫著變成豎立狀態,游戲區圖形框中第三行的第一個方塊的編號為20,所以長條造型的第一個小方塊的編號n(0)必須要大於20。同樣,長條型方塊在下落到底部的時候也有限制。如果長條下落到最後一行也將無法由橫著變成豎立狀態。
3.1.4如何實現方塊的運動和自動消除滿行的方塊
我們的這個俄羅斯方塊游戲主要是利用command控制項的visible屬性完成效果的,其實在游戲區圖形框可以看成是由許多的command小方塊組成,方塊運動的過程就是造型里方塊顯示或者隱藏,就像現在的霓虹燈效果一樣,由時鍾控制項控制visible屬性改變的速度,上一層的消失,下一層的顯示,這樣,從視覺效果可以看到方塊的下落運動效果。
方塊在下落的過程中會自動判斷每一行方塊的visible屬性,如果全部為true時,就會將這一行小方塊的visible屬性全部變成false,在將上面的小方塊向下移動,利用for語句進行循環判斷,將所有這樣情況的行改變小方塊visible屬性。當有多行同時出現這樣情況時使用遞歸調用,實現連續消行。具體程序代碼如下:
For i = 190 To 10 Step -10
If cmdfang(i).Visible = True And _
cmdfang(i + 1).Visible = True And _
cmdfang(i + 2).Visible = True And _
cmdfang(i + 3).Visible = True And _
cmdfang(i + 4).Visible = True And _
cmdfang(i + 5).Visible = True And _
cmdfang(i + 6).Visible = True And _
cmdfang(i + 7).Visible = True And _
cmdfang(i + 8).Visible = True And _
cmdfang(i + 9).Visible = True Then
For j = i + 4 To i Step -1
t = 1
cmdfang(j).Visible = False
cmdfang(2 * i + 9 - j).Visible = False
For k = 1 To 4000
DoEvents
Next
t = 0
Next
linenum = linenum + 1
For j = i - 1 To 0 Step -1
If cmdfang(j).Visible = True Then
cmdfang(j).Visible = False
cmdfang(j + 10).Visible = True
End If
Next
clearline '為了實現連消數行,這里使用遞歸調用
End If
Next
3.1.5游戲速度和游戲級別自由選擇
游戲速度的自由選擇無非就是改變時鍾控制項的頻率,我們在菜單中添加了選擇速度的功能,還有添加了考驗功能,將欲覽窗中的方塊造型隱藏,給玩家提高了難度,如果你不願意接受考驗也可以點擊顯示還原成原來狀態。
游戲級別的自由選擇是讓用戶選擇游戲開始時候,游戲區底部出現一定行數的隨機方塊,同樣給玩家增加了難度,功能代碼如下:
For i = 19 To 20 - Val(txthard.Text) Step -1
For j = i * 10 To i * 10 + 9
If Rnd >= 0.5 Then cmdfang(j).Visible = True
Next
Next
可以根據你選擇的難度系數在底層的每一行隨機產生超過半數(即5個以上)以上的小方塊,這樣適合喜歡高難度的玩家。
3.1.6游戲得分的計算和游戲菜單的編輯
游戲得分的計算主要是根據消除的行數來決定的,當然每一次同時消除的行數不一樣,每一行的得分也不一樣,如果你每次消除的行數為1,則最後得分是100分,如果同時消除2行,則最後得分是300分,同時消除3行,得分為700分,同時消除4行,得分為1500分,這由公式:得分 = 原來分數+ 100 * (2 ^ 同時消除的行數-1)。
游戲的編輯,讀者可以參照下面的功能介紹。
3.2 游戲功能的介紹
文件-------開始:開始游戲。
繼續:繼續游戲。
暫停:暫時停止游戲,點擊繼續的時候可以繼續游戲。
退出:退出遊戲。
設置-------選擇游戲級別。
選擇游戲速度。
考驗-------顯示:顯示欲覽去方塊。
隱藏:隱藏欲覽去方塊。
幫助-------操作提示以及版本信息和作者資料。
用戶界面具體如圖:
圖—登陸界面 圖—游戲界面
圖—菜單編輯界面 圖—游戲幫助界面
有關說明
經過兩個多星期的設計和開發,俄羅斯方塊游戲已經成功。其功能基本符合用戶需求,能夠完成游戲的控制,方塊的變換以及消層等功能。並提供游戲設置,對於一些技術性比較過硬的玩家,可以調游戲級別、以及游戲速度,使得玩家能夠充分的發揮競技游戲的特色,可以不斷的挑戰自我,挑戰極限。
4.1游戲設計中的不足之處
但是由於課程設計時間較短,所以該游戲還有許多不盡如人意的地方,比如方塊類型太少,退出遊戲不能存儲進度等多方面問題。這些都有待進一步改善,我們在游戲中還可以更換背景音樂,以適合不同的玩家,在每通過一關可以給玩家播放一段flash,吸引玩家去挑戰極限,不斷提高玩家的興趣,相信在以後的製作過程中我們將給大家帶來一個更新功能更全面的游戲。
4.2VB與C語言之間的不同之處
我們這個小游戲也可以用C語言來實現,在程序的編程上沒有VB語言方便實用,C語言和VB語言之間存在很多的共同點,雖然語法方面有點差異,但是在編程思路上完全一樣,VB能夠實現很多C#不能做到的功能,如When語句、Optional參數、局部Static變數、對象實例訪問靜態方法、Handles綁定事件、On Error處理異常、Object直接後期綁定等等。VB和C#語言,編譯出來的是同樣的CIL,但為什麼VB支持很多有趣的特性呢。我們一起來探究一下。
4.21局部靜態變數
VB支持用Static關鍵字聲明局部變數,這樣在過程結束的時候可以保持變數的數值:
Public Sub Test1()
Static i As Integer
i += 1 '實現一個過程調用計數器
End Sub
我們實現了一個簡單的過程計數器。每調用一次Test,計數器的數值就增加1。其實還有很多情況我們希望保持變數的數值。而C#的static是不能用在過程內部的。因此要實現過程計數器,我們必須聲明一個類級別的變數。這樣做明顯不如VB好。因為無法防止其他過程修改計數器變數。這就和對象封裝一個道理,本來應該是一個方法的局部變數,現在我要被迫把它獨立出來,顯然是不好的設計。那麼VB是怎麼生成局部靜態變數的呢?將上述代碼返匯編,我們可以清楚地看到在VB生成的CIL中,i不是作為局部變數,而是作為類的Field出現的: .field private specialname int32 $STATIC$Test1$2001$i
也就是說,i被改名作為一個類的欄位,但被冠以specialname。在代碼中試圖訪問$STATIC$Test1$2001$i是不可能的,因為它不是一個有效的標識符。但是在IL中,將這個變數加一的代碼卻與一般的類欄位完全一樣,是通過ldfld載入的。我覺得這個方法十分聰明,把靜態變數變成生命周期一樣的類欄位,但是又由編譯器來控制訪問的許可權,讓它成為一個局部變數。同時也解釋了VB為什麼要用兩個不同的關鍵字來聲明靜態變數——Static和Shared。由於局部靜態變數的實質是類的欄位,所以它和真正的局部變數還是有所不同的。比如在多線程條件下,對局部靜態變數的訪問就和訪問欄位相同。
4.2.2Handles和WithEvents
VB除了可以用C#那樣的方法來處理事件響應以外,還有從VB5繼承下來的獨特的事件處理方式——WithEvents。
我喜歡稱這種事件處理方式為靜態的事件處理,書寫響應事件的方法時就已經決定該方法響應的是哪一個事件,而C#則是在代碼中綁定事件的。VB中WithEvents靜態方法是非常有用的,它可以顯著增強代碼可讀性,同時也讓VB.net中的事件處理非常方便,不像C#那樣離開了窗體設計器就必須手工綁定事件。
4.2.3類型轉換運算符
在Visual Basic 2005中將加入一個新的運算符——TryCast,相當於C#的as運算符。我一直希望VB有這樣一個運算符。VB目前的類型轉換運算符主要有CType和DirectCast。他們的用法幾乎一樣。我詳細比較了一下這兩個運算符,得出以下結論:
1.在轉換成引用類型時,兩者沒有什麼區別,都是直接調用castclass指令,除非重載了類型轉換運算符CType。DirectCast運算符是不能重載的。
2.轉換成值類型時,CType會調用VB指定的類型轉換函數(如果有的話),比如將String轉換為Int32時,就會自動調用。
4.2.4默認屬性和屬性參數
在原先的VB6里,有一項奇特的功能——默認屬性。在VB6中,對象的名稱可以直接表示該對象的默認屬性。
4.2.5可選參數和按名傳遞
VB從4.0開始支持「可選參數」這一特性。就是說,函數或子程序的參數有些是可選的,調用的時候可以不輸入。其實VB從1.0開始就有一些函數帶有可選參數,只不過到了4.0才讓用戶自己開發這樣的過程。在VB4里,可選參數可以不帶默認值,而在VB里,如果使用可選參數,則必須帶有默認值。在調用的時候,VB若發現參數被省略,則自動讀取.param部分的默認值,並顯式傳遞給過程。這一部分完全由編譯器處理,而且沒有任何性能損失,和手工傳遞所有參數是完全一樣的。至於按名傳遞,VB會自動調整參數的順序,其結果與傳統方式的傳遞也沒有任何的不同。這說明我們可以放心地使用這項便利。而且帶有可選參數的過程拿到C#中,頂多變成不可選參數,也不會造成什麼其他的麻煩。
PS.很多COM組件都使用了默認參數,而且有些過程的參數列表非常長,在VB里可以輕松地處理它們,而在C#中經常讓開發者傳參數傳到吐血。
4.2.6在經過對比之後可得以下一個結論:
1.目前的主流編程語言沒有簡單的,如果你想學精通的話。
2.VB的門檻比較低,編程思想較容易接受。
3.學習C不能短期內見到成效。
4.據用戶調查69%的考生覺得VB更容易接受
致謝
在本次課程設計中,我從指導老師牛榮和李鵬身上學到了很多東西。老師認真負責的工作態度,嚴謹的治學精神和深厚的理論水平都使我收益匪淺。他無論在理論上還是在實踐中,都給與我很大的幫助,使我得到不少的提高這對於我以後的工作和學習都有一種巨大的幫助,感謝他耐心的輔導。
另外,在游戲開發過程中化希耀老師和杜義君老師也給於我們很大的幫助,幫助解決了不少的難點,使得游戲能及時開發完成,還有所有的同學同樣給與我不少幫助,這里一並表示感。
參考文獻:
[1]Vsual Basic 程序設計教程 作者:龔沛曾,陸慰民,楊志強 高等教育出版社出版
[2]Vsual Basic 6.0程序設計 作者:劉新民,蔡瓊,白糠生 清華大學出版社出版
[3]80例上手 VB6 編程 作者:唐凱軍,湯惠莉 山東電子音像出版社
[4]Vsual Basic 實例教程 作者:盧毅 科學出版社出版
[5]Vsual Basic 經典範例50講 作者:趙欣勝,亢慧娟,劉晟宏 科學出版社出版
㈡ 怎樣製作俄羅斯方塊
以下代碼粘貼在主場經第一禎,測試影片就看到了:
N = 20;//行數
WIDTH = 20;//方塊邊長
level = 0;//開始等級(下落速度)
ret = new Array();//當前出現的方塊
nextret = new Array();//下一個出現的方塊
bg = new Array();//背景數組
createEmptyMovieClip("panel", 1048575);//所有方塊都在此mc里
for (i = 0; i < 5; i++) {
//初始化方塊數組,2*5格式,前四行代表每個方塊的4個小塊的位置坐標,最後一行第一列是方塊形狀,第二列是方塊旋轉方向
ret.push(new Array(2));
nextret.push(new Array(2));
}
for (i = 0; i < 20; i++) {//初始化背景數組,10*20格式
bg.push(new Array(10));
}
X = Y = panel._x = panel._y = 0;//換為X、Y表示
function reach(x:Number, y:Number, ret:Object) {
//x、y為方塊位置,ret為方塊形狀,若方塊ret下落一格碰到邊界或者方塊返回1
var i:Number, j:Number, k:Number;
for (i = 0; i < N; i++) {
for (j = 0; j < 10; j++) {
if (bg[i][j] == 219) {
for (k = 0; k < 4; k++) {
if (x + ret[k][0] == j && y + ret[k][1] + 1 == i) {
return 1;
}
}
}
}
}
return 0;
}
function lrnotout(lorr:Number, a:Object) {
//lorr==-1代表a往左邊一格可行性的判斷,lorr==1代表右邊一格可行性的判斷,lorr==0代表a的位置合理性的判斷,出現不合理則返回0
var i:Number;
if (lorr == -1) {
for (i = 0; i < 4; i++) {
if (x + a[i][0] - 1 < 0 || reach(x - 1, y - 1, a)) {
return 0;
}
}
}
if (lorr == 1) {
for (i = 0; i < 4; i++) {
if (x + a[i][0] + 1 > 9 || reach(x - 1, y + 1, a)) {
return 0;
}
}
}
if (lorr == 0) {
for (i = 0; i < 4; i++) {
if (x + a[i][0] < 0 || x + a[i][0] > 9) {
return 0;
}
}
}
return 1;
}
function rv(a:Object, ret:Object) {
//方塊賦值,將a方塊賦值到ret方塊
var i:Number;
for (i = 0; i < 5; i++) {
ret[i][0] = a[i][0], ret[i][1] = a[i][1];
}
}
function rotate(ret:Object) {
//根據方塊ret最後一行(分別是形狀指示變數和旋轉方向變數)為ret的前四行賦以具體形狀值
switch (ret[4][0]) {
case 0 ://方形
a = [[1, 0], [2, 0], [1, 1], [2, 1], [0, 0]];
rv(a, ret);
return;
case 1 ://長形
switch (ret[4][1]) {
case 1 :
a = [[0, 0], [1, 0], [2, 0], [3, 0], [1, 0]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 0 :
a = [[1, 0], [1, 1], [1, 2], [1, 3], [1, 1]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
}
case 2 ://Z形
switch (ret[4][1]) {
case 1 :
a = [[0, 1], [1, 1], [1, 2], [2, 2], [2, 0]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 0 :
a = [[2, 0], [1, 1], [2, 1], [1, 2], [2, 1]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
}
case 3 ://反Z形
switch (ret[4][1]) {
case 1 :
a = [[1, 1], [2, 1], [0, 2], [1, 2], [3, 0]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 0 :
a = [[1, 0], [1, 1], [2, 1], [2, 2], [3, 1]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
}
case 4 ://T形
switch (ret[4][1]) {
case 3 :
a = [[1, 0], [0, 1], [1, 1], [2, 1], [4, 0]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 0 :
a = [[1, 0], [0, 1], [1, 1], [1, 2], [4, 1]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 1 :
a = [[0, 1], [1, 1], [2, 1], [1, 2], [4, 2]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 2 :
a = [[1, 0], [1, 1], [2, 1], [1, 2], [4, 3]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
}
case 5 ://倒L形
switch (ret[4][1]) {
case 3 :
a = [[1, 0], [2, 0], [1, 1], [1, 2], [5, 0]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 0 :
a = [[0, 1], [0, 2], [1, 2], [2, 2], [5, 1]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 1 :
a = [[2, 0], [2, 1], [1, 2], [2, 2], [5, 2]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 2 :
a = [[0, 1], [1, 1], [2, 1], [2, 2], [5, 3]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
}
case 6 ://L形
switch (ret[4][1]) {
case 3 :
a = [[1, 0], [2, 0], [2, 1], [2, 2], [5, 0]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 0 :
a = [[0, 1], [1, 1], [2, 1], [0, 2], [5, 1]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 1 :
a = [[1, 0], [1, 1], [1, 2], [2, 2], [5, 2]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
case 2 :
a = [[2, 1], [0, 2], [1, 2], [2, 2], [5, 3]];
if (lrnotout(0, a) && !reach(x, y - 1, a)) {
rv(a, ret);
}
return;
}
}
}
function generate(ret:Object) {//隨機產生方塊函數(可進一步修正)
ret[4][0] = Math.floor(Math.random() * 7);
ret[4][1] = Math.floor(Math.random() * 4);
rotate(ret);//完成方塊ret的具體形狀的賦值
}
function init() {//初始化背景、方塊、運動函數
var i:Number, j:Number;
for (i = 0; i < N; i++) {//初始化背景,邊界為219,其餘為' '
for (j = 0; j < 10; j++) {
if (i == N - 1) {
bg[i][j] = 219;
} else {
bg[i][j] = ' ';
}
}
}
for (i = 0; i < 5; i++) {//為當前方塊賦初值0
ret[i][0] = ret[i][1] = 0;
}
generate(ret);//產生當前方塊
generate(nextret);//產生下一個方塊
y = 0, x = 3, score = lines = 0, level=0;//當前位置坐標和計分系統初始化
_tetris.removeTextField();//如果從結束過的游戲恢復,刪除結束標志
display();//顯示畫面
frameflag = 0;//標示下落時間間隔
onEnterFrame = function () {
frameflag++;
if (10 - frameflag < level) {//根據等級level確定下落時間間隔
frameflag = 0;
go();//下落及判斷
}
};
}
function drawblock(a, b, c, d) {//繪制方塊的小塊
with (panel) {
beginFill(0x000FFF, 100);
lineStyle(1, 0xFF00FF);
moveTo(panel._x + a, panel._y + b);
lineTo(panel._x + c, panel._y + b);
lineTo(panel._x + c, panel._y + d);
lineTo(panel._x + a, panel._y + d);
lineTo(panel._x + a, panel._y + b);
endFill();
}
}
function erase() {//刪除一行方塊
var n:Number = 0, i:Number, j:Number, k:Number, l:Number;
for (i = 0; i < N - 1; i++) {
for (j = 0; j < 10; j++) {
if (bg[i][j] == ' ') {//如果該行有空,則開始判斷下一行
i++, j = -1;
if (i == N - 1) {//行N-1為底線,不判斷
break;
}
} else if (j == 9) {//判斷到該行最後一列都沒有空
for (k = i; k >= 1; k--) {//上方方塊下落
for (l = 0; l < 10; l++) {
bg[k][l] = bg[k - 1][l];
}
}
for (l = 0; l < 10; l++) {//刪除該行
bg[0][l] = ' ';
}
n++;//此次刪除行數變數增一
if ((lines + n) % 30 == 0) {//刪除行數總數到30的倍數則等級上升
level = (level + 1) % 10;
}
}
}
}
lines += n, score += (n * n + n) * 50;//總行數增n,計算得分
}
function display() {
//顯示函數,採用全部清除再重繪制的方法(因為這個程序本來是在Turbo C 2.0的文本環境下完成的)
var i:Number, j:Number;
panel.clear();
with (panel) {//畫邊界
lineStyle(1, 0x0000FF);
moveTo(panel._x, panel._y);
lineTo(panel._x + WIDTH * 10, panel._y);
lineTo(panel._x + WIDTH * 10, panel._y + WIDTH * (N - 1));
lineTo(panel._x, panel._y + WIDTH * (N - 1));
lineTo(panel._x, panel._y);
}
for (i = 0; i < 4; i++) {//當前方塊占據的地方賦值為邊界類型219
bg[y + ret[i][1]][x + ret[i][0]] = 219;
}
for (i = 0; i < N - 1; i++) {//繪制背景方塊
for (j = 0; j < 10; j++) {
if (bg[i][j] == 219) {
drawblock(j * WIDTH + X, i * WIDTH + Y, j * WIDTH + WIDTH + X, i * WIDTH + WIDTH + Y);
}
}
}
for (i = 0; i < 4; i++) {//繪制當前方塊
drawblock(nextret[i][0] * WIDTH + 14 * WIDTH + X, nextret[i][1] * WIDTH + 12 * WIDTH + Y, nextret[i][0] * WIDTH + WIDTH + 14 * WIDTH + X, nextret[i][1] * WIDTH + WIDTH + 12 * WIDTH + Y);
}
for (i = 0; i < 4; i++) {//當前方塊繪制完畢,重新將當前位置改為' '
bg[y + ret[i][1]][x + ret[i][0]] = ' ';
}
createTextField("_lvltxt", 1, 270, 100, 100, 20);//繪制計分系統
createTextField("_scrtxt", 2, 270, 130, 100, 20);
createTextField("_lnstxt", 3, 270, 160, 100, 20);
_lvltxt.text = "Level: " + level;
_scrtxt.text = "Score: " + score;
_lnstxt.text = "Lines: " + lines;
}
function go() {//下落函數
var sss:Number = reach(x, y, ret);//當前方塊下落一格是否碰到邊界或方塊
var ii:Number;
if (!sss) {
y++;//如果當前方塊下落一格沒有碰到邊界或方塊則下落一格
}
display();//重新繪制
if (sss) {//碰到邊界或方塊
score += 10;//得10分
display();//重新繪制
for (ii = 0; ii < 4; ii++) {//修改背景數組,將當前方塊的位置改為邊界類型
bg[y + ret[ii][1]][x + ret[ii][0]] = 219;
}
erase();//刪除行判斷及執行
rv(nextret, ret);//將下一個方塊賦值為當前方塊
y = 0, x = 3;//重置方塊位置
generate(nextret);//生成下一個方塊
display();//重新繪制
if (reach(x, y, ret)) {//如果下一格碰到方塊則游戲結束
createTextField("_tetris", 100000, WIDTH * 3.3, WIDTH * N / 3, 70, 20);
_tetris._x += 200;
_tetris._y += 50;
_tetris._xscale = 300;
_tetris._yscale = 300;
_tetris.background = true;
_tetris.text = "Game Over!";
onEnterFrame = function () {//停止下落
};
}
}
}
function key() {
if (Key.isDown(Key.UP)) {
rotate(ret);
display();
}
if (Key.isDown(Key.LEFT)) {
if (lrnotout(-1, ret)) {//左移可行性判斷
x--;
display();
}
}
if (Key.isDown(Key.RIGHT)) {
if (lrnotout(1, ret)) {//右移可行性判斷
x++;
display();
}
}
if (Key.isDown(Key.DOWN)) {//鍵盤控制下落
go();
}
if (Key.isDown(Key.SPACE)) {//一鍵下落到底
while (!reach(x, y, ret)) {
y++;
}
go();
}
if (Key.isDown(82)) { //重新開始游戲
init();
}
}
init();//初始化
setInterval(key, 80);//每個80毫秒執行一次鍵盤事件函數
createTextField("hinttxt",33324,200,20,300,50);
hinttxt.text="鍵盤鍵:上,下,左,右,R(reset),空格";
㈢ 俄羅斯方塊怎麼做(要思想)
不要留空的
㈣ 怎樣用c語言編寫俄羅斯方塊程序
俄羅斯方塊C源代碼
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<time.h>
#defineZL4 //坐標增量,不使游戲窗口靠邊
#defineWID36 //游戲窗口的寬度
#defineHEI20 //游戲窗口的高度
inti,j,Ta,Tb,Tc; //Ta,Tb,Tc用於記住和轉換方塊變數的值
inta[60][60]={0}; //標記游戲屏幕各坐標點:0,1,2分別為空、方塊、邊框
intb[4]; //標記4個"口"方塊:1有,0無,類似開關
intx,y,level,score,speed; //方塊中心位置的x,y坐標,游戲等級、得分和游戲速度
intflag,next; //當前要操作的方塊類型序號,下一個方塊類型序號
voidgtxy(intm,intn); //以下聲明要用到的自編函數
voidgflag(); //獲得下一方塊序號
voidcsh(); //初始化界面
voidstart(); //開始部分
voidprfk(); //列印方塊
voidclfk(); //清除方塊
voidmkfk(); //製作方塊
voidkeyD(); //按鍵操作
intifmov(); //判斷方塊能否移動或變體
void clHA(); //清除滿行的方塊
voidclNEXT(); //清除邊框外的NEXT方塊
intmain()
{csh();
while(1)
{start();//開始部分
while(1)
{prfk();
Sleep(speed); //延時
clfk();
Tb=x;Tc=flag;//臨存當前x坐標和序號,以備撤銷操作
keyD();
y++;//方塊向下移動
if(ifmov()==0){y--;prfk();dlHA();break;}//不可動放下,刪行,跨出循環
}
for(i=y-2;i<y+2;i++){if(i==ZL){j=0;}} //方塊觸到框頂
if(j==0){system("cls");gtxy(10,10);printf("游戲結束!");getch();break;}
clNEXT(); //清除框外的NEXT方塊
}
return0;
}
voidgtxy(intm,intn)//控制游標移動
{COORDpos;//定義變數
pos.X=m;//橫坐標
pos.Y=n;//縱坐標
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
voidcsh()//初始化界面
{gtxy(ZL+WID/2-5,ZL-2);printf("俄羅斯方塊");//列印游戲名稱
gtxy(ZL+WID+3,ZL+7);printf("*******NEXT:");//列印菜單信息
gtxy(ZL+WID+3,ZL+13);printf("**********");
gtxy(ZL+WID+3,ZL+15);printf("Esc:退出遊戲");
gtxy(ZL+WID+3,ZL+17);printf("↑鍵:變體");
gtxy(ZL+WID+3,ZL+19);printf("空格:暫停游戲");
gtxy(ZL,ZL);printf("╔");gtxy(ZL+WID-2,ZL);printf("╗");//列印框角
gtxy(ZL,ZL+HEI);printf("╚");gtxy(ZL+WID-2,ZL+HEI);printf("╝");
a[ZL][ZL+HEI]=2;a[ZL+WID-2][ZL+HEI]=2;//記住有圖案
for(i=2;i<WID-2;i+=2){gtxy(ZL+i,ZL);printf("═");}//列印上橫框
for(i=2;i<WID-2;i+=2){gtxy(ZL+i,ZL+HEI);printf("═");a[ZL+i][ZL+HEI]=2;}//下框
for(i=1;i<HEI;i++){gtxy(ZL,ZL+i);printf("║");a[ZL][ZL+i]=2;}//左豎框記住有圖案
for(i=1;i<HEI;i++){gtxy(ZL+WID-2,ZL+i);printf("║");a[ZL+WID-2][ZL+i]=2;}//右框
CONSOLE_CURSOR_INFOcursor_info={1,0};//以下是隱藏游標的設置
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
level=1;score=0;speed=400;
gflag();flag=next;//獲得一個當前方塊序號
}
voidgflag() //獲得下一個方塊的序號
{srand((unsigned)time(NULL));next=rand()%19+1; }
voidstart()//開始部分
{gflag();Ta=flag;flag=next;//保存當前方塊序號,將下一方塊序號臨時操作
x=ZL+WID+6;y=ZL+10;prfk();//給x,y賦值,在框外列印出下一方塊
flag=Ta;x=ZL+WID/2;y=ZL-1;//取回當前方塊序號,並給x,y賦值
}
voidprfk()//列印俄羅斯方塊
{for(i=0;i<4;i++){b[i]=1;}//數組b[4]每個元素的值都為1
mkfk();//製作俄羅斯方塊
for(i=x-2;i<=x+4;i+=2)//列印方塊
{for(j=y-2;j<=y+1;j++){if(a[i][j]==1&&j>ZL){gtxy(i,j);printf("□");}}}
gtxy(ZL+WID+3,ZL+1); printf("level:%d",level); //以下列印菜單信息
gtxy(ZL+WID+3,ZL+3); printf("score:%d",score);
gtxy(ZL+WID+3,ZL+5); printf("speed:%d",speed);
}
voidclfk()//清除俄羅斯方塊
{for(i=0;i<4;i++){b[i]=0;}//數組b[4]每個元素的值都為0
mkfk();//製作俄羅斯方塊
for(i=x-2;i<=x+4;i+=2)//清除方塊
{for(j=y-2;j<=y+1;j++){if(a[i][j]==0&&j>ZL){gtxy(i,j);printf("");}}}
}
voidmkfk()//製作俄羅斯方塊
{a[x][y]=b[0];//方塊中心位置狀態:1-有,0-無
switch(flag)//共6大類,19種小類型
{case1:{a[x][y-1]=b[1];a[x+2][y-1]=b[2];a[x+2][y]=b[3];break;}//田字方塊
case2:{a[x-2][y]=b[1];a[x+2][y]=b[2];a[x+4][y]=b[3];break;}//直線方塊:----
case3:{a[x][y-1]=b[1];a[x][y-2]=b[2];a[x][y+1]=b[3];break;}//直線方塊:|
case4:{a[x-2][y]=b[1];a[x+2][y]=b[2];a[x][y+1]=b[3];break;}//T字方塊
case5:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x-2][y]=b[3];break;}//T字順時針轉90度
case6:{a[x][y-1]=b[1];a[x-2][y]=b[2];a[x+2][y]=b[3];break;}//T字順轉180度
case7:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x+2][y]=b[3];break;}//T字順轉270度
case8:{a[x][y+1]=b[1];a[x-2][y]=b[2];a[x+2][y+1]=b[3];break;}//Z字方塊
case9:{a[x][y-1]=b[1];a[x-2][y]=b[2];a[x-2][y+1]=b[3];break;}//Z字順轉90度
case10:{a[x][y-1]=b[1];a[x-2][y-1]=b[2];a[x+2][y]=b[3];break;}//Z字順轉180度
case11:{a[x][y+1]=b[1];a[x+2][y-1]=b[2];a[x+2][y]=b[3];break;}//Z字順轉270度
case12:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x-2][y-1]=b[3];break;}//7字方塊
case13:{a[x-2][y]=b[1];a[x+2][y-1]=b[2];a[x+2][y]=b[3];break;}//7字順轉90度
case14:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x+2][y+1]=b[3];break;}//7字順轉180度
case15:{a[x-2][y]=b[1];a[x-2][y+1]=b[2];a[x+2][y]=b[3];break;}//7字順轉270度
case16:{a[x][y+1]=b[1];a[x][y-1]=b[2];a[x+2][y-1]=b[3];break;}//倒7字方塊
case17:{a[x-2][y]=b[1];a[x+2][y+1]=b[2];a[x+2][y]=b[3];break;}//倒7字順轉90度
case18:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x-2][y+1]=b[3];break;}//倒7字順轉180度
case19:{a[x-2][y]=b[1];a[x-2][y-1]=b[2];a[x+2][y]=b[3];break;}//倒7字順轉270度
}
}
voidkeyD()//按鍵操作
{if(kbhit())
{intkey;
key=getch();
if(key==224)
{key=getch();
if(key==75){x-=2;}//按下左方向鍵,中心橫坐標減2
if(key==77){x+=2;}//按下右方向鍵,中心橫坐標加2
if(key==72)//按下向上方向鍵,方塊變體
{if(flag>=2&&flag<=3){flag++;flag%=2;flag+=2;}
if(flag>=4&&flag<=7){flag++;flag%=4;flag+=4;}
if(flag>=8&&flag<=11){flag++;flag%=4;flag+=8;}
if(flag>=12&&flag<=15){flag++;flag%=4;flag+=12;}
if(flag>=16&&flag<=19){flag++;flag%=4;flag+=16;}}
}
if(key==32)//按空格鍵,暫停
{prfk();while(1){if(getch()==32){clfk();break;}}} //再按空格鍵,繼續游戲
if(ifmov()==0){x=Tb;flag=Tc;} //如果不可動,撤銷上面操作
else{prfk();Sleep(speed);clfk();Tb=x;Tc=flag;} //如果可動,執行操作
}
}
intifmov()//判斷能否移動
{if(a[x][y]!=0){return0;}//方塊中心處有圖案返回0,不可移動
else{if((flag==1&&(a[x][y-1]==0&&a[x+2][y-1]==0&&a[x+2][y]==0))||
(flag==2&&(a[x-2][y]==0&&a[x+2][y]==0&&a[x+4][y]==0))||
(flag==3&&(a[x][y-1]==0&&a[x][y-2]==0&&a[x][y+1]==0))||
(flag==4&&(a[x-2][y]==0&&a[x+2][y]==0&&a[x][y+1]==0))||
(flag==5&&(a[x][y-1]==0&&a[x][y+1]==0&&a[x-2][y]==0))||
(flag==6&&(a[x][y-1]==0&&a[x-2][y]==0&&a[x+2][y]==0))||
(flag==7&&(a[x][y-1]==0&&a[x][y+1]==0&&a[x+2][y]==0))||
(flag==8&&(a[x][y+1]==0&&a[x-2][y]==0&&a[x+2][y+1]==0))||
(flag==9&&(a[x][y-1]==0&&a[x-2][y]==0&&a[x-2][y+1]==0))||
(flag==10&&(a[x][y-1]==0&&a[x-2][y-1]==0&&a[x+2][y]==0))||
(flag==11&&(a[x][y+1]==0&&a[x+2][y-1]==0&&a[x+2][y]==0))||
(flag==12&&(a[x][y-1]==0&&a[x][y+1]==0&&a[x-2][y-1]==0))||
( flag==13 && ( a[x-2][y]==0 && a[x+2][y-1]==0 && a[x+2][y]==0 ) ) ||
( flag==14 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x+2][y+1]==0 ) ) ||
(flag==15 && ( a[x-2][y]==0 && a[x-2][y+1]==0 && a[x+2][y]==0 ) ) ||
(flag==16 && ( a[x][y+1]==0 && a[x][y-1]==0 && a[x+2][y-1]==0 ) ) ||
( flag==17 && ( a[x-2][y]==0 && a[x+2][y+1]==0 && a[x+2][y]==0 ) ) ||
(flag==18 && ( a[x][y-1]==0 &&a[x][y+1]==0 && a[x-2][y+1]==0 ) ) ||
(flag==19 && ( a[x-2][y]==0 && a[x-2][y-1]==0
&&a[x+2][y]==0))){return1;}
}
return0; //其它情況返回0
}
voidclNEXT() //清除框外的NEXT方塊
{flag=next;x=ZL+WID+6;y=ZL+10;clfk();}
void clHA() //清除滿行的方塊
{intk,Hang=0; //k是某行方塊個數,Hang是刪除的方塊行數
for(j=ZL+HEI-1;j>=ZL+1;j--)//當某行有WID/2-2個方塊時,則為滿行
{k=0;for(i=ZL+2;i<ZL+WID-2;i+=2)
{if(a[i][j]==1)//豎坐標從下往上,橫坐標由左至右依次判斷是否滿行
{k++; //下面將操作刪除行
if(k==WID/2-2) { for(k=ZL+2;k<ZL+WID-2;k+=2)
{a[k][j]=0;gtxy(k,j);printf("");Sleep(1);}
for(k=j-1;k>ZL;k--)
{for(i=ZL+2;i<ZL+WID-2;i+=2)//已刪行數上面有方塊,先清除再全部下移一行
{if(a[i][k]==1){a[i][k]=0;gtxy(i,k);printf("");a[i][k+1]=1;
gtxy(i,k+1);printf("□");}}
}
j++;//方塊下移後,重新判斷刪除行是否滿行
Hang++;//記錄刪除方塊的行數
}
}
}
}
score+=100*Hang; //每刪除一行,得100分
if(Hang>0&&(score%500==0||score/500>level-1)) //得分滿500速度加快升一級
{speed-=20;level++;if(speed<200)speed+=20; }
}
㈤ 求一份用C語言編寫的俄羅斯方塊的源代碼!
俄羅斯方塊C源代碼
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<time.h>
#defineZL4 //坐標增量,不使游戲窗口靠邊
#defineWID36 //游戲窗口的寬度
#defineHEI20 //游戲窗口的高度
inti,j,Ta,Tb,Tc; //Ta,Tb,Tc用於記住和轉換方塊變數的值
inta[60][60]={0}; //標記游戲屏幕各坐標點:0,1,2分別為空、方塊、邊框
intb[4]; //標記4個"口"方塊:1有,0無,類似開關
intx,y,level,score,speed; //方塊中心位置的x,y坐標,游戲等級、得分和游戲速度
intflag,next; //當前要操作的方塊類型序號,下一個方塊類型序號
voidgtxy(intm,intn); //以下聲明要用到的自編函數
voidgflag(); //獲得下一方塊序號
voidcsh(); //初始化界面
voidstart(); //開始部分
voidprfk(); //列印方塊
voidclfk(); //清除方塊
voidmkfk(); //製作方塊
voidkeyD(); //按鍵操作
intifmov(); //判斷方塊能否移動或變體
void clHA(); //清除滿行的方塊
voidclNEXT(); //清除邊框外的NEXT方塊
intmain()
{csh();
while(1)
{start();//開始部分
while(1)
{prfk();
Sleep(speed); //延時
clfk();
Tb=x;Tc=flag;//臨存當前x坐標和序號,以備撤銷操作
keyD();
y++;//方塊向下移動
if(ifmov()==0){y--;prfk();dlHA();break;}//不可動放下,刪行,跨出循環
}
for(i=y-2;i<y+2;i++){if(i==ZL){j=0;}} //方塊觸到框頂
if(j==0){system("cls");gtxy(10,10);printf("游戲結束!");getch();break;}
clNEXT(); //清除框外的NEXT方塊
}
return0;
}
voidgtxy(intm,intn)//控制游標移動
{COORDpos;//定義變數
pos.X=m;//橫坐標
pos.Y=n;//縱坐標
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
voidcsh()//初始化界面
{gtxy(ZL+WID/2-5,ZL-2);printf("俄羅斯方塊");//列印游戲名稱
gtxy(ZL+WID+3,ZL+7);printf("*******NEXT:");//列印菜單信息
gtxy(ZL+WID+3,ZL+13);printf("**********");
gtxy(ZL+WID+3,ZL+15);printf("Esc:退出遊戲");
gtxy(ZL+WID+3,ZL+17);printf("↑鍵:變體");
gtxy(ZL+WID+3,ZL+19);printf("空格:暫停游戲");
gtxy(ZL,ZL);printf("╔");gtxy(ZL+WID-2,ZL);printf("╗");//列印框角
gtxy(ZL,ZL+HEI);printf("╚");gtxy(ZL+WID-2,ZL+HEI);printf("╝");
a[ZL][ZL+HEI]=2;a[ZL+WID-2][ZL+HEI]=2;//記住有圖案
for(i=2;i<WID-2;i+=2){gtxy(ZL+i,ZL);printf("═");}//列印上橫框
for(i=2;i<WID-2;i+=2){gtxy(ZL+i,ZL+HEI);printf("═");a[ZL+i][ZL+HEI]=2;}//下框
for(i=1;i<HEI;i++){gtxy(ZL,ZL+i);printf("║");a[ZL][ZL+i]=2;}//左豎框記住有圖案
for(i=1;i<HEI;i++){gtxy(ZL+WID-2,ZL+i);printf("║");a[ZL+WID-2][ZL+i]=2;}//右框
CONSOLE_CURSOR_INFOcursor_info={1,0};//以下是隱藏游標的設置
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
level=1;score=0;speed=400;
gflag();flag=next;//獲得一個當前方塊序號
}
voidgflag() //獲得下一個方塊的序號
{srand((unsigned)time(NULL));next=rand()%19+1; }
voidstart()//開始部分
{gflag();Ta=flag;flag=next;//保存當前方塊序號,將下一方塊序號臨時操作
x=ZL+WID+6;y=ZL+10;prfk();//給x,y賦值,在框外列印出下一方塊
flag=Ta;x=ZL+WID/2;y=ZL-1;//取回當前方塊序號,並給x,y賦值
}
voidprfk()//列印俄羅斯方塊
{for(i=0;i<4;i++){b[i]=1;}//數組b[4]每個元素的值都為1
mkfk();//製作俄羅斯方塊
for(i=x-2;i<=x+4;i+=2)//列印方塊
{for(j=y-2;j<=y+1;j++){if(a[i][j]==1&&j>ZL){gtxy(i,j);printf("□");}}}
gtxy(ZL+WID+3,ZL+1); printf("level:%d",level); //以下列印菜單信息
gtxy(ZL+WID+3,ZL+3); printf("score:%d",score);
gtxy(ZL+WID+3,ZL+5); printf("speed:%d",speed);
}
voidclfk()//清除俄羅斯方塊
{for(i=0;i<4;i++){b[i]=0;}//數組b[4]每個元素的值都為0
mkfk();//製作俄羅斯方塊
for(i=x-2;i<=x+4;i+=2)//清除方塊
{for(j=y-2;j<=y+1;j++){if(a[i][j]==0&&j>ZL){gtxy(i,j);printf("");}}}
}
voidmkfk()//製作俄羅斯方塊
{a[x][y]=b[0];//方塊中心位置狀態:1-有,0-無
switch(flag)//共6大類,19種小類型
{case1:{a[x][y-1]=b[1];a[x+2][y-1]=b[2];a[x+2][y]=b[3];break;}//田字方塊
case2:{a[x-2][y]=b[1];a[x+2][y]=b[2];a[x+4][y]=b[3];break;}//直線方塊:----
case3:{a[x][y-1]=b[1];a[x][y-2]=b[2];a[x][y+1]=b[3];break;}//直線方塊:|
case4:{a[x-2][y]=b[1];a[x+2][y]=b[2];a[x][y+1]=b[3];break;}//T字方塊
case5:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x-2][y]=b[3];break;}//T字順時針轉90度
case6:{a[x][y-1]=b[1];a[x-2][y]=b[2];a[x+2][y]=b[3];break;}//T字順轉180度
case7:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x+2][y]=b[3];break;}//T字順轉270度
case8:{a[x][y+1]=b[1];a[x-2][y]=b[2];a[x+2][y+1]=b[3];break;}//Z字方塊
case9:{a[x][y-1]=b[1];a[x-2][y]=b[2];a[x-2][y+1]=b[3];break;}//Z字順轉90度
case10:{a[x][y-1]=b[1];a[x-2][y-1]=b[2];a[x+2][y]=b[3];break;}//Z字順轉180度
case11:{a[x][y+1]=b[1];a[x+2][y-1]=b[2];a[x+2][y]=b[3];break;}//Z字順轉270度
case12:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x-2][y-1]=b[3];break;}//7字方塊
case13:{a[x-2][y]=b[1];a[x+2][y-1]=b[2];a[x+2][y]=b[3];break;}//7字順轉90度
case14:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x+2][y+1]=b[3];break;}//7字順轉180度
case15:{a[x-2][y]=b[1];a[x-2][y+1]=b[2];a[x+2][y]=b[3];break;}//7字順轉270度
case16:{a[x][y+1]=b[1];a[x][y-1]=b[2];a[x+2][y-1]=b[3];break;}//倒7字方塊
case17:{a[x-2][y]=b[1];a[x+2][y+1]=b[2];a[x+2][y]=b[3];break;}//倒7字順轉90度
case18:{a[x][y-1]=b[1];a[x][y+1]=b[2];a[x-2][y+1]=b[3];break;}//倒7字順轉180度
case19:{a[x-2][y]=b[1];a[x-2][y-1]=b[2];a[x+2][y]=b[3];break;}//倒7字順轉270度
}
}
voidkeyD()//按鍵操作
{if(kbhit())
{intkey;
key=getch();
if(key==224)
{key=getch();
if(key==75){x-=2;}//按下左方向鍵,中心橫坐標減2
if(key==77){x+=2;}//按下右方向鍵,中心橫坐標加2
if(key==72)//按下向上方向鍵,方塊變體
{if(flag>=2&&flag<=3){flag++;flag%=2;flag+=2;}
if(flag>=4&&flag<=7){flag++;flag%=4;flag+=4;}
if(flag>=8&&flag<=11){flag++;flag%=4;flag+=8;}
if(flag>=12&&flag<=15){flag++;flag%=4;flag+=12;}
if(flag>=16&&flag<=19){flag++;flag%=4;flag+=16;}}
}
if(key==32)//按空格鍵,暫停
{prfk();while(1){if(getch()==32){clfk();break;}}} //再按空格鍵,繼續游戲
if(ifmov()==0){x=Tb;flag=Tc;} //如果不可動,撤銷上面操作
else{prfk();Sleep(speed);clfk();Tb=x;Tc=flag;} //如果可動,執行操作
}
}
intifmov()//判斷能否移動
{if(a[x][y]!=0){return0;}//方塊中心處有圖案返回0,不可移動
else{if((flag==1&&(a[x][y-1]==0&&a[x+2][y-1]==0&&a[x+2][y]==0))||
(flag==2&&(a[x-2][y]==0&&a[x+2][y]==0&&a[x+4][y]==0))||
(flag==3&&(a[x][y-1]==0&&a[x][y-2]==0&&a[x][y+1]==0))||
(flag==4&&(a[x-2][y]==0&&a[x+2][y]==0&&a[x][y+1]==0))||
(flag==5&&(a[x][y-1]==0&&a[x][y+1]==0&&a[x-2][y]==0))||
(flag==6&&(a[x][y-1]==0&&a[x-2][y]==0&&a[x+2][y]==0))||
(flag==7&&(a[x][y-1]==0&&a[x][y+1]==0&&a[x+2][y]==0))||
(flag==8&&(a[x][y+1]==0&&a[x-2][y]==0&&a[x+2][y+1]==0))||
(flag==9&&(a[x][y-1]==0&&a[x-2][y]==0&&a[x-2][y+1]==0))||
(flag==10&&(a[x][y-1]==0&&a[x-2][y-1]==0&&a[x+2][y]==0))||
(flag==11&&(a[x][y+1]==0&&a[x+2][y-1]==0&&a[x+2][y]==0))||
(flag==12&&(a[x][y-1]==0&&a[x][y+1]==0&&a[x-2][y-1]==0))||
( flag==13 && ( a[x-2][y]==0 && a[x+2][y-1]==0 && a[x+2][y]==0 ) ) ||
( flag==14 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x+2][y+1]==0 ) ) ||
(flag==15 && ( a[x-2][y]==0 && a[x-2][y+1]==0 && a[x+2][y]==0 ) ) ||
(flag==16 && ( a[x][y+1]==0 && a[x][y-1]==0 && a[x+2][y-1]==0 ) ) ||
( flag==17 && ( a[x-2][y]==0 && a[x+2][y+1]==0 && a[x+2][y]==0 ) ) ||
(flag==18 && ( a[x][y-1]==0 &&a[x][y+1]==0 && a[x-2][y+1]==0 ) ) ||
(flag==19 && ( a[x-2][y]==0 && a[x-2][y-1]==0
&&a[x+2][y]==0))){return1;}
}
return0; //其它情況返回0
}
voidclNEXT() //清除框外的NEXT方塊
{flag=next;x=ZL+WID+6;y=ZL+10;clfk();}
void clHA() //清除滿行的方塊
{intk,Hang=0; //k是某行方塊個數,Hang是刪除的方塊行數
for(j=ZL+HEI-1;j>=ZL+1;j--)//當某行有WID/2-2個方塊時,則為滿行
{k=0;for(i=ZL+2;i<ZL+WID-2;i+=2)
{if(a[i][j]==1)//豎坐標從下往上,橫坐標由左至右依次判斷是否滿行
{k++; //下面將操作刪除行
if(k==WID/2-2) { for(k=ZL+2;k<ZL+WID-2;k+=2)
{a[k][j]=0;gtxy(k,j);printf("");Sleep(1);}
for(k=j-1;k>ZL;k--)
{for(i=ZL+2;i<ZL+WID-2;i+=2)//已刪行數上面有方塊,先清除再全部下移一行
{if(a[i][k]==1){a[i][k]=0;gtxy(i,k);printf("");a[i][k+1]=1;
gtxy(i,k+1);printf("□");}}
}
j++;//方塊下移後,重新判斷刪除行是否滿行
Hang++;//記錄刪除方塊的行數
}
}
}
}
score+=100*Hang; //每刪除一行,得100分
if(Hang>0&&(score%500==0||score/500>level-1)) //得分滿500速度加快升一級
{speed-=20;level++;if(speed<200)speed+=20; }
}