贪吃蛇小游戏记录(带简陋登录界面,MessageBox现学现卖),不带解释

#include <stdio.h>
#include <stdlib.h>
#include <time.h> //time(NULL)
#include <windows.h> //gotoxy(); Windows API函数:MessageBox()
#include <conio.h> //getch
#define _ROW 20 //ROW与系统定义冲突——warning
#define _COL 20
/*
    函数名:gotoxy(int x, int y)
    函数功能:实现光标的定位
    函数参数:x代表列,y代表行
    函数返回值:无
*/
void gotoxy(int x, int y);

//打印登录背景
void paintWindow(int x,int y,int height, int width);

//贪吃蛇游戏
void SnakeGame();
/*
1.使用□绘制背景地图   (ps:使用二维数组存储蛇的身体位置)
int snake[100][2]={ {10, 10},
{10,11} };
2.随机生成蛇头▲、食物★的位置(x,y),并使用gotoxy(x,y)打印到地图上
3.使用w s a d按键,完成蛇头的上下左右移动
4.蛇头碰撞到食物后,吃下食物变成蛇身的一部分●,重新生成食物位置,显示在地图上——目前只会打印蛇身长度为1的情况
5.蛇撞墙后或蛇咬到自己的身体,程序结束,统计吃到的食物数量
*/
void Login()  //二维数组:符合某组登录账户
{
    //用户名和密码的长度;i;用户名和密码的匹配结果
    int n_len=0, p_len=0, i=0, nf = 0, pf = 0;
    char ch=0;//初始化='\0'
    //已存在的用户名和密码:
    char login_name[3][10]={
        "lily123","admins","kity123"
    };
    char login_pwd[3][10]={
        "123456","123123","111111"
    };
    //用户输入的用户名和密码:
    char name[10] = {0};
    char pwd[7] = {0};

    //画各个组件:(相对位置固定——宏定义和默认参数)
    int x=5, y=32, height=20, width=60;
    //用户名和密码的输入位置、登录或返回的选择位置——光标闪动+按下按键
    int pos[][2]={
        {(y+y+width)/2-6, (x+x+height)/2-2},
        {(y+y+width)/2-6, (x+x+height)/2+2},
        {(y+y+width)/2-5, x+height-2},
        {(y+y+width)/2+5, x+height-2}
    };
    //printf("请指定窗口位置(行列)、高和宽:");
    //scanf("%d%d%d%d",&x,&y,&height,&width);

    //void paintWindow(int x,int y,int height, int width);
    //Button功能组件???
    paintWindow(x,y,height,width);
    /*
    //组件位置数组pos
    int pos[][2]={
        {(y+y+width-sizeof(title)/sizeof(char))/2, x+2},
        {(y+y+width)/2-15, (x+x+height)/2-2},
        {(y+y+width)/2-15, (x+x+height)/2+2},
        {(y+y+width)/2-5, x+height-2},
        {(y+y+width)/2+5, x+height-2}
    };
    */

    while(!(nf && pf))
    {
        //清空数组
        memset(name,0,sizeof(name)/sizeof(char));
        memset(pwd,0,sizeof(pwd)/sizeof(char));
        //从头写入
        n_len = 0;
        p_len = 0;
        
        //20个空格覆盖用户名和密码:
        for(i=0 ; i<2 ; i++)
        {
            gotoxy(pos[i][0], pos[i][1]);
            printf("                    ");
        }

        //用户名:
        gotoxy(pos[0][0], pos[0][1]);
        //printf("Name:");
        while(1)
        {
            ch = getch();
            if((ch>='a'&&ch<='z' || ch>='A'&&ch<='Z'|| ch>='0'&&ch<='9') && n_len<8)
            {
                putch(ch); //'*'
                //存储到数组
                name[n_len++] = ch;
            }//回退
            else if(ch == '\b' && n_len>0)
            {
                name[--n_len] = '\0';//删除
                printf("\b \b");//覆盖
            }
            //=8就应该自动结束输入
            if(n_len>7 || ch=='\r')
            {
                break;
            }

        }//while-1
        
        for(i=0 ; i<3 ; i++)
        {
            if(strcmp(name,login_name[i])==0)
            {
                nf = 1;
                break;
            }//if
        }//for
        if(!nf)
        {
            //gotoxy(pos[0][0], pos[0][1]);
            //printf("用户名不存在!\n");
            //Sleep(1000);
            MessageBox(NULL,"用户名不存在!","登录验证",MB_OK|MB_ICONINFORMATION);
            
            continue;
        }

        //密码:
        gotoxy(pos[1][0], pos[1][1]);
        //printf("\nPassword:");
        while(1)
        {
            ch = getch();
            if(ch>='0' && ch<='9' && p_len<6)
            {
                putch('*');
                //存储到数组
                pwd[p_len++] = ch;
            }//回退
            else if(ch == '\b' && p_len>0)
            {
                pwd[--p_len] = '\0';//删除
                printf("\b \b");//覆盖
            }
            //=6就应该自动结束输入
            if(p_len>5 || ch=='\r')
            {
                break;
            }
        }//while-2
        
        if(strcmp(pwd,login_pwd[i])==0)
        {
            pf = 1;
        }//if

        if(!pf)
        {
            //gotoxy(pos[1][0], pos[1][1]);
            //printf("密码错误!\n");
            //Sleep(1000);
            MessageBox(NULL,"密码错误!","登录验证",MB_OK|MB_ICONINFORMATION);
            
            continue;
        }
    }//while-flag
    //弹窗实现:
    //printf("登录成功!");
    MessageBox(NULL,"登录成功!","登录验证",MB_OK|MB_ICONINFORMATION);
    //system("pause");
    system("cls");
}//Login

void log_PLay()
{
    int flag=2;
    //登录
    Login();
    while(flag)
    {
        printf("0——退出游戏\n1——贪吃蛇\n");
        //控制台中两列宽度 = 
        printf("请选择:");
        scanf("%d",&flag);
        switch(flag)
        {
        case 0:
            system("pause");
            system("cls");
            return;
        case 1:
            SnakeGame();
            break;
        default:
            break;
        }
        system("pause");
        system("cls");
    }//游戏
    return;
}//log_Play

int main()
{
    int flag = 2;
    //登录两次之后退出整个程序
    while(flag--)
    {
        log_PLay();
        //试想:按下返回才是真的退出
    }
    return 0;
}//main

//3、贪吃蛇游戏
void SnakeGame()
{
    //初始蛇长度为0,即没有蛇身; fnum为吃到的食物个数;flag=1时结束
    int len = 0, fnum = 0, flag = 0;
    //循环打印变量
    int i=0, j=0;
    //地图初始位置(y,x)
    int x=0, y=0;
    //食物位置、蛇头保留位置hx,yx
    int fx=0, fy=0, hx=0, hy=0;
    //按键控制
    char ch = 0;
    //规定蛇的坐标——x = row,y = col,然后gotoxy(y,x)
    int snake[100][2] = {
        {0,0}, //蛇头——(0,0)  (row,col)
        //{0,1}  //蛇身——(0,1)
    };

    printf("请输入地图打印位置——行列:");
    scanf("%d%d",&x, &y);
    //随机数种子
    srand(time(NULL));
    //随机坐标:蛇头位置、蛇身位置、食物位置
    snake[0][0] = rand()%_ROW+x;
    snake[0][1] = rand()%_COL*2+y;
    /*
    hx = snake[0][0];
    hy = snake[0][1];
    */

    //食物——被吃了才刷新
    fx = rand()%_ROW+x;
    fy = rand()%_COL*2+y;
    //1、打印地图:
    for(i=0 ; i<_ROW ; i++)
    {
        gotoxy(y,x+i);
        for(j=0 ; j<_COL ; j++) //中文字符横向占两格,要*2
        {
            //特殊的
            if( i+x == snake[0][0] && 2*j+y == snake[0][1])
            {
                printf("▲");
            }//头
            else if(i+x == fx && 2*j+y == fy)
            {
                printf("★");
            }//食物
            else 
            {
                printf("□");
            }//背景
        }//for-j                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
    }//for-i
    system("pause"); //暂停
    //监听键盘
    while(ch = getch())
    {
        //优化1:有移动
        if(ch=='w' || ch=='s' || ch=='a' || ch=='d')
        {
            //保留未加长的尾巴位置
            hx = snake[len][0];
            hy = snake[len][1];
            //蛇身长和吃下的食物有关
            for(i=len ; i>0 ; i--)
            {
                //不能先动蛇头
                snake[i][0] = snake[i-1][0];
                snake[i][1] = snake[i-1][1];
            }
        }
        //如果要先动蛇头,保留的应该是蛇头位置,这样snake数组存放的位置就是从尾到头——反过来的
        //2、移动蛇头——先动身:w——↑  a—— ←  s——↓  d——→
        switch(ch)
        {
        case 'w':
            if(snake[0][0] >= x)
            {
                snake[0][0]--;
            }
            break;
        case 's':
            if(snake[0][0] <= _ROW+x) //要=,否则=的时候进不来,没办法结束
            {
                /*
                //繁琐:
                for(i=len ; i>0 ; i--)
                {
                    //不能先动蛇头
                    snake[i][0] = snake[i-1][0];
                    snake[i][1] = snake[i-1][1];
                }
                */
                snake[0][0]++;
                
            }
            break;
        case 'a':
            if(snake[0][1] >= y) //横向每次移动2格,否则会变成▲●交替出现
            {
                snake[0][1] -= 2;
                
            }
            break;
        case 'd':
            if(snake[0][1] <= 2*_COL+y)  //要=,否则=的时候进不来,没办法结束
            {
                snake[0][1] += 2;
            }
            break;
        default:break;
        }//s-c
        /*
        //优化2:不用一个个这样判断:
        //判断是否越界/吃到蛇身,要在蛇身移动之前
                if(snake[0][1]+2 >= 2*_COL+y || (snake[0][0] == snake[1][0] && snake[0][1]+2 == snake[1][1]))
                {
                    printf("游戏结束!\n");
                    printf("共吃到%d个食物。\n",fnum);
                    return;
                }
        */
        //两种游戏异常结束的情况:在食物刷新前统计结果
        //1、是否越界
        if(snake[0][0]<x || snake[0][0]>=_ROW+x || snake[0][1]<y || snake[0][1]>=2*_COL+y)
        {
            flag = 1;
        }else 
        {
            //2、是否吃到自己
            for(i=1 ; i<=len ; i++)
            {
                if(snake[0][0]==snake[i][0] && snake[0][1]==snake[i][1])
                {
                    flag = 1;
                    break;
                }
            }
        }//if--else
        if(flag)
        {
            //打印在坐标信息下一行:
            gotoxy(0,x+_ROW+1);
            printf("游戏结束!\n");
            printf("共吃到%d个食物。\n",fnum);
            return;
        }

        //3、吃到食物:
        if(snake[0][0] == fx && snake[0][1] == fy)
        {
            fnum++;
            //食物刷新
            fx = rand()%_ROW+x;
            fy = rand()%_COL*2+y;
            //蛇身加长
            len++;
            //尝试3.0:
            snake[len][0] = hx;
            snake[len][1] = hy;

            //接在后面——缩头蛇。。。
            /*
            //尝试2.0:
            for(i=len ; i>0 ; i--)
            {
                snake[len][0] = snake[len-1][0];
                snake[len][1] = snake[len-1][1];
            }
            */

            /*
            //尝试1.0:
            snake[len][0] = snake[len-1][0];
            snake[len][1] = snake[len-1][1];
            //有bug:会超出背景(根据刚才按下的按键反推出原本的位置)
            switch(ch)
            {
            case 'w':
                snake[len][0] ++;
                break;
            case 's':
                snake[len][0] --;
                break;
            case 'a'://刚才向左吃到了食物
                snake[len][1] += 2;
                break;
            case 'd'://刚才向右吃到了食物
                snake[len][1] -= 2;
            default:
                break;
            }//s-c
            */
            
        }//if
        
        //4、刷新蛇的位置、食物的位置
        //system("cls");
        //优化3:不用清屏
        gotoxy(y,x);
        for(i=0 ; i<_ROW ; i++)
        {
            gotoxy(y,x+i);
            for(j=0 ; j<_COL ; j++)
            {
                //printf("□");
                //特殊的
                if( i+x == snake[0][0] && 2*j+y == snake[0][1])
                {
                    printf("▲");
                }//头
                else if(i+x == fx && 2*j+y == fy)
                {
                    printf("★");
                }//食物
                else 
                {
                    printf("□");
                }//背景
            }//for-j                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
        }//for-i
        //优化4:完善原来的不足,身体另外打印:<=len是因为i从1开始,<len的话不够用
        for(i=1 ; i<=len ; i++)
        {
            //printf("\nsnake[%d][1]=%d,snake[%d][0]=%d",i,snake[i][1],i,snake[i][0]);
            gotoxy(snake[i][1],snake[i][0]);
            printf("●");
        }
        //打印提示信息:
        gotoxy(0,x+_ROW);
        printf("(sx,sy)=(%d,%d),(ssx,ssy)=(%d,%d),(fx,fy)=(%d,%d)\n",snake[0][0],snake[0][1],snake[1][0],snake[1][1],fx,fy);
    }//while
}//SnakeGame

//打印登录背景:┌─┐ │└─┘
void paintWindow(int x,int y,int height, int width)
{
    //char title[]="贪吃蛇登录界面", uid[]="用户名:", upw[]="密码:", logb[]="登录", bkb[]="返回";
    //组件信息数组
    char info[][20]={
        "贪吃蛇登录界面",
            "用户名:",
            "密码:", 
            "登录",
            "返回"
    };
    //组件位置数组pos
    int pos[][2]={
        {(y+y+width-sizeof(info[0])/sizeof(char))/2, x+2},
        {(y+y+width)/2-15, (x+x+height)/2-2},
        {(y+y+width)/2-15, (x+x+height)/2+2},
        {(y+y+width)/2-5, x+height-2},
        {(y+y+width)/2+5, x+height-2}
    };
    

    int i=0, j=0;
    //x--row,y--col
    gotoxy(y,x);
    printf("┌");
    for(i=0 ; i<width-1 ; i++)
    {
        printf("─");
    }
    printf("┐");
    //height>=2才打印中间行
    for(i=1 ; i<height ; i++)
    {
        gotoxy(y,x+i);
        printf("│");
        gotoxy(y+width,x+i);
        printf("│");
    }
    gotoxy(y,x+height);
    printf("└");
    for(i=0 ; i<width-1 ; i++)
    {
        printf("─");
    }
    printf("┘");

    //相对位置打印组件:title、edit、button
    /*
    gotoxy(pos[0][0], pos[0][1]);
    printf("%s",title);
    gotoxy(pos[1][0], pos[1][1]);
    printf("%s",uid);
    gotoxy(pos[2][0], pos[2][1]);
    printf("%s",upw);
    gotoxy(pos[3][0], pos[3][1]);
    printf("%s",logb);
    gotoxy(pos[4][0], pos[4][1]);
    printf("%s",bkb);
    */
    //优化:把字符串都给到二维数组中就可以用for循环来遍历了
    for(i=0 ; i<sizeof(info)/(sizeof(char)*20) ; i++)
    {
        gotoxy(pos[i][0], pos[i][1]);
        printf("%s",info[i]);
    }

}//paintWindow

//光标定位:
void gotoxy(int x, int y)//形参
{
    HANDLE hOut;
    COORD pos = {x, y};
    // 光标的起始位(第1列,第3行) 0是第1列 2是第3行
    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOut, pos);
    //printf("定位光标位置搜索(%d,%d)\n",pos.X,pos.Y);
}//gotoxy

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值