疫情期在家,开学遥遥无期,为了打发无聊的时间,我写了一个贪吃蛇小游戏来打发时间。当然,这也是受朋友启发 用JS实现贪吃蛇小游戏,我也想用C++写一个。当然,本蒟蒻刚学C++没多久,代码会有些凌乱,不足之处望各位dalao指出来
1.游戏规则
通过上下左右控制蛇的移动,来吃到随机生成的食物,吃到食物后蛇的长度会增加,并且获得一定的分数,蛇头不能碰到墙壁。
2.设计思路
1.画出地图
2.需要构造两个类,一个是蛇,另一个是食物
3.读取上下左右的输入
4.一些人机交互的信息
3.具体实现
预先准备
包含的头文件
#include <iostream>
#include <windows.h>
#include <conio.h>
#include <cstdlib>
#include <ctime>
#include <cstdio>
需要的函数
void gotoxy(int x, int y)
{
HANDLE hout;
COORD coord;
coord.X = x;
coord.Y = y;
hout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hout, coord);
}//将光标移动到x,y,命令行左上角为(0,0),向下为y轴正向,向右为x轴正向
蛇
蛇具有头部和身体,可以用不同的字符来表示,需要实现的功能有:移动,变长,吃食物等。 综合考虑这些特点,用链表来实现蛇更方便操作。蛇类如下:
typedef struct Node{
int x;
int y;//蛇每个节点的坐标
struct Node *p;
}Node;//这是蛇的节点
class snake{
private:
Node *head;
char Head;//头部字符
char Body;//身体字符
public:
void set(char c1, char c2){
Head = c1;
Body = c2;
}//设置蛇的样式
snake(){
Node *node = new Node;
node->p = NULL;
head = node;
head->x=10;
head->y=10;
add();
}//蛇的初始化,即添加上头部和一个身体节点
void move();//移动
void add();//增加一个身体节点
void print();//显示蛇
void read();//读取键盘操作(可能放在这里不合适,不过影响不大)
bool eat(int x, int y);//吃食物
bool die();//死亡
};
蛇类里各种功能的实现,有难度的是蛇的移动,后来才想到,其实每一个节点都是头节点的复制。所以把前一个节点的坐标复制给后面一个节点就行了。
下面是蛇功能的具体实现:
void snake::move()
{
Node* temp=new Node;
Node* temp2=new Node;
*temp = *head;
Node* t = head->p;
if(!kbhit())
{
if(head->x==t->x&&head->y<t->y)
head->y --;
if(head->x==t->x&&head->y>t->y)
head->y ++;
if(head->y==t->y&&head->x<t->x)
head->x --;
if(head->y==t->y&&head->x>t->x)
head->x ++;
}else{
read();
}//这个if-else是头节点的变动,也可单独写成一个函数
//没输入时就按原方向,有输入就按输入改变
while(t!=NULL)
{
gotoxy(t->x, t->y);
cout<<" ";//这是清除前面节点的方法,在相应位置输出空格
*temp2 = *t;
t->x = temp->x;
t->y = temp->y;
t = t->p;
*temp = *temp2;
}
}
void snake::add()
{
Node *t = head;
while(t->p!=NULL)
t = t->p;//遍历到最后一个节点,然后在最后加一个节点
Node *q = new Node;
q->x = t->x-1;//要把最后节点的坐标赋值(这里不完整,可能看上去有点别扭)
q->y = head->y;
q->p = NULL;
t->p = q;
}
void snake::print()
{
gotoxy(head->x,head->y);
cout<<Head;
Node *t = head->p;
while(t!=NULL)
{
gotoxy(t->x,t->y);
cout<<Body;
t = t->p;
}
}
void snake::read()//读入键盘上下左右方向键的输入
{
char ch = getch();
if (ch == -32)
{
ch = getch();
switch (ch)
{
case 72:
head->y--;
break;
case 80:
head->y++;
break;
case 75:
head->x--;
break;
case 77:
head->x++;
break;
}
}
}
bool snake::eat(int x, int y)
{
if(head->x == x&&head->y == y)
{
add();
return true;
}
return false;
}
bool snake::die()
{
if(head->x<=0||head->x>=50)
return true;
if(head->y<=0||head->y>=25)
return true;
return false;
}
食物:
这个比较简单,只需要有食物的坐标,并且会产生随机数就行
class food{
private:
int x;
int y;//食物坐标
public:
int create();
int getX();
int getY();
};
//*********下面是实现*********
int food::create()//返回的是每个食物对应的分数
{
srand(time(NULL));//对随机数函数初始化
x = rand()%49+1;//要保证产生的食物在地图里面
y = rand()%14+1;
gotoxy(x,y);
int ret = 1+x*y%9;
cout<<ret;//在屏幕上显示食物
return ret;
}
int food::getX()
{
return x;
}
int food::getY()
{
return y;
}
地图和人机交互界面比较容易实现,可以根据自己的兴趣实现
最后,在主函数里进行调用就行
下面是全部代码:
#include <iostream>
#include <windows.h>
#include <conio.h>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
typedef struct Node{
int x;
int y;
struct Node *p;
}Node;
void gotoxy(int x, int y);
void printMap();
class snake{
private:
Node *head;
char Head;
char Body;
public:
void set(char c1, char c2){
Head = c1;
Body = c2;
}
snake(){
Node *node = new Node;
node->p = NULL;
head = node;
head->x=10;
head->y=10;
add();
}
void move();
void add();
void print();
void read();
bool eat(int x, int y);
bool die();
};
class food{
private:
int x;
int y;
public:
int create();
int getX();
int getY();
};
int main()
{
start:
system("cls");
cout<<"按任意键开始游戏"<<endl;
getchar();
system("cls");
printMap();
snake s;
s.set('@', '#');
s.print();
food f;
int i=f.create();
int score=0;
while(1)
{
Sleep(200);
s.move();
if(s.die())
{
system("cls");
gotoxy(50,9);
cout<<"Game Over!"<<endl;
gotoxy(50,10);
cout<<"Your Score:"<<score<<endl;
getchar();
goto start;
}
s.print();
if(s.eat(f.getX(),f.getY()))
{
score+=i;
i = f.create();
if(score>=100)
{
system("cls");
gotoxy(50,9);
cout<<"You WIN!!!"<<endl;
gotoxy(50,10);
cout<<"你赢了!!"<<endl;
gotoxy(50,11);
cout<<"你得了"<<score<<"分!"<<endl;
gotoxy(50,12);
cout<<"按任意键重新开始"<<endl;
getchar();
goto start;
}
}
}
return 0;
}
void snake::move()
{
Node* temp=new Node;
Node* temp2=new Node;
*temp = *head;
Node* t = head->p;
if(!kbhit())
{
if(head->x==t->x&&head->y<t->y)
head->y --;
if(head->x==t->x&&head->y>t->y)
head->y ++;
if(head->y==t->y&&head->x<t->x)
head->x --;
if(head->y==t->y&&head->x>t->x)
head->x ++;
}else{
read();
}
while(t!=NULL)
{
gotoxy(t->x, t->y);
cout<<" ";
*temp2 = *t;
t->x = temp->x;
t->y = temp->y;
t = t->p;
*temp = *temp2;
}
}
void snake::add()
{
Node *t = head;
while(t->p!=NULL)
t = t->p;
Node *q = new Node;
q->x = t->x-1;
q->y = head->y;
q->p = NULL;
t->p = q;
}
void snake::print()
{
gotoxy(head->x,head->y);
cout<<Head;
Node *t = head->p;
while(t!=NULL)
{
gotoxy(t->x,t->y);
cout<<Body;
t = t->p;
}
}
void snake::read()
{
char ch = getch();
if (ch == -32)
{
ch = getch();
switch (ch)
{
case 72:
head->y--;
break;
case 80:
head->y++;
break;
case 75:
head->x--;
break;
case 77:
head->x++;
break;
}
}
}
bool snake::eat(int x, int y)
{
if(head->x == x&&head->y == y)
{
add();
return true;
}
return false;
}
bool snake::die()
{
if(head->x<=0||head->x>=50)
return true;
if(head->y<=0||head->y>=25)
return true;
return false;
}
void gotoxy(int x, int y)
{
HANDLE hout;
COORD coord;
coord.X = x;
coord.Y = y;
hout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hout, coord);
}
void printMap()
{
for(int i=0; i<51; i++)
cout<<"-";
cout<<endl;
for(int j = 0; j<15; j++)
{
if(j%2==0)
cout<<"."<<endl;
for(int i=0; i<51; i++)
{
if(i==0||i==50)
cout<<"|";
else
cout<<" ";
}
cout<<endl;
}
for(int i=0; i<51; i++)
cout<<"-";
cout<<endl;
}
int food::create()
{
srand(time(NULL));
x = rand()%49+1;
y = rand()%14+1;
gotoxy(x,y);
int ret = 1+x*y%9;
cout<<ret;
return ret;
}
int food::getX()
{
return x;
}
int food::getY()
{
return y;
}
运行效果如下:
4.总结
用到的比较重要的知识:
1.学会对链表的操作,增加,删除,遍历,复制
2.一些Windows api的使用,如控制光标,这些可百度
3.代码还可以进一步优化,使游戏更加美观
呼~终于写完了,最后,希望大家一起来学习,指出代码中的不足之处!!