软件使用
EasyX、VS2013
效果图
具体实现
地图用数组实现,效果图中每个小方格其实都是数组中的一个元素。当然这里用的是二维数组,初始化为0,而刚开始的蛇就是数组中的一串数字12345,1是蛇头,5是蛇尾。除蛇以外的所有元素都是0。而蛇的移动由不停改变这串数字的位置实现,具体实现为令每个数字都自增1,由此变成为23456,在2前面的元素变为1,再将6变成0,这就实现了蛇往前走一步的动作,不停的重复这个操作就实现了蛇的移动。
源代码version1.0
增加了随着蛇长度增长,移动速度变快的设定
修复了食物会出现在蛇身上的bug(增添一个散列表isSnake,蛇身都映射为true,而食物只会出现在false的位置)
修复了蛇往反方向运动时导致游戏失败的bug(每次按一个键都判断这个方向蛇头的前方是否为蛇身)
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define HEIGHT 30
#define WIDTH 40
#define BLOCK_SIZE 20
char moveDirection;
int snakeLen = 5, velocity = 35, nowHead_i, nowHead_j;
int food_i, food_j;
bool isFailure = false, flag;
int Blocks[HEIGHT][WIDTH] = { 0 };
bool isSnake[HEIGHT][WIDTH];
void start();
void draw_map();
void move_snake();
void updateWithInput();
void updateWithoutInput();
int main()
{
start();
while (1)
{
draw_map();
updateWithoutInput();
updateWithInput();
}
return 0;
}
void start()
{
//food
food_i = rand() % (HEIGHT - 5) + 2;
food_j = rand() % (WIDTH - 5) + 2;
//snake
Blocks[HEIGHT / 2][WIDTH / 2] = 1; //初始蛇头的位置
isSnake[HEIGHT / 2][WIDTH / 2] = true;
for (int i = 1; i < snakeLen; i++)
{
Blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1; //初始蛇身
isSnake[HEIGHT / 2][WIDTH / 2 - i] = true;
}
moveDirection = 'd'; //初始方向是右
initgraph(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE);
setlinecolor(RGB(200, 200, 200));
BeginBatchDraw();
}
void draw_map()
{
cleardevice();
//snake
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (Blocks[i][j] > 0)
setfillcolor(BLACK); //蛇用黑色表示
else
setfillcolor(RGB(150, 150, 150)); //除蛇以外的方块都是灰色
fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); //绘制地图
}
}
//绘制食物
setfillcolor(GREEN);
fillrectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, (food_j + 1) * BLOCK_SIZE, (food_i + 1) * BLOCK_SIZE);
if (isFailure) //如果游戏结束,输出文字
{
setbkmode(TRANSPARENT);
settextcolor(RGB(250, 0, 0));
settextstyle(80, 0, _T("宋体"));
outtextxy(350, 220, _T("菜"));
}
FlushBatchDraw();
}
void move_snake()
{
//令每个数字自增1
for (int i = 0; i < HEIGHT; i++)
for (int j = 0; j < WIDTH; j++)
if (Blocks[i][j] > 0)
Blocks[i][j]++;
int old_tail_i, old_tail_j, old_head_i, old_head_j;
int maxn = 0;
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (Blocks[i][j] > maxn) //这个if用来找蛇尾
{
maxn = Blocks[i][j];
old_tail_i = i;
old_tail_j = j;
}
if (Blocks[i][j] == 2) //这个if用来找蛇头
{
old_head_i = i;
old_head_j = j;
}
}
}
int new_head_i = old_head_i;
int new_head_j = old_head_j;
//改变方向
if (moveDirection == 'w')
new_head_i = old_head_i - 1;
else if (moveDirection == 'a')
new_head_j = old_head_j - 1;
else if (moveDirection == 's')
new_head_i = old_head_i + 1;
else if (moveDirection == 'd')
new_head_j = old_head_j + 1;
if (new_head_i >= HEIGHT || new_head_i < 0 || new_head_j < 0 || new_head_j >= WIDTH || Blocks[new_head_i][new_head_j] > 0)
{
//碰到身子或者出界则游戏结束
isFailure = true;
return;
}
nowHead_i = new_head_i;
nowHead_j = new_head_j;
Blocks[new_head_i][new_head_j] = 1;
isSnake[new_head_i][new_head_j] = true;
if (new_head_i == food_i && new_head_j == food_j)
{
//如果蛇头在食物的位置,就代表吃到了
//则重新生成食物,并且蛇身变成(蛇尾不用变成0)
food_i = rand() % (HEIGHT - 5) + 2;
food_j = rand() % (WIDTH - 5) + 2;
while (isSnake[food_i][food_j])
{
food_i = rand() % (HEIGHT - 5) + 2;
food_j = rand() % (WIDTH - 5) + 2;
}
snakeLen += 1;
flag = true;
}
else
{
//如果没吃到食物,蛇尾变0
Blocks[old_tail_i][old_tail_j] = 0;
isSnake[old_tail_i][old_tail_j] = false;
}
}
void updateWithInput()
{
if (_kbhit() && !isFailure)
{
char input = _getch();
if (input == 'w' && Blocks[nowHead_i - 1][nowHead_j] == 0)
{
moveDirection = input;
move_snake();
}
else if (input == 'a' && Blocks[nowHead_i][nowHead_j - 1] == 0)
{
moveDirection = input;
move_snake();
}
else if (input == 's' && Blocks[nowHead_i + 1][nowHead_j] == 0)
{
moveDirection = input;
move_snake();
}
else if (input == 'd' && Blocks[nowHead_i][nowHead_j + 1] == 0)
{
moveDirection = input;
move_snake();
}
}
}
void updateWithoutInput()
{
if (isFailure)
return;
static int waitIndex = 1;
waitIndex++;
//控制蛇身移动速度,waitIndex每到达velocity则移动一次
//所以velocity越小,移动频率越高,速度越快
if (waitIndex == velocity)
{
move_snake();
waitIndex = 1;
if (flag && snakeLen >= 10 && snakeLen % 5 == 0)
//蛇身超过10并且能被5整除,则速度增加
{
velocity -= 5;
if (velocity <= 5)
velocity = 5;
flag = false;
}
}
}
源代码version2.0
蛇有了皮肤
去掉按住一个方向键会加速的设定
去掉原先随着蛇身变长,移动速度变快的设定,改为随机生成加速食物(红)、减速食物(蓝)和普通食物(绿)
修复了刚开始游戏按a会直接游戏结束的bug(因为nowHead_i和nowHead_j没有初始化为HEIGHT / 2和WIDTH / 2)
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define HEIGHT 30
#define WIDTH 40
#define BLOCKSIZE 20
char moveDirection;
bool fast_food, slow_food;
int food_i, food_j;
int nowHead_i, nowHead_j, velocity = 20, step;
bool isFailure;
int map[HEIGHT][WIDTH];
bool isSnake[HEIGHT][WIDTH];
void start();
void draw_map();
void move_snake();
void updateWithoutInput();
void updateWithInput();
void creatFood();
int main()
{
start();
while (1)
{
if (step == 30)
{
//去除食物给的加速\减速效果
step = 0;
velocity = 20;
}
draw_map();
updateWithoutInput();
updateWithInput();
}
_getch();
closegraph();
return 0;
}
void start()
{
//snake
map[HEIGHT / 2][WIDTH / 2] = 1;
for (int i = 1; i < 5; i++)
{
map[HEIGHT / 2][WIDTH / 2 - i] = i + 1;
isSnake[HEIGHT / 2][WIDTH / 2 - i] = true;
}
moveDirection = 'd';
//food
creatFood();
initgraph(WIDTH * BLOCKSIZE, HEIGHT * BLOCKSIZE);
setlinecolor(RGB(200, 200, 200));
BeginBatchDraw();
}
void draw_map()
{
cleardevice();
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (map[i][j] > 0)
setfillcolor(HSVtoRGB(map[i][j] * 10, 0.9, 1));
else
setfillcolor(RGB(125, 125, 125));
fillrectangle(j * BLOCKSIZE, i * BLOCKSIZE, (j + 1) * BLOCKSIZE, (i + 1) * BLOCKSIZE);
}
}
if (fast_food)
setfillcolor(RED);
else if (slow_food)
setfillcolor(BLUE);
else
setfillcolor(GREEN);
fillrectangle(food_j * BLOCKSIZE, food_i * BLOCKSIZE, (food_j + 1) * BLOCKSIZE, (food_i + 1) * BLOCKSIZE);
if (isFailure)
{
setbkmode(TRANSPARENT);
settextcolor(RGB(250, 0, 0));
settextstyle(80, 0, _T("宋体"));
outtextxy(350, 220, _T("菜"));
}
FlushBatchDraw();
}
void move_snake()
{
for (int i = 0; i < HEIGHT; i++)
for (int j = 0; j < WIDTH; j++)
if (map[i][j] > 0)
map[i][j]++;
int old_head_i, old_head_j, old_tail_i, old_tail_j;
int maxn = 0;
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (map[i][j] == 2)
{
old_head_i = i;
old_head_j = j;
}
if (map[i][j] > maxn)
{
maxn = map[i][j];
old_tail_i = i;
old_tail_j = j;
}
}
}
int new_head_i = old_head_i, new_head_j = old_head_j;
if (moveDirection == 'a')
new_head_j = old_head_j - 1;
else if (moveDirection == 'w')
new_head_i = old_head_i - 1;
else if (moveDirection == 's')
new_head_i = old_head_i + 1;
else if (moveDirection == 'd')
new_head_j = old_head_j + 1;
if (new_head_i >= HEIGHT || new_head_i < 0 || new_head_j >= WIDTH || new_head_j < 0 || map[new_head_i][new_head_j] > 0)
{
isFailure = true;
return;
}
step++;
nowHead_i = new_head_i;
nowHead_j = new_head_j;
map[new_head_i][new_head_j] = 1;
if (new_head_i == food_i && new_head_j == food_j)
{
if (fast_food)
{
//如果是加速食物,速度变成原来的2倍
velocity /= 2;
fast_food = false;
}
else if (slow_food)
{
//减速食物反之
velocity *= 2;
slow_food = false;
}
else
velocity = 20;
creatFood();
}
else
map[old_tail_i][old_tail_j] = 0;
}
void updateWithoutInput()
{
if (isFailure)
return;
static int index = 1;
index++;
if (index == velocity)
{
move_snake();
index = 1;
}
}
void updateWithInput()
{
if (_kbhit() && !isFailure)
{
char input = _getch();
if (input == 'w' && map[nowHead_i - 1][nowHead_j] == 0 && moveDirection != 'w')
{
moveDirection = 'w';
move_snake();
}
else if (input == 'a' && map[nowHead_i][nowHead_j - 1] == 0 && moveDirection != 'a')
{
moveDirection = 'a';
move_snake();
}
else if (input == 's' && map[nowHead_i + 1][nowHead_j] == 0 && moveDirection != 's')
{
moveDirection = 's';
move_snake();
}
else if (input == 'd' && map[nowHead_i][nowHead_j + 1] == 0 && moveDirection != 'd')
{
moveDirection = 'd';
move_snake();
}
}
}
void creatFood()
{
food_i = rand() % (HEIGHT - 5) + 2;
food_j = rand() % (WIDTH - 5) + 2;
while (isSnake[food_i][food_j] == true)
{
food_i = rand() % (HEIGHT - 5) + 2;
food_j = rand() % (WIDTH - 5) + 2;
}
if (rand() % 5 == 0 && slow_food == false) //随机生成的数能被5整除,则是加速食物
fast_food = true;
else if (rand() % 7 == 0 && fast_food == false) //能被7整除则是减速食物
slow_food = true;
}