整理一下以前学习时找到的程序。
一、游戏框架
1、蛇
蛇时以链表的形式保存的,增加长度是就新建节点,每次移动(刷新)蛇头向前进方向移动一格,把最后的节点删除;如果吃到食物就不删除尾部。
2、游戏
(1)撞墙:判断头部是否到达超过边界
(2)撞自己:遍历链表,判断头部是否在链表中位置一样
(3)加速减速:改变每次刷新(延时)时间
二、游戏代码
1、snake.h
#pragma once
#ifndef __SNAKE_H__
#define __SNAKE_H__
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <time.h>
#include <malloc.h>
#include <assert.h>
//标识地图大小
#define ROW_MAP 30 //地图的行
#define COL_MAP 90 //地图的列
#define SUCCESS_SCORE 1000 //通关分数
enum Direction //蛇行走的方向
{
R, //右
L, //左
U, //上
D //下
}Direction;
enum State
{
ERROR_SELF, //咬到自己
ERROR_WALL, //撞到墙
NORMAL, //正常状态
SUCCESS //通关
}State;
typedef struct Snake
{
size_t x; //行
size_t y; //列
struct Snake* next;
}Snake, *pSnake;
void StartGame();
void RunGame();
void EndGame();
#endif
2、snake.cpp
#include "Snake.h"
pSnake head = NULL; //定义蛇头指针
pSnake Food = NULL; //定义食物指针
int sleeptime = 500;//间隔时间,用来控制速度
int Score = 0; //总分
int everyScore = 1; //每步得分
//定义游戏中用到的符号
const char food = '*';
const char snake = '0';
//控制输出光标
void Pos(int x, int y) //控制输出光标
{
COORD pos; //pos为结构体
pos.X = x; //控制列
pos.Y = y; //控制行
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);//读取标准输出句柄来控制光标为pos
}
//初始化界面
void Face()
{
system("color 0B");
printf("\t\t\t\t*******************************************************\n");
printf("\t\t\t\t* Welcome to Snake Game! *\n");
printf("\t\t\t\t* *\n");
printf("\t\t\t\t* -> 开始游戏 Enter 键 *\n");
printf("\t\t\t\t* -> 退出游戏 Esc 键 *\n");
printf("\t\t\t\t* -> 暂停游戏 Space 键 *\n");
printf("\t\t\t\t* -> F1键减速 F2键加速 *\n");
printf("\t\t\t\t* -> 上下左右控制蛇的移动 *\n");
printf("\t\t\t\t*******************************************************\n");
}
//初始化地图
void Map()
{
int i = 0;
for (i = 0; i < COL_MAP; i += 2) //打印上下边框(每个■占用两列)
{
Pos(i, 0);
printf("■");
Pos(i, ROW_MAP - 1);
printf("■");
}
for (i = 0; i < ROW_MAP; i++) //打印左右边框
{
Pos(0, i);
printf("■");
Pos(COL_MAP - 2, i);
printf("■");
}
}
//打印蛇
void PrintSnake()
{
pSnake cur = head;
while (cur)
{
Pos(cur->y, cur->x);
printf("%c", snake);
cur = cur->next;
}
}
//初始化蛇身
void InitSnake()
{
int initNum = 3;
int i = 0;
pSnake cur;
head = (pSnake)malloc(sizeof(Snake));
head->x = 5;
head->y = 10;
head->next = NULL;
cur = head;
for (i = 1; i < initNum; i++)
{
pSnake newNode = (pSnake)malloc(sizeof(Snake));
newNode->x = 5;
newNode->y = 10 - i;
newNode->next = NULL;
cur->next = newNode;
cur = cur->next;
}
PrintSnake();
}
//在地图上随机产生一个食物
void CreateFood()
{
pSnake cur = head;
Food = (pSnake)malloc(sizeof(Snake));
//产生x~y的随机数 k=rand()%(Y-X+1)+X;
srand((unsigned)time(NULL));
Food->x = rand() % (ROW_MAP - 2 - 1 + 1) + 1;
Food->y = rand() % (COL_MAP - 3 - 2 + 1) + 2;
Food->next = NULL;
while (cur) //检查食物是否与蛇身重合
{
if (cur->x == Food->x && cur->y == Food->y)
{
free(Food);
Food = NULL;
CreateFood();
return;
}
cur = cur->next;
}
Pos(Food->y, Food->x);
printf("%c", food);
}
//游戏开始的所有设置
void StartGame()
{
Face();
system("pause");
if (GetAsyncKeyState(VK_RETURN))
{
system("cls");
Pos(COL_MAP + 5, 1);
printf("当前分/通关分:");
Pos(COL_MAP + 20, 1);
printf("%d/%d", Score, SUCCESS_SCORE);
Pos(COL_MAP + 5, 2);
printf("当前每步得分:");
Pos(COL_MAP + 20, 2);
printf("%d", everyScore);
Pos(COL_MAP + 5, 3);
printf("\n");
Pos(COL_MAP + 5, 4);
printf("速度越快 得分越高哦!!\n");
Map();
InitSnake();
CreateFood();
}
else if (GetAsyncKeyState(VK_ESCAPE))
{
exit(0);
}
}
//判断是否碰到墙
int IsCrossWall()
{
if (head->x <= 0 || head->x >= ROW_MAP - 1 || head->y <= 1 || head->y >= COL_MAP - 2)
{
State = ERROR_WALL;
return 0;
}
return 1;
}
//判断是否咬到自己
int IsEatSelf(pSnake newHead)
{
pSnake cur = head;
assert(newHead);
while (cur)
{
if (cur->x == newHead->x && cur->y == newHead->y)
{
State = ERROR_SELF;
return 0;
}
cur = cur->next;
}
return 1;
}
//判断该位置是不是食物
int IsFood(pSnake pos)
{
assert(pos);
if (pos->x == Food->x && pos->y == Food->y)
{
return 1;
}
return 0;
}
//蛇移动一次
void SnakeMove()
{
pSnake newHead = NULL;
newHead = (pSnake)malloc(sizeof(Snake));
if (Direction == R) //右
{
newHead->x = head->x;
newHead->y = head->y + 1;
newHead->next = head;
}
else if (Direction == L) //左
{
newHead->x = head->x;
newHead->y = head->y - 1;
newHead->next = head;
}
else if (Direction == U) //上
{
newHead->x = head->x - 1;
newHead->y = head->y;
newHead->next = head;
}
else if (Direction == D) //下
{
newHead->x = head->x + 1;
newHead->y = head->y;
newHead->next = head;
}
if (IsFood(newHead))
{
head = newHead;
PrintSnake();
CreateFood();
Score += everyScore;
Pos(COL_MAP + 20, 1);
printf("%d/%d", Score, SUCCESS_SCORE);
if (Score >= SUCCESS_SCORE)
{
State = SUCCESS;
}
}
else
{
if (IsCrossWall() && IsEatSelf(newHead))
{
pSnake cur = NULL;
head = newHead;
cur = head;
//删除蛇尾并打印
while (cur->next->next != NULL)
{
Pos(cur->y, cur->x);
printf("%c", snake);
cur = cur->next;
}
Pos(cur->y, cur->x);
printf("%c", snake);
Pos(cur->next->y, cur->next->x);
printf(" "); //打印空格来覆盖频幕上的蛇尾
free(cur->next);
cur->next = NULL;
}
else
{
free(newHead);
newHead = NULL;
}
}
}
//延时
void Pause()
{
while (1)
{
Sleep(sleeptime);
if (GetAsyncKeyState(VK_SPACE))
{
break;
}
}
}
//用键盘控制游戏
void ControlSnake()
{
if (GetAsyncKeyState(VK_UP) && Direction != D)
{
Direction = U;
}
else if (GetAsyncKeyState(VK_DOWN) && Direction != U)
{
Direction = D;
}
else if (GetAsyncKeyState(VK_LEFT) && Direction != R)
{
Direction = L;
}
else if (GetAsyncKeyState(VK_RIGHT) && Direction != L)
{
Direction = R;
}
else if (GetAsyncKeyState(VK_F1))
{
if (sleeptime < 500)
{
sleeptime = sleeptime + 50;
everyScore = everyScore - 1;
Pos(COL_MAP + 20, 2);
printf("%d", everyScore);
}
}
else if (GetAsyncKeyState(VK_F2))
{
if (sleeptime > 50)
{
sleeptime = sleeptime - 50;
everyScore = everyScore + 1;
Pos(COL_MAP + 20, 2);
printf("%d", everyScore);
}
}
else if (GetAsyncKeyState(VK_SPACE))
{
Pause();
}
else if (GetAsyncKeyState(VK_ESCAPE))
{
exit(0);
}
}
//判断游戏失败或成功
void StateGame()
{
if (State == ERROR_SELF)
{
system("cls");
printf("很遗憾,蛇咬到自己,游戏失败!\n");
}
else if (State == ERROR_WALL)
{
system("cls");
printf("很遗憾,蛇碰到墙壁,游戏失败!\n");
}
else if (State == SUCCESS)
{
system("cls");
printf("恭喜您,已通关!!!\n");
}
}
//开始游戏
void RunGame()
{
Direction = R; //蛇初始行走方向为右
State = NORMAL;//游戏初始为正常状态
while (1)
{
ControlSnake();
SnakeMove();
if (State != NORMAL)
{
StateGame();
break;
}
Sleep(sleeptime);
}
}
//结束游戏,释放链表并恢复默认值
void EndGame()
{
pSnake cur = head;
while (cur)
{
pSnake del = cur;
cur = cur->next;
free(del);
del = NULL;
}
head = NULL;
if (Food != NULL)
{
free(Food);
Food = NULL;
}
Score = 0;
everyScore = 1;
sleeptime = 500;
}
int main()
{
while (1)
{
StartGame();
RunGame();
EndGame();
}
system("pause");
return 0;
}