本人目前大二,C语言程序设计是大一下学期学的,暂时还没有学数据结构,C语言中比较深入一点的知识也是浅尝辄止,路过的大佬请多多指教!
C语言是一种接近底层的语言,个人认为如果想要用C语言做一个游戏的话还是多运用一些必要的C语言库比较容易实现,所以再开始做项目之前我自学了eaxyx库。本人在接触C语言之前进行过较为系统的Python学习,在学习期间对Python中的pygame库颇感兴趣,在听到C语言期末作业要做一个游戏的时候首先有了‘C语言有没有自己的图形库’之类的疑问,并带着疑问百度搜索,最后在C语言中文网学习了《easyx初级教程》,简单来讲,它的功能就在于可以在C语言环境中进行图形绘制。(easyx的简单使用可以自行百度,太多了,但是建议只学会代码怎么用就好)easyx安装地址https://easyx.cn/
首先,在做事之前先对自己进行能力定位是我的一大习惯。我要用仅有的编程知识做出一个游戏就要尽可能降低难度,所以我选择了钢琴块。钢琴块的实现的简单之处在于它只需要对一个对象做考虑,也就是随机位置落下的方块。
在整个程序中用到的头文件:
#include<stdio.h>//C语言最基本的库所需头文件,不做解释
#include<stdlib.h>//运用链表时所要用到的库所需头文件
#include<graphics.h>//easyx库所需头文件,用于简单的图形绘制
#include<conio.h>//_kbhit()函数所需头文件,用于监听键盘输入,它和scanf()函数最大的区别在于它在进行键盘输入时不需要按回车键
- 首先我需要绘制背景和实现小球的降落,这里我用了三条线作为边界(两竖一横),实现代码为
我将屏幕设置成了大致和手机屏幕类似的竖屏,并分为四个区域,之后的方块会在四个区域中的随机区域开始降落。现在的方块只能在第一区域降落一次,并且方块暂时用填充小球代替
- 然后我需要实现方块在随机区域的出现,为了实现随机这个特点,我用到了rand()函数,它可以取连续的随机数,但是我要实现的四个区域的X坐标显然是不连续的(75、185、295、405),所以我又声明了一个新的变量xl,并且用switch()函数实现了随机区域的功能。当然,方块既然是从随机区域开始降落,那他就不止一次降落,所以这一就又要用到循环,所以我需要用到链表+for循环的方式。之所以用链表实现,是因为方块这一结构可能不止一个成员,比如我需要考虑它的随机区域的X坐标的值,后面还要判断它是否被消灭(判断游戏是否可以继续或结束),当然,更大的原因是想证明我可以熟练运用链表。
创建并初始化链表:
随机区域的实现:
这个for循环的意思是一共会出现51个方块,定义整型变量a并赋予0-3之间的一个随机数,然后用开关函数根据随机数a给整型变量xl赋上X坐标的值,定义整型变量xl而不是直接给x赋值的原因是我认为后面用q->x=xl;更容易理解,当然在开关函数中直接用q->x=75;的方式赋值也是可以的。
然后是用_kbhit()函数进行键盘输入的接收和游戏是否能继续或结束的判断
方块下落到一定高度范围时通过按下所对应区域的按键消灭他,否则方块触底时将会判定为游戏失败。这里我是通过判断Y坐标(高度)实现的,660-720是游戏可以继续的判定范围,当方块落入此区域时按下对应按键时即可消灭方块(p->state=1)。其中_kbhit()意为判断按下了按键,定义整型变量put赋予接收按键对应的数值,接收数值由_getch()函数实现,72是键盘←的对应数值,80,75,77分别对应键盘↓,→,↑的数值。
这里有个问题,就是程序对键盘的命令非常迟钝,经常读取不到键盘命令,所以我一般都是狂按键盘,无解。
游戏结束的判定:
当方块触底且方块未被消灭(p->state==0)时游戏结束(清屏)。
增加亿点细节
增加游戏难度,随已循环次数增加方块下落速度也增加,最大值为30ms
给方块换个造型:
这里比较简单,就是用line()函数画几条线,游戏是否继续或结束的判定用方块的下边界作为判定
最后,我想要加上游戏得分的显示功能,不过我不知道怎样才能在屏幕上输出变量的值,所以作罢。如果想要再增加游戏难度还可以增加一个新的结构体,然后增加新的一条链表,在同一个循环里运行两条链表,最后用延时效果就可以实现了,但是VS崩溃了,本人才疏学浅,暂时无法解决。
完整代码:
#include <stdio.h>
#include<stdlib.h>
#include <graphics.h>
#include<conio.h>
struct black
{
int state;//方块是否被消灭,1为是0为否
int x;//方块位置
struct black* next;
};
typedef struct black Black;
int main()
{
Black* head, * p, * q;
p = (Black*)malloc(sizeof(Black));
p->state = 0;
p->x = 185;
head = p;
initgraph(480, 720);//屏幕大小
setfillcolor(WHITE);//方块填充色
for (int i = 0; i <= 50; i++)
{
int a = rand() % 3;
int xl;
switch (a)
{
case 1:
xl = 75;
break;
case 2:
xl = 185;
break;
case 3:
xl = 295;
break;
case 0:
xl = 405;
break;
}
q = (Black*)malloc(sizeof(Black));
q->state = 0;
q->x = xl;
p->next = q;
p = q;
}
for (Black* p = head; p != NULL; p = p->next)
{
double speed = 80;
for (int y = 0; y <= 720; y += 10)
{
line(20, 0, 20, 720);//左边界
line(460, 0, 460, 720);//右边界
line(0, 680, 480, 680);//下边界
line(130, 0, 130, 720);//从左边界开始数第一条竖线
line(240, 0, 240, 720);//第二条竖线
line(350, 0, 350, 720);//第三条竖线
line(460, 0, 460, 720);//第四条竖线
line(p->x + 15, y - 60, p->x + 15, y);//方块右边界
line(p->x - 15, y - 60, p->x - 15, y);//方块左边界
line(p->x - 15, y - 60, p->x + 15, y - 60);//方块上边界
line(p->x - 15, y, p->x + 15, y);//方块下边界
Sleep(speed);
cleardevice();
switch (p->x)
{
case 75:
if (y > 660 && y < 720 && _kbhit())
{
int put = _getch();
if (put == 72)
{
p->state = 1;
}
}
case 185:
if (y > 660 && y < 720 && _kbhit())
{
int put = _getch();
if (put == 80)
{
p->state = 1;
}
}
case 295:
if (y > 660 && y < 720 && _kbhit())
{
int put = _getch();
if (put == 75)
{
p->state = 1;
}
}
case 405:
if (y > 660 && y < 720 && _kbhit())
{
int put = _getch();
if (put == 77)
{
p->state = 1;
}
}
}
if (y >= 720 && p->state == 0)
{
getchar();
closegraph();
}
}
if (speed <= 30)
{
speed -= 5;
}
}
getchar();
closegraph();
return 0;
}