helehappy 发表于 2015-7-10 12:23:26

Linux终端贪吃蛇--

这几天看了下linux程序设计,昨天没事干,突发奇想写个贪吃蛇怎么样,因为想想这个游戏也简单!代码全是自己写!

要是有win下的童鞋,注意,这个是linux 版的,用到curses库和pthread库(多线程库)

前提都要安装相关的库
curses库   sudo apt-get install libncurses5-dev
pthread 库sudo apt-get install glibc-doc    sudo apt-get install manpages-posix-dev

编译的时候带上两库 gcc greedsnake.c -o greedsnake -lcurses -lpthread

注:代码全是自己想和写的,没有参照网上代码,故代码质量较差,高人勿喷!而且这个是刚刚完工的版本,存在bug,但是对于刚入门linuxC的来说
已经满意啦!

游戏实现:
        0,因为终端贪吃蛇,所以用字符表示它的身体了,哈
        1,首先是用键盘几个方向键控制贪吃蛇的方向,我这里用全局变量way表示,0 向左,1 向上,2 向右,3 向下
        2,当头部触及到食物的时候,向前走一步,把食物纳为自己身体,同时最后一节身体不丢失,实现身长+1
        3,触及到墙壁或者自己身体的时候,那么蛇死

游戏重点分析:
        一    运行分析
                因为我没有接触到多线程那些,昨天刚开始写的时候只用了curses库,发现贪吃蛇既要向已定的方向移动,又要监视键盘的输入,刚开始我都没有想到要用多线程,后面写完主体实现后发现,运行点击键盘就崩溃程序,百思不得妻姐,后来脑子一闪,想到了java中的多线程,因为接触C都从来没有用过多线程,所以就仓促百度了下实现过程:
        这里,监视键盘输入做为主线程,而游戏运动作为游戏开始后再创立的线程,这样就能实现键盘输入和游戏运行互不影响

        二   如何让终端描绘贪吃蛇
                错误观点:因为使用curses库终端就是一个24×80的屏幕(默认大小),我这里首先想到用一个二维数组,刚开始全部赋值0,表示终端对应x,y坐标不显示任何东西,而要是array = 1 那么对应就是贪吃蛇的身体一个点,我首先用这种思想试了,贪吃蛇成功走起,但是bug非常多,每前进一步,头部向前移,尾部点消失,就是这个关键,尾部点的坐标,一开始我是用rear_x 和rear_y保存尾部点,但是,当蛇向前移的时候,下一个尾部点的对应坐标是什么呢?是它的四个方向的哪一个?刚开始想的是哪个方向点不为空就是谁,但是为题来了,当蛇身体有一部分在身边如何判断?(就是它尾部点周围方向又有其他身体点,如蛇的缠绕在一起,尾部周围可能都是点,——) 所以二维行不通,
                正确:那就使用三维数组把,假设那个点存在,那么就保留当前点的时候蛇的前进方向,这样,有了rear_x rear_y就能通过当前点的方向找到下一个尾部节点,比如array = 1 array = 2表示当前点为蛇的身体一节点,该节点的前进方向是2(向右)那么这个节点的后一个节点就是
array,以此类推,那么找到尾节点就不是问题、

至此,游戏大概思路就这样,主线程处理按键输入,另一线程让贪吃蛇按照既定方向前进

不说,直接上代码
#include <curses.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>

#define Q_line 22
#define width 78
#define height 22

int array={0};
int head_x = 10;
int head_y = 10;
int rear_x = 10;
int rear_y = 10;
int fool_x;
int fool_y;
int way = 3;
pthread_t id;
//0 left 1 up 2 right 3down


int getchoice();//获取键盘输入
void strat_game();//开始游戏
void creat_fool();//产生一个食物节点
void go();//贪吃蛇的运行前进
void refresh_win();//刷新界面
void creat_fool();//
int check_fool();//检测当前方向的前一个节点是不是食物
void go_catch();//吃掉食物
void find_rear();//找到后一个尾节点
void all_check();//检测是不是墙壁或者吃到自身
void snake_die();//死亡方法

int main()
{
    int choice;
    int first =0,key;
    initscr();
    noecho();
    cbreak();
    keypad(stdscr,1);
    mvprintw(5,5,"My Greedy Snake Game V1.0");
    mvprintw(6,10,"Power by HeLe");
    mvprintw(Q_line,5,"Press space to start");
    refresh();

    while((key = getchoice()) != 'q'){
      switch(key){
            case ' ':if(!first){strat_game();first=1;}
            break;
            case KEY_UP:if(way != 3){way = 1;array = 1;}
            break;
            case KEY_DOWN:if(way != 1){way = 3;array = 3;}
            break;
            case KEY_LEFT:if(way !=2){ way = 0;array = 0;}
            break;
            case KEY_RIGHT:if(way != 0) {way = 2;array = 2;}
            break;
      }
    }
    endwin();
    exit(EXIT_SUCCESS);
}

void snake_die()
{
    mvprintw(Q_line-1,5,"Snake has die,Press Q to quti");
    refresh();
    pthread_exit("Ok");
   
}

void all_check(int tway)      //check die
{
    if(head_x > Q_line || head_x < 1 || head_y > 77 || head_y < 1)snake_die();
    switch(tway){
      case 0:if(array == 1)snake_die();
      break;
      case 1:if(array == 1)snake_die();
      break;
      case 2:if(array == 1)snake_die();
      break;
      case 3:if(array == 1) snake_die();
      break;
    }
}

void refresh_win()
{
    int x,y;
    clear();
    for(x = 1; x <= height;x++ )
    {
      for(y = 1; y <= width; y++)
      {
            if(array == 1)
            {
                mvprintw(x,y,"%s","*");
            }
            if(x == rear_x && y==rear_y){
                mvprintw(x,y,"%s","$");
            }
            if(x==head_x && y == head_y){
                mvprintw(x,y,"%s","@");
            }
      }
    }
    for(x = 0 ,y =0;y < 78;y++)
    {
      mvprintw(x,y,"-");
      mvprintw(y,x,"|");
      mvprintw(Q_line+1,y,"-");
      mvprintw(y,width,"|");
    }
    move(height,width);
    refresh();
    usleep(200000);
    go();
}

int getchoice(){
    int key;
    key = getch();
    return key;
}

void creat_fool()
{
    srand((unsigned)time(NULL));
    fool_x = rand() %21+1;
    fool_y = rand()%77+1;
    while(array == 1)
    {
      fool_x = rand()%22+1;
      fool_y = rand()%78+1;
    }
    array = 1;
}

void strat_game()
{
    clear();
    //box(stdscr,'|','-');
    array = 1;
    array = 3;
    creat_fool();
    if((pthread_create(&id,NULL,(void*)refresh_win,NULL)) !=0){
      endwin();
      exit(1);
    }
}

int check_fool()
{
    switch(way)
    {
      case 0:if(head_x == fool_x && (head_y-1) == fool_y)return 1;
      else return 0;
      break;
      case 1:if((head_x-1) == fool_x && head_y == fool_y)return 1;
      else return 0;
      break;
      case 2:if(head_x == fool_x && (head_y+1) == fool_y)return 1;
      else return 0;
      break;
      case 3:if((head_x+1) == fool_x && head_y == fool_y)return 1;
      else return 0;
      break;
    }
}
void go_catch(int tway)
{
    array = 1;
    array = tway;
    head_x = fool_x;
    head_y = fool_y;
    creat_fool();
}

void find_rear()
{
    array = 0;
    switch(array){
      case 0:rear_y--;
      break;
      case 1:rear_x--;
      break;
      case 2:rear_y++;
      break;
      case 3:rear_x++;
      break;
    }
}

void go()
{
    switch(way)
    {
      case 0:if(check_fool()){
            go_catch(0);
      }
      else {
            all_check(0);
            array[--head_y] = 1;
            array = 0;
            array = 0;
            find_rear();
      }
      break;
      case 1:if(check_fool()){
            go_catch(1);
      }
      else {
            all_check(1);
            array[--head_x] = 1;
            array = 1;
            array = 0;
            find_rear();
      }
      break;
      case 2:if(check_fool()){
            go_catch(2);
      }
      else {
            all_check(2);
            array[++head_y] = 1;
            array = 2;
            array = 0;
            find_rear();
      }
      break;
      case 3:if(check_fool()){
            go_catch(3);
      }
      else {
            all_check(3);
            array[++head_x] = 1;
            array = 3;
            array = 0;
            find_rear();
      }
      break;
    }
    refresh_win();
}



如果有童鞋有更好的实现方法,可以说说我实现下,哈! 毕竟这个贪吃蛇完全出于我的手!!

helehappy 发表于 2015-7-10 12:27:05

图片效果

有为青年 发表于 2015-12-26 02:57:00

刚学习不久,很多看不懂,只能默默支持一下

tokyoghoul 发表于 2017-8-21 23:00:19

厉害了{:10_254:}
页: [1]
查看完整版本: Linux终端贪吃蛇--