文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>贪吃蛇原型实现基本思路

贪吃蛇原型实现基本思路

时间:2010-07-19  来源:bilipan

贪吃蛇的原型是在windows控制台下即在字符模式下利用C++编写贪吃蛇。

主要实现的效果就是,用户利用'w'、's'、'a'、'd'分别表示上下左右,当蛇碰到障碍物时通不过,当碰到食物时,分数加1,同时,在另外一个地方生成新的食物,并且身体会增加一个字符的长度。

在实现该原型前必须实现两项技术:
  • 字符上色,这个利用了网上的代码
  • 字符位置控制


什么意思呢?主要是因为考虑到在通常情况下,在控制台下编写的程序,默认都是黑白色的,颜色单一,而且蛇和障碍物、食物之间无法被互相区分,所以加上更多的颜色,视觉上会更舒服些。字符位置控制呢,是必不可缺的。这个是因为在命令行模式下,程序是默认顺序接收用户输入的,偶尔可以跳至同一行稍前些的位置。但是,由于蛇要到处爬,所以这就遇到一个问题,如何让输入光标跳至窗口下的任意位置成了开发的基础和前提。具体的我后面会讲到我的解决方案。

我的实现思路:

首先,我要创建一个游戏背景,具体指的是贪吃蛇的移动范围。这个呢,我用二维的数组来表示。每个单元格有几个参数---是否存在障碍物、是否存在食物,如果有的话,就用true,否则为false。

//这个是背景的单元格数据结构
const length = 40;
const width = 20;
struct square{
   bool blocked;  //是否有障碍物
   bool food;       //是否有食物
   int x;               //单元格在背景中的相对横坐标
   int y;               //单元格在背景中的相对纵坐标
}bg[length][width];  //直接创建游戏背景

//设置背景
void setBG(int length, int width){
        HANDLE hOut;
    COORD OutChar;      
        OutChar.X = 10; 
        OutChar.Y = 10;
        int i = 0;
        int j = 0;
        for(i = 0; i < width; i++){
                for(j = 0; j < length; j++){
                        bg[i][j].x = i;
                        bg[i][j].y = j;
                        bg[i][j].blocked = false;
                        bg[i][j].food = false;
                        OutChar.X = j+10;
                        hOut = GetStdHandle(STD_OUTPUT_HANDLE);
                        SetConsoleCursorPosition(hOut,OutChar);
                        cout << col(BG_WHITE,true) << " ";
                }
                cout << endl;
                OutChar.Y = i+10;
                SetConsoleCursorPosition(hOut,OutChar);
        }
}


接下来,就是要在背景上创建障碍物,在创建它们之前,首先得解决如何在指定的单元格式绘制单元。思路很简单,就是编写一个函数将光标定位到相应的坐标位置,然后输入一个空白的上色字符就解决了。然后就可以利用这个函数在真正的背景上相应的位置构建障碍物了。同时可以实现随机创建任意个、任意位置的障碍物了。
//构造障碍物
void createBlock(int x, int y, unsigned short color){
        HANDLE hOut;
             COORD OutChar;     
        OutChar.X = x; 
        OutChar.Y = y;
        hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleCursorPosition(hOut,OutChar);  //定位光标输入
        cout << col(color, true) << " ";  //一个颜色为color的空白字符
}

//生成单个障碍物
void createWall(int x,int y){
        createBlock(x+10,y+10,BG_GREEN);
        bg[x][y].blocked = true;
}

//判断所指坐标是否被占用
bool checkExisted(int x,int y){
        if(bg[x][y].blocked == true || bg[x][y].food == true){
                return false;
        }
        return true;
}

//随机生成障碍物
void rand_createWall(void){
        srand((unsigned)time(NULL));
        int n = rand() % 70+10;
        int pos_x = 0;
        int pos_y = 0;
        int i = 0;
        for(i = 0; i < n; i++){
                pos_x = rand() % length;
                pos_y = rand() % (width-1);
                if(checkExisted(pos_x,pos_y) == true){ //防止障碍物重叠
                        createWall(pos_x,pos_y);
                }else{
                        n++;
                }
                //createWall(pos_x,pos_y);
        }
}

同理,食物的创建也一样。
//创建食物
void createFood(int x,int y){
        createBlock(x+10,y+10,BG_BLUE);
        bg[x][y].food = true;
}

//随机创建食物
void rand_createFood(void){
        srand((unsigned)time(NULL));
        int n = 1;//rand() % 20;
        int pos_x = 0;
        int pos_y = 0;
        int i = 0;
        for(i = 0; i < n; i++){
                pos_x = rand() % length;
                pos_y = rand() % (width-1);
                if(checkExisted(pos_x,pos_y) == true){  //防止在障碍物上生成食物
                        createFood(pos_x,pos_y);
                }else{
                        n++;
                }
        }
}

背景、障碍物和食物都创建好了,接下来就要构建蛇的模型了。由于考虑到蛇在吃完食物后,身体会变长,所以我采用了顺序表的数据结构来记录蛇的信息。那如何来表现蛇的移动呢?我的思路是,将身体靠近头的信息传递到次靠近头的,同时将新的下一步要走的坐标信息传给头部,同时有擦除掉尾部信息即可。
//物体信息,这是蛇的单元模型
const objLen = 5;
struct obj{
        int x;
        int y;
}snake[objLen];

//创建蛇
LinList<struct obj> newSnake;
void createSnake(void){
        int i = 0;
        for(i = 0; i < objLen; i++){
                snake[i].x = i;
                snake[i].y = 0;
                newSnake.Insert(snake[i],i);
        }
}

//绘制蛇
void drawSnake(int len){
        int i = 0;
        struct obj t;
        for(i = 0; i < len; i++){
                t = newSnake.GetData(i);
                createBlock(t.x,t.y,BG_RED);
        }
}

//增长蛇的身体
void insreaseSnake(int x,int y){
        struct obj t;
        t.x = x;
        t.y = y;
        newSnake.Insert(t,0);
        createBlock(x,y,BG_RED);
}

//传递蛇的信息
void transSnake(int x,int y,int len){
        int i = 0;
        struct obj t1,t2;
        for(i = 0; i < len-1; i++){
                t1 = newSnake.GetData(i);
                t2 = newSnake.GetData(i+1);
                newSnake.Delete(i);
                t1.x = t2.x;
                t1.y = t2.y;
                newSnake.Insert(t1,i);
        }
        newSnake.Delete(newSnake.Size()-1);
        t1.x = x;
        t1.y = y;
        newSnake.Insert(t1,newSnake.Size()-1);
}



这里的相对位置是指以背景左上方的点为原点即(0,0),右下方为(length-1,width-1)。

接着呢,就是要获取用户的方向控制操作,并执行它们。由于采用的二维数组的方式表示蛇的形状以及游戏背景,所以当接收到命令如果是‘上’时,横坐标不变,而纵坐标减1,同时擦除原形状,如此一来,蛇就向上爬了。擦除函数的原理很简单,就是将对应的背景单元格的信息全部还原为初始值,就可以了。
//清除物体移动轨迹
void removeTrack(int x, int y){
        HANDLE hOut;
    COORD OutChar;
        OutChar.X = x; 
    OutChar.Y = y;
        hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleCursorPosition(hOut,OutChar);
        cout << col(BG_WHITE,true) << " ";
}

//移动物体
int x = 10;
int y = 10;
int tail_x = 0;
int tail_y = 0;
void moveBlock(char direction){
        HANDLE hOut2;
    COORD OutChar2;
        OutChar2.X = x; 
    OutChar2.Y = y;
        struct obj t;
        t = newSnake.GetData(0);
        tail_x = t.x;
        tail_y = t.y;
        hOut2 = GetStdHandle(STD_OUTPUT_HANDLE);
        removeTrack(t.x,t.y);
        switch(direction){
                case 'w':{
                        OutChar2.Y--;
                        y--;
                        SetConsoleCursorPosition(hOut2,OutChar2);
                        break;
                }
                case 's':{
                        OutChar2.Y++;
                        y++;
                        SetConsoleCursorPosition(hOut2,OutChar2);
                        break;
                }
                case 'a':{
                        OutChar2.X--;
                        x--;
                        SetConsoleCursorPosition(hOut2,OutChar2);
                        break;
                }
                case 'd':{
                        OutChar2.X++;
                        x++;
                        SetConsoleCursorPosition(hOut2,OutChar2);
                        break;
                }
        }

        transSnake(x,y,newSnake.Size());
        drawSnake(newSnake.Size());
}

做完这个,不要以为就这样结束了,因为我们还没对蛇的运动范围作出限制,而且还要实现蛇的触发事件即碰到食物后身体变长,食物数增加1。
//判断是否碰到障碍物或边界
bool checkView(char direction){
        if(direction == 'w' && y >= 10){
                if(y == 10 || bg[x-10][y-10-1].blocked == true){return false;}
        }
        else if(direction == 's' && y < 10+width){
                if(y == 10+width-2 || bg[x-10][y-10+1].blocked == true){return false;}
        }
        else if(direction == 'a' && x >= 10){
                if(x == 10 || bg[x-10-1][y-10].blocked == true){return false;}
        }
        else if(direction == 'd' && x < 10+length){
                if(x == 10+length-1 || bg[x-10+1][y-10].blocked == true){return false;}
        }
        return true;
}

//判断是否吃到食物
bool checkFood(int x, int y){
        if(bg[x-10][y-10].food == true){return true;}
        return false;
}


下面就是游戏原型的主函数:
int main()
{
        HANDLE hOut;
    COORD OutChar;      

        OutChar.X = 0; 
        OutChar.Y = 0;
        hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleCursorPosition(hOut,OutChar);

/*
                struct square **bgR = new square*[width];
                struct square *bgC = new square[length];
                for(int i = 0; i < width; i++){
                        bgR[i] = bgC;
                }
*/
        //设置背景
        setBG(length,width);
        //设置障碍物
        rand_createWall();
        //设置食物
        rand_createFood();
        //创建蛇
        createSnake();
        //移动物体
        char direction;
        int score = 0;
        for(;;){
                direction = getch();
                if(checkView(direction) == true){//判断能否移动
                        moveBlock(direction);
                        if(checkFood(x,y) == true){//判断是否吃到食物
                                bg[x-10][y-10].food = false;
                                score++;
                                insreaseSnake(tail_x,tail_y);//增长身体
                                rand_createFood();//吃完后随机在创建一个食物
                        }
                }
                OutChar.X = 0; 
                OutChar.Y = 0;
                hOut = GetStdHandle(STD_OUTPUT_HANDLE);
                SetConsoleCursorPosition(hOut,OutChar);
                cout << col(BG_WHITE,true) << "Scores: " << score;
        }
        return 0;
}


这个贪吃蛇原型是我一时兴起弄的,考虑的也比较简单,况且是第一次写这种文章,所以哪里讲的不清楚或是程序有问题的,请大家多包涵。如果有建议或不清楚的地方,我会尽力解答的。谢谢。
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载