int main()
{
Init(); //初始化
while (!die)
{
ProcessKey(); //处理按键
Move(); //移动蛇
Judge(); //碰撞检测
Draw(); //画图
Sleep(snack.timeperstep); //延时
}
while (_getch() != 27); //游戏结束后按esc退出
}
void Init()
{
SetConsoleTitleW(L"贪吃蛇");
system("MODE CON: COLS=64 LINES=32");
snack.body.push_back(new COORD{
15,15});
snack.body.push_back(new COORD{
14,15 });
GenerateFood();
}
这里有坑,方向键会产生两个键码,所以要用两次getch。方向键会先产生-32键码,然后产生72 75 77 80这四个键码中的一个
void ProcessKey()
{
Direction before = snack.heading;
snack.timeperstep = 1000 / snack.body.size();
char ch1, ch2;
while (_kbhit())
{
ch1 = _getch();
switch (ch1)
{
case VK_ESCAPE:
if (_getch() == 27)exit(0);
break;
case -32:
switch (ch2 = _getch())
{
case 72://up
if (Direction::down != before)
snack.heading = Direction::up;
break;
case 80://down
if (Direction::up != before)
snack.heading = Direction::down;
break;
case 75://left
if (Direction::right != before)
snack.heading = Direction::left;
break;
case 77://right
if (Direction::left != before)
snack.heading = Direction::right;
}
break;
case VK_SPACE:
snack.timeperstep = snack.timeperstep = 300 / snack.body.size();;
}
}
}
这里只是把头往前移动了一格
void Move()
{
COORD* head = snack.body.front();
switch (snack.heading)
{
case Direction::up:
snack.body.push_front(new COORD{
head->X,head->Y - 1 });
break;
case Direction::down:
snack.body.push_front(new COORD{
head->X,head->Y + 1 });
break;
case Direction::left:
snack.body.push_front(new COORD{
head->X - 1,head->Y });
break;
case Direction::right:
snack.body.push_front(new COORD{
head->X + 1,head->Y });
break;
}
}
判断头有没有和食物、墙、身体重叠。这里的坑就是判断身体的时候,一定要掐头去尾来判断
void Judge()
{
COORD* head = snack.body.front();
if (food.X == head->X && food.Y == head->Y)
GenerateFood();
else if (head->X < 0 || head->Y < 0 || head->X == 30 || head->Y == 30)
die = true;
else
{
delete snack.body.back();
snack.body.pop_back();
for (list<COORD*>::iterator i = ++snack.body.begin(); i != snack.body.end(); i++)
{
if ((*i)->X == head->X && (*i)->Y == head->Y)
die = true;
}
}
}
用缓冲,先把要输出到屏幕的东西写道缓冲区,解决屏闪。大致顺序是先画墙,再画食物,再画蛇,如果蛇死了就再画一个lost
void Draw()
{
HANDLE houtbuf = CreateConsoleScreenBuffer(GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
CONSOLE_CURSOR_INFO cci{
25,0 };
SetConsoleCursorInfo(houtbuf, &cci);
DWORD NumberOfCharsWritten;
COORD coord;
coord.Y = 0;
for (coord.X = 0; coord.X < 64; coord.X += 2)
{
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
coord.Y = 31;
for (coord.X = 0; coord.X < 64; coord.X += 2)
{
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
coord.X = 0;
for (coord.Y = 0; coord.Y < 32; coord.Y++)
{
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
coord.X = 62;
for (coord.Y = 0; coord.Y < 32; coord.Y++)
{
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
coord.Y = food.Y + 1;
coord.X = (food.X + 1) * 2;
FillConsoleOutputAttribute(houtbuf, FOREGROUND_BLUE, 2, coord, &NumberOfCharsWritten);
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
for (COORD* node : snack.body)
{
coord.X = (1 + node->X) * 2;
coord.Y = 1 + node->Y;
FillConsoleOutputAttribute(houtbuf, FOREGROUND_GREEN, 2, coord, &NumberOfCharsWritten);
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
if (die)
{
coord.Y = 16;
coord.X = 28;
FillConsoleOutputAttribute(houtbuf, FOREGROUND_RED, 8, coord, &NumberOfCharsWritten);
WriteConsoleOutputCharacterW(houtbuf, L"##LOST##", 8, coord, &NumberOfCharsWritten);
die = true;
}
SetConsoleActiveScreenBuffer(houtbuf);
}
用来生成一个和蛇身不重叠的食物
void GenerateFood()
{
unfished:
food.X = rand() % 30;
food.Y = rand() % 30;
for (COORD* node : snack.body)
{
if (node->X == food.X && node->Y == food.Y)
goto unfished;
}
}
#include
#include
#include
#include
#include
using namespace std;
enum Direction {
up, down, left, right };
struct {
list<COORD*> body;
Direction heading = Direction::right;
int timeperstep;
}snack;
COORD food;
bool die;
void ProcessKey()
{
Direction before = snack.heading;
snack.timeperstep = 1000 / snack.body.size();
char ch1, ch2;
while (_kbhit())
{
ch1 = _getch();
switch (ch1)
{
case VK_ESCAPE:
if (_getch() == 27)exit(0);
break;
case -32:
switch (ch2 = _getch())
{
case 72://up
if (Direction::down != before)
snack.heading = Direction::up;
break;
case 80://down
if (Direction::up != before)
snack.heading = Direction::down;
break;
case 75://left
if (Direction::right != before)
snack.heading = Direction::left;
break;
case 77://right
if (Direction::left != before)
snack.heading = Direction::right;
}
break;
case VK_SPACE:
snack.timeperstep = snack.timeperstep = 300 / snack.body.size();;
}
}
}
void Draw()
{
HANDLE houtbuf = CreateConsoleScreenBuffer(GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
CONSOLE_CURSOR_INFO cci{
25,0 };
SetConsoleCursorInfo(houtbuf, &cci);
DWORD NumberOfCharsWritten;
COORD coord;
coord.Y = 0;
for (coord.X = 0; coord.X < 64; coord.X += 2)
{
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
coord.Y = 31;
for (coord.X = 0; coord.X < 64; coord.X += 2)
{
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
coord.X = 0;
for (coord.Y = 0; coord.Y < 32; coord.Y++)
{
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
coord.X = 62;
for (coord.Y = 0; coord.Y < 32; coord.Y++)
{
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
coord.Y = food.Y + 1;
coord.X = (food.X + 1) * 2;
FillConsoleOutputAttribute(houtbuf, FOREGROUND_BLUE, 2, coord, &NumberOfCharsWritten);
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
for (COORD* node : snack.body)
{
coord.X = (1 + node->X) * 2;
coord.Y = 1 + node->Y;
FillConsoleOutputAttribute(houtbuf, FOREGROUND_GREEN, 2, coord, &NumberOfCharsWritten);
WriteConsoleOutputCharacterW(houtbuf, L"■", 1, coord, &NumberOfCharsWritten);
}
if (die)
{
coord.Y = 16;
coord.X = 28;
FillConsoleOutputAttribute(houtbuf, FOREGROUND_RED, 8, coord, &NumberOfCharsWritten);
WriteConsoleOutputCharacterW(houtbuf, L"##LOST##", 8, coord, &NumberOfCharsWritten);
die = true;
}
SetConsoleActiveScreenBuffer(houtbuf);
}
void GenerateFood()
{
unfished:
food.X = rand() % 30;
food.Y = rand() % 30;
for (COORD* node : snack.body)
{
if (node->X == food.X && node->Y == food.Y)
goto unfished;
}
}
void Init()
{
SetConsoleTitleW(L"贪吃蛇");
system("MODE CON: COLS=64 LINES=32");
snack.body.push_back(new COORD{
15,15});
snack.body.push_back(new COORD{
14,15 });
GenerateFood();
}
void Move()
{
COORD* head = snack.body.front();
switch (snack.heading)
{
case Direction::up:
snack.body.push_front(new COORD{
head->X,head->Y - 1 });
break;
case Direction::down:
snack.body.push_front(new COORD{
head->X,head->Y + 1 });
break;
case Direction::left:
snack.body.push_front(new COORD{
head->X - 1,head->Y });
break;
case Direction::right:
snack.body.push_front(new COORD{
head->X + 1,head->Y });
break;
}
}
void Judge()
{
COORD* head = snack.body.front();
if (food.X == head->X && food.Y == head->Y)
GenerateFood();
else if (head->X < 0 || head->Y < 0 || head->X == 30 || head->Y == 30)
die = true;
else
{
delete snack.body.back();
snack.body.pop_back();
for (list<COORD*>::iterator i = ++snack.body.begin(); i != snack.body.end(); i++)
{
if ((*i)->X == head->X && (*i)->Y == head->Y)
die = true;
}
}
}
int main()
{
Init();
while (!die)
{
ProcessKey();
Move();
Judge();
Draw();
Sleep(snack.timeperstep);
}
while (_getch() != 27);
}