#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
贪吃蛇小游戏记录(带简陋登录界面,MessageBox现学现卖),不带解释
最新推荐文章于 2024-09-29 15:33:28 发布