学C语言一年了, 一直想写个游戏练练手。 这次放假没有课设, 想写个贪吃蛇。 在网上找了一些资料, 有的很复杂几百行, 有的很简单几十行。 参照其他人的想法终于是写出了自己的 小「贪吃蛇」。
第一种方法是, 定义一个二维数组 map[][] , 用例如 1,2,3 等数字标记墙,蛇身和食物。 根据键盘动作修改数组,再根据权值打印 map 。
1 int main(void){ 2 3 int direction = UP; //初始方向向上 4 init_game(); //初始化游戏界面 5 for(; ;){ 6 direction = get_dir(direction); 7 move_snake(direction); //贪吃蛇做下一步的动作 8 flag_map(); //标记 map 数组 9 print_map(); //按照数组打印图形 10 Sleep(500); //延迟 x ms 11 if(!is_alive()) 12 break; 13 } 14 printf(" Game Over ! "); 15 return 0; 16 }
get_dir( direction ) 函数功能为获取键盘方向, 返回按下的方向键的值。 根据键盘码可知, 方向键对应的值我们可以定义 :
#define LEFT 75 #define UP 72 #define RIGHT 77 #define DOWN 80
标记 map 和打印 map 的函数很简单, 只是数组的循环并判断 :
1 void flag_map(){ 2 int i, j; 3 Snake *p = NULL; 4 for(i=0; i<ROWS; i++){ 5 for(j=0; j<COLUMNS; j++){ 6 if(i==0 || i==ROWS-1 || j==0 || j==COLUMNS-1) 7 map[i][j] = 1; // 1 表示墙 8 else 9 map[i][j] = 0; // 0 表示空 10 } 11 } 12 for(p = head; p; p = p->next) //2 表示蛇 13 map[p->cor.Y][p->cor.X] = 2; 14 //3 表示食物, 首先得CreatFood() 15 map[Food.y][Food.x] = 3; 16 } 17 18 void print_map(){ 19 int i, j; 20 system("cls"); 21 for(i=0; i<ROWS; i++){ 22 for(j=0; j<COLUMNS; j++){ 23 if(map[i][j] == 1) 24 printf("#"); 25 else if(map[i][j] == 2) 26 printf("*"); 27 else if(map[i][j] == 3) 28 printf("@");// □ 29 else 30 printf(" "); 31 } 32 putchar(' '); 33 }
这种写法简单,但是低效, 更大的问题是由于每次的动作都通过清除屏幕, 再打印整个数组实现的所以有可能会出现闪屏现象。
所以这种方法不够好, 墙打印一次就够了, 不需要再打印, 蛇只需要随着蛇头坐标的改变而打印, 按照是否吃到了食物选择该不该去尾, 食物只需要被吃的时候打印。 这些我们该怎么实现呢?
为了局部刷新,用到了gotoxy()函数,TC自带(不知道TC是啥),所以自己写一个,其实就是一个转到x,y坐标的一个函数。
void gotoxy(COORD pt)
{
HANDLE hout;
hout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hout, pt);
}
HANDLE(句柄)在windows编程中是一个十分重要的概念。在window编程中,对于一个Object(对象)我们只能通过Handle来访问它。觉得不好理解的同学把句柄当作指针来看待就好了。
GetStdHandle函数获取一个指向特定标准设备的句柄,包括标准输入,标准输出和标准错误。STD_OUTPUT_HANDLE正是代表标准输出(也就是显示屏)的宏。
SetConsoleCursorPosition函数用于设置控制台光标的位置。
有了这个我们就可以思考新的方法了, 即局部更新。 在此只是给了一个想法, 没有给出数据结构, 蛇的移动函数(核心), 创建食物的算法。 (H b)会在下一篇局部更新和链表的方法中给出整个思路及代码。