GitHub:【C语言】实现俄罗斯方块源代码
Head.h
#ifndef _HEAD_H_
#define _HEAD_H_
#include<graphics.h>
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#define _CRT_SECURE_NO_WARNINGS 1
#define WALL_SQUARE_WIDTH 10 //围墙方块的宽度
#define xWALL_SQUARE_NUM 30 //x轴方向的方块的数目
#define yWALL_SQUARE_WIDTH 46 //y轴方向的方块的数目
#define GAME_WALL_WIDTH (WALL_SQUARE_WIDTH*xWALL_SQUARE_NUM) //游戏区域的宽度 300
#define GAME_WALL_HTGH (WALL_SQUARE_WIDTH*yWALL_SQUARE_WIDTH) //游戏区域的高度 460
#define WINDOW_WIDTH 480 // 游戏总窗口宽度 480
#define WINDOW_HIGH 460 // 游戏总窗口高度 460
#define ROCK_SQUARE_WIDTH (2*WALL_SQUARE_WIDTH) //俄罗斯方块的大小是围墙的两倍 20
#define xROCK_SQUARE_NUM ((GAME_WALL_WIDTH -20)/ROCK_SQUARE_WIDTH) // 游戏区x轴放的方块数目:14
#define yROCK_SQUARE_NUM ((GAME_WALL_HTGH -20)/ROCK_SQUARE_WIDTH) // 游戏区y轴放的方块数目:22
#define DIRECT_UP 3
#define DIRECT_DOWN 2
#define DIRECT_LEFT -1
#define DIRECT_RIGHT 1
typedef
struct ROCK
{
unsigned
short rockShapeBits;
int nextRockIndex;
} RockType;
typedef
struct LOCATE
{
int left;
int top;
} RockLocation_t;
int game_board[yROCK_SQUARE_NUM +
2][xROCK_SQUARE_NUM +
2] = {
0 };
int game_socres =
0;
int rockTypeNum =
19;
RockType RockArray[
19] = { (
0,
0) };
RockLocation_t preRockLocation = {GAME_WALL_WIDTH+
70,
70};
RockLocation_t initRockLocation = { (WALL_SQUARE_WIDTH +
100),
WALL_SQUARE_WIDTH };
void DrawGameWindow();
void DisplayRock(
int rockIdx, RockLocation_t* LocatePtr,
bool displayed);
void InitGame();
void PlayGame();
bool IsGameOver();
#endif
Draw.h
#include"Head.h"
void DrawGameWindow()
{
setcolor(BLUE);
setlinestyle(PS_SOLID,
NULL,
0);
setfillcolor(BLUE);
for (
int x = WALL_SQUARE_WIDTH; x <= GAME_WALL_WIDTH; x += WALL_SQUARE_WIDTH)
{
fillrectangle(x - WALL_SQUARE_WIDTH,
0, x, WALL_SQUARE_WIDTH);
fillrectangle(x - WALL_SQUARE_WIDTH, GAME_WALL_HTGH - WALL_SQUARE_WIDTH, x, GAME_WALL_HTGH);
}
for (
int y = WALL_SQUARE_WIDTH; y <= GAME_WALL_HTGH; y += WALL_SQUARE_WIDTH)
{
fillrectangle(
0, y, WALL_SQUARE_WIDTH, y + WALL_SQUARE_WIDTH);
fillrectangle(GAME_WALL_WIDTH - WALL_SQUARE_WIDTH, y, GAME_WALL_WIDTH, y + WALL_SQUARE_WIDTH);
}
setcolor(WHITE);
setlinestyle(PS_DASH,
2);
line(GAME_WALL_WIDTH +
20,
0, GAME_WALL_WIDTH +
20, GAME_WALL_HTGH);
LOGFONT font;
gettextstyle(&font);
settextstyle(
18,
0, _T(
"宋体"));
font
.lfQuality = ANTIALIASED_QUALITY;
outtextxy(GAME_WALL_WIDTH +
80,
30, _T(
"预览"));
outtextxy(GAME_WALL_WIDTH +
80,
170, _T(
"分数"));
outtextxy(GAME_WALL_WIDTH +
65,
250, _T(
"操作说明"));
outtextxy(GAME_WALL_WIDTH +
40,
290, _T(
"w a s d控制方向"));
outtextxy(GAME_WALL_WIDTH +
40,
335, _T(
"空格 暂停"));
setcolor(RED);
outtextxy(GAME_WALL_WIDTH +
90,
200,
'0');
}
void DisplayRock(
int rockIdx, RockLocation_t* LocatePtr,
bool displayed)
{
int color;
int lineColor = WHITE;
int boardFalg =
0;
int xRock =
0;
int yRock =
0;
unsigned short rockCode = RockArray[rockIdx]
.rockShapeBits;
displayed ? (color = RED, boardFalg =
1) : (color = BLACK,lineColor = BLACK, boardFalg =
0);
setcolor(lineColor);
setfillcolor(color);
setlinestyle(PS_SOLID);
xRock = LocatePtr->left;
yRock = LocatePtr->top;
int count =
0;
unsigned short mask =
1;
for (
int i =
1; i <=
16; ++i)
{
mask =
1 << (
16 - i);
if ((rockCode & mask) !=
0)
{
fillrectangle(xRock , yRock, xRock + ROCK_SQUARE_WIDTH, yRock + ROCK_SQUARE_WIDTH);
}
if (i %
4 ==
0)
{
yRock = yRock + ROCK_SQUARE_WIDTH;
xRock = xRock = LocatePtr->left;
}
else
{
xRock += ROCK_SQUARE_WIDTH;
}
}
}
Init.h
#include"Head.h"
static void ShapeStrToBit(
unsigned char *rockShapeStr,
unsigned short& rockShapeBit);
static void ReadRcok();
void InitGame()
{
for (
int i =
0; i < xROCK_SQUARE_NUM +
2; i++)
{
game_board[
0][i] =
1;
game_board[yROCK_SQUARE_NUM +
1][i] =
1;
}
for (
int i =
0; i < yROCK_SQUARE_NUM +
2; i++)
{
game_board[i][
0] =
1 ;
game_board[i][xROCK_SQUARE_NUM +
1] =
1;
}
ReadRcok();
}
void ReadRcok()
{
FILE* fp = fopen(
"RockShape.ini",
"r");
if (
NULL == fp)
{
printf(
"打开文件失败\n");
return;
}
unsigned char readBuf[
1024];
unsigned short rockShapeBit =
0;
unsigned char rockShapeStr[
16];
int ShapeStrIdx =
0;
int rockNum =
0;
int rocknext =
0;
int rockShapeStart =
0;
while (
true)
{
size_t readSize = fread(readBuf,
1,
1024, fp);
if (readSize ==
0)
break;
for (size_t idx =
0; idx < readSize; ++idx)
{
while (ShapeStrIdx <
16 && idx < readSize)
{
if (readBuf[idx] ==
'@' || readBuf[idx] ==
'#')
{
rockShapeStr[ShapeStrIdx] = (
unsigned char)readBuf[idx];
++ShapeStrIdx;
}
++idx;
if (readBuf[idx] ==
'*')
{
idx +=
5;
RockArray[--rockNum]
.nextRockIndex = rockShapeStart;
rockNum++;
rockShapeStart = rockNum;
rocknext = rockShapeStart ;
}
}
if (ShapeStrIdx <
16)
{
break;
}
else
{
ShapeStrIdx =
0;
ShapeStrToBit(rockShapeStr, rockShapeBit);
rocknext++;
RockArray[rockNum]
.rockShapeBits = rockShapeBit;
RockArray[rockNum]
.nextRockIndex = rocknext;
rockNum++;
}
}
}
fclose(fp);
}
void ShapeStrToBit(
unsigned char *rockShapeStr,
unsigned short& rockShapeBit)
{
rockShapeBit =
0;
for (size_t idx =
0; idx <
16; ++idx)
{
if (rockShapeStr[idx] ==
'@')
{
rockShapeBit |= (
1 << (
16 - idx -
1));
}
}
}
game.h
#include"Head.h"
#define _CRT_SECURE_NO_WARNINGS 1
bool MoveAble(
int rockIndex, RockLocation_t* currentLocatePtr,
int f_direction);
void SetGameBoardFlag(
int rockIdx, RockLocation_t* curRockLocation);
void UserHitKeyBoard(
char userHit,
int* RockIndex, RockLocation_t* curRockLocation);
void FullLine();
void UpdateSocres(
int scores);
void DelCurLine(
int rowIdx);
bool IsGameOver();
void PlayGame()
{
char userHit =
0;
int curRockIndex =
0;
int nextRockIndex =
0;
RockLocation_t curRockLocation;
curRockLocation
.left = initRockLocation
.left;
curRockLocation
.top = initRockLocation
.top;
DWORD oldtime =
0;
srand((
unsigned int)time(
NULL));
curRockIndex = rand() % rockTypeNum;
nextRockIndex = rand() % rockTypeNum;
DisplayRock(curRockIndex, &initRockLocation,
1);
DisplayRock(nextRockIndex, &preRockLocation,
1);
bool moveAbled =
false;
while (
true)
{
moveAbled = MoveAble(curRockIndex, &curRockLocation, DIRECT_DOWN);
if (!moveAbled)
{
SetGameBoardFlag(curRockIndex, &curRockLocation);
FullLine();
if (IsGameOver())
{
MessageBox(
NULL, _T(
"游戏结束"), _T(
"GAME OVER"), MB_OK);
exit(
0);
}
DisplayRock(nextRockIndex, &preRockLocation,
false);
curRockIndex = nextRockIndex;
nextRockIndex = rand() % rockTypeNum;
DisplayRock(curRockIndex, &initRockLocation,
1);
DisplayRock(nextRockIndex, &preRockLocation,
1);
FlushBatchDraw();
curRockLocation
.left = initRockLocation
.left;
curRockLocation
.top = initRockLocation
.top;
}
if (kbhit())
{
userHit = getch();
UserHitKeyBoard(userHit, &curRockIndex, &curRockLocation);
}
DWORD newtime = GetTickCount();
if (newtime - oldtime >= (
unsigned int)(
300) && moveAbled ==
TRUE)
{
oldtime = newtime;
DisplayRock(curRockIndex, &curRockLocation,
false);
curRockLocation
.top += ROCK_SQUARE_WIDTH;
}
DisplayRock(curRockIndex, &curRockLocation,
1);
FlushBatchDraw();
Sleep(
20);
}
}
void UserHitKeyBoard(
char userHit,
int* RockIndex, RockLocation_t* curRockLocation)
{
switch (userHit)
{
case 'W':
case 'w':
if (MoveAble(RockArray[*RockIndex]
.nextRockIndex, curRockLocation, DIRECT_UP))
{
DisplayRock(*RockIndex, curRockLocation,
false);
*RockIndex = RockArray[*RockIndex]
.nextRockIndex;
}
break;
case 'S':
case 's':
if (MoveAble(*RockIndex, curRockLocation, DIRECT_DOWN))
{
DisplayRock(*RockIndex, curRockLocation,
false);
curRockLocation->top +=
2 * (ROCK_SQUARE_WIDTH);
if (!MoveAble(*RockIndex, curRockLocation, DIRECT_DOWN))
{
curRockLocation->top -= ROCK_SQUARE_WIDTH;
}
}
break;
case 'A':
case 'a':
if (MoveAble(*RockIndex, curRockLocation, DIRECT_LEFT))
{
DisplayRock(*RockIndex, curRockLocation,
false);
curRockLocation->left -= ROCK_SQUARE_WIDTH;
}
break;
case 'D':
case 'd':
if (MoveAble(*RockIndex, curRockLocation, DIRECT_RIGHT))
{
DisplayRock(*RockIndex, curRockLocation,
FALSE);
curRockLocation->left += ROCK_SQUARE_WIDTH;
}
break;
case ' ':
while (
1)
{
userHit = getch();
if (userHit ==
' ')
break;
}
break;
default:
break;
}
}
void FullLine()
{
bool linefull =
true;
int idx = yROCK_SQUARE_NUM;
int count =
0;
while (count != xROCK_SQUARE_NUM )
{
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++;
}
idx--;
}
}
void UpdateSocres(
int scores)
{
setcolor(RED);
TCHAR s[
10];
_stprintf(s, _T(
"%d"), scores);
outtextxy(GAME_WALL_WIDTH +
90,
200, s);
}
void DelCurLine(
int rowIdx)
{
setcolor(BLACK);
setfillcolor(BLACK);
for (
int i =
1; i < xROCK_SQUARE_NUM; ++i)
{
fillrectangle(WALL_SQUARE_WIDTH + (i -
1)*ROCK_SQUARE_WIDTH, (rowIdx -
1)*ROCK_SQUARE_WIDTH + WALL_SQUARE_WIDTH,
WALL_SQUARE_WIDTH + i*ROCK_SQUARE_WIDTH, rowIdx*ROCK_SQUARE_WIDTH + WALL_SQUARE_WIDTH);
}
int cnt =
0;
while (cnt != xROCK_SQUARE_NUM)
{
cnt =
0;
for (
int i =
1; i <= xROCK_SQUARE_NUM; i++)
{
game_board[rowIdx][i] = game_board[rowIdx -
1][i];
setcolor(BLACK);
setfillcolor(BLACK);
fillrectangle(WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i - ROCK_SQUARE_WIDTH ,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*(rowIdx -
1) - ROCK_SQUARE_WIDTH ,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*(rowIdx -
1));
if (game_board[rowIdx][i] ==
1)
{
setcolor(WHITE);
setfillcolor(RED);
fillrectangle(WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i - ROCK_SQUARE_WIDTH ,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*rowIdx - ROCK_SQUARE_WIDTH ,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i,
WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*rowIdx);
}
if (game_board[rowIdx][i] ==
0)
cnt++;
}
rowIdx--;
}
}
bool MoveAble(
int rockIndex, RockLocation_t* currentLocatePtr,
int f_direction)
{
int mask;
int rockX;
int rockY;
rockX = currentLocatePtr->left;
rockY = currentLocatePtr->top;
mask = (
unsigned short)
1 <<
15;
for (
int i =
1; i <=
16; i++)
{
if ((RockArray[rockIndex]
.rockShapeBits & mask) !=
0)
{
if (f_direction == DIRECT_UP)
{
if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH +
1]
[(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH +
1] ==
1)
return false;
}
else if (f_direction == DIRECT_DOWN)
{
if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH +
2]
[(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH +
1] ==
1)
return false;
}
else
{
if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH +
1]
[(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH +
1 + f_direction] ==
1)
return false;
}
}
i %
4 ==
0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = currentLocatePtr->left)
: rockX += ROCK_SQUARE_WIDTH;
mask >>=
1;
}
return true;
}
void SetGameBoardFlag(
int rockIdx, RockLocation_t* curRockLocation)
{
int mask;
int rockX;
int rockY;
rockX = curRockLocation->left;
rockY = curRockLocation->top;
mask = (
unsigned int)
1 <<
15;
for (
int i =
1; i <=
16; i++)
{
if ((RockArray[rockIdx]
.rockShapeBits & mask) !=
0)
{
game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH +
1]
[(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH +
1] =
1;
}
i %
4 ==
0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = curRockLocation->left)
: rockX += ROCK_SQUARE_WIDTH;
mask >>=
1;
}
}
bool IsGameOver()
{
bool topLineHaveRock =
false;
bool bottomLineHaveRock =
false;
for (
int i =
1; i < xROCK_SQUARE_NUM; ++i)
{
if (game_board[
1][i] ==
1)
topLineHaveRock =
true;
if (game_board[yROCK_SQUARE_NUM][i] ==
1)
bottomLineHaveRock =
true;
}
if (bottomLineHaveRock && topLineHaveRock)
return true;
else
return false;
}
main.cpp
#include"Head.h"
#include"Draw.h"
#include"Init.h"
#include"game.h"
int main()
{
initgraph(WINDOW_WIDTH,WINDOW_HIGH);
DrawGameWindow();
HWND hWnd = GetHWnd();
SetWindowText(hWnd, _T(
"俄罗斯方块"));
InitGame();
PlayGame();
getchar();
closegraph();
system(
"pause");
return 0;
}
配置文件:RockShape.ini
@###
@###
@@##
####
@@@#
@###
####
####
@@##
#@##
#@##
####
##@#
@@@#
####
####
****
#@##
#@##
@@##
####
@###
@@@#
####
####
@@##
@###
@###
####
@@@#
##@#
####
####
****
#@##
@@@#
####
####
@###
@@##
@###
####
@@@#
#@##
####
####
#@##
@@##
#@##
####
****
#@##
@@##
@###
####
@@##
#@@#
####
####
****
@###
@@##
#@##
####
#@@#
@@##
####
####
****
@###
@###
@###
@###
@@@@
####
####
####
****
@@##
@@##
####
####
****