C语言结构数组实现贪吃蛇小游戏攻略
前言
贪吃蛇是一种经典的小游戏,类似于蛇果子等。在游戏中,玩家需要控制蛇吃掉食物,并不断地变长,直到撞墙或撞到自己的身体为止。这个游戏对于程序员来说是一个很好的练手项目,也是锻炼从事编程工作所需的基本能力必不可少的一步。在本文中,我们将详细讲解如何使用C语言结构数组实现贪吃蛇小游戏。
开发环境准备
在实现这个小游戏前,我们需要一些开发环境的准备。首先需要安装Code::Blocks和Dev-C++两个IDE,以及游戏需要的Windows库文件。
- Code::Blocks下载地址:https://www.codeblocks.org/downloads/binaries/
- Dev-C++下载地址:https://sourceforge.net/projects/orwelldevcpp/
- Windows库文件下载地址:https://www.mediafire.com/file/zh4adh6l1msthz5/windows_lib_files.zip/file
下载完之后解压缩到C盘根目录下。
完整代码
以下是实现贪吃蛇小游戏的完整代码。代码注释翻译如下:
#include<graphics.h>
#include<conio.h>
#include<time.h>
#define DELAY 100
#define HEIGHT 30
#define WIDTH 30
#define SNAKE_LEN_MAX (HEIGHT-2)*(WIDTH-2)
/*结构体:坐标位置*/
struct point {
int x;
int y;
};
/*枚举类型:方向*/
enum direction {
UP,
DOWN,
LEFT,
RIGHT,
STOP
};
/*全局变量*/
int HEIGHT_PIXEL;
int WIDTH_PIXEL;
int CELL_SIZE;
int DELAY_TIME;
int MOVE_SPEED;
int SCORE;
int SNAKE_LEN;
struct point snake[SNAKE_LEN_MAX+1];
struct point food;
enum direction dir;
/*函数原型*/
void init(); /*初始化*/
void add_a_food(); /*添加一个食物*/
void move(); /*蛇移动*/
void change_dir(); /*改变蛇的移动方向*/
int is_snake_hit_wall(); /*判断蛇是否撞墙*/
int is_snake_hit_food(); /*判断蛇是否撞到食物*/
int is_snake_hit_self(); /*判断蛇是否撞到自己*/
void game_over(); /*游戏结束*/
void draw_score(); /*画分数*/
void draw_food(); /*画食物*/
void draw_snake_head(); /*画蛇头*/
void draw_snake_tail(); /*画蛇尾*/
void draw_snake_body(); /*画蛇身*/
void draw_snake(); /*画整条蛇*/
void draw_string(); /*画字符串*/
int main()
{
init();
while(1) {
add_a_food();
while(!kbhit()) {
move();
delay(DELAY_TIME);
}
change_dir();
if(is_snake_hit_wall() || is_snake_hit_self()) {
game_over();
break;
}
if(is_snake_hit_food()) {
SCORE++;
SNAKE_LEN++;
if(SNAKE_LEN > SNAKE_LEN_MAX) {
game_over();
break;
}
add_a_food();
}
cleardevice();
draw_snake();
draw_food();
draw_score();
}
getch();
return 0;
}
void init()
{
int mousex, mousey;
/*初始化图形库*/
initgraph(&mousex, &mousey, "C:\\WINDOWS\\system32\\msimg32.dll"); /*此处是Windows基础库文件,需要判断文件位置*/
/*设置窗口大小*/
HEIGHT_PIXEL = 500;
WIDTH_PIXEL = 500;
setaspectratio(1,1);
setbkcolor(BLACK);
cleardevice();
/*设置游戏速度*/
MOVE_SPEED = 6;
DELAY_TIME = 1000/MOVE_SPEED;
/*初始化蛇身*/
SNAKE_LEN = 1;
snake[1].x = WIDTH/2;
snake[1].y = HEIGHT/2;
/*初始化方向*/
dir = LEFT;
}
void add_a_food()
{
struct point temp;
/*随机生成一个食物坐标(不能在蛇身上)*/
while(1) {
temp.x = 1 + rand() % (WIDTH-2);
temp.y = 1 + rand() % (HEIGHT-2);
for(int i =1; i <= SNAKE_LEN; i++) {
if(snake[i].x == temp.x && snake[i].y == temp.y) {
temp.x = 0;
temp.y = 0;
break;
}
}
if(temp.x != 0) {
break;
}
}
/*将随机生成的食物坐标赋值给全局变量*/
food.x = temp.x;
food.y = temp.y;
}
void move()
{
/*将蛇尾设为蛇头*/
for(int i = SNAKE_LEN; i > 0; i--) {
snake[i] = snake[i-1];
}
/*根据方向改变蛇头位置*/
switch(dir) {
case UP:
snake[1].y--;
break;
case DOWN:
snake[1].y++;
break;
case LEFT:
snake[1].x--;
break;
case RIGHT:
snake[1].x++;
break;
case STOP:
break;
default:
break;
}
}
void change_dir()
{
/*改变移动方向*/
if(kbhit()) {
int input = getch();
switch(input) {
case 'w':
case 'W':
case 72: /*方向键上*/
if(dir != DOWN)
dir = UP;
break;
case 's':
case 'S':
case 80: /*方向键下*/
if(dir != UP)
dir = DOWN;
break;
case 'a':
case 'A':
case 75: /*方向键左*/
if(dir != RIGHT)
dir = LEFT;
break;
case 'd':
case 'D':
case 77: /*方向键右*/
if(dir != LEFT)
dir = RIGHT;
break;
case 27:
dir = STOP;
break;
default:
break;
}
}
}
int is_snake_hit_wall()
{
/*判断是否撞墙*/
if(snake[1].x == 0 || snake[1].x == (WIDTH-1) || snake[1].y == 0 || snake[1].y == (HEIGHT-1)) {
return 1;
}
return 0;
}
int is_snake_hit_food()
{
/*判断是否吃到食物*/
if(snake[1].x == food.x && snake[1].y == food.y) {
return 1;
}
return 0;
}
int is_snake_hit_self()
{
/*判断是否撞到自己*/
for(int i=2; i <= SNAKE_LEN; i++) {
if(snake[1].x == snake[i].x && snake[1].y == snake[i].y) {
return 1;
}
}
return 0;
}
void game_over()
{
draw_string("Game Over", WIDTH/2, HEIGHT/2);
getch();
}
void draw_score()
{
char score_str[10];
sprintf(score_str, "Score:%d", SCORE);
draw_string(score_str, 1, 1);
}
void draw_food()
{
setfillstyle(SOLID_FILL, YELLOW);
setcolor(YELLOW);
fillellipse(food.x * CELL_SIZE, food.y * CELL_SIZE, CELL_SIZE/2, CELL_SIZE/2);
}
void draw_snake_head()
{
setfillstyle(SOLID_FILL, GREEN);
setcolor(GREEN);
fillellipse(snake[1].x * CELL_SIZE, snake[1].y * CELL_SIZE, CELL_SIZE/2, CELL_SIZE/2);
}
void draw_snake_tail()
{
setfillstyle(SOLID_FILL, BLACK);
setcolor(BLACK);
bar(snake[SNAKE_LEN].x * CELL_SIZE, snake[SNAKE_LEN].y * CELL_SIZE, (snake[SNAKE_LEN].x+1) * CELL_SIZE, (snake[SNAKE_LEN].y+1) * CELL_SIZE);
}
void draw_snake_body(int i)
{
setfillstyle(SOLID_FILL, GREEN);
setcolor(GREEN);
bar(snake[i].x * CELL_SIZE, snake[i].y * CELL_SIZE, (snake[i].x+1) * CELL_SIZE, (snake[i].y+1) * CELL_SIZE);
}
void draw_snake()
{
draw_snake_head();
for(int i = 2; i < SNAKE_LEN; i++) {
draw_snake_body(i);
}
draw_snake_tail();
}
void draw_string(char *str, int x, int y)
{
outtextxy(x*CELL_SIZE, y*CELL_SIZE, str);
}
整体思路
本篇文章使用结构体数组来实现贪吃蛇小游戏。在游戏中,使用全局变量来存储对游戏状态的控制和存储蛇的位置、食物的位置、本局游戏得分等信息。在每一个游戏循环内,我们需要判断以下几个事项:
- 是否添加了食物
- 是否需要移动蛇的位置
- 是否撞到了墙或自己,如果是,则游戏结束
- 是否撞到了食物
对于以上每一个判断条件,我们都可以为之定义一个函数。同时,使用图形处理库来绘制游戏界面。当蛇移动时,会先把蛇尾的位置删除,再新生成一条蛇头。
示例说明
示例1
下面是一个简单的实例,当蛇移动时,它的头部始终向右:
void move()
{
/*将蛇尾设为蛇头*/
for(int i = SNAKE_LEN; i > 0; i--) {
snake[i] = snake[i-1];
}
/*改变蛇头位置*/
snake[1].x++;
}
示例2
下面是一个更复杂的示例,当蛇头受到用户控制改变方向时,蛇会按照改变后的方向移动:
void change_dir()
{
/*改变移动方向*/
if(kbhit()) {
int input = getch();
switch(input) {
case 'w':
case 'W':
case 72: /*方向键上*/
if(dir != DOWN)
dir = UP;
break;
case 's':
case 'S':
case 80: /*方向键下*/
if(dir != UP)
dir = DOWN;
break;
case 'a':
case 'A':
case 75: /*方向键左*/
if(dir != RIGHT)
dir = LEFT;
break;
case 'd':
case 'D':
case 77: /*方向键右*/
if(dir != LEFT)
dir = RIGHT;
break;
case 27:
dir = STOP;
break;
default:
break;
}
}
}
void move()
{
/*将蛇尾设为蛇头*/
for(int i = SNAKE_LEN; i > 0; i--) {
snake[i] = snake[i-1];
}
/*根据方向改变蛇头位置*/
switch(dir) {
case UP:
snake[1].y--;
break;
case DOWN:
snake[1].y++;
break;
case LEFT:
snake[1].x--;
break;
case RIGHT:
snake[1].x++;
break;
case STOP:
break;
default:
break;
}
}
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言结构数组实现贪吃蛇小游戏 - Python技术站