贪吃蛇中的小思考

版权声明:转载请声明~谢谢 https://blog.csdn.net/wq_151/article/details/84702543

贪吃蛇中的小技术

程序设计思路

  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等封装好的图形界面设计里,优化效果会好点?这个目前还没有找到答案。

猜你喜欢

转载自blog.csdn.net/wq_151/article/details/84702543