前言
因为想做属于自己的游戏所以选择从事计算机行业,如今大三了,注意全在web和算法,游戏碰都没碰。
下面的代码是在观看一个贪吃蛇教程后自行制作,这是教程地址。自己在其基础上做了些改进,如添加背景音乐、校验键盘输入控制方向…等等。由于实力有限,代码有不足之处,还望多多包涵。
运行环境
vs2019(注:背景音乐路径地址请自行修改,这是下载地址)
源代码
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<time.h>
#include <windows.h>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
#define MAP_MODE "■" // 地图边缘样式
#define FOOD_MODE "■" // 食物样式
#define SNAKE_HEAD "○" // 蛇头
#define SNAKE_BODY "□" // 蛇身
#define MAP_WIDTH 60 // 地图宽度
#define MAP_HEIGHT 20 // 地图高度
#define BGM_LOCATION L"C:\\Users\\BestRiven\\source\\repos\\GluttonousSnake\\music.wav" // 背景音乐路径(注:去除""前的L,会导致播放音乐失效)
void first_page();
void play_music();
void start_game();
void create_map();
void gotoxy(int x, int y);
void reback();
void create_foot();
void create_snake();
void move_snake();
int judge_statement();
struct Food {
int x;
int y;
int isCreate;
} food;
struct Snake {
int x[MAP_WIDTH * MAP_HEIGHT];
int y[MAP_WIDTH * MAP_HEIGHT];
int currentLen;
int direct;
} snake;
int main() {
// 显示首页
first_page();
// 播放音乐
play_music();
// 准备开始游戏
start_game();
// 创建地图
create_map();
// 创建食物
create_foot();
// 创建蛇
create_snake();
// 移动蛇
while (TRUE) {
// 判断蛇的状态
if (judge_statement()) {
gotoxy(MAP_WIDTH / 2 - 6, MAP_HEIGHT / 2);
printf("GAME OVER!");
gotoxy(MAP_WIDTH / 2 - 6, MAP_HEIGHT - 3);
printf("您的得分是:%d", snake.currentLen - 3);
reback();
system("pause");
exit(0); // 退出程序
}
// 如果食物未创建就创建食物
if (food.isCreate == 0) {
create_foot();
}
// 移动蛇
move_snake();
Sleep(300);
}
return 0;
}
int judge_statement() {
// 如果蛇头撞到蛇身就返回1
for (int i = 1; i < snake.currentLen; i++) {
if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i]) return 1;
}
// 如果蛇头越界也返回1
if (snake.x[0] < 1 || snake.x[0] > MAP_WIDTH - 1 || snake.y[0] < 1 || snake.y[0] > MAP_HEIGHT - 1) {
return 1;
}
return 0;
}
// 输入两个字符,判断是否方向相反
int judge_contrary(char c1, char c2) {
if (c1 == c2) return 0;
switch(c1) {
case 'w':
case 'W':
return c2 == 's' || c2 == 'S';
case 's':
case 'S':
return c2 == 'w' || c2 == 'W';
case 'a':
case 'A':
return c2 == 'd' || c2 == 'D';
case 'd':
case 'D':
return c2 == 'a' || c2 == 'A';
}
return 0;
}
// 输入一个字符,判断是否合法
int judge_valid(char c) {
switch (c) {
case 'w':
case 'W':
case 's':
case 'S':
case 'a':
case 'A':
case 'd':
case 'D':
return 1;
}
return 0;
}
void move_snake() {
char cur_direct = snake.direct;
if (_kbhit()) { // 监听键盘输入
fflush(stdin);
cur_direct = _getch();
}
// 先判断输入是否合法,并且方向和原方向不相反,都满足就更新
if (judge_valid(cur_direct) && !judge_contrary(snake.direct,cur_direct))
snake.direct = cur_direct;
// 擦掉蛇尾(刚生成的蛇尾需要过滤
if (snake.x[snake.currentLen - 1] != 0) {
gotoxy(snake.x[snake.currentLen - 1], snake.y[snake.currentLen - 1]);
printf(" ");
}
// 打印蛇身
for (int i = snake.currentLen - 1; i > 0; i--) {
snake.x[i] = snake.x[i - 1];
snake.y[i] = snake.y[i - 1];
gotoxy(snake.x[i], snake.y[i]);
printf(SNAKE_BODY);
}
// 根据方向更新蛇头
switch(snake.direct) {
case 'w':
case 'W':
snake.y[0]--;
break;
case 's':
case 'S':
snake.y[0]++;
break;
case 'a':
case 'A':
snake.x[0] -= 2;
break;
case 'd':
case 'D':
snake.x[0] += 2;
break;
}
// 打印蛇头
gotoxy(snake.x[0], snake.y[0]);
printf(SNAKE_HEAD);
// 如果蛇头和食物重合,那么蛇长++
if (snake.x[0] == food.x && snake.y[0] == food.y) {
snake.currentLen++;
// 设置食物未创建
food.isCreate = 0;
}
reback();
}
void create_snake() {
// 初始化变量
snake.x[0] = MAP_WIDTH / 2;
snake.y[0] = MAP_HEIGHT / 2;
snake.currentLen = 3;
snake.direct = 'a';
// 画蛇头
gotoxy(snake.x[0], snake.y[0]);
printf(SNAKE_HEAD);
// 画蛇身
for (int i = 1; i < snake.currentLen; i++) {
snake.x[i] = snake.x[i - 1] + 2;
snake.y[i] = snake.y[i - 1];
gotoxy(snake.x[i], snake.y[i]);
printf(SNAKE_BODY);
}
reback();
}
void create_foot() {
// 设置食物已创建
food.isCreate = 1;
int flag = 1;
while(flag == 1){
// 产生随机数
srand(time(NULL));
// 生成随机食物
food.x = rand() % (MAP_WIDTH - 1) + 2;
if (food.x&1) continue;
food.y = rand() % (MAP_HEIGHT - 1) + 1;
flag = 0;
// 判断生成的随机食物是否和蛇身冲突
for (int i = 0; i < snake.currentLen; i++) {
if (food.x == snake.x[i] && food.y == snake.y[i]) {
flag = 1;
break;
}
}
}
gotoxy(food.x, food.y);
printf(FOOD_MODE);
reback();
}
void create_map() {
// 打印上下
for (int i = 0; i <= MAP_WIDTH; i++) {
gotoxy(i, 0);
printf(MAP_MODE);
gotoxy(i, MAP_HEIGHT);
printf(MAP_MODE);
}
// 打印左右
for (int i = 1; i < MAP_HEIGHT; i++) {
gotoxy(0, i);
printf(MAP_MODE);
gotoxy(MAP_WIDTH, i);
printf(MAP_MODE);
}
reback();
}
void first_page() { // 显示封面
printf("\t\t欢迎试玩《贪吃蛇》\n\n");
printf("开始游戏:\t按空格开始游戏\n");
printf("控制方向:\tw a s d控制蛇的方向\n\n\n\n");
}
void play_music() {
PlaySound(BGM_LOCATION, NULL, SND_FILENAME | SND_ASYNC);
}
void start_game() {
// 读入空格进入游戏
while (' ' != _getch());
// 暂停音乐
PlaySound(NULL, 0, 0);
// 清屏
system("cls");
}
void gotoxy(int x, int y) { // 系统辅助函数
COORD pos = { x , y };
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut, pos);
}
// 光标归位
void reback() {
gotoxy(MAP_WIDTH + 8, 0);
}