发布时间:2022-08-16 16:04:04来源:网络整理浏览:122
本文涵盖了游戏背景搭建、积木建模、按键响应、随机生成积木和生成下一个小积木等内容,记录一个C语言练习。本项目涉及图形,可以使用EasyX库绘制简单图形。这个库的下载和使用可以在百度找到。
本项目使用的软件是2019,新建一个C++空项目编译代码。文件的项目结构如右图所示。一共三个文件,一个头文件,两个C++文件。之所以使用cpp后缀是因为EasyX库只能在C++文件中使用,工程代码全部用C语言编译。
基本概念:
网格:指游戏区域内的小条纹,大小为20*20;
小方格:指日式小方格,由4*4共16个小碎花组成,大小为80*80;
游戏区域:背景为网格线作为游戏区域,大小为300*500,有25*15=375个方格;
图形区:图形区包括游戏区和文字显示部分,大小为500*500;
小方块坐标点:定义小方块左下角的坐标点为整个小方块的坐标点;
小方块的行号和列号:统计条带的个数,第一个条带的行号为0,列号为0;个数与坐标点的关系为:行数*20=坐标点的y,列数*20=坐标点的x; 二、构建游戏背景
//game.c
void context(void)
{
initgraph(500, 500); // 初始化图形模式
setorigin(0, 500); //重新定义原点
setaspectratio(1, -1); //将Y上半部分设定为正半轴
setlinestyle(PS_SOLID); //设定画线样式为虚线
setlinecolor(WHITE); //线条颜色为白色
for (size_t i = 0; i <= 25; i++) //画出游戏区域网格线,宽300,高500
line(0, 0 + 20 * i, 300, 0 + 20 * i); //横线
for (size_t i = 0; i <= 15; i++)
line(0 + 20 * i, 0, 0 + 20 * i, 500); //竖线
for (size_t i = 0; i <= 4; i++) //画出下一个方块网格线,宽80,高80
line(370, 300 + 20 * i, 450, 300+20 * i); //横线
for (size_t i = 0; i <= 4; i++)
line(370 + 20 * i, 300, 370 + 20 * i, 380); //竖线
setaspectratio(1, 1);
settextstyle(25, 0, _T("Consolas"));
outtextxy(310, -430, _T("SCORE:0 points"));
outtextxy(310, -410, _T("下一个方块:"));
outtextxy(310, -270, _T("w 转换方向"));
outtextxy(310, -240, _T("s 加快下降速度"));
outtextxy(310, -210, _T("a 左移"));
outtextxy(310, -0, _T("d 右移"));
outtextxy(310, -150, _T("h 重启"));
setaspectratio(1, -1);
}
首先对图形区域进行初始设置,设置线的样式为黄色实线;
用两个循环画出游乐区的横竖线,共25行15列,大小为300*500;
用两个循环画下一个区域的网格线,共4行4列,大小为80*80;
绘制提示文字,主要写分数和操作提示;
疗效如右图所示。
三、块建模
研究日本小方块的各种形状,你会发现它们都是4*4的方块,考虑到C语言的短数据类型正好有2个字节和16bit的粗细。所以我们可以使用short数据类型来表示我们的小方块。比如下面的日文小方块可以表示为11000,换算成16的补码就是8888H。
考虑到每个日本方格都有不同的方向,不同的方位对应不同的态度,我创建了一个二维链表来表示所有的德国小方格。一共有7个日式小方块,每个有4个方向的变化,有些变化还是和以前一样。在game.h头文件中声明显示日文小方块和位置结构,以小方块左下角点的坐标作为整个小方块的坐标点。
//main.c
unsigned short Diamond[7][4] = {
{0x000f,0x8888,0x000f,0x8888},
{0x008E,0x0c88,0x00E2,0x044c},
{0x002E,0x088c,0x00E8,0x0c44},
{0x00CC,0x00CC,0x00CC,0x00CC},
{0x006C,0x08c4,0x006c,0x08c4},
{0x004E,0x08c8,0x00E4,0x04c4},
{0x00C6,0x04c8,0x00c6,0x04c8} };
//game.h
//方块的坐标
typedef struct LOCATE
{
int x;
int y;
} Location;
//俄罗斯方块展示函数
void DisplayDiamond(unsigned short diamond, Location Loca, int cur_color);
日文小方块显示功能主要使用了EasyX上面的功能,可以画一个带边框的实心圆。
以下是日文小方块显示功能的具体代码。判断短数据中的每一位是否为1。如果是,则填充一朵小花。辨析。这个函数也是用来擦除的,只是颜色变成了背景色(红色),变相达到了擦除的效果。
int color[15][35] = { 0 }; //定义网格属性
//俄罗斯方块展示函数
void DisplayDiamond(unsigned short diamond, Location Loca, int draw_color)
{
int num_x, num_y;
int k = 0;
setfillcolor(draw_color); //设定填充颜色
for (int i = 3; i >= 0; i--) //四行填充
{
for (int j = 0; j < 4; j++) //四列填充
{
if (diamond & (0x8000 >> k))//判断格子是否存在1,20是格子边长
{
fillrectangle(Loca.x + 20 * j, Loca.y + 20 * i, Loca.x + 20 * (j + 1), Loca.y + 20 * (i + 1));
num_x = Loca.x / 20 + j;
num_y = Loca.y / 20 + i;
color[num_x][num_y] = draw_color;
}
k++;
}
}
}
设置填充颜色,这是EasyX的外部函数,直接引用即可;双循环,填写四行四列;函数内部判断,对于每一个短数据类型(小日本方块)用一位来判别,如果为1则填充,如果为0则跳过; color是一个二维链表,用来记录条带对应的颜色,一共25行15列,对应条带的个数。这个变量是一个全局变量,所以game.c文件中的所有函数都可以引用或参数化这个变量。显示所有小印度方块并验证上述建模是否正确。从右图可以看出,形状是正确的,符合我们的设想。
四、关键回应
连接和翻转需要鼠标选择,所以这涉及到与按钮的交互,所以需要包含头文件conio.h。 conio.h不是C标准库中的头文件,而是vc下的头文件。 conio是Input/(控制台输入输出)的缩写,定义了通过控制台进行数据输入和数据输出的功能,主要是一些用户通过按键形成的相应操作,如getch()函数等.
1.实现小方块自由落体
//main.c
while (MoveEnable(CurDiamond, CurLocation, EnableDown) == 0)
{
DisplayDiamond(CurDiamond, CurLocation, BLACK); //先擦除
CurLocation.y -= 20;
DisplayDiamond(CurDiamond, CurLocation, cur_color); //再更新
Sleep(speed);
if (_kbhit()) //如果敲击了键盘,就会返回1
{
userHit = _getch(); //获取敲击键盘字符
Keyboard(userHit, &row, &column, &CurLocation, &speed);
CurDiamond = Diamond[row][column];
}
}
//game.h
#define EnableDown 1
#define EnableLeft 2
#define EnableRight 3
//game.c
bool MoveEnable(unsigned short diamond, Location CurLocation, int direction)
{
bool stop=0;
int num_x,num_y;
switch (direction)
{
case EnableDown: //判断是否可以下移
{
for (int i = 0; i < GetWidth(diamond); i++) //对每一列进行判断
{
for (int j = 0; j < GetHigh(diamond); j++) //对该列每一行进行判断
{
num_x = CurLocation.x / 20 + i ; //小方格的列序号
num_y = CurLocation.y / 20 + j ; //小方格的行序号
if( diamond & (0x0001<<(3-i+4*j)) )
//如果该小方格是为1,即方块该列最底部
{
if ((color[num_x][num_y - 1] != BLACK) || (CurLocation.y == 0))
//如果下面那个小方格也是非黑色,就要停止
{
stop = 1;
}
break; //找到底部小格子即可跳出循环,进行下一列的判断
}
}
if (stop == 1) break; //既然已经要停止了,就不用去判断下一列
}
break;
}
}
return stop;
}
以上是字符处理函数。上面只判断部分代码是否可以下移,代码是否可以左右移动类似,这里就不展示了。
swith语句选择是判断增长,左移,右移;生长判定,虽然是找出每一列最下面的那一行彩色小花,并在找到它下面的条纹后判断,如果下面的条纹也是彩色小花,则说明它不能生长;如果下面的条纹是红色的小花,它可以生长;然后拿出来,找到第二列最上面的小格子,因为有可能第一列没有被挡住,第二列被挡住了。当其中一列下有彩色条纹时填充方块,可以将stop变量设置为1,然后不判断下一列就跳出循环。函数返回bool数据类型,停止这个变量。如果为1,表示有阻塞,不能再连接。如果为0,则表示没有障碍物,可以继续连接。以上是函数的逻辑。
实现小方块的变化方向和速度
//game.c
//响应键盘函数
void Keyboard(char userHit, int *row, int *column, Location *CurLocation, int *speed)
{
unsigned short Diamond[7][4] = {
{0x000f,0x8888,0x000f,0x8888},
{0x008E,0x0c88,0x00E2,0x044c},
{0x002E,0x088c,0x00E8,0x0c44},
{0x00CC,0x00CC,0x00CC,0x00CC},
{0x006C,0x08c4,0x006c,0x08c4},
{0x004E,0x08c8,0x00E4,0x04c4},
{0x00C6,0x04c8,0x00c6,0x04c8} };
unsigned short CurDiamond;
switch(userHit)
{
case 'w': //改变方向
{
CurDiamond = Diamond[*row][*column];
DisplayDiamond(CurDiamond, *CurLocation, BLACK); //先擦除
if ((*column) < 3)
(*column)++;
else
(*column) = 0;
CurDiamond = Diamond[*row][*column];
DisplayDiamond(CurDiamond, *CurLocation, cur_color); //再更新
break;
}
case 's': //增加下降速度
{
if ((*speed) > 50 )
{
(*speed) -= 50;
}
break;
}
case 'h': //重新开始
{
for (size_t i =0; i < 25; i++) //25行
{
for (size_t j = 0; j < 15; j++) //15列
{
color[j][i] = BLACK; //每一个格子填充黑色
setfillcolor(color[j][i]);
fillrectangle(20 * j, 20 * i, 20 * (j + 1), 20 * (i + 1));
}
}
break;
}
}
}
以上是响应鼠标的函数。首先对传入的字符进行判断,最后要进行左移、右移、加快滑动速度、改变方向、重启操作。由于我们的日本小方块模型是一个7*4的二维链表,对应7种印度小方块的四个方向。因此,虽然改变方向就是改变的列号,但是只要从0到4循环,就可以达到这些疗效。由于行和列都需要保存并传出函数,所以这里使用指针。
通过影响中间的区间来改变速率,只要区间短,增长速率就快。所以每按一次s,速度变量减少50,速度变快。同理,函数外也传速度,也用针。按'h'是重新开始,也就是清除掉下来的日本小方块填充方块,所以只要把游戏区的所有条纹都填上红色,就可以达到治疗效果,而且属性颜色条纹必须同时更换。
左右连线和小方块的下落一样,只是x变了。 x 每变化 20,就是一个条带的宽度。先擦除,再重新更新小方块,即可达到预期效果。
五、随机生成块和生成下一个小块
//main.c
unsigned short CurDiamond; //下一个方块
unsigned short NewDiamond; //下一个方块
context(); //画出游戏背景
row = 0;
column = 0;
CurDiamond = Diamond[row][column];
cur_color = BLUE;
while(1)
{
RandomDiamond(&new_row, &new_column, &CurLocation, &speed); //随机生成方块
NewDiamond = Diamond[new_row][new_column];
DisplayDiamond(NewDiamond, { 370,300 }, new_color); //画出下一块方块
while (MoveEnable(CurDiamond, CurLocation, EnableDown) == 0)
{
//自由下落+按键响应代码
}
row = new_row;
column = new_column;
cur_color = new_color;
CurDiamond = Diamond[row][column];
DisplayDiamond(NewDiamond, { 370,300 }, BLACK); //先擦除
FullJudge();
}
小方块的随机生成使用自定义函数,在链表的行列中生成小方块,给它们赋值,然后在下一个小方块区域绘制。 while 部分中的小块自由落体和键盘响应在不能落下时会跳出 while 循环。将先前随机生成的新行号和列号分配给当前行总和,并分配生成的颜色。之后就可以擦除下一个区域的小方块,等待新的生成。
最后会进行全线判定,全线会消失。接下来我会讲到这个。
以上是日本小方块的随机生成函数。一开始会产生随机的行和,相当于随机的日本小方块的形状。同时,颜色也会生成。颜色使用了链表的内部循环,所以生成了五颜六色的日式小方块。
六、全行清理和更新
//game.c
void FullJudge()
{
int color_num=0;
for (size_t i = 0; i < 25; i++) //25行
{
for (size_t j = 0; j < 15; j++) //15列
if (color[j][i] != BLACK) color_num++;
if (color_num == 15) //遇到满行
{
setfillcolor(BLACK); //设定填充黑色
for (size_t j = 0; j < 15; j++) //填充该行15列,即消除该行
{
fillrectangle(j*20, i*20 ,(j+1)*20, (i+1)*20);
color[j][i] = BLACK;
}
Updata(i);//更新
i--; //重新判断该行
}
color_num = 0;
}
}
//消除满行后,上面往后降,重新判断该行
void Updata(int row)
{
//从满行的第row行开始
for (size_t i = row; i < 25; i++)
{
for (size_t j = 0; j < 15; j++) //15列
{
color[j][i] = color[j][i + 1]; //每一个格子等于上面格子的颜色
setfillcolor(color[j][i]);
fillrectangle( 20 * j, 20 * i, 20 * (j + 1), 20 * (i + 1));
}
}
static int game_point = 0;
game_point++; //更新分数
setaspectratio(1, 1);
TCHAR s1[5];
settextstyle(25, 0, _T("Consolas"));
swprintf_s(s1, _T("%d"), game_point);
outtextxy(380, -426, s1);
setaspectratio(1, -1);
}
全行判断是逐行判断。首先判断第一行,判断每条条纹的颜色。如果统计条带颜色为非蓝色(即有小方块),列数为15,即遇到满行情况。如果确定是整行,则将该行的所有条纹都用红色填充,相当于去掉了。
去掉后,里面的条纹应该是掉下来的,相当于把整个往下移。这是函数的任务,必须更新分数,每行一行。整条线下移后,需要重新判断这条线。事实上,掉下来的线路可能已经满了。循环判断25行后,任务完成。
七、判断真长真高
//game.c
//计算方块的真实高度
int GetHigh(unsigned short diamond)
{
int a=0;
for (size_t i = 0; i < 4; i++)
{
if ( (diamond & (0x000f << 4 * i)) > 0)
a++;
}
return a;
}
//计算方块的真实宽度
int GetWidth(unsigned short diamond)
{
int a = 0;
for (size_t i = 0; i < 4; i++)
{
if ((diamond & (0x8888 >> i)) > 0)
a++;
}
return a;
}
从下面的美式小方格可以看出,即使每个日式小方格占据4*4小花的空间大小,其实日式小方格的真实高度和长度也不一定是4。连接左右,还需要判断日本小方块的真实高度和长度,即长度为1,高度为4。判断的逻辑是求和,逻辑运算,然后是否小于0。如果等于0,则表示该行/列全为0,即未占用的空间。
以上是日文小方块的大部分代码,不是全部的代码,有的只讲逻辑,大家可以自由发挥。
八、跑步效果
007球探网即时比分 足球手机版下载_007球探网即时比分 足球手机版「EV2.0」下载
热门手游
下载02s515排水检查井下载_02s515排水检查井「EV2.0」下载
热门手游
下载0515返利网下载_0515返利网「Ve2.2」下载
热门手游
下载03g101图集下载_03g101图集「V1.25」下载
热门手游
下载1.70合击下载_1.70合击「VE1.10」下载
热门手游
下载1 2 fan club下载_1 2 fan club「EV2.0」下载
热门手游
下载1.70金币版下载_1.70金币版「V1.2」下载
热门手游
下载.net framework 3.0下载_.net framework 3.0「VE1.10」下载
热门手游
下载