注:本文档需与c语言课程设计之贪吃蛇文档配套使用。c语言实现贪吃蛇代码可随意下载 c语言课程设计报告也可随意下载
1.本代码在VS2013下可正常运行,其他版本需根据版本需要进行调试。
2.代码在Csnake-Csnake里,想直接打开整个工程直接进入Cnake,点击Csnake.sln打开 注意这里可能需要使用相关的IDE环境才能打开。
3.代码注释为全英文注释,若有疑问可借助百度翻译,或者看文档报告。
文档链接可直接百度云下载:链接:https://pan.baidu.com/s/1vnXkR8d9-R5lAYpxzcMYxw 密码:i1q6
说到大学都要做的课程设计和报告我还是决定分享出来,为什么呢?(大学就是给这些无聊的课程,无聊报告和画图耽误的,才会有那么多大学生找不到工作)节省大家时间啦 嘿嘿。。。。。。请叫我雷锋先生。。。
说到贪吃蛇还是直接上代码吧,解释最后来。。。。。
首先是main.cpp文件,控制调用函数。
#include "snake.h" //Transposed structure object extern struct Food food; extern struct Snake snake; //main function int main() { ret = menu(); if (ret == 1) { while (finish) { initMap(); //Initialization map while (TRUE) { updataFood(); //updata food getSpeed(); //speed moveSnake(); //move snake Sleep(snake.speed); //Control the speed of the snake printFont(FONT_WINDOW_STARTX, FONT_WINDOW_STARTY, snake.speed); //Right interface if (!(isAlive())) break; } if (finish) //Death or customs clearance { system("cls"); gotoxy(22, 5); printf("Game Over!"); gotoxy(24, 5); printf("按(1)键退出游戏,按其他任意键重玩"); if (getch() == 49) break; system("cls"); } else { system("cls"); gotoxy(22, 5); printf("恭喜你通关了"); gotoxy(24, 5); printf("按(1)键退出游戏,按其他任意键重玩"); if (getch() == 49) break; system("cls"); } } } return 0; }
snake.h 主要声明函数和定义变量。
#pragma once #ifndef _SNAKE_H_ #define _SNAKE_H_ #include <stdio.h> #include <windows.h> #include <time.h> #include <conio.h> #include <time.h> #pragma warning(disable: 4996) #define FONT_WINDOW_STARTY 41 //define font window #define FONT_WINDOW_STARTX 2 #define FRAME_HEIGHT 20 //define map size #define FRAME_WIDTH 40 #define UP 'w' //define operate key #define DOWN 's' #define LEFT 'a' #define RIGHT 'd' #define SNAKE_LEN 50 #define ADD 3 static int i, j, k; static char ch = UP; //initial first direction static char Direction = UP; static int grow = 0; //flag: if snake grow static int ret = 0; static int finish = 1; //Structure declaration struct Food{ int x; int y; }; struct Snake{ int x[SNAKE_LEN]; int y[SNAKE_LEN]; int len; int speed; }; //snake[0] is head //Initialization map void initMap(void); //updataFood void updataFood(void); //moveSnake void moveSnake(void); //Judge whether the snake is alive or not int isAlive(void); //get snake speed void getSpeed(void); //move cursor void gotoxy(int x, int y); //Right interface void printFont(int x, int y, int speed); //menu int menu(); #endif
snake.cpp文件 主要实现函数功能。
#include "snake.h" //Initialization of structure struct Food food; struct Snake snake; //menu int menu() { gotoxy(14, 45); printf("欢迎来到贪吃蛇小游戏...."); gotoxy(16, 45); printf("开始游戏请按(1)"); gotoxy(18, 45); printf("按其他任意键退出游戏QAQ"); int ch = getch(); while (TRUE) { if (ch == 49) //The ASCII value of 1 { ret = 1; break; } else { break; } } system("cls"); return ret; } //initialize Map void initMap(void) { ch = UP; Direction = UP; //initial food srand(time(NULL)); //Set random number seed food.x = rand() % (FRAME_HEIGHT - 2) + 1; food.y = rand() % (FRAME_WIDTH - 2) + 1; gotoxy(food.x, food.y); printf("!"); //initial snake snake.x[0] = FRAME_HEIGHT / 2; snake.y[0] = FRAME_WIDTH / 2; gotoxy(snake.x[0], snake.y[0]); printf("@"); snake.len = 3; snake.speed = 200; for (k = 1; k<snake.len; k++) { snake.x[k] = snake.x[k - 1] + 1; snake.y[k] = snake.y[k - 1]; gotoxy(snake.x[k], snake.y[k]); printf("@"); } //initial bar for (j = 0; j<FRAME_WIDTH; j++) { gotoxy(0, j); printf("#"); gotoxy(FRAME_HEIGHT - 1, j); printf("#"); } for (i = 1; i<FRAME_HEIGHT - 1; i++) { gotoxy(i, 0); printf("#"); gotoxy(i, FRAME_WIDTH - 1); printf("#"); } } //Right interface void printFont(int x, int y, int speed) { int i = 1; gotoxy(x, y); printf("召唤师,欢迎来到贪吃蛇峡谷"); gotoxy(x + ADD, y); if (speed == 200) { printf("现在的速度是:%d级", i); } else if (speed == 100) { printf("现在的速度等级是:%d级", i + 1); } else if (speed == 50) { printf("现在的速度等级是:%d级", i + 2); } else { printf("恭喜你,召唤师,现在是*"); } gotoxy(x + 2 * ADD, y); printf("上下左右操作键分别是:w,s,a,d"); gotoxy(x + 3 * ADD, y); printf("当吃到自己身体或者撞墙时游戏结束"); gotoxy(x + 4 * ADD, y); printf("按空格键暂停,在按空格键继续"); } //generate food void updataFood() { if (snake.x[0] == food.x&&snake.y[0] == food.y) //When the snake eats food update { srand(time(NULL)); food.x = rand() % (FRAME_HEIGHT - 2) + 1; food.y = rand() % (FRAME_WIDTH - 2) + 1; gotoxy(food.x, food.y); printf("!"); snake.len++; grow = 1; } } //move snake void moveSnake() { if (!grow) { gotoxy(snake.x[snake.len - 1], snake.y[snake.len - 1]); printf(" "); //The tail will be empty } for (k = snake.len - 1; k>0; k--) { snake.x[k] = snake.x[k - 1]; snake.y[k] = snake.y[k - 1]; } if (kbhit()) { ch = getch(); if (ch == ' ') //Pause or continue by space while (getch() != ' '){}; if (ch != UP && ch != DOWN && ch != LEFT && ch != RIGHT) //Other keys to prevent interference { ch = Direction; goto sport; } if (Direction != ch) { if ((Direction == UP &&ch != DOWN) || (Direction == DOWN &&ch != UP) || (Direction == LEFT && ch != RIGHT) || (Direction == RIGHT && ch != LEFT)) //Prevent reverse movement { Direction = ch; goto sport; } else { ch = Direction; goto sport; } } else { goto sport; } } else { sport: switch (ch) //Move the snake's head { case UP: snake.x[0]--; break; case DOWN: snake.x[0]++; break; case LEFT: snake.y[0]--; break; case RIGHT: snake.y[0]++; break; default: break; } } gotoxy(snake.x[0], snake.y[0]); printf("@"); //print the snake's head grow = 0; gotoxy(FRAME_HEIGHT, 0); } //Judge whether the snake is alive or not int isAlive(void) { if (snake.x[0] == 0 || snake.x[0] == FRAME_HEIGHT - 1 || snake.y[0] == FRAME_WIDTH - 1 || snake.y[0] == 0) //When you touch a wall or eat your own body, you die return 0; for (k = 1; k<snake.len; k++) if (snake.x[k] == snake.x[0] && snake.y[k] == snake.y[0]) return 0; return 1; } //speed updata void getSpeed(void) { if (snake.len <= 6) snake.speed = 200; else if (snake.len <= 10) snake.speed = 100; else if (snake.len <= 20) snake.speed = 50; else if (snake.len <= 30) snake.speed = 30; else snake.speed = 20; if (snake.len == 40) finish = 0; } //move cursor void gotoxy(int x, int y) { HANDLE hout; //Defining handle objects COORD cor; //Defining coordinate objects hout = GetStdHandle(STD_OUTPUT_HANDLE); //Get the handle of the output screen buffer cor.X = y; cor.Y = x; SetConsoleCursorPosition(hout, cor); //Move Cursor }
接下来是课程设计的报告。
1. 课程设计目的1
2. 课程设计的内容1
3. 课程设计的功能要求1
3.1. 菜单模块:1
3.2. 地图初始化模块:1
3.3. 食物更新模块:1
3.4. 移动贪吃蛇模块:1
3.5. 贪吃蛇生命模块:1
3.7. 获取贪吃蛇速度模块:.........................................................................................................1
3.7. 移动窗口光标模块:.............................................................................................................1
3.8 帮助系统模块:.........................................................................................................................................1
3.8 退出系统模块:.........................................................................................................................................1
4. 概要设计2
4.1. 系统功能框架图2
4.2. 功能模块描述2
5. 详细设计3
5.1. 各功能模块的具体实现算法——流程图3
5.1.1. 主控main函数流程图3
5.2. 重点设计描述3
6. 系统测试与调试3
7. 课程设计心得体会4
参考资料4
1. 课程设计目的
进一步加深、巩固所学专业课程《C语言程序设计》的基本理论知识,理论联系实际,进一步培养自己综合分析问题和解决问题的能力。掌握运用C语言独立地编写、调试应用程序和进行其它相关设计的技能。熟悉使用结构体与时间函数和windows窗口控制函数。
2. 课程设计的内容
设计并实现一个贪吃蛇小游戏,要求具有以下功能模块:
(1) 页面菜单模块。
(2) 初始化地图模块。
(3) 食物更新模块。
(4) 移动贪吃蛇模块。
(5) 判断贪吃蛇是否存活模块。
(6) 获取贪吃蛇速度模块。
(7) 移动窗口光标模块。
(8) 帮助系统模块
(9) 退出系统模块
3. 课程设计的功能要求
3.1. 页面菜单模块:
² 开始游戏
² 退出游戏
3.2. 初始化地图模块:
² 实现贪吃蛇存在范围(这里用围墙来限定区域)
² 初始化贪吃蛇(3单位身体长度)
² 初始化食物
3.3. 食物更新模块:
² 在区域内随机刷新食物
² 食物不与蛇身体重合
3.4. 移动贪吃蛇模块:
² 根据玩家按键移动贪吃蛇(w,s,a,d)
² Space 空格可暂停或继续游戏
² 当贪吃蛇前进时按相反方向移动无效
² 除了程序控制键之外的其他按键不会影响贪吃蛇
² 移动贪吃蛇时不会造成屏幕闪烁BUG
3.5. 贪吃蛇生命模块:
² 当蛇吃到自己身体或者触碰围墙时蛇死亡
3.6. 获取贪吃蛇速度模块:
² 根据蛇的身体长度来设置速度等级
² 当身体长度足够长时则通关游戏
3.7. 移动光标模块:
² 获取输出流窗口句柄
² 定义使用存储坐标结构体
² 将坐标与窗口句柄传入函数实现移动光标
3.8. 帮助系统模块:
² 提示玩家一些按键控制和游戏规则
3.9. 退出系统模块:
² 游戏通关或游戏结束时给予退出或重玩选择
4. 概要设计
4.1. 系统功能框架图
图1 系统功能模块图
4.2. 各功能模块描述:
4.3. 页面菜单模块:
² 开始游戏
² 退出游戏
4.4. 初始化地图模块:
² 实现贪吃蛇存在范围(这里用围墙来限定区域)
² 初始化贪吃蛇(3单位身体长度)
² 初始化食物
4.5. 食物更新模块:
² 在区域内随机刷新食物
² 食物不与蛇身体重合
4.6. 移动贪吃蛇模块:
² 根据玩家按键移动贪吃蛇(w,s,a,d)
² Space 空格可暂停或继续游戏
² 当贪吃蛇前进时按相反方向移动无效
² 除了程序控制键之外的其他按键不会影响贪吃蛇
² 移动贪吃蛇时不会造成屏幕闪烁BUG
4.7. 贪吃蛇生命模块:
² 当蛇吃到自己身体或者触碰围墙时蛇死亡
4.8. 获取贪吃蛇速度模块:
² 根据蛇的身体长度来设置速度等级
² 当身体长度足够长时则通关游戏
4.9. 移动光标模块:
² 获取输出流窗口句柄
² 定义使用存储坐标结构体
² 将坐标与窗口句柄传入函数实现移动光标
4.10. 帮助系统模块:
² 提示玩家一些按键控制和游戏规则
4.11. 退出系统模块:
² 游戏通关或游戏结束时给予退出或重玩选择
5. 详细设计
- 思想:一条蛇可以看成由许多正方形的“小格子”拼凑成,称作节。节是蛇身上最小的单位。通过移动窗口光标来打印蛇。
- 参考资料:《徐飞机博客园》,网上资料,《c语言程序设计》,《windows程序设计》
- 基本设计理念:程序关键在于表示蛇的图形及蛇的移动。用一个@字符表示蛇的一节身体,身体每长一节,在身体最后增加一个@。移动时必须从蛇头开始,所以蛇不能向相反的方向移动,如果不按任意键,蛇自行在当前方向上前移,但按下有效方向键后,蛇头朝着该方向移动,一步移动一节身体,所以按下有效方向键后,先确定蛇头的位置,而后蛇的身体随蛇头移动,图形的实现是吃到食物就在下一个坐标信息加一个@, 没吃到食物就将尾巴置空,蛇头前在加一个@,蛇的XY数组长度为保存蛇每个节点的信息。食物的出现是先确定一组随机数,再填充方格,食物的消失是由于被蛇身体覆盖,当吃掉食物后就不再重画本次食物,而是生成一组新的随机数,画新的食物。当蛇头的位置坐标和围墙的坐标或者自己身体的某个节点的坐标相同时,蛇就死掉了,游戏结束。
- 代码模块示意:
//Initialization map
void initMap(void);
//updataFood
void updataFood(void);
//moveSnake
void moveSnake(void);
//Judge whether the snake is alive or not
int isAlive(void);
//get snake speed
void getSpeed(void);
//move cursor
void gotoxy(int x, int y);
//Right interface
void printFont(int x, int y, int speed);
//menu
int menu();
5.1. 各功能模块的具体实现算法——流程图
5.1.1. 主控main函数流程图
图2 主控main函数流程图
5.2. 重点设计描述
Gotoxy();函数来实现打印贪吃蛇整个程序的光标移动,在里面我们首先获取到输出流缓冲区的窗口句柄,然后在根据结构体存储X,Y坐标信息来实现整个窗口的光标移动
控制蛇的移动模块moveSnake();这里在下根据grow值来判断是否吃到食物,并实现打印贪吃蛇的移动,贪吃蛇的移动只打印头部和尾部,这样防止了每次刷新页面造成的闪烁。当grow为0的时候代表没有吃到食物,先移动光标到蛇尾将蛇尾置空,然后根据位置信息在蛇头前加一个节点@,代表这个蛇往前移动了一个节点单位。当grow为1时则不对尾部进行操作,直接根据XY数组信息进行添加一个@节点代表蛇的移动。
另外在移动蛇里我加了一些判断限制,避免了除系统指定按键之外按键的干扰导致程序提前终止,也加了一些过滤判断,比如当蛇向上移动时,不能直接向下移动。
当按空格键的时候可以实现贪吃蛇游戏的暂停和继续。
6. 系统测试与调试
在调试贪吃蛇的过程中主要出现以下几个BUG:
第一:一开始调试时连续快速的按某个方向键会使程序崩溃(原因是程序内部没有进行过滤操作),此问题已经解决。
第二:当贪吃蛇向上移动时,按下方向键程序奔溃游戏结束(原因是无过滤操作),此问题已解决。
第三:贪吃蛇在移动的时候窗口会不断闪烁,影响游戏体验(原因是每次都打印一条蛇,导致整个窗口刷新),此问题已解决。
第四:有时蛇的长度会自己增加(原因食物出现与身体重合),此问题已经解决。
第五:主main函数文件调用其他文件变量时无法调用(原因没有用extern进行转置跨文件调用)
7. 课程设计心得体会
通过这次课程设计,我对c语言又有了更深刻的认识。也有了更深一步的喜爱,决定一定要努力学好c语言,并能更好的应用于以后的学习工作中。
这次贪吃蛇的设计,做的不是很完美,也没想象中的那么好,但也获得了许多宝贵的经验:
1) 在设计程序之前,务必要对自己所要设计的题目和内容有一个系统的,大概的了解,知道所设计的题目和内容包含哪些资源。
2) 设计程序采用什么编程语言并不是非常重要,关键是要有一个清晰的思路和一个完整的软件流程图,所有要先把设计原理与思路搞清楚,再把流程图画出来,这样设计起来就简单多了。
参考资料
[1] 《Windows程序设计》
[2] 《c语言程序设计》