伪代码:
地图为二位数组
int main(){
死循环
刷新地图
生成水果
获取键盘
移动头部
判定死亡、吃到水果
if(没有吃到水果)
{
移动尾部
}
等待指定秒数
清屏
}
首先,我们因该可以把大框架写出来了。地图是一个二维数组,这里叫做snmap。
我们需要一个函数来创建地图,地图由边缘(killword)和空白(mapword)组成
killword是边缘,snword是蛇的字母,mapword是空白处的字母
mapx,mapy分别对应地图尺寸
int map_cz()//初始化地图数据
{
for(int i = 1;i < mapy;i++)//填充地图
{
for(int j = 0;j < mapx;j++)
{
snmap[i][j] = mapword;//
}
}
for(int j = 0;j < mapx;j++) snmap[0][j] = killword;//这四行是设置地图边缘
for(int j = 0;j < mapx;j++) snmap[mapy-1][j] = killword;
for(int i = 0;i < mapy;i++) snmap[i][0] = killword;
for(int i = 0;i < mapy;i++) snmap[i][mapx-1] = killword;
}
然后需要一个函数来重构地图,也就是在每次循环之后重新输出一遍
killword是边缘,snword是蛇的字母,mapword是空白处的字母
mapx,mapy分别对应地图尺寸
int map_cz()//初始化地图数据
{
for(int i = 1;i < mapy;i++)//填充地图
{
for(int j = 0;j < mapx;j++)
{
snmap[i][j] = mapword;//
}
}
for(int j = 0;j < mapx;j++) snmap[0][j] = killword;//这四行是设置地图边缘
for(int j = 0;j < mapx;j++) snmap[mapy-1][j] = killword;
for(int i = 0;i < mapy;i++) snmap[i][0] = killword;
for(int i = 0;i < mapy;i++) snmap[i][mapx-1] = killword;
}
我们需要绘制一个初始蛇,这里需要用到一些变量:头的位置(headx,heady),尾部的位置(tallx,tally)和蛇的长度(snlong)
for(int i = 0;i < snlong;i++)//绘制初始蛇
{
snmap[head_y][head_x+i] = snword;
snnum[head_y][head_x+i] = i+1;
}
现在地图有了,贪吃蛇有了,接下来就要让他动起来。我们需要获取键盘数据来控制他的头部移动,把他的头部坐标放在下一个位置,然后把头部坐标的那个点换成蛇的字母(snword)
int jd = 65,jdnum = 0;
if (jd = _kbhit())
{
jd = _getch();
}
//更新头部方向
if(jd == 97) jdnum = 0;
if(jd == 119) jdnum = 1;
if(jd == 100) jdnum = 2;
if(jd == 115) jdnum = 3;
if(jd == 113) zt();//暂停
//更新头部
if(jdnum == 0) head_x--;
if(jdnum == 1) head_y--;
if(jdnum == 2) head_x++;
if(jdnum == 3) head_y++;
//中间还要加上死亡判定再更新
snmap[head_y][head_x] = snword;
头的部分会增加,尾巴也需要消失,蛇才能动起来。所以我们就需要更新尾部。更新尾部要复杂的多,第一步要先把再尾部位置(tellx,telly)的字母换成空的(mapword),第二步找到新的尾部位置并更新这两个变量(tellx,telly)。第一步好说,问题就出在第二步上,新的位置难以确定。所以我们就需要一个新的二维数组来存放蛇走过的顺序(nummap)。这个数组和snmap是一一对应恶的。每次头部跟新时都在nummap上留下一个数字,这个数字是递增的。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 这样我们在更新尾部的时候就是需要找出除当前尾部之外最小的那个数的坐标作为新的尾部就可以了,因为这两个数组是同步的,坐标都相通。
int main()
int num = 0;
snnum[head_y][head_x] = num;//这两行夹在哪里都行
num++;
if(snlong == snlong_old)//长度没有增加,更新尾部
{
snmap[tall_y][tall_x] = mapword;
snnum[tall_y][tall_x] = 0;
int min = 2137384637,minx,miny;
for(int y = tall_y-1;y < tall_y+2;y++)//寻找新的尾部
{
for(int x = tall_x-1;x < tall_x+2;x++)
{
if(snnum[y][x] < min&&snnum[y][x] != 0)
{
min = snnum[y][x];
minx = x,miny = y;
}
}
}
tall_y = miny;
tall_x = minx;
}
最后再用时间种子随机数生成水果
这是更新苹果的
//更新苹果xy坐标
if(appleflag == 0)
//如果苹果不存在,更新苹果
{
if(snmap[apy][apx] != snword)
{
snmap[apy][apx] = apple;
Sleep(10);
if(snmap[apy][apx] == apple)appleflag = 1;
//设置苹果状态为存在
}
}
这是用随机数生成苹果xy坐标的
int apple_xy()//随机生成苹果位置
{
srand((int)time(0));
apx = rand()%(mapx-2);
apy2 = apx;
apy = (apy*apy2)%(mapy-2);
apx2 = apy;
//cout<<apx<<" "<<apy;
if(apx*apy==0)
{
apx++;
apy++;
}
}
再加上死亡判定和吃水果的判定
if(snmap[head_y][head_x] == apple)//水果判定
{
appleflag = 0;
snlong++;
}
//死亡判定
if(snmap[head_y][head_x] == snword||snmap[head_y][head_x] == killword)
{
Sleep(1000);
return 0;
}
这个小游戏就初步完成了,注意!是初步!
为什么是初步呢?因为你发现完成后的这个代码会闪瞎你的眼。(下面)
#include<bits/stdc++.h>
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include <conio.h>
#include "stdio.h"
#include "stdlib.h"
using namespace std;
//初始数据部分
const int mapy = 20,mapx = 40;//地图尺寸
int snlong =3,sd = 200;//初始长度
const char snword = 'O',mapword = ' ',apple = '@',killword = '#';//地图元素
//变量部分
int head_y = 5,head_x = 10,tall_y = head_y,tall_x = head_x+snlong;//头尾坐标
int snnum[mapy][mapx],num = 4;//snmap地图数组
char snmap[mapy+1][mapx];
int apx = 6,apy = 3,appleflag = 0;//关于苹果的变量
int apx2 = 4,apy2 = 9;
int showflag = 0;
int map_cz()//初始化地图数据
{
for(int i = 1;i < mapy;i++)//填充地图
{
for(int j = 0;j < mapx;j++)
{
snmap[i][j] = mapword;//
}
}
for(int j = 0;j < mapx;j++) snmap[0][j] = killword;//这四行是设置地图边缘
for(int j = 0;j < mapx;j++) snmap[mapy-1][j] = killword;
for(int i = 0;i < mapy;i++) snmap[i][0] = killword;
for(int i = 0;i < mapy;i++) snmap[i][mapx-1] = killword;
}
int map_output()//更新地图显示
{
for(int i = 0;i < mapy;i++)
{
for(int j = 0;j < mapx;j++)
{
printf( "%c",snmap[i][j]);
}
printf("\n");
}
Sleep(sd);
}
int num_output()//调试nummap数组
{
for(int i = 0;i < mapy;i++)
{
for(int j = 0;j < mapx;j++)
{
printf( "%d",snnum[i][j]);
}
printf("\n");
}
}
int apple_xy()//随机生成苹果位置
{
srand((int)time(0));
apx = rand()%(mapx-2);
apy2 = apx;
apy = (apy*apy2)%(mapy-2);
apx2 = apy;
//cout<<apx<<" "<<apy;
if(apx*apy==0)
{
apx++;
apy++;
}
}
int zt()//暂停
{
int p;
while(1)
{
if (p = _kbhit())
{
p = _getch();
}
if(p == 113)
{
return 0;
}
Sleep(100);
}
}
//____________________________________________________________________________
int snlong_old = snlong;//snlong记录蛇长
int main()
{
//_______________________________________________________________________
map_cz();//加载地图
for(int i = 0;i < snlong;i++)//绘制初始蛇
{
snmap[head_y][head_x+i] = snword;
snnum[head_y][head_x+i] = i+1;
}
int jd = 65,jdnum = 0;
//________________________________________________________________
while(1)//主循环
{
apple_xy();
//更新苹果xy坐标
if(appleflag == 0)
//如果苹果不存在,更新苹果
{
if(snmap[apy][apx] != snword)
{
snmap[apy][apx] = apple;
Sleep(10);
if(snmap[apy][apx] == apple)appleflag = 1;
//设置苹果状态为存在
}
}
snnum[head_y][head_x] = num;
num++;
snlong_old = snlong;
map_output();
if (jd = _kbhit())
{
jd = _getch();
}
//更新头部方向
if(jd == 97) jdnum = 0;
if(jd == 119) jdnum = 1;
if(jd == 100) jdnum = 2;
if(jd == 115) jdnum = 3;
if(jd == 113) zt();//暂停
//更新头部
if(jdnum == 0) head_x--;
if(jdnum == 1) head_y--;
if(jdnum == 2) head_x++;
if(jdnum == 3) head_y++;
//更新头部
snmap[head_y][head_x] = snword;
if(snmap[head_y][head_x] == apple)
{
appleflag = 0;
snlong++;
}
//死亡判定
if(snmap[head_y][head_x] == snword||snmap[head_y][head_x] == killword)
{
Sleep(1000);
return 0;
}
if(snlong == snlong_old)//长度没有增加,更新尾部
{
snmap[tall_y][tall_x] = mapword;
snnum[tall_y][tall_x] = 0;
int min = 2137384637,minx,miny;
for(int y = tall_y-1;y < tall_y+2;y++)//寻找新的尾部
{
for(int x = tall_x-1;x < tall_x+2;x++)
{
if(snnum[y][x] < min&&snnum[y][x] != 0)
{
min = snnum[y][x];
minx = x,miny = y;
}
}
}
tall_y = miny;
tall_x = minx;
}
system("cls");
}
return 0;
}
这是反复清屏导致的,我们可以加入双缓冲技术。(懂得都懂)
//这是开头
HANDLE hOutput, hOutBuf;//控制台屏幕缓冲区句柄
COORD coord = { 0,0 };
//双缓冲处理显示
DWORD bytes = 0;
int main()
{
//创建新的控制台缓冲区
hOutBuf = CreateConsoleScreenBuffer(
GENERIC_WRITE,//定义进程可以往缓冲区写数据
FILE_SHARE_WRITE,//定义缓冲区可共享写权限
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
hOutput = CreateConsoleScreenBuffer(
GENERIC_WRITE,//定义进程可以往缓冲区写数据
FILE_SHARE_WRITE,//定义缓冲区可共享写权限
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
//隐藏两个缓冲区的光标
CONSOLE_CURSOR_INFO cci;
cci.bVisible = 0;
cci.dwSize = 1;
SetConsoleCursorInfo(hOutput, &cci);
SetConsoleCursorInfo(hOutBuf, &cci);
int map_output()//更新地图显示的函数也该改一改
{
/*for(int i = 0;i < mapy;i++)
{
for(int j = 0;j < mapx;j++)
{
printf( "%c",snmap[i][j]);
}
printf("\n");
}
*/
if(showflag == 0)
{
for (int i = 0; i <= mapy; i++)
{
coord.Y = i;
WriteConsoleOutputCharacterA(hOutBuf, snmap[i],mapx, coord, &bytes);
}
showflag = 1;
SetConsoleActiveScreenBuffer(hOutBuf);
}
else
{
for (int i = 0; i <= mapy; i++)
{
coord.Y = i;
WriteConsoleOutputCharacterA(hOutput, snmap[i],mapx, coord, &bytes);
}
//设置新的缓冲区为活动显示缓冲
SetConsoleActiveScreenBuffer(hOutput);
showflag = 0;
}
Sleep(sd);
}
最后就完成了
#include<bits/stdc++.h>
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include <conio.h>
#include "stdio.h"
#include "stdlib.h"
using namespace std;
HANDLE hOutput, hOutBuf;//控制台屏幕缓冲区句柄
COORD coord = { 0,0 };
//双缓冲处理显示
DWORD bytes = 0;
//初始数据部分
const int mapy = 20,mapx = 40;//地图尺寸
int snlong =3,sd = 200;//初始长度
const char snword = 'O',mapword = ' ',apple = '@',killword = '#';//地图元素
//变量部分
int head_y = 5,head_x = 10,tall_y = head_y,tall_x = head_x+snlong;//头尾坐标
int snnum[mapy][mapx],num = 4;//snmap地图数组
char snmap[mapy+1][mapx];
int apx = 6,apy = 3,appleflag = 0;//关于苹果的变量
int apx2 = 4,apy2 = 9;
int showflag = 0;
int map_cz()//初始化地图数据
{
for(int i = 1;i < mapy;i++)//填充地图
{
for(int j = 0;j < mapx;j++)
{
snmap[i][j] = mapword;//
}
}
for(int j = 0;j < mapx;j++) snmap[0][j] = killword;//这四行是设置地图边缘
for(int j = 0;j < mapx;j++) snmap[mapy-1][j] = killword;
for(int i = 0;i < mapy;i++) snmap[i][0] = killword;
for(int i = 0;i < mapy;i++) snmap[i][mapx-1] = killword;
}
int map_output()//更新地图显示
{
/*for(int i = 0;i < mapy;i++)
{
for(int j = 0;j < mapx;j++)
{
printf( "%c",snmap[i][j]);
}
printf("\n");
}
*/
if(showflag == 0)
{
for (int i = 0; i <= mapy; i++)
{
coord.Y = i;
WriteConsoleOutputCharacterA(hOutBuf, snmap[i],mapx, coord, &bytes);
}
showflag = 1;
SetConsoleActiveScreenBuffer(hOutBuf);
}
else
{
for (int i = 0; i <= mapy; i++)
{
coord.Y = i;
WriteConsoleOutputCharacterA(hOutput, snmap[i],mapx, coord, &bytes);
}
//设置新的缓冲区为活动显示缓冲
SetConsoleActiveScreenBuffer(hOutput);
showflag = 0;
}
Sleep(sd);
}
int num_output()//调试nummap数组
{
for(int i = 0;i < mapy;i++)
{
for(int j = 0;j < mapx;j++)
{
printf( "%d",snnum[i][j]);
}
printf("\n");
}
}
int apple_xy()//随机生成苹果位置
{
srand((int)time(0));
apx = rand()%(mapx-2);
apy2 = apx;
apy = (apy*apy2)%(mapy-2);
apx2 = apy;
//cout<<apx<<" "<<apy;
if(apx*apy==0)
{
apx++;
apy++;
}
}
int zt()//暂停
{
int p;
while(1)
{
if (p = _kbhit())
{
p = _getch();
}
if(p == 113)
{
return 0;
}
Sleep(100);
}
}
//____________________________________________________________________________
int snlong_old = snlong;//snlong记录蛇长
int main()
{
//创建新的控制台缓冲区
hOutBuf = CreateConsoleScreenBuffer(
GENERIC_WRITE,//定义进程可以往缓冲区写数据
FILE_SHARE_WRITE,//定义缓冲区可共享写权限
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
hOutput = CreateConsoleScreenBuffer(
GENERIC_WRITE,//定义进程可以往缓冲区写数据
FILE_SHARE_WRITE,//定义缓冲区可共享写权限
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
//隐藏两个缓冲区的光标
CONSOLE_CURSOR_INFO cci;
cci.bVisible = 0;
cci.dwSize = 1;
SetConsoleCursorInfo(hOutput, &cci);
SetConsoleCursorInfo(hOutBuf, &cci);
//_______________________________________________________________________
map_cz();//加载地图
for(int i = 0;i < snlong;i++)//绘制初始蛇
{
snmap[head_y][head_x+i] = snword;
snnum[head_y][head_x+i] = i+1;
}
int jd = 65,jdnum = 0;
//________________________________________________________________
while(1)//主循环
{
apple_xy();
//更新苹果xy坐标
if(appleflag == 0)
//如果苹果不存在,更新苹果
{
if(snmap[apy][apx] != snword)
{
snmap[apy][apx] = apple;
Sleep(10);
if(snmap[apy][apx] == apple)appleflag = 1;
//设置苹果状态为存在
}
}
snnum[head_y][head_x] = num;
num++;
snlong_old = snlong;
map_output();
if (jd = _kbhit())
{
jd = _getch();
}
//更新头部方向
if(jd == 97) jdnum = 0;
if(jd == 119) jdnum = 1;
if(jd == 100) jdnum = 2;
if(jd == 115) jdnum = 3;
if(jd == 113) zt();//暂停
//更新头部
if(jdnum == 0) head_x--;
if(jdnum == 1) head_y--;
if(jdnum == 2) head_x++;
if(jdnum == 3) head_y++;
if(snmap[head_y][head_x] == apple)
{
appleflag = 0;
snlong++;
}
//死亡判定
if(snmap[head_y][head_x] == snword||snmap[head_y][head_x] == killword)
{
Sleep(1000);
return 0;
}
//更新头部
snmap[head_y][head_x] = snword;
if(snlong == snlong_old)//长度没有增加,更新尾部
{
snmap[tall_y][tall_x] = mapword;
snnum[tall_y][tall_x] = 0;
int min = 2137384637,minx,miny;
for(int y = tall_y-1;y < tall_y+2;y++)//寻找新的尾部
{
for(int x = tall_x-1;x < tall_x+2;x++)
{
if(snnum[y][x] < min&&snnum[y][x] != 0)
{
min = snnum[y][x];
minx = x,miny = y;
}
}
}
tall_y = miny;
tall_x = minx;
}
}
return 0;
}
?代码比较简陋,有什么不足欢迎指正。
|