c++实现的贪吃蛇

类别:编程语言 点击:0 评论:0 推荐:

在tc 3.0下调试通过,因为tc 3.0不支持bool 类型,所以程序中自定义了个枚举类型变量bool
如果在vc或者bc中运行,可以把这个bool类型注释掉.
贪吃蛇的核心算法时如何实现移动和吃掉食物.
没有碰到食物的时候,把当前运动方向上的下个节点入队,并以蛇节点的颜色重绘这个节点.
然后把头指针所指的节点出队,并以游戏框架内部背景色重绘出队的节点,这样就可以达到移动的效果.
而在吃到食物的时候,则只需把食物入队即可.


// greedsnake.cpp
#include <bios.h>
#include <conio.h>
#include <dos.h>
#include <graphics.h>
#include <stdlib.h>
#include <time.h>
#include "conf.h"

typedef struct node
{
     int x,y;
     struct node *next;
}Node;

typedef struct
{
     Node *head,*tail;
     int length;
}Snake;
typedef struct                    
{
     int left,top,right,bottom;
}Frame;

typedef enum                    //四个方向
{
     up,down,left,right
}Direction;
typedef enum
{
     false,true
}bool;

void InitGraphMode();                     //初始化图形驱动
void CloseGraphMode();                
void Foot(int,int);                            
void Head(int,int);
void CreateFrame();                    //完成整个游戏框架的绘制    
void CreateSnake();                    //创建一条两个节点的蛇,蛇的每一节是队列中的一个节点
bool PlayGame();                        //游戏的主体函数,
int Hit(int,int);                               //判断是否越界,或者撞到自身,两个参数分别是新的头接点的x,y坐标
bool GameOver();                        //绘制游戏结束时弹出的对话框                       
void Enqueue(Node);                    //入队函数
Node Dequeue();                        //出队函数
void ClearKeyBuf();                       //清除键盘缓冲,此函数可以消除不停的按无效键的影响

Snake snake;
Frame frame;
void main()
{
     InitGraphMode();
     do
     {
      CreateFrame();
     }while(PlayGame());
     CloseGraphMode();
}
void InitGraphMode()
{
     int gdriver=DETECT,gmode;
     initgraph(&gdriver,&gmode,"../bgi/");
     cleardevice();
}
void CloseGraphMode()
{
     cleardevice();
     closegraph();
}
void CreateFrame()
{
     setbkcolor(CYAN);                    
//下面的四行代码用于计算主框架的左上角和右下角的坐标
     frame.left=(getmaxx()+1-BlockWidth*RowOfFrame)/2; 
     frame.top=(getmaxy()+1-BlockHeight*ColumnOfFrame)/2;
     frame.right=frame.left+BlockWidth*RowOfFrame;
     frame.bottom=frame.top+BlockHeight*ColumnOfFrame;
     Head(frame.left+100,frame.top-20);
     setfillstyle(SOLID_FILL,LIGHTGRAY);
     bar(frame.left,frame.top,frame.right,frame.bottom);
     setlinestyle(SOLID_LINE,1,1);
     setcolor(DARKGRAY);
     line(frame.left,frame.top,frame.right,frame.top);
     line(frame.left,frame.top,frame.left,frame.bottom);
     setlinestyle(SOLID_LINE,1,1);
     setcolor(WHITE);
     line(frame.left,frame.bottom,frame.right,frame.bottom);
     line(frame.right,frame.top,frame.right,frame.bottom);
     setlinestyle(DOTTED_LINE,1,1);
     setcolor(BLUE);
     for(int row=1;row<RowOfFrame;row++)
          line(frame.left+row*BlockWidth,frame.top,frame.left+row*BlockWidth,frame.bottom);
     for(int column=1;column<ColumnOfFrame;column++)
          line(frame.left,frame.top+column*BlockHeight,frame.right,frame.top+column*BlockHeight);
     Foot(frame.left,frame.bottom+20);
}
void CreateSnake()
{
     Node *node1=new Node;
     Node *node2=new Node;
      node1->x=frame.left+BlockWidth;
     node1->y=frame.top;
     node1->next=NULL;
     snake.tail=node1;
     node2->x=frame.left;
     node2->y=frame.top;
     node2->next=snake.tail;
     snake.head=node2;
     snake.length=2;
     setfillstyle(SOLID_FILL,BLUE);
     bar(snake.head->x+1,snake.head->y+1,snake.head->x+BlockWidth-1,snake.head->y+BlockHeight-1);
     bar(snake.tail->x+1,snake.tail->y+1,snake.tail->x+BlockWidth-1,snake.tail->y+BlockHeight-1);
}

bool PlayGame()
{
    int speed=300,key;
    Direction CurrentDirection=right;
    Node randomNode;
    Node newNode,outNode;
    bool neednode=true;
    bool overlap=false;
    int randx,randy;
    CreateSnake();

 while(true)
 {
     if(neednode==true)
      {
          randomize();
          do
           {
               randx=frame.left+rand()%RowOfFrame*BlockWidth;
               randy=frame.top+rand()%ColumnOfFrame*BlockHeight;  
               for(Node *p=snake.head;p!=NULL;p=p->next)//hit itself
                    if(randx==p->x&&randy==p->y)
                        {overlap=true;break;}
       }
      while(overlap==true);
      randomNode.x=randx;
      randomNode.y=randy;
      randomNode.next=NULL;
      setfillstyle(SOLID_FILL,RED);
      bar(randomNode.x+1,randomNode.y+1,randomNode.x+BlockWidth-1,randomNode.y+BlockHeight-1);
      neednode=false;
  }

 if((key=bioskey(1))!=0)
 {
      switch(key)
      {
       case ESC:  return false;
       case UP:
            if(CurrentDirection!=down)
                 CurrentDirection=up;
               ClearKeyBuf();
              break;
       case DOWN:
            if(CurrentDirection!=up)
                 CurrentDirection=down;
                ClearKeyBuf();
                break;
       case LEFT:
            if(CurrentDirection!=right)
                 CurrentDirection=left;
                 ClearKeyBuf();
                 break;
       case RIGHT:
            if(CurrentDirection!=left)
                 CurrentDirection=right;
                ClearKeyBuf();
                break;
       case PAGEUP:speed=speed-100;
            if(speed<100)
                 speed=100;
            ClearKeyBuf();
            break;
       case PAGEDOWN:speed=speed+100;
            if(speed>500)
                 speed=500;
            ClearKeyBuf();
            break;
       default :break;
      }
 }
 int headx=snake.tail->x;
 int heady=snake.tail->y;
 switch(CurrentDirection)
 {
  case up: heady-=BlockHeight;break;
  case down: heady+=BlockHeight;break;
  case left: headx-=BlockWidth;break;
  case right: headx+=BlockWidth;break;
 }
 if(Hit(headx,heady))    //whether the snake hit the wall or itself
  return GameOver();
 else
 {       //eat
  if(headx==randomNode.x&&heady==randomNode.y)
  {
   Enqueue(randomNode);
   setfillstyle(SOLID_FILL,BLUE);
   bar(randomNode.x+1,randomNode.y+1,randomNode.x-1+BlockWidth,randomNode.y-1+BlockHeight);
   neednode=true;
  }
  else     //no eat
  {
   newNode.x=headx;
   newNode.y=heady;
   newNode.next=NULL;
   Enqueue(newNode);
   outNode=Dequeue();
   setfillstyle(SOLID_FILL,LIGHTGRAY);
   bar(outNode.x+1,outNode.y+1,outNode.x+BlockWidth-1,outNode.y+BlockHeight-1);
   setfillstyle(SOLID_FILL,BLUE);
   bar(newNode.x+1,newNode.y+1,newNode.x-1+BlockWidth,newNode.y-1+BlockHeight);
  }
 }
 delay(speed);
 }
}
void ClearKeyBuf()
{
 do
  bioskey(0);
 while(bioskey(1));
}

void Foot(int x,int y)
{
 setcolor(BLUE);
 outtextxy(x,y,"writer:[T]RealXL E-MAIL:[email protected]");
}
void Head(int x,int y)
{
 setcolor(RED);
 outtextxy(x,y,"GREEDY SNAKE");
}
void Enqueue(Node inNode)
{
 Node *p=new Node;
 p->x=inNode.x;
 p->y=inNode.y;
 p->next=inNode.next;
 snake.tail->next=p;
 snake.tail=p;
 snake.length++;
}
Node Dequeue()
{
 Node *p=snake.head;
 Node outNode=*p;
 snake.head=p->next;
 snake.length--;
 delete p;
 return outNode;
}

int Hit(int x,int y)
{
 if(x<frame.left||x>=frame.right||y<frame.top||y>=frame.bottom)//hit the wall
  return 1;
 Node *p=snake.head->next;
 for(int i=snake.length-1;i>3;i--,p=p->next)//hit itself
  if(x==p->x&&y==p->y)
   return 1;
 return 0;
}

bool GameOver()
{
 int x=getmaxx()/2-50;
 int y=getmaxy()/2-20;
 setfillstyle(SOLID_FILL,DARKGRAY);
 bar(x+3,y+3,x+103,y+43);
 setfillstyle(SOLID_FILL,MAGENTA);
 bar(x,y,x+100,y+40);
 setlinestyle(0,3,1);
 setcolor(RED);
 rectangle(x,y,x+100,y+40);
 outtextxy(x+20,y+10,"GAGE OVER!");
 char c;
 while(true)                                        //按q或Q表示退出程序,按r或R表示重新开始游戏
 {
  c=getch();
  if(c=='q'||c=='Q')
   return false;
  else if(c=='r'||c=='R')
   return true;
 }
}
//conf.h                                                           
#ifndef _conf_h
#define _conf_h
#define RowOfFrame    20         //主框架的行数
#define ColumnOfFrame 20         //主框架的列数
#define BlockWidth    15        //每个蛇节点的宽度
#define BlockHeight   15        //每个蛇节点的高度
#define UP   18432
#define DOWN  20480
#define LEFT  19200
#define RIGHT  19712
#define ESC   283
#define ENTER  7181
#define PAGEUP  18688
#define PAGEDOWN 20736
#endif

本文地址:http://com.8s8s.com/it/it26832.htm