贪吃蛇原型实现基本思路
貪吃蛇的原型是在windows控制臺下即在字符模式下利用C++編寫貪吃蛇。?
主要實現的效果就是,用戶利用'w'、's'、'a'、'd'分別表示上下左右,當蛇碰到障礙物時通不過,當碰到食物時,分數加1,同時,在另外一個地方生成新的食物,并且身體會增加一個字符的長度。?
在實現該原型前必須實現兩項技術:?
- 字符上色,這個利用了網上的代碼
- 字符位置控制
什么意思呢?主要是因為考慮到在通常情況下,在控制臺下編寫的程序,默認都是黑白色的,顏色單一,而且蛇和障礙物、食物之間無法被互相區分,所以加上更多的顏色,視覺上會更舒服些。字符位置控制呢,是必不可缺的。這個是因為在命令行模式下,程序是默認順序接收用戶輸入的,偶爾可以跳至同一行稍前些的位置。但是,由于蛇要到處爬,所以這就遇到一個問題,如何讓輸入光標跳至窗口下的任意位置成了開發的基礎和前提。具體的我后面會講到我的解決方案。?
我的實現思路:?
首先,我要創建一個游戲背景,具體指的是貪吃蛇的移動范圍。這個呢,我用二維的數組來表示。每個單元格有幾個參數---是否存在障礙物、是否存在食物,如果有的話,就用true,否則為false。?
2 const length = 40;
3 const width = 20;
4 struct square{
5 bool blocked; //是否有障礙物
6 bool food; //是否有食物
7 int x; //單元格在背景中的相對橫坐標
8 int y; //單元格在背景中的相對縱坐標
9 }bg[length][width]; //直接創建游戲背景
10
11 //設置背景
12 void setBG(int length, int width){
13 HANDLE hOut;
14 COORD OutChar;
15 OutChar.X = 10;
16 OutChar.Y = 10;
17 int i = 0;
18 int j = 0;
19 for(i = 0; i < width; i++){
20 for(j = 0; j < length; j++){
21 bg[i][j].x = i;
22 bg[i][j].y = j;
23 bg[i][j].blocked = false;
24 bg[i][j].food = false;
25 OutChar.X = j+10;
26 hOut = GetStdHandle(STD_OUTPUT_HANDLE);
27 SetConsoleCursorPosition(hOut,OutChar);
28 cout << col(BG_WHITE,true) << " ";
29 }
30 cout << endl;
31 OutChar.Y = i+10;
32 SetConsoleCursorPosition(hOut,OutChar);
33 }
34 }
接下來,就是要在背景上創建障礙物,在創建它們之前,首先得解決如何在指定的單元格式繪制單元。思路很簡單,就是編寫一個函數將光標定位到相應的坐標位置,然后輸入一個空白的上色字符就解決了。然后就可以利用這個函數在真正的背景上相應的位置構建障礙物了。同時可以實現隨機創建任意個、任意位置的障礙物了。
1 //構造障礙物2 void createBlock(int x, int y, unsigned short color){
3 HANDLE hOut;
4 COORD OutChar;
5 OutChar.X = x;
6 OutChar.Y = y;
7 hOut = GetStdHandle(STD_OUTPUT_HANDLE);
8 SetConsoleCursorPosition(hOut,OutChar); //定位光標輸入
9 cout << col(color, true) << " "; //一個顏色為color的空白字符
10 }
11
12 //生成單個障礙物
13 void createWall(int x,int y){
14 createBlock(x+10,y+10,BG_GREEN);
15 bg[x][y].blocked = true;
16 }
17
18 //判斷所指坐標是否被占用
19 bool checkExisted(int x,int y){
20 if(bg[x][y].blocked == true || bg[x][y].food == true){
21 return false;
22 }
23 return true;
24 }
25
26 //隨機生成障礙物
27 void rand_createWall(void){
28 srand((unsigned)time(NULL));
29 int n = rand() % 70+10;
30 int pos_x = 0;
31 int pos_y = 0;
32 int i = 0;
33 for(i = 0; i < n; i++){
34 pos_x = rand() % length;
35 pos_y = rand() % (width-1);
36 if(checkExisted(pos_x,pos_y) == true){ //防止障礙物重疊
37 createWall(pos_x,pos_y);
38 }else{
39 n++;
40 }
41 //createWall(pos_x,pos_y);
42 }
43 }
同理,食物的創建也一樣。
1 //創建食物2 void createFood(int x,int y){
3 createBlock(x+10,y+10,BG_BLUE);
4 bg[x][y].food = true;
5 }
6
7 //隨機創建食物
8 void rand_createFood(void){
9 srand((unsigned)time(NULL));
10 int n = 1;//rand() % 20;
11 int pos_x = 0;
12 int pos_y = 0;
13 int i = 0;
14 for(i = 0; i < n; i++){
15 pos_x = rand() % length;
16 pos_y = rand() % (width-1);
17 if(checkExisted(pos_x,pos_y) == true){ //防止在障礙物上生成食物
18 createFood(pos_x,pos_y);
19 }else{
20 n++;
21 }
22 }
23 }
背景、障礙物和食物都創建好了,接下來就要構建蛇的模型了。由于考慮到蛇在吃完食物后,身體會變長,所以我采用了順序表的數據結構來記錄蛇的信息。那如何來表現蛇的移動呢?我的思路是,將身體靠近頭的信息傳遞到次靠近頭的,同時將新的下一步要走的坐標信息傳給頭部,同時有擦除掉尾部信息即可。?
2 const objLen = 5;
3 struct obj{
4 int x;
5 int y;
6 }snake[objLen];
7
8 //創建蛇
9 LinList<struct obj> newSnake;
10 void createSnake(void){
11 int i = 0;
12 for(i = 0; i < objLen; i++){
13 snake[i].x = i;
14 snake[i].y = 0;
15 newSnake.Insert(snake[i],i);
16 }
17 }
18
19 //繪制蛇
20 void drawSnake(int len){
21 int i = 0;
22 struct obj t;
23 for(i = 0; i < len; i++){
24 t = newSnake.GetData(i);
25 createBlock(t.x,t.y,BG_RED);
26 }
27 }
28
29 //增長蛇的身體
30 void insreaseSnake(int x,int y){
31 struct obj t;
32 t.x = x;
33 t.y = y;
34 newSnake.Insert(t,0);
35 createBlock(x,y,BG_RED);
36 }
37
38 //傳遞蛇的信息
39 void transSnake(int x,int y,int len){
40 int i = 0;
41 struct obj t1,t2;
42 for(i = 0; i < len-1; i++){
43 t1 = newSnake.GetData(i);
44 t2 = newSnake.GetData(i+1);
45 newSnake.Delete(i);
46 t1.x = t2.x;
47 t1.y = t2.y;
48 newSnake.Insert(t1,i);
49 }
50 newSnake.Delete(newSnake.Size()-1);
51 t1.x = x;
52 t1.y = y;
53 newSnake.Insert(t1,newSnake.Size()-1);
54 }
這里的相對位置是指以背景左上方的點為原點即(0,0),右下方為(length-1,width-1)。?
接著呢,就是要獲取用戶的方向控制操作,并執行它們。由于采用的二維數組的方式表示蛇的形狀以及游戲背景,所以當接收到命令如果是‘上’時,橫坐標不變,而縱坐標減1,同時擦除原形狀,如此一來,蛇就向上爬了。擦除函數的原理很簡單,就是將對應的背景單元格的信息全部還原為初始值,就可以了。?
2 void removeTrack(int x, int y){
3 HANDLE hOut;
4 COORD OutChar;
5 OutChar.X = x;
6 OutChar.Y = y;
7 hOut = GetStdHandle(STD_OUTPUT_HANDLE);
8 SetConsoleCursorPosition(hOut,OutChar);
9 cout << col(BG_WHITE,true) << " ";
10 }
11
12 //移動物體
13 int x = 10;
14 int y = 10;
15 int tail_x = 0;
16 int tail_y = 0;
17 void moveBlock(char direction){
18 HANDLE hOut2;
19 COORD OutChar2;
20 OutChar2.X = x;
21 OutChar2.Y = y;
22 struct obj t;
23 t = newSnake.GetData(0);
24 tail_x = t.x;
25 tail_y = t.y;
26 hOut2 = GetStdHandle(STD_OUTPUT_HANDLE);
27 removeTrack(t.x,t.y);
28 switch(direction){
29 case 'w':{
30 OutChar2.Y--;
31 y--;
32 SetConsoleCursorPosition(hOut2,OutChar2);
33 break;
34 }
35 case 's':{
36 OutChar2.Y++;
37 y++;
38 SetConsoleCursorPosition(hOut2,OutChar2);
39 break;
40 }
41 case 'a':{
42 OutChar2.X--;
43 x--;
44 SetConsoleCursorPosition(hOut2,OutChar2);
45 break;
46 }
47 case 'd':{
48 OutChar2.X++;
49 x++;
50 SetConsoleCursorPosition(hOut2,OutChar2);
51 break;
52 }
53 }
54
55 transSnake(x,y,newSnake.Size());
56 drawSnake(newSnake.Size());
57 }
做完這個,不要以為就這樣結束了,因為我們還沒對蛇的運動范圍作出限制,而且還要實現蛇的觸發事件即碰到食物后身體變長,食物數增加1。?
2 bool checkView(char direction){
3 if(direction == 'w' && y >= 10){
4 if(y == 10 || bg[x-10][y-10-1].blocked == true){return false;}
5 }
6 else if(direction == 's' && y < 10+width){
7 if(y == 10+width-2 || bg[x-10][y-10+1].blocked == true){return false;}
8 }
9 else if(direction == 'a' && x >= 10){
10 if(x == 10 || bg[x-10-1][y-10].blocked == true){return false;}
11 }
12 else if(direction == 'd' && x < 10+length){
13 if(x == 10+length-1 || bg[x-10+1][y-10].blocked == true){return false;}
14 }
15 return true;
16 }
17
18 //判斷是否吃到食物
19 bool checkFood(int x, int y){
20 if(bg[x-10][y-10].food == true){return true;}
21 return false;
22 }
下面就是游戲原型的主函數:
2 {
3 HANDLE hOut;
4 COORD OutChar;
5
6 OutChar.X = 0;
7 OutChar.Y = 0;
8 hOut = GetStdHandle(STD_OUTPUT_HANDLE);
9 SetConsoleCursorPosition(hOut,OutChar);
10
11 /*
12 struct square **bgR = new square*[width];
13 struct square *bgC = new square[length];
14 for(int i = 0; i < width; i++){
15 bgR[i] = bgC;
16 }
17 */
18 //設置背景
19 setBG(length,width);
20 //設置障礙物
21 rand_createWall();
22 //設置食物
23 rand_createFood();
24 //創建蛇
25 createSnake();
26 //移動物體
27 char direction;
28 int score = 0;
29 for(;;){
30 direction = getch();
31 if(checkView(direction) == true){//判斷能否移動
32 moveBlock(direction);
33 if(checkFood(x,y) == true){//判斷是否吃到食物
34 bg[x-10][y-10].food = false;
35 score++;
36 insreaseSnake(tail_x,tail_y);//增長身體
37 rand_createFood();//吃完后隨機在創建一個食物
38 }
39 }
40 OutChar.X = 0;
41 OutChar.Y = 0;
42 hOut = GetStdHandle(STD_OUTPUT_HANDLE);
43 SetConsoleCursorPosition(hOut,OutChar);
44 cout << col(BG_WHITE,true) << "Scores: " << score;
45 }
46 return 0;
47 }
這個貪吃蛇原型是我一時興起弄的,考慮的也比較簡單。
轉載于:https://www.cnblogs.com/bilipan/archive/2012/03/30/2425442.html
總結
以上是生活随笔為你收集整理的贪吃蛇原型实现基本思路的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpendidCRM:在admin-la
- 下一篇: Asp.net MVC3 一语道破