
正文
c语言课程设计俄罗斯方块问题描述,c语言编写俄罗斯方块全部程序
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
C语言俄罗斯方块问题
char box[2];
这么定义是不行的
需要这么定义:
char box[4][4];
box[0][0]=1,box[0][1]=0,box[0][2]=0,box[0][3]=0
box[1][0]=1,box[1][1]=0,box[1][2]=0,box[1][3]=0
box[2][0]=1,box[2][1]=1,box[2][2]=0,box[2][3]=0
box[3][0]=0,box[3][1]=0,box[3][2]=0,box[3][3]=0
相关问答
Q1: c语言俄罗斯方块问题
在写一个程序之前得先有思路,本题中得思路是:
随机给出不同的形状(长条形、Z字形、反Z形、田字形、7字形、反7形、T字型)下落填充给定的区域,若填满一条便消掉,记分,当达到一定的分数时,过关,每关方块下落的速度不同,若在游戏中各形状填满了给定区域,为输者。
有了思路再动手,如果不会可以参考一下别人开源的项目!
因为项目复杂性,我给出了一个俄罗斯方块程序的项目地址在最后,祝您好运!
项目地址:俄罗斯方块游戏
Q2: 一个简单的c语言写的俄罗斯方块程序?
1、考虑怎么存储俄罗斯方块
俄罗斯方块的形状一共有19种类型,如果拿数组来表示的话,可能会比较会浪费空间(网上有很多实现代码)
考虑到每种方块形状的范围是4 *4的小方块,用 字模点阵的方式来存储,即设置一个4行4列的数组,元素置1即代表这个位置有小
方块,元素置0即代表这个位置无小方块,这个整个的4*4的数组组成俄罗斯方块的形状。
1000
1000
1100
0000
上述4*4来表示L形状的方块。
4*4 =16 bit 正好为short类型,所以每一个方块可以用一个short类型的数据来表示。
我们把俄罗斯方块点阵的数位存在rockArray中,我们可以事先把这19种方块的字模点阵自己转化成十六进制,然后在rockArray数组的初始化时赋值进去。
但是这种方式扩展性不好,每当有一种新方块时需要改动,
所以可以写一个配置文件来表示19种方块。(RockShape.ini)
@###@###@@######1234
从配置文件中读取方块的类型的代码在(Init.h的ReadRock函数中)在下面3中解释下代码如何实现
2如何画出方块
可以使用EasyX库来画出简单的图形,
EasyX库是在VC下实现TC的简单绘图功能的一个库,这个库很容易学会(直接 百度EasyX库,里面有详细的教程)
那么如何画出方块,方块已经存储到一个short类型中了
从short中读取出,可以用一个掩码mask = 1来与short的每个bit位相与,结果为1,则画出一个小方块;
函数声明:
void DisplayRock(int rockIdx, RockLocation_t* LocatePtr, bool displayed)1
参数1:表示在数组中的下标,取出short类型的方块表示数据
参数2:表示当前坐标,即画出方块的左上角的坐标x,y
参数3:true表示画出该方块,false 表示擦除该方块。
//方块在图形窗口中的位置(即定位4*4大块的左上角坐标) typedef struct LOCATE
{ int left; int top;
} RockLocation_t;123456
3如何实现同一种类型方块的翻转,
在按‘↑’时应该翻转同一种类型的方块,
比如下面的横杆和竖杆
@###@###@###@###@@@@############****1234567891011
可以假想成静态循环链表来实现这种方式
使同一种类型的方块循环起来,
用一个struct结构来表示一种方块
typedef struct ROCK
{ //用来表示方块的形状(每一个字节是8位,用每4位表示方块中的一行)
unsigned short rockShapeBits; int nextRockIndex; //下一个方块,在数组中的下标 } RockType;123456
定义一个RockType类型的数组来存储19种方块
RockType RockArray[19] = { (0, 0) };
当我们按“↑”时,把传入画方块函数DrawRock中的rockIndex变为当前方块结构体中的nextRockIndex即可。
简单解释下ReadRock函数的实现:当读取到空行的时候表示 一种方块已经读取完毕,当读取到**** 行时 表示同一种类型的方块读取完毕,具体看代码实现,代码中具体的注释
4、主要游戏实现的逻辑
贴一个预览图吧
注:上述预览图的游戏控制区和游戏显示区在Draw.h的DrawGameWindow()函数实现的
(1)在初始位置画出方块,在预览区画出下一次的方块
(2)方块有两种行为:响应键盘命令UserHitKeyBoard(),自由下落
如果敲击键盘了(w ,a ,s ,d, )空格表示暂停,如果在规定时间内没有敲击键盘的话,方块自由下落一个单位
if (kbhit()) //如果敲击键盘了 就处理按键
{
userHit = getch();
UserHitKeyBoard(userHit, curRockIndex, curRockLocation);
} //没有 就自动下移一个单位 :不能用else,因为可能按键不是上下左右
DWORD newtime = GetTickCount(); if (newtime - oldtime = (unsigned int)(300) moveAbled == TRUE)
{
oldtime = newtime;
DisplayRock(curRockIndex, curRockLocation, false);
curRockLocation.top += ROCK_SQUARE_WIDTH; //下落一格
}1234567891011121314
(3)当方块落地(即不能下移了)时,判断是否满行,如果满行则消除,然后再判断游戏是否结束,游戏结束的话,直接退出游戏
判断满行:FullLine()函数,从最底下的一行开始判断,直到遇到一行空行,
while (count != xROCK_SQUARE_NUM ) //遇到空行 14
{
linefull = true; count = 0; for (int i = 1; i = xROCK_SQUARE_NUM; ++i)
{ if (game_board[idx][i] == 0)
{
linefull = false; count++;
}
} if (linefull) //满行,消除当前行,更新分数
{
DelCurLine(idx);//消除满行
game_socres += 3;
UpdateSocres(game_socres);
idx++;//因为下面要减1
}
idx--;
}123456789101112131415161718192021
(4)消除满行
将要删除的满行擦除:即将方块化成与背景色相同的,该代码为黑色
然后将上面的一行向下移,移一行删除一行,直到遇到空行
具体看代码的具体实现 game.h
void DelCurLine(int rowIdx)
(4)判断方块是否能移动
在game.h中实现
bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction)1
**比较当前位置的坐标(左上角)开始,能否放下rockIndex的方块。
注:f_direction为”↑”的话,则传入的rockIndex为下一个方块**
如果不能移动的话,给游戏game_board设置标记表示该位置被占有
//全局变量-游戏板的状态描述(即表示当前界面哪些位置有方块) //0表示没有,1表示有(多加了两行和两列,形成一个围墙,便于判断方块是否能够移动) int game_board[yROCK_SQUARE_NUM + 2][xROCK_SQUARE_NUM + 2] = { 0 };123
实现过程遇到的一些问题
(1)在快速下落的时候,可能方块会掉出围墙的范围内,
快速下落是使方块每次下落2个单位距离。
在判断不能下落时,使当前坐标的top即y减去一个单位的距离
(2)遇到多行满行时消除不了,
在判断满行时,循环找出满行,找出一个满行,就消除一行,然后继续判断是否满行,直到遇到空行
Q3: 用c语言编写俄罗斯方块程序 求详解
1、用C语言绘制图形界面
EasyX图形库()即TC的图形库在VC下的移植。
包含库#include graphics.h
先初始化图形窗口
initgraph(WINDOW_WIDTH, WINDOW_HIGH) ;WINDOW_WIDTH为窗口的宽带,WINDOW_HIGH为窗口的高度。
清空绘图设备
cleardevice();
设置画笔颜色
setcolor(RED) ;
设置线条风格
setlinestyle(PS_SOLID, NULL, 0);
画矩形
rectangle
还有画线、显示文字等函数,可以参照其帮助文档。
注意:由于我们用的是EasyX图形库,故源文件后缀要为.cpp,但其中内容都是C的语法。
2、存储表示出俄罗斯方块的形状
一、我们可以用编号,不同的编号代表不同的俄罗斯方块,根据编号把不同方块的画法写在代码中,这样19种
方块就得有19种相应的代码来描绘。而且这样扩展性不好,若以后设计了新的方块,则需要更改大量源代码。
二、我们很自然的想到可用字模点阵的形式来表示,即设置一个4行4列的数组,元素置1即代表这个位置有小
方块,元素置0即代表这个位置无小方块,这个整个的4*4的数组组成俄罗斯方块的形状。
1000
1000
1100
0000
这个方法挺靠谱,但我们还可以优化一下:不用4*4的数组,而是用16个bit位来表示这个点阵。这样存储起来比较方便,故我们用unsigned int 的低16位来表示方块的点阵。
我们可以用掩码与表示俄罗斯方块的位进行操作,来识别并在屏幕上画出方块。
我们把俄罗斯方块点阵的数位存在rockArray中,我们可以事先把这19种方块的字模点阵自己转化成十六进制,然后在rockArray数组的初始化时赋值进去。
但这样做未免有点太费力,且扩展性也不太好,若以后设计的新方块种类加入,要改变数组rockArray中的值。
我们可以考虑把所有俄罗斯方块的点阵存储在配置文件中,在程序初始化时读取文件,把这些点阵转换成unsigned int的变量存储在rockArray中。
这样,以后我们增添新的方块形状只需要在配置文件中增加新的点阵即可。
@###
@###
@@##
#### (为使得看起来更醒目,我们用@表示1,用#表示0)
3、让图形动起来
在某位置处用函数DrawRock在屏幕上画出俄罗斯方块,然后再擦除掉(即用背景色在原位置处重绘一次方块),最后在下落的下一个位置处用函数DrawRock在屏幕上画出俄罗斯方块,如此循环,中间用计时器间隔一段时间以控制下落的速度。
同理,按下屏幕的左右键也是如此,只是在按下键盘时把方块的位置重新计算了。
那么按下上方向键时,如何让方块翻转呢?
我们在配置文件中就把方块的顺时针翻转形态放在了一起:
@###
@###
@@##
####
@@@#
@###
####
####
@@##
#@##
#@##
####
##@#
@@@#
####
####
我们每按一次上方向键改变一次方块的形状即可。若一直按上键,形状应该是循环地翻滚。
我们想到了循环链表的数据结构可实现这个效果。
可是我们若把这些一种类的方块的各种形态串成循环链表形式,那么每次重新生成方块时我们就难以随机地生成方块了。
故还是得用数组来存储,但又要有循环链表的功能,于是我们想到了静态循环链表。
我们用结构体来作为一个方块在rockArray中的元素
typedef struct ROCK
{ //用来表示方块的形状(每一个字节是8位,用每4位表示方块中的一行)
unsigned int rockShapeBits ;
int nextRockIndex ; //下一个方块,在数组中的下标
} RockType ;
这样,当我们按下上方向键时,把传入函数DrawRock中的rockIndex变为当前方块结构体中的nextRockIndex即可。
参考资料:C语言图形界面篇
Q4: c语言编写俄罗斯方块
俄罗斯方块C源代码
#include stdio.h
#include windows.h
#include conio.h
#include time.h
#define ZL 4 //坐标增量, 不使游戏窗口靠边
#define WID 36 //游戏窗口的宽度
#define HEI 20 //游戏窗口的高度
int i,j,Ta,Tb,Tc; // Ta,Tb,Tc用于记住和转换方块变量的值
int a[60][60]={0}; //标记游戏屏幕各坐标点:0,1,2分别为空、方块、边框
int b[4]; //标记4个"口"方块:1有,0无,类似开关
int x,y, level,score,speed; //方块中心位置的x,y坐标,游戏等级、得分和游戏速度
int flag,next; //当前要操作的方块类型序号,下一个方块类型序号
void gtxy(int m, int n); //以下声明要用到的自编函数
void gflag( ); //获得下一方块序号
void csh( ); //初始化界面
void start( ); //开始部分
void prfk ( ); //打印方块
void clfk( ); //清除方块
void mkfk( ); //制作方块
void keyD( ); //按键操作
int ifmov( ); //判断方块能否移动或变体
void clHA( ); //清除满行的方块
void clNEXT( ); //清除边框外的NEXT方块
int main( )
{ csh( );
while(1)
{start( ); //开始部分
while(1)
{ prfk( );
Sleep(speed); //延时
clfk( );
Tb=x;Tc=flag; //临存当前x坐标和序号,以备撤销操作
keyD( );
y++; //方块向下移动
if (ifmov( )==0) { y--; prfk( ); dlHA( ); break;} //不可动放下,删行,跨出循环
}
for(i=y-2;iy+2;i++){ if (i==ZL) { j=0; } } //方块触到框顶
if (j==0) { system("cls");gtxy(10,10);printf("游戏结束!"); getch(); break; }
clNEXT( ); //清除框外的NEXT方块
}
return 0;
}
void gtxy(int m, int n) //控制光标移动
{COORD pos; //定义变量
pos.X = m; //横坐标
pos.Y = n; //纵坐标
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void csh( ) //初始化界面
{gtxy(ZL+WID/2-5,ZL-2); printf("俄罗斯方块"); //打印游戏名称
gtxy(ZL+WID+3,ZL+7); printf("******* NEXT:"); //打印菜单信息
gtxy(ZL+WID+3,ZL+13); printf("**********");
gtxy(ZL+WID+3,ZL+15); printf("Esc :退出游戏");
gtxy(ZL+WID+3,ZL+17); printf("↑键:变体");
gtxy(ZL+WID+3,ZL+19); printf("空格:暂停游戏");
gtxy(ZL,ZL); printf("╔"); gtxy(ZL+WID-2,ZL); printf("╗"); //打印框角
gtxy(ZL,ZL+HEI); printf("╚"); gtxy(ZL+WID-2,ZL+HEI); printf("╝");
a[ZL][ZL+HEI]=2; a[ZL+WID-2][ZL+HEI]=2; //记住有图案
for(i=2;iWID-2;i+=2) {gtxy(ZL+i,ZL); printf("═"); } //打印上横框
for(i=2;iWID-2;i+=2) {gtxy(ZL+i,ZL+HEI); printf("═"); a[ZL+i][ZL+HEI]=2; } //下框
for(i=1;iHEI;i++) { gtxy(ZL,ZL+i); printf("║"); a[ZL][ZL+i]=2; } //左竖框记住有图案
for(i=1;iHEI;i++) {gtxy(ZL+WID-2,ZL+i); printf("║"); a[ZL+WID-2][ZL+i]=2; } //右框
CONSOLE_CURSOR_INFO cursor_info={1,0}; //以下是隐藏光标的设置
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),cursor_info);
level=1; score=0; speed=400;
gflag( ); flag=next; //获得一个当前方块序号
}
void gflag( ) //获得下一个方块的序号
{ srand((unsigned)time(NULL)); next = rand()%19+1; }
void start( ) //开始部分
{ gflag( ); Ta=flag; flag=next; //保存当前方块序号,将下一方块序号临时操作
x=ZL+WID+6; y=ZL+10; prfk( ); //给x,y赋值,在框外打印出下一方块
flag=Ta; x=ZL+WID/2; y=ZL-1; //取回当前方块序号,并给x,y赋值
}
void prfk ( ) //打印俄罗斯方块
{ for(i=0;i4;i++) {b[i]=1; } //数组b[4]每个元素的值都为1
mkfk ( ); //制作俄罗斯方块
for( i= x-2; i=x+4; i+=2 ) //打印方块
{ for(j=y-2;j= y+1;j++) { if( a[i][j]==1 jZL ){ gtxy(i,j); printf("□"); } } }
gtxy(ZL+WID+3,ZL+1); printf("level : %d",level); //以下打印菜单信息
gtxy(ZL+WID+3,ZL+3); printf("score : %d",score);
gtxy(ZL+WID+3,ZL+5); printf("speed : %d",speed);
}
void clfk( ) //清除俄罗斯方块
{ for(i=0;i4;i++) { b[i]=0; } //数组b[4]每个元素的值都为0
mkfk ( ); //制作俄罗斯方块
for( i=x-2; i=x+4; i+=2 ) //清除方块
{ for(j=y-2;j=y+1;j++){ if( a[i][j]==0 jZL ){ gtxy(i,j); printf(" "); } } }
}
void mkfk( ) //制作俄罗斯方块
{ a[x][ y]=b[0]; //方块中心位置状态: 1-有,0-无
switch(flag) //共6大类,19种小类型
{ case 1: { a[x][y-1]=b[1]; a[x+2][y-1]=b[2]; a[x+2][y]=b[3]; break; } //田字方块
case 2: { a[x-2][y]=b[1]; a[x+2][y]=b[2]; a[x+4][y]=b[3]; break; } //直线方块:----
case 3: { a[x][y-1]=b[1]; a[x][y-2]=b[2]; a[x][y+1]=b[3]; break; } //直线方块: |
case 4: { a[x-2][y]=b[1]; a[x+2][y]=b[2]; a[x][y+1]=b[3]; break; } //T字方块
case 5: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x-2][y]=b[3]; break; } //T字顺时针转90度
case 6: { a[x][y-1]=b[1]; a[x-2][y]=b[2]; a[x+2][y]=b[3]; break; } //T字顺转180度
case 7: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x+2][y]=b[3]; break; } //T字顺转270度
case 8: { a[x][y+1]=b[1]; a[x-2][y]=b[2]; a[x+2][y+1]=b[3]; break; } //Z字方块
case 9: { a[x][y-1]=b[1]; a[x-2][y]=b[2]; a[x-2][y+1]=b[3]; break; } //Z字顺转90度
case 10: { a[x][y-1]=b[1]; a[x-2][y-1]=b[2]; a[x+2][y]=b[3]; break; } //Z字顺转180度
case 11: { a[x][y+1]=b[1]; a[x+2][y-1]=b[2]; a[x+2][ y]=b[3]; break; } //Z字顺转270度
case 12: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x-2][y-1]=b[3]; break; } //7字方块
case 13: {a[x-2][y]=b[1]; a[x+2][y-1]=b[2]; a[x+2][y]=b[3]; break; } //7字顺转90度
case 14: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x+2][y+1]=b[3]; break; } //7字顺转180度
case 15: { a[x-2][y]=b[1]; a[x-2][y+1]=b[2]; a[x+2][y]=b[3]; break; } //7字顺转270度
case 16: { a[x][y+1]=b[1]; a[x][y-1]=b[2]; a[x+2][y-1]=b[3]; break; } //倒7字方块
case 17: { a[x-2][y]=b[1]; a[x+2][y+1]=b[2]; a[x+2][y]=b[3]; break; } //倒7字顺转90度
case 18: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x-2][y+1]=b[3]; break; } //倒7字顺转180度
case 19: { a[x-2][y]=b[1]; a[x-2][y-1]=b[2]; a[x+2][y]=b[3]; break; } //倒7字顺转270度
}
}
void keyD( ) //按键操作
{ if (kbhit( ))
{ int key;
key=getch();
if (key==224)
{ key=getch();
if (key==75) { x-=2; } //按下左方向键,中心横坐标减2
if (key==77) { x+=2; } //按下右方向键,中心横坐标加2
if (key==72) //按下向上方向键,方块变体
{ if (flag=2 flag=3 ) { flag++; flag%=2; flag+=2; }
if ( flag=4 flag=7 ) { flag++; flag%=4; flag+=4; }
if (flag=8 flag=11 ) { flag++; flag%=4; flag+=8; }
if (flag=12 flag=15 ) { flag++; flag%=4; flag+=12; }
if ( flag=16 flag=19 ) { flag++; flag%=4; flag+=16; } }
}
if (key==32) //按空格键,暂停
{ prfk( ); while(1) { if (getch( )==32) { clfk( );break;} } } //再按空格键,继续游戏
if (ifmov( )==0) { x=Tb; flag=Tc; } //如果不可动,撤销上面操作
else { prfk( ); Sleep(speed); clfk( ); Tb=x;Tc=flag;} //如果可动,执行操作
}
}
int ifmov( ) //判断能否移动
{ if (a[x][y]!=0) { return 0; } //方块中心处有图案返回0,不可移动
else{ if ( (flag==1 ( a[x][ y-1]==0 a[x+2][y-1]==0 a[x+2][y]==0 ) ) ||
(flag==2 ( a[x-2][y]==0 a[x+2][y]==0 a[x+4][y]==0 ) ) ||
(flag==3 ( a[x][y-1]==0 a[x][y-2]==0 a[x][y+1]==0 ) ) ||
(flag==4 ( a[x-2][y]==0 a[x+2][y]==0 a[x][y+1]==0 ) ) ||
(flag==5 ( a[x][y-1]==0 a[x][y+1]==0 a[x-2][y]==0 ) ) ||
(flag==6 ( a[x][ y-1]==0 a[x-2][y]==0 a[x+2][y]==0 ) ) ||
(flag==7 ( a[x][y-1]==0 a[x][y+1]==0 a[x+2][y]==0 ) ) ||
(flag==8 ( a[x][y+1]==0 a[x-2][y]==0 a[x+2][y+1]==0 ) ) ||
(flag==9 ( a[x][y-1]==0 a[x-2][y]==0 a[x-2][y+1]==0 ) ) ||
(flag==10 ( a[x][y-1]==0 a[x-2][y-1]==0 a[x+2][y]==0 ) ) ||
(flag==11 ( a[x][y+1]==0 a[x+2][y-1]==0 a[x+2][y]==0 ) ) ||
(flag==12 ( a[x][y-1]==0 a[x][y+1]==0 a[x-2][y-1]==0 ) ) ||
( flag==13 ( a[x-2][y]==0 a[x+2][y-1]==0 a[x+2][y]==0 ) ) ||
( flag==14 ( a[x][y-1]==0 a[x][y+1]==0 a[x+2][y+1]==0 ) ) ||
(flag==15 ( a[x-2][y]==0 a[x-2][y+1]==0 a[x+2][y]==0 ) ) ||
(flag==16 ( a[x][y+1]==0 a[x][y-1]==0 a[x+2][y-1]==0 ) ) ||
( flag==17 ( a[x-2][y]==0 a[x+2][y+1]==0 a[x+2][y]==0 ) ) ||
(flag==18 ( a[x][y-1]==0 a[x][y+1]==0 a[x-2][y+1]==0 ) ) ||
(flag==19 ( a[x-2][y]==0 a[x-2][y-1]==0
a[x+2][y]==0 ) ) ) { return 1; }
}
return 0; //其它情况返回0
}
void clNEXT( ) //清除框外的NEXT方块
{ flag = next; x=ZL+WID+6; y=ZL+10; clfk( ); }
void clHA( ) //清除满行的方块
{ int k, Hang=0; //k是某行方块个数, Hang是删除的方块行数
for(j=ZL+HEI-1;j=ZL+1;j--) //当某行有WID/2-2个方块时,则为满行
{ k=0; for(i=ZL+2;iZL+WID-2;i+=2)
{ if (a[i][j]==1) //竖坐标从下往上,横坐标由左至右依次判断是否满行
{ k++; //下面将操作删除行
if (k==WID/2-2) { for(k=ZL+2;kZL+WID-2;k+=2)
{ a[k][j]=0; gtxy(k,j); printf(" "); Sleep(1); }
for(k=j-1;kZL;k--)
{ for(i=ZL+2;iZL+WID-2;i+=2) //已删行数上面有方块,先清除再全部下移一行
{ if(a[i][k]==1) { a[i][k]=0; gtxy(i,k); printf(" ");a[i][k+1]=1;
gtxy(i,k+1); printf("□"); } }
}
j++; //方块下移后,重新判断删除行是否满行
Hang++; //记录删除方块的行数
}
}
}
}
score+=100*Hang; //每删除一行,得100分
if ( Hang0 (score%500==0 || score/500 level-1 ) ) //得分满500速度加快升一级
{ speed-=20; level++; if(speed200)speed+=20; }
}
关于c语言课程设计俄罗斯方块问题描述和c语言编写俄罗斯方块全部程序的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。







