#include<graphics.h>
#include<conio.h>
#include<vector>
using namespace std;
const short SCR_WIDTH=500;
const short SCR_HEIGHT=360;
const short CELL=15;//一个格子宽度
const short TMARGIN=40;//操作区离窗体左边横向距离
const short LMARGIN=30;//操作区离窗体上边纵向距离
const short ROW=16;//操作区行数
const short COLUMN=28;//操作区列数
struct Position
{
short x;
short y;
};
enum Status{BLANK,FILLED,SCORE};
enum Direction{LEFT,UP,RIGHT,DOWN};
void DrawTitle()//画游戏名及操作提示
{
setbkmode(TRANSPARENT);
setfillcolor(RGB(255,255,180));
bar(0,0,SCR_WIDTH,SCR_HEIGHT);
settextcolor(RGB(180,180,180));
settextstyle(40,20,"黑体");
outtextxy(SCR_WIDTH/3,SCR_HEIGHT/2.3,"贪吃蛇");
settextcolor(BLACK);
outtextxy(SCR_WIDTH/3-3,SCR_HEIGHT/2.3-3,"贪吃蛇");
settextstyle(16,8,"宋体");
settextcolor(RED);
outtextxy(SCR_WIDTH*0.25,SCR_HEIGHT*0.75,"方向键控制蛇移动,按q键离开游戏");
}
void DrawScene()//画场景
{
setfillcolor(RGB(180,180,180));
bar(0,0,SCR_WIDTH,SCR_HEIGHT);
setfillcolor(BLUE);
fillrectangle(LMARGIN-CELL,TMARGIN-CELL,LMARGIN+(COLUMN+1)*CELL,TMARGIN+(ROW+1)*CELL);
setfillcolor(BLACK);
setlinecolor(BLACK);
fillrectangle(LMARGIN,TMARGIN,LMARGIN+COLUMN*CELL,TMARGIN+ROW*CELL);
}
Status stat[ROW][COLUMN];
void Initialize()
{
short i,j;
for(i=0;i<ROW;i++)
for(j=0;j<COLUMN;j++)
stat[i][j]=BLANK;
}
class Snake
{
protected:
vector<Position>v;
Direction dir;
public:
void DrawHead()
{
setfillcolor(GREEN);
switch(dir)
{
case LEFT:
case RIGHT:
bar(LMARGIN+v[0].x*CELL,TMARGIN+v[0].y*CELL+2,LMARGIN+v[0].x*CELL+CELL,TMARGIN+v[0].y*CELL+CELL-2);
break;
case UP:
case DOWN:
bar(LMARGIN+v[0].x*CELL+2,TMARGIN+v[0].y*CELL,LMARGIN+v[0].x*CELL+CELL-2,TMARGIN+v[0].y*CELL+CELL);
break;
}
}
Snake()//建立一条只有四格的蛇
{
short i;
Position p={12,10};
for(i=0;i<4;i++)//用循环为蛇添加身体长度
{
p.x=12-i;
v.push_back(p);
stat[p.y][p.x]=FILLED;
}
dir=RIGHT;//最开始时方向向右
}
void DrawBegin()//只执行一次(画最初的蛇)
{
short i;
setfillcolor(GREEN);
for(i=0;i<v.size();i++)
bar(LMARGIN+v[i].x*CELL,TMARGIN+v[i].y*CELL+2,LMARGIN+v[i].x*CELL+CELL,TMARGIN+v[i].y*CELL+CELL-2);
}
void DrawTurning(Direction later,Direction former)//根据传入的两个方向值画拐点,第一个参数是拐弯后的方向,第二个是拐弯前的方向
{
short i=0;
setfillcolor(BLACK);
bar(LMARGIN+v[i].x*CELL,TMARGIN+v[i].y*CELL,LMARGIN+v[i].x*CELL+CELL,TMARGIN+v[i].y*CELL+CELL);//先用背景色清除掉原先的蛇头
setfillcolor(GREEN);//重置颜色准备画拐点
if(later==UP&&former==RIGHT||later==LEFT&&former==DOWN)
{
bar(LMARGIN+v[i].x*CELL+2,TMARGIN+v[i].y*CELL,LMARGIN+v[i].x*CELL+CELL-2,TMARGIN+v[i].y*CELL+CELL-2);
bar(LMARGIN+v[i].x*CELL,TMARGIN+v[i].y*CELL+2,LMARGIN+v[i].x*CELL+CELL-2,TMARGIN+v[i].y*CELL+CELL-2);
}
if(later==UP&&former==LEFT||later==RIGHT&&former==DOWN)
{
bar(LMARGIN+v[i].x*CELL+2,TMARGIN+v[i].y*CELL,LMARGIN+v[i].x*CELL+CELL-2,TMARGIN+v[i].y*CELL+CELL-2);
bar(LMARGIN+v[i].x*CELL+2,TMARGIN+v[i].y*CELL+2,LMARGIN+v[i].x*CELL+CELL,TMARGIN+v[i].y*CELL+CELL-2);
}
if(later==DOWN&&former==RIGHT||later==LEFT&&former==UP)
{
bar(LMARGIN+v[i].x*CELL+2,TMARGIN+v[i].y*CELL+2,LMARGIN+v[i].x*CELL+CELL-2,TMARGIN+v[i].y*CELL+CELL);
bar(LMARGIN+v[i].x*CELL,TMARGIN+v[i].y*CELL+2,LMARGIN+v[i].x*CELL+CELL-2,TMARGIN+v[i].y*CELL+CELL-2);
}
if(later==DOWN&&former==LEFT||later==RIGHT&&former==UP)
{
bar(LMARGIN+v[i].x*CELL+2,TMARGIN+v[i].y*CELL+2,LMARGIN+v[i].x*CELL+CELL-2,TMARGIN+v[i].y*CELL+CELL);
bar(LMARGIN+v[i].x*CELL+2,TMARGIN+v[i].y*CELL+2,LMARGIN+v[i].x*CELL+CELL,TMARGIN+v[i].y*CELL+CELL-2);
}
}
void EraseTail()//擦掉尾巴
{
short len=v.size();
setfillcolor(BLACK);
bar(LMARGIN+v[len-1].x*CELL,TMARGIN+v[len-1].y*CELL,LMARGIN+v[len-1].x*CELL+CELL,TMARGIN+v[len-1].y*CELL+CELL);
stat[v[len-1].y][v[len-1].x]=BLANK;
v.erase(v.end()-1);
}
bool HeadOn(Direction d)//返回假表明Game over
{
Position head_pos;
switch(d)
{
case RIGHT:
if(v[0].x==COLUMN-1) return false;
else
{
head_pos.x=v[0].x+1;
head_pos.y=v[0].y;
}
break;
case UP:
if(v[0].y==0) return false;
else
{
head_pos.x=v[0].x;
head_pos.y=v[0].y-1;
}
break;
case LEFT:
if(v[0].x==0) return false;
else
{
head_pos.x=v[0].x-1;
head_pos.y=v[0].y;
}
break;
case DOWN:
if(v[0].y==ROW-1) return false;
else
{
head_pos.x=v[0].x;
head_pos.y=v[0].y+1;
}
break;
}
if(d!=dir)//若正在转拐
{
DrawTurning(d,dir);
}
v.insert(v.begin(),head_pos);
if(stat[head_pos.y][head_pos.x]==FILLED)//撞上自己身体
return false;
stat[head_pos.y][head_pos.x]=FILLED;
dir=d;
DrawHead();
return true;
}
Direction GetDirection(){return dir;}//获得蛇当前的前进方向
bool Eat(short _x,short _y)//传入食物坐标,看是否吃到食物
{
return v[0].x==_x&&v[0].y==_y;
}
};
class Food
{
protected:
short x;//食物出现的x坐标
short y;//食物出现的y坐标
short time_left;//计时,到一定时长某些加高分的食物会消失
public:
Food()
{
//随机取得一个新产生食物的横纵坐标
do
{
x=rand()%COLUMN;
y=rand()%ROW;
}while(stat[y][x]==FILLED);//用while循环确保产生的食物不会正好出现在蛇身上
time_left=(rand()%5==0?(25+rand()%6):-1);//若剩余时间置为正数,该正数为衰减步数,如果为-1,则不衰减(食物永不消失直到被吃掉)
}
bool Elapse()//时间消耗尽了返回真
{
if(time_left>0) --time_left;
if(time_left==0) return true;
else return false;
}
void Paint()
{
if(time_left!=-1)
setfillcolor(RGB(50+rand()%205,50+rand()%205,50+rand()%205));//为食物赋一个随机颜色
else
setfillcolor(YELLOW);//普通食物为黄色
fillellipse(LMARGIN+x*CELL+2,TMARGIN+y*CELL+2,LMARGIN+x*CELL+CELL-2,TMARGIN+y*CELL+CELL-2);
}
void Clear()//清除食物
{
setfillcolor(BLACK);setlinecolor(BLACK);
fillellipse(LMARGIN+x*CELL,TMARGIN+y*CELL,LMARGIN+x*CELL+CELL,TMARGIN+y*CELL+CELL);
}
short GetX(){return x;}
short GetY(){return y;}
bool IsSpecialFood(){return time_left!=-1;}//判断食物是不是特殊食物,如果为真,是特殊食物
};
HWND wnd;
int main()
{
initgraph(SCR_WIDTH,SCR_HEIGHT);
wnd=GetHWnd();
Snake*sn;//建立蛇的指针
Food*fd;//建立食物的指针
short score;//用于保存积分
bool exit=false;
Direction changed_dir;//changed_dir用来保存蛇新变换的方向
short keypress;
bool survive=true;//表示游戏在进行中
char str_title[20]="Score: ";//用于显示得分的字符串, 显示在窗口标题栏
char str_score[6]="0";//用于显示分数的字符串,和前一个字符串合并显示在标题栏上
while(true)
{
DrawTitle();
keypress=getch();
if(keypress=='q'||keypress=='Q') break;//按q键离开游戏
DrawScene();
sn=new Snake();//实例化原始状态的蛇
sn->DrawBegin();//将最初的蛇画出
fd=new Food();//实例化一个食物
fd->Paint();//将新产生的食物画出
score=0;
strcpy(str_title,"Score: 0");
SetWindowText(wnd,str_title);//显示在标题栏上
changed_dir=sn->GetDirection();//获得蛇初始的方向
survive=true;//游戏刚开始,是有生命状态
while(survive)
{
if(kbhit()!=0)//如果有按键行为才处理这里
{
if(getch()==224)
{
switch(getch())
{
case 72://up
if(sn->GetDirection()==LEFT||sn->GetDirection()==RIGHT)
changed_dir=UP;
break;
case 80://down
if(sn->GetDirection()==LEFT||sn->GetDirection()==RIGHT)
changed_dir=DOWN;
break;
case 75://left
if(sn->GetDirection()==UP||sn->GetDirection()==DOWN)
changed_dir=LEFT;
break;
case 77://right
if(sn->GetDirection()==UP||sn->GetDirection()==DOWN)
changed_dir=RIGHT;
break;
}
}
}
if(!sn->HeadOn(changed_dir))
{
MessageBox(wnd,"Game over!","Prompt",MB_OK);
survive=false;
}
if(sn->Eat(fd->GetX(),fd->GetY()))//如果吃到食物
{
score+=(10+20*fd->IsSpecialFood());//吃到普通食物得10分,特殊食物得30分
strcpy(str_title,"Score: ");
itoa(score,str_score,10);//将分数转换成字符串
strcat(str_title, str_score);//合并成Score: 后面加分数的样式
SetWindowText(wnd,str_title);
delete fd;
fd=new Food();//在另外位置新产生一个食物
fd->Paint();//画出来
}
else
sn->EraseTail();//没有吃到食物就擦掉蛇尾
if(fd->Elapse())
{
fd->Clear();//先擦掉再释放内存
delete fd;
fd=new Food();
fd->Paint();//画出食物
}
/*
if(GetAsyncKeyState(VK_UP)==-32767)
{
if(sn.GetDirection()==LEFT||sn.GetDirection()==RIGHT)
changed_dir=UP;
}
if(GetAsyncKeyState(VK_DOWN)==-32767)
{
if(sn.GetDirection()==LEFT||sn.GetDirection()==RIGHT)
changed_dir=DOWN;
}
if(GetAsyncKeyState(VK_LEFT)==-32767)
{
if(sn.GetDirection()==UP||sn.GetDirection()==DOWN)
changed_dir=LEFT;
}
if(GetAsyncKeyState(VK_RIGHT)==-32767)
{
if(sn.GetDirection()==UP||sn.GetDirection()==DOWN)
changed_dir=RIGHT;
}
*/
Sleep(180);
}
}
closegraph();
return 0;
}
(Dev-c++)为什么会报错[Error] ld returned 1 exit status?
- 写回答
- 好问题 0 提建议
- 追加酬金
- 关注问题
- 邀请回答
-
3条回答 默认 最新
悬赏问题
- ¥15 C# datagridview 栏位进度
- ¥15 vue3页面el-table页面数据过多
- ¥100 vue3中融入gRPC-web
- ¥15 kali环境运行volatility分析android内存文件,缺profile
- ¥15 写uniapp时遇到的问题
- ¥15 vs 2008 安装遇到问题
- ¥15 matlab有限元法求解梁带有若干弹簧质量系统的固有频率
- ¥15 找一个网络防御专家,外包的
- ¥100 能不能让两张不同的图片md5值一样,(有尝)
- ¥15 informer代码训练自己的数据集,改参数怎么改