目录
前言
拓展知识
介绍system("pause")
First:制作可控移动的小蛇
Second:添加食物
Third:如何Game Over
完整代码
前言
声明:本游戏参考《c语言课程设计与游戏开发实践教程》。
这个小游戏尤其可以加深对整体循环、二维数组的理解。
我将用循序渐进的步骤制作。
如果想直接学习完整代码,目录最后一条可直接查看完整代码(带解析)。
先来放一个游戏效果视频
贪吃蛇
- 开局小蛇在画面中央,会自动向右移动。用户通过键盘按键'w''s''a''d'控制小蛇上下左右移动。
- 小蛇吃到食物后会增加一节长度
- 小蛇撞到边界,或者咬到自己就会game over!
涉及到的知识点:
printf和scanf,宏定义常量,运算符,定义全局变量,for循环,while循环,if语句,二维数组,自定义函数。
(可能的)拓展知识:
system("pause")函数,rand函数,Sleep函数,自定义清屏函数gotoxy,自定义隐藏光标函数,getch函数,kbhit函数。(如果不认识不要害怕,这些拓展知识都会在文章中有详细的说明介绍)
拓展知识
- kbhit函数,getch函数,rand函数,gotoxy函数,隐藏光标函数:见(在该文章目录中查找)
- Sleep函数:见(在该文章目录中查找)
介绍system("pause")
- 位于<stdlib.h>函数库,头文件加上#include<stdlib.h>。
- 作用:使程序暂停
- 使用:system("pause");
First:制作可控移动的小蛇
- 画面描述:小蛇开局在画面中央,会自动向右移动。用户可以通过按键'w''s''a''d'控制小蛇上下左右移动。
- 原理描述:我们用二维数组制作整个画面。二维数组a[y][x],这个yx就相当于坐标(x,y),数组不同位置被赋予不同的值。空白画面被赋值为0,边界被赋值为-1,蛇头被赋值为1,蛇身被依次赋值为2、3、4、5...(初始身体有4节)。然后控制相应数值的地方显示不同的画面。小蛇每向前移动一步,原来蛇身和蛇头数值都被+1,而原蛇头前方对应的数组的值被赋值为1(新的蛇头),尾巴被赋值为0。
下方见代码,附有保姆级解析
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
//宏定义画面大小
#define high 20
#define width 30
int a[high][width]={0};//画面储存在这个二维数组中
int direction;//小蛇移动的方向
void start()//初始化
{
int i,n;
//初始化边框,边框对应的数组值为-1
for(i=0;i<high;i++)
{
a[i][0]=-1;//第一列
a[i][width-1]=-1;//最后一列
}
for(n=1;n<width;n++)
{
a[0][n]=-1;//第一行
a[high-1][n]=-1;//最后一行
}//重复赋值是没问题的
a[high/2][width/2]=1;//蛇头赋值为1
//蛇身,四节分别赋值2345
for(i=1;i<=4;i++)
{
a[high/2][width/2-i]=i+1;
}
//初始蛇向右移动,4代表向右
direction=4;
}
int movesnake()//小蛇移动时给数组重新赋值
{
int i,n;
//先给蛇头和蛇身对应的数组的值都+1
for(i=1;i<high-1;i++)
{
for(n=1;n<width-1;n++)
{
if(a[i][n]>0)
a[i][n]++;
}
}
int oldtail_y,oldtail_x,oldhead_y,oldhead_x;//变量可以在用的地方随时定义
int max=0;
//找出原先的蛇尾和蛇头,并且赋值给oldtail和oldhead
for(i=1;i<high;i++)
{
for(n=1;n<width;n++)
{
if(a[i][n]>0)
{
if(max<a[i][n])
{
max=a[i][n];
oldtail_y=i;
oldtail_x=n;
}
if(a[i][n]==2)
{
oldhead_y=i;
oldhead_x=n;
}
}
}
}
a[oldtail_y][oldtail_x]=0;//把蛇尾赋值为0
//蛇头移动方向:1上,2下,3左,4右
//对蛇头坐标进行+-实现不同方向移动
if(direction==1)
a[oldhead_y-1][oldhead_x]=1;
if(direction==2)
a[oldhead_y+1][oldhead_x]=1;
if(direction==3)
a[oldhead_y][oldhead_x-1]=1;
if(direction==4)
a[oldhead_y][oldhead_x+1]=1;
}
void gotoxy(int x,int y)//清屏函数。原理是每循环一次让光标回归到指定坐标
{
HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X=x;
pos.Y=y;
SetConsoleCursorPosition(handle,pos);
}
void HideCursor()//隐藏光标函数
{
CONSOLE_CURSOR_INFO cursor_info={1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
void show()//根据数组不同的值输出不同画面
{
gotoxy(0,0);//每次循环都将光标移动到(0,0)位置,相当于清屏
int i,n;
for(i=0;i<high;i++)
{
for(n=0;n<width;n++)
{
if(a[i][n]==0)
printf(" ");
else if(a[i][n]==-1)
printf("+"); //边界
else if(a[i][n]==1)
printf("0"); //蛇头(0当作字符就好)
else if(a[i][n]>1)
printf("o"); //蛇身
}
printf("\n");
}
Sleep(100);// //减慢蛇的移动速度,自由调整
}
void put() //用户通过键盘控制小蛇移动方向
{
char move;
if(kbhit())
{
move=getch();
if(move=='a')
{
direction=3;
movesnake();
}
if(move=='d')
{
direction=4;
movesnake();
}
if(move=='w')
{
direction=1;
movesnake();
}
if(move=='s')
{
direction=2;
movesnake();
}
}
}
int main() //主函数
{
start(); //数据初始化要放在外边
while(1)
{
show();
movesnake();
put();
HideCursor();
}
}
Second:添加食物
- 画面描述:小蛇吃到食物后身体长度+1,食物随机重现。
- 原理描述:我们已经知道画面的显示依靠数组不同的值。食物对应数组的值为-2,小蛇吃到食物后,把原本食物位置的数组值从-2变为1,原本蛇头和身体对应数组值全部+1,这样一来食物被吃掉后相当于变成新的蛇头,蛇尾不再赋值为0,不对蛇尾进行操作。
见代码
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#define high 20
#define width 30
int a[high][width]={0};
int direction;//蛇头移动方向
int food_y,food_x;
//0为空格,-1为边框,-2为食物,1是蛇头,>1是蛇身
int movesnake()
{
int i,n;
//扫描所有位置,找到蛇并全部+1
for(i=1;i<high-1;i++)
for(n=1;n<width-1;n++)
if(a[i][n]>0)
a[i][n]++;
int oldtail_y,oldtail_x,oldhead_y,oldhead_x;
int max=0;
//定位此时的头尾
for(i=1;i<high-1;i++)
for(n=1;n<width-1;n++)
if(a[i][n]>0)
{
if(max<a[i][n])
{//定位尾巴
max=a[i][n];
oldtail_y=i;
oldtail_x=n;
}
if(a[i][n]==2)
{//全部+1之后的2就是原来的头
oldhead_y=i;
oldhead_x=n;
}
}
int newhead_y,newhead_x;
//上下左右移动
if(direction==1)
{
newhead_y=oldhead_y-1;
newhead_x=oldhead_x;
}
if(direction==2)
{
newhead_y=oldhead_y+1;
newhead_x=oldhead_x;
}
if(direction==3)
{
newhead_y=oldhead_y;
newhead_x=oldhead_x-1;
}
if(direction==4)
{
newhead_y=oldhead_y;
newhead_x=oldhead_x+1;
}
//如果蛇头吃到食物
if(a[newhead_y][newhead_x]==-2)
{
a[food_y][food_x]=0;
food_x=rand()%(width-5)+2;
food_y=rand()%(high-5)+2;
a[food_y][food_x]=-2;
//原来的蛇尾被+1后自动保留了
}
else
a[oldtail_y][oldtail_x]=0;
//更新蛇头坐标
a[newhead_y][newhead_x]=1;
//不让蛇游得太快
Sleep(100);
}
void gotoxy(int x,int y)
{
HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X=x;
pos.Y=y;
SetConsoleCursorPosition(handle,pos);
}
void HideCursor()
{
CONSOLE_CURSOR_INFO cursor_info={1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
void start()
{
int i,n;
//初始化边框
for(i=0;i<high;i++)
{
a[i][0]=-1;//第一列
a[i][width-1]=-1;//最后一列
}
for(n=1;n<width;n++)
{
a[0][n]=-1;//第一行
a[high-1][n]=-1;//最后一行
}//重复赋值是没问题的
//蛇头
a[high/2][width/2]=1;
//蛇身,四节分别赋值2345
for(i=1;i<=4;i++)
{
a[high/2][width/2-i]=i+1;
}
//初始蛇向右移动
direction=4;
food_y=rand()%(high-5)+2;
food_x=rand()%(width-5)+2;
a[food_y][food_x]=-2;
}
void show()
{
gotoxy(0,0);
int i,n;
for(i=0;i<high;i++)
{
for(n=0;n<width;n++)
{
if(a[i][n]==0)
printf(" ");
else if(a[i][n]==-1)
printf("+");
else if(a[i][n]==1)
printf("0");
else if(a[i][n]>1)
printf("o");
else if(a[i][n]==-2)
printf("*");
}
printf("\n");
}
Sleep(100);
}
void put() //用户使用键盘控制小蛇
{
char move;
if(kbhit())
{
move=getch();
if(move=='a')
{
direction=3;
movesnake();
}
if(move=='d')
{
direction=4;
movesnake();
}
if(move=='w')
{
direction=1;
movesnake();
}
if(move=='s')
{
direction=2;
movesnake();
}
}
}
int main() //主函数
{
start();
while(1)
{
show();
movesnake();
put();
HideCursor();
}
return 0;
}
Third:如何Game Over
- 画面效果:小蛇咬到自己或者撞墙就会game over!
- 原理:蛇头坐标和身体/墙重合的时候输出game over
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
//宏定义画面大小
#define high 20
#define width 30
int a[high][width]={0};//画面储存在这个二维数组中
int direction;//小蛇移动的方向
int food_y,food_x;//食物坐标
void start()//初始化
{
int i,n;
//初始化边框,边框对应的数组值为-1
for(i=0;i<high;i++)
{
a[i][0]=-1;//第一列
a[i][width-1]=-1;//最后一列
}
for(n=1;n<width;n++)
{
a[0][n]=-1;//第一行
a[high-1][n]=-1;//最后一行
}//重复赋值是没问题的
a[high/2][width/2]=1;//蛇头赋值为1
//蛇身,四节分别赋值2345
for(i=1;i<=4;i++)
{
a[high/2][width/2-i]=i+1;
}
//初始蛇向右移动,4代表向右
direction=4;
}
int movesnake()//小蛇移动时给数组重新赋值
{
int i,n;
//先给蛇头和蛇身对应的数组的值都+1
for(i=1;i<high-1;i++)
{
for(n=1;n<width-1;n++)
{
if(a[i][n]>0)
a[i][n]++;
}
}
int oldtail_y,oldtail_x,oldhead_y,oldhead_x;//变量可以在用的地方随时定义
int max=0;
//找出原先的蛇尾和蛇头,并且赋值给oldtail和oldhead
for(i=1;i<high;i++)
{
for(n=1;n<width;n++)
{
if(a[i][n]>0)
{
if(max<a[i][n])
{//定位尾巴
max=a[i][n];
oldtail_y=i;
oldtail_x=n;
}
if(a[i][n]==2)
{//定位蛇头
oldhead_y=i;
oldhead_x=n;
}
}
}
}
int newhead_y,newhead_x;
//蛇头移动方向:1上,2下,3左,4右
//对蛇头坐标进行+-实现不同方向移动
if(direction==1)
{
newhead_y=oldhead_y-1;
newhead_x=oldhead_x;
}
if(direction==2)
{
newhead_y=oldhead_y+1;
newhead_x=oldhead_x;
}
if(direction==3)
{
newhead_y=oldhead_y;
newhead_x=oldhead_x-1;
}
if(direction==4)
{
newhead_y=oldhead_y;
newhead_x=oldhead_x+1;
}
//如果蛇头吃到食物
if(a[newhead_y][newhead_x]==-2)
{
a[food_y][food_x]=0;
food_x=rand()%(width-5)+2;
food_y=rand()%(high-5)+2;
a[food_y][food_x]=-2;
//原来的蛇尾被+1后自动保留了
}
else
a[oldtail_y][oldtail_x]=0;
//蛇碰壁或者咬到自己就game over!
if((a[newhead_y][newhead_x]>0)||(a[newhead_y][newhead_x]==-1))
{
printf("Game Over!\n");
system("pause");
exit(0);
}
else
{
a[newhead_y][newhead_x]=1;
}
Sleep(100);
}
void gotoxy(int x,int y)//清屏函数。原理是每循环一次让光标回归到指定坐标
{
HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X=x;
pos.Y=y;
SetConsoleCursorPosition(handle,pos);
}
void HideCursor()//隐藏光标函数
{
CONSOLE_CURSOR_INFO cursor_info={1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
void show()//根据数组不同的值输出不同画面
{
gotoxy(0,0);//每次循环都将光标移动到(0,0)位置,相当于清屏
int i,n;
for(i=0;i<high;i++)
{
for(n=0;n<width;n++)
{
if(a[i][n]==0)
printf(" ");
else if(a[i][n]==-1)
printf("+"); //边界
else if(a[i][n]==1)
printf("0"); //蛇头(0当作字符就好)
else if(a[i][n]>1)
printf("o"); //蛇身
}
printf("\n");
}
Sleep(100);// //减慢蛇的移动速度,自由调整
}
void put() //用户通过键盘控制小蛇移动方向
{
char move;
if(kbhit())
{
move=getch();
if(move=='a')
{
direction=3;
movesnake();
}
if(move=='d')
{
direction=4;
movesnake();
}
if(move=='w')
{
direction=1;
movesnake();
}
if(move=='s')
{
direction=2;
movesnake();
}
}
}
int main() //主函数
{
start(); //数据初始化要放在外边
while(1)
{
show();
movesnake();
put();
HideCursor();
}
}
如果有不懂的可以随时问我
就酱,拜拜~