贪吃蛇
直接上代码:
- Model.h
#pragma once
//坐标的结构体
typedef struct Coordinate
{
int x;
int y;
} Coordinate;
//链表的节点结构体
typedef struct Node
{
Coordinate Coord;
struct Node* next;
} Node;
//蛇前进的方向
typedef enum
{
UP, RIGHT, DOWN, LEFT
} Direction;
//蛇
typedef struct Snake
{
Node* head;
Direction direction;
} Snake;
//游戏元素
typedef struct Game
{
Snake snake;
Coordinate food;
int width;
int height;
int speed;
int score;
} Game;
void GameInit(Game *pGame);
void FoodInit(Coordinate *pFood, int width,
int height, const Snake *pSnake);
void GameDestroy(Game *pGame);
void AddSnakeHead(Snake* pSnake,Coordinate nextCoord);
void RemoveSnakeTail(Snake* pSnake);
- Model.c
#define _CRT_SECURE_NO_DEPRECATE 1
#include "Model.h"
#include "stdbool.h"
#include "stdlib.h"
#include "view.h"
void SnakeInit(Snake *pSnake)
{
pSnake->direction = RIGHT;
pSnake->head = NULL;
for (int i = 0; i < 3;i++)
{
int x = 3 + i;
int y = 3;
Node* node = (Node*)malloc(sizeof(Node));
node->Coord.x = x;
node->Coord.y = y;
node->next = pSnake->head;
pSnake->head = node;
}
}
static bool IsOverlapSnake(int x, int y, const Snake *pSnake)
{
Node* cur = pSnake->head;
while (cur!=NULL)
{
if (cur->Coord.x==x&&cur->Coord.y==y)
{
return true;
}
cur = cur->next;
}
return false;
}
// 生成食物
// 1. 随机
// 2. 不能出框
// 3. 不能和蛇重叠
void FoodInit(Coordinate *pFood, int width, int height, const Snake *pSnake)
{
int x; int y;
do
{
x = rand() % width;
y = rand() % height;
} while (IsOverlapSnake(x,y,pSnake));
pFood->x = x;
pFood->y = y;
DisplayFood(x, y);
}
void GameInit(Game *pGame)
{
SnakeInit(&pGame->snake);
pGame->width = 28;
pGame->height = 27;
pGame->speed = 300;
pGame->score = 0;
FoodInit(&pGame->food,pGame->width,pGame->height,&pGame->snake);
DisplayScore(pGame->score);
}
static void SnakeDestroy(Snake *pSnake)
{
Node* cur = pSnake->head;
while (cur!=NULL)
{
Node* Del = cur;
cur = cur->next;
free(Del);
}
}
void GameDestroy(Game *pGame)
{
SnakeDestroy(&pGame->snake);
}
void AddSnakeHead(Snake* pSnake,Coordinate nextCoord)
{
Node* node = (Node*)malloc(sizeof(Node));
node->Coord.x = nextCoord.x;
node->Coord.y = nextCoord.y;
node->next = pSnake->head;
pSnake->head = node;
DisplaySnakeBlock(nextCoord.x, nextCoord.y);
}
void RemoveSnakeTail(Snake* pSnake)
{
Node* cur = pSnake->head;
while (cur->next->next!=NULL)
{
cur = cur->next;
}
CleanSnakeBlock(cur->next->Coord.x, cur->next->Coord.y);
free(cur->next);
cur->next = NULL;
}
Controller.c
#define _CRT_SECURE_NO_DEPRECATE 1
#include "Model.h"
#include "Windows.h"
#include "stdbool.h"
#include "view.h"
#include "time.h"
static void _Pause()
{
while (1)
{
Sleep(300);
if (GetAsyncKeyState(VK_SPACE))
{
break;
}
}
}
static Coordinate GetNextCoord(Snake* pSnake)
{
Coordinate nextCoord = pSnake->head->Coord;
switch (pSnake->direction)
{
case UP:
nextCoord.y -= 1;
break;
case DOWN:
nextCoord.y += 1;
break;
case LEFT:
nextCoord.x -= 1;
break;
case RIGHT:
nextCoord.x += 1;
break;
default:
break;
}
return nextCoord;
}
static bool IsFood(Coordinate nextCord, Coordinate Food)
{
return nextCord.x == Food.x && nextCord.y == Food.y ? true : false;
}
static bool IsHitWall(int width, int height, Coordinate nextCoord)
{
if (nextCoord.x<0||nextCoord.x>=width||nextCoord.y<0||nextCoord.y>=height)
{
return true;
}
return false;
}
static bool IsHitSelf(Snake* pSnake, Coordinate nextCoord)
{
Node*cur = pSnake->head->next;
while (cur!=NULL)
{
if (cur->Coord.x==nextCoord.x&&cur->Coord.y==nextCoord.y)
{
return true;
}
cur = cur->next;
}
return false;
}
void RunGame()
{
Game game;
GameInit(&game);
ViewInit(game.width, game.height);
DisplayWall(game.width, game.height);
DisplaySnake(&game.snake);
while (1)
{
if (GetAsyncKeyState(VK_UP)&&game.snake.direction!=DOWN)
{
game.snake.direction = UP;
}
else if (GetAsyncKeyState(VK_DOWN) && game.snake.direction != UP)
{
game.snake.direction = DOWN;
}
else if (GetAsyncKeyState(VK_LEFT) && game.snake.direction != RIGHT)
{
game.snake.direction = LEFT;
}
else if (GetAsyncKeyState(VK_RIGHT) && game.snake.direction != LEFT)
{
game.snake.direction = RIGHT;
}
else if (GetAsyncKeyState(VK_SPACE))
{
_Pause();
}
else if (GetAsyncKeyState(VK_ESCAPE))
{
break;
}
else if (GetAsyncKeyState(VK_F1))
{
game.speed = 100;
}
Coordinate nextCoord = GetNextCoord(&game.snake);
if (IsFood(nextCoord,game.food))
{
AddSnakeHead(&game.snake, nextCoord);
game.score += 10;
if (game.speed>=100)
{
game.speed -= 10;
}
DisplayScore(game.score);
FoodInit(&game.food, game.width, game.height, &game.snake);
}
else
{
RemoveSnakeTail(&game.snake);
AddSnakeHead(&game.snake, nextCoord);
}
if (IsHitWall(game.width, game.height, nextCoord))
{
break;
}
if (IsHitSelf(&game.snake,nextCoord))
{
break;
}
Sleep(game.speed);
}
GameDestroy(&game);
}
int main()
{
srand((unsigned)time(NULL));
Menu();
RunGame();
return 0;
}
View.h
#pragma once
#include "Model.h"
void DisplaySnake(const Snake *pSnake);
void DisplaySnakeBlock(int x, int y);
void CleanSnakeBlock(int x, int y);
void ViewInit(int width, int height);
void DisplayWall(int width, int height);
void DisplayFood(int x, int y);
void DisplayScore(int score);
View.c
#define _CRT_SECURE_NO_DEPRECATE 1
#include "Model.h"
#include <Windows.h>
#include <stdio.h>
static void SetCurPos(int X, int Y)
{
HANDLE hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
// 标准输入/标准输出/标准错误输出
COORD coord = { X, Y };
//设置终端光标位置
SetConsoleCursorPosition(hStdOutput, coord);
}
void ViewInit(int width, int height)
{
HANDLE hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO info;
GetConsoleCursorInfo(hStdOutput, &info);
info.bVisible = 0;
SetConsoleCursorInfo(hStdOutput, &info);
}
void DisplayWall(int width, int height)
{
SetCurPos(0, 0);
for (int i = 0; i < width + 2; i++)
{
printf("█");
}
SetCurPos(0, height + 1);
for (int i = 0; i < width + 2; i++)
{
printf("█");
}
for (int j = 0; j < height + 2; j++)
{
SetCurPos(0, j);
printf("█");
}
for (int j = 0; j < height + 2; j++)
{
SetCurPos(2*(width+1), j);
printf("█");
}
}
void Menu()
{
SetCurPos(46, 10);
printf("※※※贪吃蛇小游戏※※※\n");
SetCurPos(50, 12);
system("pause");
system("cls");
}
void DisplaySnake(const Snake *pSnake)
{
for (Node* cur = pSnake->head; cur != NULL;cur=cur->next)
{
SetCurPos(2*(cur->Coord.x+1), cur->Coord.y+1);
printf("█");
}
}
void DisplaySnakeBlock(int x, int y)
{
SetCurPos(2*(x+1), y+1); // 先统一两个坐标系
printf("█");
}
void CleanSnakeBlock(int x, int y)
{
SetCurPos(2*(x+1), y+1); // 先统一两个坐标系
printf(" ");
}
void DisplayFood(int x, int y)
{
SetCurPos(2 * (x + 1), y+1);
printf("█");
}
void DisplayScore(int score)
{
SetCurPos(2 * 31, 24);
for (int i = 0; i < 10;i++)
{
printf("※");
}
SetCurPos(2 * 31, 28);
for (int i = 0; i < 10; i++)
{
printf("※");
}
for (int j = 0; j < 5;j++)
{
SetCurPos(2 * 31, 24 + j);
printf("※");
}
for (int j = 0; j < 5; j++)
{
SetCurPos(2 * 40, 24 + j);
printf("※");
}
SetCurPos(2 * 32, 26);
printf("分数:%d", score);
}
演示: