Linux下用C語言實(shí)現(xiàn)推箱子游戲
前面有Linux的常用命令和vim文本編輯器還沒有介紹,之后我會(huì)補(bǔ)上的。
今天來介紹如何用C語言寫一個(gè)簡(jiǎn)單的小游戲,叫做“小老鼠推箱子”。雖然游戲的編寫過程不復(fù)雜,但是我覺得能夠從中找到自己對(duì)于編程的不足和完善自己的編程思維是最重要的。游戲代碼不多,所以直接寫在一個(gè)c文件中。本人小白,有不足之處還望指教
游戲介紹
下圖是游戲開始界面,$是小老鼠,#是墻,O是終點(diǎn),當(dāng)小老鼠把所有箱子推進(jìn)終點(diǎn)就代表游戲通過。
游戲思維
游戲地圖用一個(gè)二維數(shù)組去存儲(chǔ)。數(shù)組中不同的值代表不同的對(duì)象(老鼠、墻、路等)。當(dāng)小老鼠在移動(dòng)時(shí),數(shù)組中的值也會(huì)隨之改變,但是為了在游戲無法進(jìn)行下去時(shí)可以從新開始游戲,所以需要另一個(gè)數(shù)組去保留地圖的初始狀態(tài)。也就是說需要兩個(gè)二維數(shù)組,一個(gè)始終不改變,一個(gè)用來記錄實(shí)時(shí)的狀態(tài)。
小老鼠在移動(dòng)時(shí)會(huì)遇到兩種情況,即可移動(dòng)和不可移動(dòng)。在編寫代碼時(shí),只需要將可移動(dòng)的情況寫完成,那么就不需要去判斷不可移動(dòng)的狀態(tài)??梢苿?dòng)的情況有下面兩種:
1、小老鼠面前什么也沒有(面前是路或者是終點(diǎn))。
2、小老鼠前面是箱子,此時(shí)分為兩種情況(箱子前面是路或者箱子前面是終點(diǎn))。
這時(shí)候,應(yīng)當(dāng)思考的是如何根據(jù)二維數(shù)組的值去判斷上述情況,以及當(dāng)小老鼠移動(dòng)和推動(dòng)箱子時(shí),二維數(shù)組的值是如何變化的。
#include <stdio.h> #include "get_keyboard.h" //地圖7行8列 行[0-6] 列[0-7] //0 路 //1 墻 //2 箱子 //3 終點(diǎn) //4 小老鼠 //7 小老鼠站在終止上 //5 箱子到達(dá)終點(diǎn)上 int g_boards[7][8] = { {0,1,1,1,1,1,1,0}, {0,1,0,0,0,0,1,1}, {1,3,0,1,1,2,0,1}, {1,0,3,3,2,0,0,1}, {1,0,0,1,2,0,0,1}, {1,0,0,4,0,1,1,1}, {1,1,1,1,1,0,0,0} }, boards[7][8]={}; //記錄小老鼠在移動(dòng)中的位置 int row = 0; int col = 0; int cnt = 0;//箱子個(gè)數(shù),用來判斷游戲是否結(jié)束。
用0~4表示地圖上面有的小老鼠等物體,值得提的是對(duì)于箱子和小老鼠來說,他們移動(dòng)時(shí)都可能會(huì)在終點(diǎn)上,那么他們移入終點(diǎn)和移開終點(diǎn)時(shí)的情況需要分別去判斷,為了能夠避免過多的判斷,當(dāng)它們移入終點(diǎn)時(shí),終點(diǎn)所在位置的值就等于它們的值加上終點(diǎn)的值。同理,當(dāng)它們移開終點(diǎn)時(shí),終點(diǎn)所在位置的值就等于終點(diǎn)的值減去它們的值。這樣就不用去判斷小老鼠和箱子在不在終點(diǎn)上了。所以,小老鼠在終點(diǎn)上的值是7。
代碼詳解
這里先從main()函數(shù)開始思考。當(dāng)游戲開始時(shí),需要先將地圖初始化,即把用來記錄實(shí)時(shí)狀態(tài)的地圖初始化成游戲開始時(shí)的地圖(就是前面提的的兩個(gè)地圖),所以這里需要init()函數(shù)。初始化后就是開始游戲,游戲過程中需要獲取方向鍵,這些在start()函數(shù)中完成。之后,在這些函數(shù)中再去思考是否需要去寫其他函數(shù)補(bǔ)足功能。
//初始化地圖 void init() { for(int i=0; i<7*8; i++) { //這里是為了當(dāng)你按下enter鍵時(shí),能夠重置游戲,重置游戲時(shí)需要重新初始化地圖 boards[i/8][i%8]=g_boards[i/8][i%8]; if(4==boards[i/8][i%8]) //這里還需要記錄老鼠的位置 { row=i/8; col=i%8; } } } //打印地圖 void print() { for(int i=0; i<7; i++) { for(int j=0; j<8; j++) { switch(boards[i][j]) { case 0: printf(" ");break; //空格代表路徑 case 1: printf("#");break; //打印墻 case 2: case 5: printf("@");break; //打印箱子 case 3: printf("O");break; //打印終點(diǎn) case 4: case 7: printf("$");break; //打印小老鼠 } } printf("\n"); } } //推箱子 void move(int nrow, int ncol, int nnrow, int nncol) { if(0==boards[nrow][ncol] || 3==boards[nrow][ncol]) //如果小老鼠前面是路或者終點(diǎn),說明可以移動(dòng) { boards[nrow][ncol] +=4;//小老鼠進(jìn)入這個(gè)位置了 boards[row][col] -=4;//小老鼠離開這個(gè)位置了 //移動(dòng)過后小老鼠的位置也改變了 row = nrow; col = ncol; } else if(2==boards[nrow][ncol] || 5==boards[nrow][ncol]) //如果小老鼠前面是箱子 { if(0==boards[nnrow][nncol] || 3==boards[nnrow][nncol]) //如果箱子前面是路或者終點(diǎn)則可以移動(dòng) { boards[nnrow][nncol] +=2; boards[nrow][ncol] -=2-4; //這里其實(shí)是boards[nrow][ncol]=boards[nrow][ncol]-2+4 //減去2是因?yàn)橄渥右谱吡耍由?是因?yàn)樾±鲜筮M(jìn)入了 boards[row][col] -=4; row=nrow; col=ncol; } } for(int i=0; i<7; i++) //統(tǒng)計(jì)游戲是否結(jié)束,當(dāng)箱子都在終點(diǎn)上時(shí)就結(jié)束了 { for(int j=0; j<8; j++) { if(5==boards[i][j]) { cnt++; } if(3==cnt) { printf("通關(guān)!\n"); exit(0);//通關(guān)退出游戲 } } } cnt=0; //如果游戲沒有結(jié)束,下次還是需要從0統(tǒng)計(jì) } //開始游戲 void start() { while(1) { print();//游戲開始時(shí)需要打印地圖,每次從鍵盤上獲得方向移動(dòng)后也需要打印地圖 int dir=get_keyboard(); //從鍵盤獲取方向 system("clear"); //下次打印地圖時(shí),先將屏幕清空 switch(dir) //每次都需要判斷小老鼠前面和前面的前面的坐標(biāo)的狀態(tài),這樣可以在move() //函數(shù)中統(tǒng)一各個(gè)方向的寫法 { case KEY_UP: move(row-1, col, row-2, col);break; case KEY_DOWN: move(row+1, col, row+2, col);break; case KEY_LEFT: move(row, col-1, row, col-2);break; case KEY_RIGHT: move(row, col+1, row, col+2);break; case KEY_ENTER: init();break; //按enter則從新開始游戲 case KEY_q: exit(0);//如果按q則退出游戲 } } } int main() { //游戲初始化 init(); system("clear"); //系統(tǒng)命令,用來清空屏幕 //開始游戲 start(); return 0; }
好了,這就是今天的內(nèi)容。這里需要的用來獲取鍵盤的頭文件直接粘貼在下面。
#ifndef GETCH_H #define GETCH_H #include <stdio.h> #include <termios.h> #include <stdlib.h> #include <unistd.h> typedef enum KEYBOARD { KEY_UP = 183, KEY_DOWN = 184, KEY_RIGHT = 185, KEY_LEFT = 186, KEY_BACKSPACE = 127, KEY_ENTER = 10, KEY_0 = 48, KEY_1 = 49, KEY_2 = 50, KEY_3 = 51, KEY_4 = 52, KEY_5 = 53, KEY_6 = 54, KEY_7 = 55, KEY_8 = 56, KEY_9 = 57, KEY_A = 65, KEY_B = 66, KEY_C = 67, KEY_D = 68, KEY_E = 69, KEY_F = 70, KEY_G = 71, KEY_H = 72, KEY_I = 73, KEY_J = 74, KEY_K = 75, KEY_L = 76, KEY_M = 77, KEY_N = 78, KEY_O = 79, KEY_P = 80, KEY_Q = 81, KEY_R = 82, KEY_S = 83, KEY_T = 84, KEY_U = 85, KEY_V = 86, KEY_W = 87, KEY_X = 88, KEY_Y = 89, KEY_Z = 90, KEY_a = 97, KEY_b = 98, KEY_c = 99, KEY_d = 100, KEY_e = 101, KEY_f = 102, KEY_g = 103, KEY_h = 104, KEY_i = 105, KEY_j = 106, KEY_k = 107, KEY_l = 108, KEY_m = 109, KEY_n = 110, KEY_o = 111, KEY_p = 112, KEY_q = 113, KEY_r = 114, KEY_s = 115, KEY_t = 116, KEY_u = 117, KEY_v = 118, KEY_w = 119, KEY_x = 120, KEY_y = 121, KEY_z = 122 }KEYBOARD; //此函數(shù)能立即從鍵盤不回顯的接收數(shù)據(jù) static int get_keyboard(void) { //接收系統(tǒng)調(diào)用的執(zhí)行結(jié)果 int ret = 0; //存儲(chǔ)終端設(shè)備的配置信息 struct termios old; //通過系統(tǒng)調(diào)用獲取終端的配置信息 ret=tcgetattr(STDIN_FILENO,&old); if(0 > ret) { perror("tcgetattr"); return -1; } //初始化新的終端配置信息 struct termios new = old; //取消回顯并立即獲取 new.c_lflag &= ~(ICANON|ECHO); //設(shè)置新的終端配置信息 ret= tcsetattr(STDIN_FILENO,TCSANOW,&new); if(0 > ret) { perror("tcsetattr"); return -2; } //在新的模式下從終端獲取數(shù)據(jù) int key_value = 0; do { key_value += getchar(); //由于和系統(tǒng)對(duì)FILE結(jié)構(gòu)體的實(shí)現(xiàn)各不相同 //linux系統(tǒng) while(stdin->_IO_read_end - stdin->_IO_read_ptr); //OS系統(tǒng) while(stdin->_r); }while(stdin->_IO_read_end - stdin->_IO_read_ptr); //還原終端的配置信息 ret = tcsetattr(STDIN_FILENO,TCSANOW,&old); if(0 > ret) { perror("tcsetattr"); return -3; } //返回獲取到的數(shù)據(jù) return key_value; } #endif//GETCH_H
更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++ sdl實(shí)現(xiàn)渲染旋轉(zhuǎn)視頻的方法分享
一般情況下播放視頻時(shí)不需要旋轉(zhuǎn),但是如果是移動(dòng)端錄制的視頻有時(shí)會(huì)出現(xiàn)rotate參數(shù),且視頻寬高也是互換的。所以本文為大家準(zhǔn)備了利用sdl實(shí)現(xiàn)渲染旋轉(zhuǎn)視頻的方法,需要的可以參考一下2022-12-12C++生成隨機(jī)浮點(diǎn)數(shù)的示例代碼
在C++11之前,我們通常采用rand函數(shù)來生成隨機(jī)數(shù),但rand函數(shù)對(duì)一些情況顯得難以處理。本文將介紹如何利用C++生成隨機(jī)浮點(diǎn)數(shù),需要的可以參考一下2022-04-04C++?Cartographer源碼中關(guān)于MapBuilder的聲明與構(gòu)造
這篇文章主要介紹了C++?Cartographer源碼中關(guān)于MapBuilder的聲明與構(gòu)造,前面已經(jīng)談到了Cartographer中添加軌跡的方法和傳感器的數(shù)據(jù)流動(dòng)走向。在添加軌跡的時(shí)候,除了添加位姿估計(jì)器還有采樣器,訂閱回調(diào)函數(shù)之外,最重要的是通過map_builder_bridge添加了一條軌跡2023-03-03C語言實(shí)現(xiàn)飛機(jī)票務(wù)系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)飛機(jī)票務(wù)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12C語言實(shí)現(xiàn)簡(jiǎn)易版掃雷的完整過程
這篇文章主要給大家介紹了關(guān)于利用C語言如何實(shí)現(xiàn)簡(jiǎn)易版掃雷的完整過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12C++面向?qū)ο笳Z言自制多級(jí)菜單功能實(shí)現(xiàn)代碼
菜單類主要負(fù)責(zé)菜單的創(chuàng)建、修改、刪除,是包含菜單結(jié)構(gòu)組織和響應(yīng)函數(shù)的模型,用戶擁有充分的自主性,可根據(jù)需要自定義菜單顯示和響應(yīng)函數(shù),這篇文章主要介紹了C++面向?qū)ο笳Z言自制多級(jí)菜單,需要的朋友可以參考下2024-06-06