适合新手的基础版贪吃蛇
<graphics.h>必须得安装easyx,挺简单的,还有官方文档
snake.h
/*
绘制蛇身的头文件
*/
#pragma once
#include <graphics.h>
#include <stdlib.h>
/*
贪吃蛇使用链表实现
蛇身就是一个一个的点连起来
每一个点的定义如下
x坐标,y坐标以及到下一个点的指针
*/
typedef struct snake_node
{
int x;
int y;
snake_node *next;
}Node;
/*
定义蛇走的方向: L-left R-right T-top B-bottom D-未赋值
*/
enum direction {L, R, T, B, D};
/*
贪吃蛇的每一个点用正方形实现
定义正方形的边长SIDE
*/
#define SIDE 20
/*
初始长度INITLENGTH
*/
#define INITLENGTH 5
/*
获得蛇头
*/
Node* get_head();
/*
获得蛇身长度
*/
int get_body();
/*
设置蛇身长度
*/
int get_body();
/*
设置蛇头方向
*/
void set_dir(direction d);
/*
获得蛇头方向
*/
direction get_dir();
/*
初始化蛇身
*/
void init_snake();
/*
绘画蛇身
*/
void paint_snake();
/*
重置贪吃蛇
*/
void reset_snake(int new_x, int new_y);
/*
移动贪吃蛇
*/
void move_snake();
/*
增加蛇的长度
*/
void add_snake();
snake.cpp
#include "snake.h"
/*
定义蛇头,因为是链表,有蛇头就能够访问整个蛇
*/
Node *head;
/*
当前蛇的长度
*/
int body;
/*
蛇头的方向
*/
direction dir = R;
/*
获得蛇头
*/
Node* get_head()
{
return head;
}
/*
获得蛇身长度
*/
int get_body()
{
return body;
}
/*
设置蛇身长度
*/
void set_body(int l)
{
body = l;
}
/*
获得蛇头方向
*/
direction get_dir()
{
return dir;
}
/*
设置蛇头方向
*/
void set_dir(direction d)
{
dir = d;
}
/*
初始化蛇身的某一个结点
*/
void init_node(Node *node, int x_cor, int y_cor)
{
node->x = x_cor;
node->y = y_cor;
node->next = (Node *)malloc( sizeof(Node) );
}
/*
初始化蛇身
*/
void init_snake()
{
// 游标cur从蛇头开始,遍历整个蛇身
// 界面是 600*600 的,一个单元格是20为边长的,整个界面也就是 30*30的
// 蛇的初始位置在 (6,6),一条横向的蛇,蛇头向右
// 把蛇的蛇身长度设置为初始长度
// 蛇尾的下一个结点是空
Node *cur;
int init_x = 7 * SIDE;
int init_y = 7 * SIDE;
int count = 0;
body = INITLENGTH;
head = (Node *)malloc( sizeof(Node) );
cur = head;
while ( count < INITLENGTH )
{
init_node(cur, init_x, init_y);
init_x -= SIDE;
cur = cur->next;
count++;
}
cur->next = NULL;
}
/*
绘制贪吃蛇蛇身
*/
void paint_snake()
{
// 遍历蛇身,把每个点用矩形画出来
int left;
int right;
int top;
int bottom;
int count = 0;
Node *cur;
cur = head;
while ( count < body )
{
left = cur->x;
top = cur->y;
right = cur->x + SIDE;
bottom = cur->y + SIDE;
setfillcolor(GREEN);
fillrectangle(left, top, right, bottom);
cur = cur->next;
count++;
}
}
/*
重置贪吃蛇
*/
void reset_snake(int new_x, int new_y)
{
// 蛇头的新位置就是传进来的参数
// 蛇身是链表,旧蛇头的每一个点的坐标都设置为它们前一项的点的坐标
Node *cur;
int setx = new_x;
int sety = new_y;
int savex;
int savey;
int count = 0;
cur = head;
while (count < body)
{
// 重置的过程
// 每次都是先保存,再赋值,然后把这次保存的置为下次赋值的
// 保存的坐标用savex,savey,赋值的坐标用setx,sety
savex = cur->x;
savey = cur->y;
cur->x = setx;
cur->y = sety;
setx = savex;
sety = savey;
cur = cur->next;
count++;
}
}
/*
移动贪吃蛇
*/
void move_snake()
{
// 根据当前方向重置蛇头坐标
int head_x = head->x;
int head_y = head->y;
switch (dir)
{
case L:
head_x -= SIDE;
break;
case R:
head_x += SIDE;
break;
case T:
head_y -= SIDE;
break;
case B:
head_y += SIDE;
break;
default:
break;
}
reset_snake(head_x, head_y);
}
/*
增加蛇的长度
*/
void add_snake()
{
// 找到蛇的最后两个结点
// 根据最后两个结点的坐标关系决定新增结点的坐标
Node *cur;
int tail_x;
int tail_y;
int front_x;
int front_y;
int new_x;
int new_y;
int count = 0;
// 找到最后两个点
cur = head;
while ( count < body )
{
if ( count == (body-2) )
{
front_x = cur->x;
front_y = cur->y;
}
if (count == (body - 1))
{
tail_x = cur->x;
tail_y = cur->y;
cur->next = (Node*)malloc(sizeof(Node));
}
cur = cur->next;
count++;
}
// 决定新增节点的坐标
if ( tail_x == front_x )
{
new_x = tail_x;
if ( tail_y > front_y )
{
new_y = tail_y + SIDE;
}
else if ( tail_y < front_y )
{
new_y = tail_y - SIDE;
}
}
else if (tail_y == front_y)
{
new_y = tail_y;
if ( tail_x < front_x )
{
new_x = tail_x - SIDE;
}
else if (tail_x > front_x)
{
new_x = tail_x + SIDE;
}
}
// 新增节点
cur->x = new_x;
cur->y = new_y;
cur->next = NULL;
body++;
}
apple.h
/*
绘制苹果的头文件
*/
#pragma once
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include "snake.h"
#include "background.h"
/*
生成苹果
*/
void create_apple();
/*
绘制苹果
*/
void paint_apple();
/*
返回苹果变量的坐标
*/
void get_apple(int *apple_x, int *apple_y);
apple.cpp
/*
绘制苹果
*/
#include "apple.h"
/*
定义一个苹果,苹果只包含横纵坐标
*/
struct Apple
{
int x;
int y;
}apple;
/*
生成一个苹果,用随机数
*/
void create_apple()
{
// 生成两个 0~29 的随机数,作为苹果左上角点的坐标
// 如果这个坐标是蛇身中的某一个点,那么重新生成
int unit_length = (LENGTH - 2*SIDE) / SIDE;
int apple_x;
int apple_y;
int count = 0;
Node *cur;
while (1)
{
apple_x = rand() % unit_length + 1;
apple_y = rand() % unit_length + 1;
cur = get_head();
while ( count < get_body() )
{
if ( ( apple_x * SIDE == cur->x )
&& ( apple_y * SIDE == cur->y ) )
{
break;
}
cur = cur->next;
count++;
}
// 直到蛇身最后一个位置都不与生成的坐标重合,那么count才会加到body
if (count == get_body())
{
break;
}
}
apple.x = apple_x * SIDE;
apple.y = apple_y * SIDE;
}
/*
把苹果变量作为矩形绘制出来
*/
void paint_apple()
{
int left = apple.x;
int top = apple.y;
int right = apple.x + SIDE;
int bottom = apple.y + SIDE;
setfillcolor(RED);
fillrectangle(left, top, right, bottom);
}
/*
返回苹果坐标
*/
void get_apple(int *apple_x, int *apple_y)
{
*apple_x = apple.x;
*apple_y = apple.y;
}
background.h
/*
绘制背景的头文件
*/
#pragma once
#include <graphics.h>
#include <stdio.h>
#include "snake.h"
#include "apple.h"
// 定义游戏界面的长和宽
#define LENGTH 32*SIDE
#define WIDTH 32*SIDE
/*
获得游戏分数
*/
int get_score();
/*
设置游戏分数
*/
void set_score(int s);
/*
重绘背景
*/
void redraw();
/*
初始化背景
*/
void init();
/*
欢迎界面
*/
void welcome();
/*
创建画布
*/
void create_picture();
/*
游戏结束
*/
void end_game();
background.cpp
/*
绘制贪吃蛇游戏的背景
*/
#include "background.h"
/*
游戏记分器
*/
int score = 0;
/*
获得游戏分数
*/
int get_score()
{
return score;
}
/*
设置游戏分数
*/
void set_score(int s)
{
score = s;
}
/*
绘制边界线
*/
void paint_frontier()
{
setlinecolor(GREEN);
line(SIDE, SIDE, SIDE, 31 * SIDE);
line(SIDE, SIDE, 31 * SIDE, SIDE);
line(SIDE, 31 * SIDE, 31 * SIDE, 31 * SIDE);
line(31 * SIDE, SIDE, 31 * SIDE, 31 * SIDE);
setlinecolor(WHITE);
}
/*
绘制游戏分数
*/
void paint_score()
{
TCHAR s[5];
_stprintf_s(s, _T("%d"), score);
setcolor(WHITE);
settextstyle(24, 0, _T("Consolas"));
outtextxy(31 * SIDE, 0, s);
}
/*
重新绘制背景
*/
void redraw()
{
cleardevice();
paint_frontier();
paint_apple();
paint_snake();
paint_score();
}
/*
初始化背景
*/
void init()
{
cleardevice();
// 画边界
paint_frontier();
// 初始化蛇
init_snake();
paint_snake();
// 初始化苹果
create_apple();
paint_apple();
// 初始化分数
paint_score();
}
/*
欢迎界面
*/
void welcome()
{
TCHAR sentence1[] = "welcome to snake";
TCHAR sentence2[] = "conduction:use 'wsad' to control directory";
TCHAR sentence3[] = "press any key to continue……";
setcolor(GREEN);
settextstyle(16, 0, _T("Consolas"));
outtextxy(10 * SIDE, 10 * SIDE, sentence1);
outtextxy(10 * SIDE, 11 * SIDE, sentence2);
outtextxy(10 * SIDE, 12 * SIDE, sentence3);
}
/*
创建画布
*/
void create_picture()
{
// 画背景
initgraph(LENGTH, WIDTH);
setbkcolor(BLACK);
cleardevice();
}
/*
游戏结束
*/
void end_game()
{
TCHAR sentence1[] = "Game over";
setcolor(RED);
settextstyle(72, 0, _T("Consolas"));
outtextxy(10 * SIDE, 10 * SIDE, sentence1);
}
brain.h
/*
游戏逻辑的头文件
*/
#pragma once
#include <graphics.h>
#include <conio.h>
#include <Windows.h>
#include "snake.h"
#include "apple.h"
#include "background.h"
/*
运行游戏
*/
void play();
brain.cpp
/*
控制游戏逻辑
*/
#include "brain.h"
/*
游戏结束的标志,结束为1,否则为0
*/
int end = 0;
/*
检测输入方向
*/
int check_direction(direction dir)
{
// 如果输入的是当前的反方向,返回0
int result = 1;
switch ( get_dir() )
{
case L:
if ( R == dir )
{
result = 0;
}
break;
case R:
if ( L == dir )
{
result = 0;
}
break;
case T:
if ( B == dir )
{
result = 0;
}
break;
case B:
if ( T == dir )
{
result = 0;
}
break;
default:
break;
}
return result;
}
/*
检测游戏结束条件
*/
void check_end()
{
// 蛇头的坐标与蛇身链表里的某一点相同,结束
// 蛇身的横纵坐标超过 29*SIDE ,结束
Node *cur;
int count = 0;
int head_x;
int head_y;
cur = get_head();
head_x = cur->x;
head_y = cur->y;
while ( count < get_body() )
{
// 前四行是越界,最后一行是撞到身体
if ( ( cur->x > 30 * SIDE )
|| ( cur->y > 30 * SIDE )
|| ( cur->x < 1 )
|| ( cur->y < 1 )
|| ( ( cur->x == head_x) && ( cur->y == head_y) && ( count > 0 ) )
)
{
end = 1;
break;
}
cur = cur->next;
count++;
}
}
/*
检测是否得分
*/
void check_score()
{
// 苹果的坐标与蛇头相同
// 重新显示得分,并且重新生成苹果
int apple_x;
int apple_y;
int score = get_score();
Node *head = get_head();
get_apple(&apple_x, &apple_y);
if ( ( apple_x == head->x ) && ( apple_y == head->y ) )
{
score++;
set_score(score);
add_snake();
create_apple();
redraw();
}
}
/*
改变蛇头方向
*/
void change_direction()
{
direction dir = D;
char inputch;
// 敲击键盘才执行以下语句
if ( _kbhit() )
{
inputch = _getch();
// 根据键盘输入 w,s,a,d 设置dir变量的值
switch (inputch)
{
case 'a':
dir = L;
break;
case 'A':
dir = L;
break;
case 'd':
dir = R;
break;
case 'D':
dir = R;
break;
case 'w':
dir = T;
break;
case 'W':
dir = T;
break;
case 's':
dir = B;
break;
case 'S':
dir = B;
break;
default:
break;
}
// 输入相反方向不做操作
if (!check_direction(dir))
{
return;
}
// 蛇移动:设置方向,移动,看是否得分,看游戏是否结束
if (!(D == dir))
{
set_dir(dir);
move_snake();
check_score();
check_end();
if (end)
{
return;
}
redraw();
}
}
}
/*
重置游戏
*/
void reset_game()
{
end = 0;
set_score(0);
}
/*
运行游戏
*/
void play()
{
while (1)
{
// 创建画布
create_picture();
// 欢迎界面
welcome();
_getch();
// 初始化页面
init();
// 执行游戏
while (1)
{
// 改变蛇头方向
change_direction();
// 没结束蛇自动向前移动
Sleep(250);
move_snake();
check_score();
check_end();
// 判断是否结束游戏
if (end)
{
break;
}
redraw();
}
// 游戏结束
end_game();
_getch();
reset_game();
closegraph();
}
}
main.cpp
/*
游戏入口文件
*/
#include "brain.h"
int main()
{
play();
return 0;
}