貪喫蛇中的小思考

貪喫蛇中的小技術

程序設計思路

  1. 構造遊戲地圖,用矩陣實現,每一個元素就是一個點
  2. 構造蛇對象,有長度,身體,移動等屬性
  3. 遊戲時,蛇一直在移動,獲取到鍵盤輸入的消息後改變方向,繼續移動
  4. 構建食物對象,位置,以及被蛇喫掉後的位置更新
  5. 程序終止條件,也就是蛇不能撞到自己或者邊界,也就是輸了;當然爲了遊戲效果,設置一個最大值,當蛇的長度超過這個值,就判定爲win

關鍵點

由於是控制檯程序,因此實現貪喫蛇的關鍵點在於將蛇移動後的界面重繪並展示出來,並隨時獲取到鍵盤輸入的消息,以及食物被喫後的重新設定。

將每次移動後的畫面重現,初步構想是把每次界面中各元素的位置記錄下來,然後清楚屏幕內容,重新輸出。(MFC中易於實現,主要是除了redraw window,不知道還有什麼方法可以去除畫過的痕跡)但實際上並沒有必要,改變的只是蛇頭和蛇尾的位置,只需要改兩個點的位置的內容就好。

隨時獲取鍵盤消息,在MFC中很方便可以實現(雖然親自試驗並沒有起作用),但在控制檯程序裏,還需要引用一些庫中的函數。

食物的重新設定,主要是位置不要出界,不要落在蛇身在的位置。

引用頭文件

標準C++程序開頭,除了常見的,還需要

#include <iostream>
#include <ctime>  //需要隨機設置食物的位置,時間作爲隨機種子
#include <conio.h>  //響應鍵盤函數
#include <windows.h>   //控制檯界面的控制

關鍵點的實現

void Snake::Move()
{
	
	gotoxy(body[len - 1].x, body[len - 1].y);
	cout <<' ';
	
	for (int i = len - 1; i > 0; --i) {
		this->body[i].x = this->body[i - 1].x;
		this->body[i].y = this->body[i - 1].y;
	}
	if (this->dir == 1) {
		this->body[0].x--;
	}
	else if (this->dir == 2) {
		this->body[0].y++;
	}
	else if (this->dir == 3) {
		this->body[0].x++;
	}
	else if (this->dir == 4) {
		this->body[0].y--;
	}
	gotoxy(this->body[0].x, this->body[0].y);
	cout <<'O';
}

這個是蛇的移動方法,同時表現了在界面裏的展示方法

if(kbhit())					//kbhit 非阻塞函數 
{
    ch=getch();	//使用 getch 函數獲取鍵盤輸入 
    switch (ch){
        case 'A':
        case 'a':
            snake.Left();
            break;
        case 's':
        case 'S':
            snake.Down();
            break;
        case 'd':
        case 'D':
            snake.Right();
            break;
        case 'w':
        case 'W':
            snake.Up();
            break;
    }
}

這裏的 kbhit() 函數就是可以實現隨時響應鍵盤輸入的函數,效果比較好

void setFood(Snake &s){
	food.x = rand() % 28 + 2;
	food.y = rand() % 78 + 2;
	int i;
	int flag = 1;
	while(flag){
		for (i = 0; i < s.len; ++i){
			if(s.body[i].x==food.x && s.body[i].y == food.y){
				break;
			}
		}
		if(i==s.len){
			flag = 0;
			gotoxy(food.x, food.y);
			cout << '$';
		}else{
			food.x = rand() % 28 + 2;
			food.y = rand() % 78 + 2;
		}
	}
	return;
}

這個就是食物設置的方法,這個的28和78是邊界大小

問題探討

目前程序實現的基本還有一個蛇身重合,也就是自己會撞自己沒有加上去(懶得改了)。其他的沒有問題。

但對於鍵盤消息響應,一直耿耿於懷,查到了還有一種方法是

#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME)&0x8000)?1:0)

if(KEY_DOWN('A')){
    ······
}else if(){
    ······
}······

但是和kbhit()比起來,效果比較卡。在實現雙擊加速時,使用了條件嵌套,結果kbhit()效果也遜色不少,所以想着應該有更好的辦法,還是說在MFC等封裝好的圖形界面設計裏,優化效果會好點?這個目前還沒有找到答案。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章