#include <iostream>
#include <graphics.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
using namespace std;
#define BLOCK_SIZE 20//注意,不要等于号=,也不要分号;
#define WIDTH 40
#define HEIGHT 30
//全局变量定义
int Blocks[HEIGHT][WIDTH];//注意二维数组第一格是行号,第二个是列号,所以第一格是HEIGHT而不是WIDTH,这个数组是30行40列的数组
char moveDirection;//方向定义为全局变量
//初始化函数
void startup()//初始化蛇身位置、颜色
{
int i;
Blocks[HEIGHT / 2][WIDTH / 2] = 1;
for (int i = 1; i < 6; i++)//从中间开始画贪吃蛇,设头部的数值为1.存入数组中,从头到尾依次增大,尾巴数值为4
{
Blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1;
}
initgraph(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE);
setlinecolor(RGB(200, 200, 200));//线条颜色设为白色,即格子与格子之间的空隙设为白色,比较好看
BeginBatchDraw();//批量绘制,防止屏幕闪烁
}
//绘制函数
void show()//把蛇身和其他方格都画出来
{
cleardevice();//清屏
for (int i = 0; i < HEIGHT; i++)//一行行遍历
for (int j = 0; j < WIDTH; j++)
{
if (Blocks[i][j] > 0)//遍历数组,数值大于0的就是贪吃蛇身体部分,需要填色
{
setfillcolor(HSVtoRGB(Blocks[i][j] * 10, 0.9, 1));/*用数组中存储的连续的数值(从1到4)来为贪吃蛇
上色就可以得到渐变色,但是1到4之间跨度太小,需要*10,颜色范围为10到40,可得较好看的渐变色*/
}
else
setfillcolor(RGB(150, 150, 150));//数值不大于0则不是贪吃蛇身体,格子设置为灰色
fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE);//填充颜色
}
FlushBatchDraw();
}
void moveSnake()//这个函数只需要实现12345这几个数值的整体向右移一格,然后放入主函数的while(1)中循环,
{
for (int i = 0; i < HEIGHT; i++)//把蛇身的四个点的数值+1,从蛇头到尾变成23456
for (int j = 0; j < WIDTH; j++)
if (Blocks[i][j] > 0)
Blocks[i][j]++;
int oldTail_i, oldTail_j, oldHead_i, oldHead_j;//定义变量存储旧的蛇尾蛇头的位置
int max = 0;
for (int i = 0; i < HEIGHT; i++)
for (int j = 0; j < WIDTH; j++)
{
if (max < Blocks[i][j])
{
max = Blocks[i][j];
oldTail_i = i;
oldTail_j = j;//遍历找到最大值,最大值就是旧的蛇尾
}
if (Blocks[i][j] == 2)
{
oldHead_i = i;
oldHead_j = j;//遍历找到等于2的值,这就是旧的蛇头的位置
}
}
int newHead_i = oldHead_i;
int newHead_j = oldHead_j;
newHead_j = oldHead_j + 1;//要做好初始化先,如果用户没有输入方向的话就先默认往右移动
if (moveDirection == 'w')//向上的话就是行数-1,列数不变
{
newHead_i = oldHead_i-1;
newHead_j = oldHead_j;
}
else if (moveDirection == 'a')//向左就是蛇头列数-1,行数不变
{
newHead_i = oldHead_i ;
newHead_j = oldHead_j - 1;
}
else if (moveDirection == 's')
{
newHead_i = oldHead_i+1;
newHead_j = oldHead_j ;
}
else if (moveDirection == 'd')
{
newHead_i = oldHead_i ;
newHead_j = oldHead_j+1;
}
Blocks[newHead_i][newHead_j] = 1;//找到之后就把就蛇头的右边那个格子的数值设为1,变为新的蛇头
Blocks[oldTail_i][oldTail_j] = 0;//就设为的数值设为0
}
//与输入无关的更新
void updateWithouInput()
{
static int waitIndex = 1;//静态局部变量,初始化时为1
waitIndex++;//每一帧+1
if (waitIndex == 30)//如果等于10才执行,这样小蛇每隔10帧移动一次
{
moveSnake();//调用小蛇移动函数
waitIndex = 1;//再变成1
}
}
//与输入有关的更新
void updateWithInput()
{
if (_kbhit())
{
char input=_getch();
if (input == 'w' || input == 'a' || input == 's' || input == 'd')
{
moveDirection = input;
moveSnake();
}
}
}
int _tmain(int argc, _TCHAR* argv[])//主函数
{
startup();
while (1)
{
show();
updateWithouInput();
updateWithInput();
}
_getch();
closegraph();
return 0;
}
/*
要实现按键操控小蛇移动:
问题1 怎么改变方向?
贪吃蛇第1部分时让小蛇往右移动是同样的道理。关键只在于蛇头newHead_i,newHead_j怎么变化
问题2 在updateWithInput函数里判断得出的moveDirection怎么传参给moveSnake函数?
直接把moveDirection定义为全局变量,判断完后直接调用moveSnake
问题3 Sleep函数在让画面停顿的同时也会让updateWithInput之类的函数停顿,小蛇的转向可能会不快速,怎么改进?
把updateWithouInput()里的sleep函数丢掉,使得每10帧小蛇才移动一次,如果改成30帧小蛇会移动得更慢,但是没有了sleep的影响,转向还是会很迅速
问题4 为什么updateWithouInput()和updateWithInput()函数都有调用moveSnake?
因为updateWithouInput()就是没有用户输入时也进行的更新,初始化moveDirection向右后,就算用户没有输入,小蛇也会一直向右移动,while(1)会使
函数中的moveSnake函数一直触发。而updateWithInput()会在用户输入后改变小蛇移动方向,所以也要调用moveSnake函数
*/