自己学习编写的贪吃蛇小游戏,内容不够精简,希望可以相互交流学习,运行环境是mac

#include<stdio.h>

#include<curses.h>

#include<sys/types.h>

#include<sys/ioctl.h>

#include<unistd.h>

#include<termios.h>

#include<sys/time.h>

#include<stdlib.h>

#include<curses.h>

#include <pthread.h>

#define LEN sizeof(struct snack)

int c_long,c_high;                                   //界面大小

int score;                                           //分数

int num;                                             //链表节点数,也是蛇的长度

int level;                                           //等级

int direct;                                          //键入方向

int direct_last;                                     //保存上一次的键入方向

bool jude;                                           //蛇是否死亡标志

bool again;                                          //游戏是否结束标志

char end;                                            //获取游戏结束指令

struct snack *p1,*p2,*head,*tail;                    //创建链表指针

WINDOW *win1,*win2,*win3;                            //创建游戏窗口

void interface(int x,int y);                         //绘制窗口win1,win2

void food_direct(void);                              //产生随机食物

void game_start(void);                               //游戏开始,产生随机蛇头,赋予初始移动方向

void move_control(int x);                            //根据键入方向,产生前进坐标

char snack_dead(void);                               //判断蛇是否死亡

void snack_show(void);                               //将蛇身链表显示在屏幕上

void snack_move(void);                               //蛇移动

void score_level(void);                              //分数和等级

void move_order(void);                               //键入移动方向

void game_end(void);                                 //游戏结束

struct food                                         //存储食物坐标

{

    int y;

    int x;

}food;

struct snack                                        //蛇身节点坐标

{

    int x;

    int y;

    struct snack *next;

    struct snack *back;

}snack;

struct snack * Creat(void)                          //建立蛇身链表

{

    ++num;

    p1=(struct snack *)malloc (LEN);

    if(num==1)  head=p1;

    else tail->next=p1;

    p1->x=snack.x;

    p1->y=snack.y;

    p1->next=NULL;

    p1->back=tail;

    tail=p1;

    return (tail);

}

int main()

{

    

    struct winsize size;                            //获取界面大小

    ioctl(STDIN_FILENO,TIOCGWINSZ,&size);

    c_long=size.ws_col;                             //屏幕长

    c_high=size.ws_row;                             //屏幕高

  

    initscr();                                      //开启curses模式

    start_color();                                  //开启颜色模式

    

    begin:                                          //循环开始节点

    score=0;                                        //考虑到代码循环使用,全局变量的初始化放在main函数循环体中

    num=0;

    jude=false;

    tail=NULL;

    

    keypad(stdscr,TRUE);                            //curses接管键盘转义

    noecho();                                       //输入不回显

    curs_set(0);                                    //不显示光标

    

    interface(c_long,c_high);                       //调用函数,游戏开始

    game_start();

    snack_show();

    food_direct();

    

    pthread_t snack;                                                           //创建两个线程

    pthread_t control;

    pthread_create(&snack, NULL, (void *)snack_move, NULL);                    //蛇移动线程

    pthread_create(&control, NULL, (void *)move_order, NULL);                  //方向控制线程

    

    pthread_join(snack, NULL);                                                 //等待蛇移动线程结束

    pthread_cancel(control);                                                   //终止方向控制线程

    

    game_end();                                                                //调用函数,决定是否循环

    if (again) goto begin;

    endwin();                                                                  //关闭curses模式

    return 0;

}

void interface(int x,int y)                                                    //绘制界面

{

    

    win1=newwin(c_high,c_long-40,0,0);//新窗口(行,列,begin_y,begin_x)            //创建新窗口win1

    box(win1,ACS_VLINE,ACS_HLINE);

    

    win2=newwin(c_high,39,0,c_long-39);//新窗口(行,列,begin_y,begin_x)           //创建新窗口win2

    box(win2,ACS_VLINE,ACS_HLINE);

    mvwprintw(win2,16,14,"Retro Snaker");                                       //窗口win2显示实时数据

    mvwprintw(win2,24,14,"Level:     1");

    mvwprintw(win2,32,14,"You Score: 0");

    

    refresh();                                                                  //刷新三个窗口

    wrefresh(win1);

    wrefresh(win2);

}

void game_start(void)                             //游戏开始,产生一个随机蛇头和初始运动方向

{

    int a,b;

    a=c_long-50;                                  //蛇头产生的位置限制在win1内

    b=c_high-5;

    srand((int)time(NULL));

    snack.y=rand()%a+1;

    srand((int)time(NULL));

    snack.x=rand()%b+1;                           //产生随机蛇头坐标

    move(snack.x,snack.y);

    

    if(snack.y<=a/2)   direct=KEY_RIGHT;          //产生初始运动方向

    else direct=KEY_LEFT;                         //蛇头在左半面初始向右,在右半面初始向左

    

}

void snack_show(void)                             //蛇链表处理与显示

{

    p2=Creat();                                   //snack结构体中的坐标纳入链表,p2指针指向蛇头

    if(num!=score+1)                              //蛇长度没有变化执行

    {

        num--;

        move(head->x,head->y);                    //蛇尾位置输出空字符

        addch(' ');

        p1=head;                                  //释放蛇尾(链表头)

        head=p1->next;

        head->back=NULL;

    }

    

    do{

        move(p2->x,p2->y);                                  //光标移动至p2所指坐标

        attron(COLOR_PAIR(1));                              //设置输出字符格式为黑底黄字

        init_pair(1, COLOR_YELLOW, COLOR_BLACK);

        addch('*');                               //输出*字符

        p1=p2->back;                              //p2指针后移

        p2=p1;

    }while(p2!=NULL);                             //输出完毕退出

    

}

void food_direct(void)                            //产生随机食物

{

    int a,b,x,y;

    bool j=true;                                  //食物是否合法标志

    a=c_long-42;                                  //食物产生的位置限制在win1内

    b=c_high-2;

    do{

        srand((int)time(NULL));                   //产生随机坐标

        y=rand()%a+1;

        srand((int)time(NULL));

        x=rand()%b+1;

        p1=tail;                                  //坐标是否在蛇身上

        do{

            if(x==p1->x&&y==p1->y) j=false;       //是,坐标非法

            else {

                p2=p1->back;

                p1=p2;

            }

        }while(p2!=NULL&&j==true);

    }while(j==false);                             //循环直至坐标合法

    food.x=x;                                     //合法坐标送至食物坐标结构体

    food.y=y;

    

    attron(COLOR_PAIR(2)|A_BLINK);                //食物显示为黑底白字,闪烁

    init_pair(2, COLOR_WHITE, COLOR_BLACK);

    mvprintw(food.x,food.y,"*");

    attroff(COLOR_PAIR(2)|A_BLINK);

    wrefresh(win1);

    

}

void move_order(void)                                                                 //方向移动指令

{

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);                                 //设置线程响应cancel指令的方式为立即响应

    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);

    

    while(!jude){                                                                     //蛇没有死亡则进入循环

        direct_last=direct;                                                           //保存当前的移动方向

        usleep(300000-level*5000);                                                    //延时去抖

        direct=getch();                                                               //键入指令

        switch(direct)                                                                //指令与当前移动方向相反则指令无效

        {

            case KEY_UP:if(direct_last==KEY_DOWN) direct=KEY_DOWN;break;

            case KEY_DOWN:if(direct_last==KEY_UP) direct=KEY_UP;break;

            case KEY_RIGHT:if(direct_last==KEY_LEFT) direct=KEY_LEFT;break;

            case KEY_LEFT:if(direct_last==KEY_RIGHT) direct=KEY_RIGHT;break;

            default:direct=direct_last;break;                                          //键入非法指令则指令无效

        }

    }

}

void move_control(int x)                              //方向控制

{

    switch (x) {

        case KEY_UP:snack.x--;break;                  //键入为上,x-1

        case KEY_DOWN:snack.x++;break;                //键入为下,x+1

        case KEY_RIGHT:snack.y++;break;               //键入为右,y+1

        case KEY_LEFT:snack.y--;break;                //键入为坐,y-1

    }

    

}

char snack_dead(void)                                   //判断蛇是否死亡

{

    

    if(snack.x==0||snack.x==c_high-1||snack.y==0||snack.y>=c_long-41)   jude=true;                //蛇撞墙,死亡

    

    else if(num!=1)                                                                               //蛇头撞上蛇身,死亡

    {  p1=tail->back;

        do

        {

            if(snack.x==p1->x&&snack.y==p1->y)   jude=true;

            else

            {

                p2=p1->back;

                p1=p2;

            }

        }while(p2!=NULL&&!jude);

    }

    return (jude);

}

void snack_move(void)                             //蛇移动

{

    while(1)

    {

        move_control(direct);

        snack_dead();

        if(jude) break;                           //蛇撞墙,退出

        score_level();

        if(score==5428) break;                    //屏幕满,退出

        snack_show();

        refresh();

        usleep(300000-level*50000);               //蛇移动的速度

    }

    

}

void score_level(void)                                   //分数与等级

{

    if(tail->x==food.x&&tail->y==food.y)                 //蛇吃到食物

    {

        score++;                                         //分数+1

        food_direct();                                   //重新产生食物坐标

        mvwprintw(win2,32,25,"%d",score);

        wrefresh(win2);

        move(tail->x,tail->y);

    }

    if(score<10)  level=1;                               //根据分数设置等级,用来控制蛇的移动速度

    else   if(10<=score&&score<25)  level=2;

    else   if(25<=score&&score<50)  level=3;

    else   if(50<=score&&score<75)  level=4;

    else   if(75<=score)     level=5;

    mvwprintw(win2,24,25,"%d",level);

    wrefresh(win2);

}

void game_end(void)                                                                     //游戏结束界面

{

    

    win3=newwin(10,40,c_high/2-8,(c_long-40)/2-20);                                      //创建新窗口win3

    box(win3,ACS_VLINE,ACS_HLINE);

    if(score==5428) mvwprintw(win3,3,10,"You Win,try again?");

    else mvwprintw(win3,3,10,"You Lost,try again?");

    mvwprintw(win3,6,13,"Y");

    mvwprintw(win3,6,25,"N");

    touchwin(win3);

    wrefresh(win3);

    do                                                                                  //再来一次?

    {

        end=getch();

    }while(end!='Y'&&end!='N'&&end!='y'&&end!='n');

    

    if(end=='Y'||end=='y') again=true;

    else again=false;

   

    while(head!= NULL)                                                                  //释放链表

    {

        p1 = head;

        head = head->next;

        free(p1);

    }

}

运行结果展示

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值