開發環境爲linux+gcc+netbeans
本來我喜歡gvim但是實在不會調試c語言。於是轉戰netbeans,能很方便地調試,就是爽。
首先要說一下思路。就是多線程,一個線程負責邏輯和畫圖,一個線程監聽按鍵。看一下線程創建的代碼。
void * waitForKey(void *para) { while (1) { input = getch(); } } pthread_t id; //聲明一個linux線程,按鍵等待線程 int ret; ret = pthread_create(&id, NULL, waitForKey, NULL);//創建線程 if (ret != 0) { exit(1); }
我還用到了一個庫,就是curses,這個好象是專門用來繪圖ui用的。但是在/usr/include裏面是沒有的,要到網上去下
sudo apt-get install libncurses-dev
使用時的格式應該是這樣
initscr();
do_some_drawing();
refresh();
endwin();
其中我用到的函數有move(x,y)是把光標定位在某行某列上。還有addStr(s)和addch(c)。是在光標處寫字符串和寫字符。
還有getch()等待用戶按鍵。還有refresh(),將緩衝的addch阿還有addStr等等的繪圖操作都輸出到屏幕上。
此外還用到了usleep(int )函數這裏的參數是 int型的,表示的是微秒數,1秒等於1000000微秒。這裏的時間間隔是蛇每次移動時的間隔時間。
代碼如下
#include<stdio.h> #include <pthread.h> #include <sys/time.h> #include <curses.h> #include <stdlib.h> #define MAX_X 70 //場地寬 #define MAX_Y 20 //場地長 #define CORNER_X 4 //左上角x座標 #define CORNER_Y 2 //左上角y座標 struct point { int x; int y; }; struct point SnakeBody[50]; struct point food; int Length = 4; //初始蛇長 int life = 1; //是否還活着 int input = 0; //記錄鍵盤按鍵的ascii pthread_t id; //聲明一個linux線程,按鍵等待線程 void FoodCheck(); void FoodProduce(); void Initializition(); void SnakeHeadMovement(); void DeathCheck(); void Paint(); void * waitForKey(void *); void drawDot(int x, int y,char s); void clearDot(int x, int y); void end(); //主函數 int main(int argc, char** argv) { Initializition(); while (life) { Paint(); usleep(200000); SnakeHeadMovement(); DeathCheck(); } end(); return 0; } void * waitForKey(void *para) { while (1) { input = getch(); } } void end() { move(1, 0); addstr("Press any key to quit!"); refresh(); getch(); endwin(); } //食物的隨機產生 void FoodProduce() { int superposition = 0; int i; srand(time(NULL)); do { food.x = (rand() % ((MAX_X-2) / 2))*2+2; //2 to MAX_X-2 and is 偶數 food.y = rand() % (MAX_Y-1)+1; //1 to MAX_Y-1 for (i = 0; i < Length; i++) { if (food.x == SnakeBody[i].x && food.y == SnakeBody[i].y) superposition = 1; } } while (superposition); /*直到沒有重合*/ } //蛇身和食物的初始化 初始化的蛇身爲4節長度 void Initializition() { initscr();//curses初始化 int i; for (i = 3; i <= 6; i++) {//初始化蛇 SnakeBody[6 - i].x = 4; SnakeBody[6 - i].y = i; } FoodProduce(); int ret; ret = pthread_create(&id, NULL, waitForKey, NULL);//創建線程 if (ret != 0) { exit(1); } for ( i = 0; i <= MAX_X; i+=2) { //畫圍牆 drawDot(i, 0,'*'); drawDot(i, MAX_Y,'*'); } for (i = 0; i <= MAX_Y; i++) { drawDot(0, i,'*'); drawDot(MAX_X, i,'*'); } } //蛇移動,依次從尾巴到頭賦值 void SnakeBodyMovement() { int i; for (i = Length - 1; i > 0; i--) { SnakeBody[i].x = SnakeBody[i - 1].x; SnakeBody[i].y = SnakeBody[i - 1].y; } } void SnakeHeadMovement() { clearDot(SnakeBody[Length - 1].x, SnakeBody[Length - 1].y); int directionX, directionY; /*定義原本蛇前進的方向,可通過蛇頭座標減去蛇的第二部分*/ int newX, newY; newX = SnakeBody[0].x; newY = SnakeBody[0].y; directionX = SnakeBody[0].x - SnakeBody[1].x; directionY = SnakeBody[0].y - SnakeBody[1].y; if (input == 'w' && directionY<=0) //不走回頭路 newY--; else if (input == 's' && directionY>=0 ) newY++; else if (input == 'a' && directionX<=0) newX -= 2; /*因爲字符高是寬的兩倍*/ else if (input == 'd' && directionX>=0) newX += 2; else { newX += directionX; newY += directionY; } FoodCheck(); SnakeBodyMovement(); SnakeBody[0].x = newX; SnakeBody[0].y = newY; } //判斷是否喫到食物,以及喫到後長度變長還有產生新的食物 void FoodCheck() { if (food.x == SnakeBody[0].x && food.y == SnakeBody[0].y) { Length = Length + 1; FoodProduce(); } } //判斷是否死亡 void DeathCheck() { int i; if (SnakeBody[0].x <=1 || SnakeBody[0].x >= MAX_X || SnakeBody[0].y <= 0 || SnakeBody[0].y >=MAX_Y) life = 0; for (i = 4; i < Length; i++) if (SnakeBody[0].x == SnakeBody[i].x && SnakeBody[0].y == SnakeBody[i].y) life = 0; } //排序和打印 void Paint() { int i = 0; drawDot(SnakeBody[i].x, SnakeBody[i].y,'@'); for (i=1; i < Length; i++) { drawDot(SnakeBody[i].x, SnakeBody[i].y,'*'); } drawDot(food.x, food.y,'$'); clearDot(0, 0); refresh();//刷新畫布 } void drawDot(int x, int y,char s) { move(y+CORNER_Y, x+CORNER_X); addch(s); } void clearDot(int x, int y) { move(y+CORNER_Y, x+CORNER_X); addch(' '); }
編譯的時候的命令如下 gcc main.c -o main -lpthread -lcurses