學(xué)習(xí)C語言/C++已經(jīng)接近一個月了搁廓,在老師的帶領(lǐng)下,我們已經(jīng)學(xué)習(xí)了c語言數(shù)據(jù)的基本類型耕皮、變量的輸入輸出境蜕、進(jìn)制轉(zhuǎn)換、運算符和分支結(jié)構(gòu)凌停、循環(huán)結(jié)構(gòu)粱年、數(shù)組、指針罚拟、函數(shù)和字符串結(jié)構(gòu)體等等台诗,在老師帶著我們作出了一個貪吃蛇的過程中讓我深刻的體會到了字符界面做游戲的快感完箩,原來c語言如此強大,利用所學(xué)的基礎(chǔ)居然可以實現(xiàn)這樣精巧的功能拉队。然后老師又介紹了一個2048的游戲弊知,說這個游戲的實現(xiàn)比較有挑戰(zhàn),本來就對c語言憧憬的我對2048這個游戲充滿了好奇粱快,然后自己下載了一個2048的游戲玩了一下就開始實現(xiàn)自己的代碼了秩彤,挑戰(zhàn)了一下自己。
下面我會把實現(xiàn)這個游戲的思路以及相應(yīng)的解決辦法進(jìn)行了總結(jié)事哭,并提供自己的代碼和詳細(xì)注釋漫雷。
1.設(shè)計目標(biāo)
(1)界面顯示
? ?////////////////
? ?/ ?2 ? 2 ? 2 ?8/
? ?/ ? ? ? ? ? ? ?/
? ?/ ? ? ?2 ? ? ? /
? ?/ ? ? ? ? ? ? ?/
? /////////////////
(2)游戲操作
r ? ---> ? ? ?開始游戲
q ? ---> ? ? ?結(jié)束游戲
2 ? ----> ? ? 下移
4 ? ----> ? ? 左移
6 ? ----> ? ? 右移
8 ? ----> ? ? 上移
任意鍵 -> ? ? ? ?重新開始
(3)游戲規(guī)則
按r鍵開始游戲,然后進(jìn)行游戲鳍咱,可以輸入任意方向鍵進(jìn)行操作;進(jìn)行相應(yīng)的平移操作珊拼,當(dāng)兩個相同的數(shù)字"相撞"則將它們兩個數(shù)字合成一個是它們和的數(shù)字,當(dāng)兩個數(shù)字不同"相撞"則不進(jìn)行合成;當(dāng)所有格子滿了并且無法進(jìn)行移動的時則判斷為輸流炕,當(dāng)數(shù)字有一個出現(xiàn)2048的字樣則判斷為贏澎现。
2.創(chuàng)新點
(1)可以改變游戲的勝利值(2048可以修改為1024等等)
(2)任何時刻都可以按住r重新開始游戲
(3)代碼用一維數(shù)組代替二維數(shù)組,減少了遍歷數(shù)組的時間復(fù)雜度
(4)操作方向的時候不需要輸入回車每辟,使用戶得到更舒適的體驗
(5)界面的刷新流暢
(6)屏蔽其他按鍵
3.對未來的展望
(1)修改成為圖形界面并增加一些動畫特效
(2)優(yōu)化代碼
4.重難點剖析
(1)如何利用2 4 6 8進(jìn)行方向控制?
答:可以利用switch...case語句剑辫,當(dāng)輸入字符為2時調(diào)用下移函數(shù),當(dāng)輸入字符為4時則調(diào)用左移函數(shù)等
(2)如何不輸入回車就可以輸入字符?
答:可以通過getch()渠欺,輸入字符并且不用輸入回車即可達(dá)到效果
(3)為什么地圖數(shù)組用一維數(shù)組代替二維數(shù)組
答:由于每一幀畫面都會要遍歷該數(shù)組妹蔽,使用一維數(shù)組可以方便的用一個循環(huán)就可以遍歷數(shù)組
(4)怎么判斷輸
答:當(dāng)數(shù)組中全部都被占用,并且每個數(shù)字的上下左右都沒有與它相同的數(shù)字即為輸
(5)怎么判斷贏
答:遍歷數(shù)組出現(xiàn)2048即為贏
(6)移動時內(nèi)部數(shù)據(jù)怎么變化
答:由于上下左右比較類似挠将,我就以左移做詳細(xì)介紹胳岂,其他的可以類推。
分析左移代碼
void MoveLeft()
{
? ? int i = 0;
? ? int tempmap[GAMERANGE ] = {0}; ??
? ? memcpy(tempmap,g_map,GAMERANGE *sizeof(int)); //拷貝移動的之前的數(shù)組
? ? for (i; i < GAMERANGE ; ++i) ?
? ? {
? ? ? ? if (g_map[i])
? ? ? ? {
? ? ? ? ? ? MoveMostLeft(i); ? ?//移動單個元素0~15
? ? ? ? ? ? }
? ? }
? ? HandleState(tempmap,g_map,GAMERANGE );//處理游戲?qū)?yīng)的狀態(tài)舔稀,判斷輸贏并做處理
}
HandleState函數(shù)我就不多解釋了乳丰, 主要是判斷輸贏并做處理的函數(shù)
下面主要看一下MoveMostLeft函數(shù), 這個函數(shù)是將數(shù)組中的pos位置的元素移動
/*游戲地圖單個坐標(biāo)左移*/
void MoveMostLeft(int pos)
{
? ? int i = pos - 1; ?//i為pos左邊的元素
? ? while (i >= pos - pos % 4 && !g_map[i]) //i不出界 && i是空格
? ? {
? ? ? ? ?--i;
? ? }
? ? ?//此時的i指向的是剛剛出左邊的界或者是pos左邊的第一個數(shù)字
? ? if (i < 0) //說明pos左邊全為0 ? ? ? ? ? ? ?//i<0 說明左邊全部是空格
? ? {
? ? ? ? g_map[i+1] = g_map[pos]; ? ? ? ? ?//將pos位置的數(shù)字賦值給最左邊的數(shù)字
? ? ? ?if (i+1 != pos) //排除i+1和pos位置一樣内贮,使得i+1的數(shù)值賦值為0
? ? ? ? ? ?{
? ? ? ? ? ? g_map[pos] = 0;
? ? ? ? ? ?}
? ? }
? ? else ? ? ? ?//說明pos左邊有非0數(shù)字产园, 左邊坐標(biāo)為i ?i指向的是左邊第一個數(shù)字
? ? {
? ? ? ? if (g_map[i] == g_map[pos]) ? ? ? ? //判斷pos位置的數(shù)字和左邊第一個數(shù)字是不是相等的,如果是相等的話夜郁,i的位置的數(shù)字乘2什燕,pos位置的值賦值為空格
? ? ? ? {
? ? ? ? ? ? g_map [i] = g_map[i] << 1;//如果i和pos數(shù)字相同,則將位置i的數(shù)值乘以2 <<左移1則是乘以2
? ? ? ? ? ? g_map[pos] = 0;
? ? ? ? }
? ? ? ? else ? ? ? ? ? ? ? ? ? //如果pos位置的值不等于左邊第一個數(shù)字的值則吧左邊第一個數(shù)字的右邊的一個空格修改為pos位置的值竞端,然后修改pos位置的值為空格
? ? ? ? {
? ? ? ? ? ? g_map[i+1] = g_map[pos];
? ? ? ? ? ? if (i+1 != pos)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? g_map[pos] = 0;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? }
}
上面主要是左移部分的代碼已經(jīng)詳細(xì)解釋屎即, 右移,上移事富,下移都類似
5.總結(jié)
在剛剛寫代碼的時候感覺方向不明確技俐,不知道如何下手埃撵,便寫了一個左移函數(shù)后來發(fā)現(xiàn)其他方向類似,其他方向的代碼基本上都是復(fù)制的左移代碼虽另,然后400多行的代碼就出來了, 寫出來之后感覺自己很有成就感饺谬,通過自己所學(xué)的東西完成了一個小小的項目捂刺,也算是對前面所學(xué)知識的一個綜合性的運用。自己對項目的編寫有了一定的體會募寨, 先將整個項目分成一些小模塊族展,然后在分開寫代碼,最后將代碼整合出來一個項目拔鹰,整個游戲就是這樣出來了仪缸,當(dāng)然一個項目的完成還會碰到一些問題,還了解了一些常見問題的解決辦法列肢。
附加: 編譯方法
gcc 2048.c -l curses ? ? //使用了curses庫