/*
*Name:Greedy Snake
*Date:2015/8/15
*Author:YangShuoliu
*/
#include <queue> //deque<int>
#include <stdio.h> // printf()
#include <conio.h>
#include <ctime> //srand() rand()
#include <Windows.h> //Sleep(),SetConsoleCursorPosition(),GetStdHandle()
/方向码
#define SNK_UP 0
#define SNK_DOWN 1
#define SNK_LEFT 2
#define SNK_RIGHT 3
#define CTL_ESC 4
#define CTL_PAUSE 5
#define GAME_OVER 6
/屏幕大小
#define SCREEN_X 70
#define SCREEN_Y 30
屏幕单位类型
#define SCREEN_FOOD 2 //食物
#define SCREEN_NONE 0 //空
#define SCREEN_BARRIER 1 //障碍
#define SCREEN_SNK 3 //蛇身体
using namespace std; //导入命名空间
struct Point
{
Point(){}
Point(int _x, int _y) :x(_x), y(_y){}
int x;
int y;
};
char Screen[SCREEN_Y][SCREEN_X]; /*屏幕矩阵*/
COORD curPos; /*光标位置*/
int scores = 0;
typedef char ScreenType;
typedef char Direction;
typedef char ExitType;
typedef deque<Point> SNAKE;
void DrawPoint(HANDLE hInstance, int x, int y, ScreenType st)
{
curPos.X = x;
curPos.Y = y;
DWORD rNum;
SetConsoleCursorPosition(hInstance, curPos);
switch (st)
{
case SCREEN_SNK:
printf("O");
break;
case SCREEN_BARRIER:
printf("*");
//WriteConsoleOutputCharacter(hInstance, TEXT("*"), 1, curPos, &rNum);
break;
case SCREEN_FOOD:
printf("#");
//WriteConsoleOutputCharacter(hInstance, TEXT("@"), 1, curPos, &rNum);
break;
case SCREEN_NONE:
printf(" ");
//WriteConsoleOutputCharacter(hInstance, TEXT(" "), 1, curPos, &rNum);
break;
default:
break;
}
}
// 绘制整个屏幕性能不好,不用这个函数,只在初始化的时候用一下
void DrawScreen()
{
for (int i = 0; i < SCREEN_Y; i++)
{
for (int j = 0; j < SCREEN_X; j++)
{
if (Screen[i][j] == SCREEN_BARRIER)
printf("*");
else if (Screen[i][j] == SCREEN_FOOD)
printf("@");
else
printf(" ");
}
printf("\n");
}
}
//
void MakeFood(HANDLE hInstance,const SNAKE & snake) //随机产生食物
{
/**/
int crood_x;
int crood_y;
bool same = true;
while (same)
{
/*same = false;*/
crood_x = rand() % (SCREEN_X - 1) + 1;
crood_y = rand() % (SCREEN_Y - 1) + 1;
if (Screen[crood_y][crood_x] == SCREEN_NONE)
same = false;
if (same == true)
{
crood_x = rand() % (SCREEN_X - 1) + 1;
crood_y = rand() % (SCREEN_Y - 1) + 1;
same = false;
}
}
Screen[crood_y][crood_x] = SCREEN_FOOD;
DrawPoint(hInstance, crood_x, crood_y, SCREEN_FOOD);
}
/******************************/
void UpdateScores(HANDLE hInstance)
{
curPos.X = 5;
curPos.Y = 0;
SetConsoleCursorPosition(hInstance, curPos);
DWORD rNum;
WriteConsoleOutputCharacter(hInstance, TEXT("SCORES="), 7, curPos, &rNum);
curPos.X = 12;
curPos.Y = 0;
SetConsoleCursorPosition(hInstance, curPos);
printf("%d", scores);
}
/******************************/
void init(HANDLE hInstance,SNAKE & snake)
{
/*初始化墙壁*/
for (int i = 0; i < SCREEN_Y; i++)
{
for (int j = 0; j < SCREEN_X; j++)
{
if (i == 0 || i == SCREEN_Y - 1 || j == 0 || j == SCREEN_X - 1)
Screen[i][j] = SCREEN_BARRIER;
else
Screen[i][j] = SCREEN_NONE;
}
}
srand((unsigned)time(NULL)); //随机数种子
int crood_x;
int crood_y;
crood_x = rand() % (SCREEN_X - 1) + 1;//产生蛇头随机位置
crood_y = rand() % (SCREEN_Y - 1) + 1;
snake.push_front(Point(crood_x, crood_y));
Screen[crood_y][crood_x] = SCREEN_SNK;
//产生异于蛇身体的食物的位置
DrawScreen();
UpdateScores(hInstance);
MakeFood(hInstance,snake);
}
/*
*根据当前头部位置,和上一次的方向以及将要行进的方向,给出下一次的方向,并且返回蛇的上一个状态的方向码
*/
Direction NextPoint(Point * LastPoint, Direction LastDirection, Direction NextDirection)
{
switch (NextDirection)
{
case SNK_UP:
if (SNK_LEFT == LastDirection || SNK_RIGHT == LastDirection)
{
LastPoint->y--;
return NextDirection;
}
else if (SNK_UP == LastDirection)
LastPoint->y--;
else
LastPoint->y++;
return LastDirection;
break;
case SNK_DOWN:
if (SNK_LEFT == LastDirection || SNK_RIGHT == LastDirection)
{
LastPoint->y++;
return NextDirection;
}
else if (SNK_UP == LastDirection)
LastPoint->y--;
else
LastPoint->y++;
break;
case SNK_LEFT:
if (SNK_UP == LastDirection || SNK_DOWN == LastDirection)
{
LastPoint->x--;
return NextDirection;
}
else if (SNK_LEFT == LastDirection)
LastPoint->x--;
else
LastPoint->x++;
break;
case SNK_RIGHT:
if (SNK_UP == LastDirection || SNK_DOWN == LastDirection)
{
LastPoint->x++;
return NextDirection;
}
else if (SNK_RIGHT == LastDirection)
LastPoint->x++;
else
LastPoint->x--;
break;
default:
break;
}
return LastDirection;
}
/*
*
*根据蛇身的位置坐标,更新屏幕矩阵,没用过
***/
inline void UpdateScreen(const SNAKE & snake)
{
for (SNAKE::const_iterator itr = snake.begin(); itr != snake.end(); ++itr)
Screen[(*itr).y][(*itr).x] = SCREEN_SNK;
}
/*
*根据单个元素的类型,更新屏幕矩阵
*/
inline void UpdateScreen(const Point * point, ScreenType st)
{
Screen[point->y][point->x] = st;
}
/*
*判断蛇头是不是会碰撞
**/
inline bool Collision(Point * snakeHead)
{
if (Screen[snakeHead->y][snakeHead->x] == SCREEN_BARRIER || Screen[snakeHead->y][snakeHead->x] == SCREEN_SNK)
return true;
return false;
}
/*
*从键盘获得方向按键
**/
inline char GetDirection(Direction lastDireciton)
{
if (GetAsyncKeyState(VK_UP))
return SNK_UP;
if (GetAsyncKeyState(VK_LEFT))
return SNK_LEFT;
if (GetAsyncKeyState(VK_RIGHT))
return SNK_RIGHT;
if (GetAsyncKeyState(VK_DOWN))
return SNK_DOWN;
if (GetAsyncKeyState(VK_ESCAPE))
return CTL_ESC;
if (GetAsyncKeyState(VK_SPACE))
return CTL_PAUSE;
return lastDireciton;
}
/*
*返回类型:
*GAME_OVER=游戏结束
*CTL_ESC=返回主菜单
*/
ExitType Game(HANDLE hInstance,SNAKE & snake,Direction initialDirection,int bodySize,DWORD level)
{
Direction lastDirection = initialDirection; //初始方向
Direction nextDirection;
Point snakeHead, snakeTail;
while (1)
{
nextDirection = GetDirection(lastDirection);
if (nextDirection == CTL_ESC)
return CTL_ESC;
//else if (nextDirection == CTL_PAUSE) //暂停
//_getch(); //按任意键开始
snakeHead = snake.front(); //取出蛇头位置
lastDirection = NextPoint(&snakeHead, lastDirection, nextDirection);
if (Screen[snakeHead.y][snakeHead.x] == SCREEN_FOOD)
{
snake.push_front(Point(snakeHead.x, snakeHead.y));
UpdateScreen(&Point(snakeHead.x, snakeHead.y), SCREEN_SNK);
DrawPoint(hInstance,snakeHead.x,snakeHead.y,SCREEN_SNK);
MakeFood(hInstance,snake);
scores++;
UpdateScores(hInstance);
}
else
{
snakeTail = snake.back();
UpdateScreen(&Point(snakeTail.x, snakeTail.y), SCREEN_NONE);
if (Collision(&snakeHead))//碰撞则游戏结束
return GAME_OVER;
snake.pop_back();
DrawPoint(hInstance, snakeTail.x, snakeTail.y, SCREEN_NONE);//清楚尾部的点
snake.push_front(Point(snakeHead.x, snakeHead.y)); //添加新位置的蛇头
UpdateScreen(&Point(snakeHead.x, snakeHead.y), SCREEN_SNK);
DrawPoint(hInstance, snakeHead.x, snakeHead.y, SCREEN_SNK);
}
Sleep(level);
}
}
int main()
{
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); //获取控制台句柄
SetConsoleDisplayMode(hStdOut, 1, NULL); //全屏显示
CONSOLE_CURSOR_INFO curInfo; //光标信息
GetConsoleCursorInfo(hStdOut, &curInfo);
curInfo.bVisible = FALSE;
SetConsoleCursorInfo(hStdOut, &curInfo); //光标不可见
SNAKE snake; //贪吃蛇身体双端队列
init(hStdOut,snake); //初始化屏幕矩阵,食物和蛇身的位置
Game(hStdOut,snake,SNK_DOWN,1,1000); //开始游戏
return 0;
}
控制台贪吃蛇
最新推荐文章于 2024-01-31 16:07:29 发布