#include
#include
#include
#define CELL 20
#define ROWS 25
#define COLS 15
//升级所需分数值
#define SCORE_LEVEL_INC 80
#define ID_TIMER 1
/全局变量/
HWND hwnd; //保存窗口句柄
int score = 0; //分数
int level = 0; //级数
int interval_unit = 25; //随级数递增的时间间隔增量
int interval_base = 300; //时间间隔基量
int old_interval; //保存当前的时间间隔,用于加速操作
int cur_left, cur_top; //记录方块当前的位置
int width_block, height_block; //方块的宽带和高度
bool isPause = false; //暂停标识
UINT timer_id = 0; //保存计时器ID
static byte* block = NULL; //方块,方块为随机大小,采用动态分配内存方式,所以这里是指针变量
byte g_panel[ROWS][COLS] = { 0 };
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawPanel(HDC hdc); //绘制表格
void RefreshPanel(HDC hdc); //刷新面板
void DoDownShift(HDC hdc); //下移
void DoLeftShift(HDC hdc); //左移
void DoRightShift(HDC hdc); //右移
void DoAccelerate(HDC hdc); //加速
void DoRedirection(HDC hdc); //改变方向
void ClearRow(HDC hdc); //消行
bool ExportBlock(); //输出方块,
//该函数会直接修改全局变量block,width_block,height_block,
//cur_left和cur_top
bool IsTouchBottom(HDC hdc); //判断是否到达底部
int main()
{
HINSTANCE hInstance = GetModuleHandle(NULL);
TCHAR szAppName[] = TEXT("teris");
MSG msg;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szAppName;
if (!RegisterClass(&wc))
{
printf("RegisterClass occur errors!");
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("Teris Demo"),
WS_OVERLAPPEDWINDOW,
0, 0, 0, 0,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
void DrawPanel(HDC hdc) //绘制游戏面板
{
int x, y;
RECT rect;
for (y = 0; y < ROWS; y++)
{
for (x = 0; x < COLS; x++)
{
//计算方块的边框范围
rect.top = y * CELL + 1;
rect.bottom = (y + 1) * CELL - 1;
rect.left = x * CELL + 1;
rect.right = (x + 1) * CELL - 1;
FrameRect(hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
}
}
}
void DoDownShift(HDC hdc) //下移
{
if (NULL == block) return;
//判断是否到达底部
if (IsTouchBottom(hdc)) //到底部
{
//消行处理
ClearRow(hdc);
ExportBlock(); //输出下一个方块
}
cur_top++;
RefreshPanel(hdc);
}
void DoLeftShift(HDC hdc) //左移
{
int x, y;
if (NULL == block) return;
if (0 == cur_left) return;
if (cur_top < 0) return; //方块没有完整显示前,不能左移
for (y = 0; y < height_block; y++)
{
for (x = 0; x < width_block; x++) //从左边开始扫描,获取该行最左边的实心方格块
{
if (*(block + y * width_block + x))
{
//判断当前方格在面板上面左边一个方格是否为实心,是就代表不能再左移
if (g_panel[cur_top + y][cur_left + x - 1]) return;
break; //只判断最左边的一个实心方格,之后直接扫描下一行
}
}
}
cur_left--;
RefreshPanel(hdc);
}
void DoRightShift(HDC hdc) //右移
{
int x, y;
if (NULL == block) return;
if (COLS - width_block == cur_left) return;
if (cur_top < 0) return; //方块完整显示前不能右移
for (y = 0; y < height_block; y++)
{
for (x = width_block - 1; x >= 0; x--) //从右边开始扫描,获取该行最右边的实心方格块
{
if (*(block + y * width_block + x))
{
//判断当前方格在面板上右边一个方格是否为实心,是就代表不能再右移
if (g_panel[cur_top + y][cur_left + x + 1]) return;
break; //只判断最右边的一个实心方格
}
}
}
cur_left++;
RefreshPanel(hdc);
}
void DoRedirection(HDC hdc) //改变方向
{
int i, j;
byte* temp = NULL;
if (NULL == block) return;
if (cur_top < 0) return; //方块完整显示前不能转向
temp = (byte*)malloc(sizeof(byte) * width_block * height_block);
for (i = 0; i < width_block; i++)
{
for (j = 0; j < height_block; j++)
{
//temp[i][j]=block[height_block-j-1][i];
*(temp + i * height_block + j) = *(block + (height_block - j - 1) * width_block + i);
}
}
//给方块重新定位
int incHeight = width_block - height_block;
int incWidth = height_block - width_block;
int temp_cur_top = cur_top - incHeight / 2;
int temp_cur_left = cur_left - incWidth / 2;
//system("cls");
//printf("temp_top=%d, temp_left=%d",temp_cur_top,temp_cur_left);
//判断当前空间是否足够让方块改变方向
int max_len = max(width_block, height_block);
//防止下标访问越界
if (temp_cur_top + max_len - 1 >= ROWS || temp_cur_left < 0 || temp_cur_left + max_len - 1 >= COLS)
{
free(temp); //退出前必须先释放内存
return;
}
for (i = 0; i < max_len; i++)
{
for (j = 0; j < max_len; j++)
{
//转向所需的空间内有已被占用的实心方格存在,即转向失败
if (g_panel[temp_cur_top + i][temp_cur_left + j])
{
free(temp); //退出前必须先释放内存
return;
}
}
}
//把临时变量的值赋给block,只能赋值,而不能赋指针值
for (i = 0; i < height_block; i++)
{
for (j = 0; j < width_block; j++)
{
//block[i][j]=temp[i][j];
*(block + i * width_block + j) = *(temp + i * width_block + j);
}
}
//全局变量重新被赋值
cur_top = temp_cur_top;
cur_left = temp_cur_left;
//交换
i = width_block;
width_block = height_block;
height_block = i;
free(temp); //释放为临时变量分配的内存
RefreshPanel(hdc);
}
void DoAccelerate(HDC hdc) //加速
{
if (NULL == block) return;
if (IsTouchBottom(hdc))
{
//消行处理
ClearRow(hdc);
ExportBlock();
}
cur_top++;
RefreshPanel(hdc);
}
bool IsTouchBottom(HDC hdc)
{
int x, y;
int i, j;
if (NULL == block) return false;
if (ROWS == cur_top + height_block)
{
//固定方块
for (i = 0; i < height_block; i++)
{
for (j = 0; j < width_block; j++)
{
if (*(block + i * width_block + j)) g_panel[cur_top + i][cur_left + j] = 1;
}
}
return true;
}
for (y = height_block - 1; y >= 0; y--) //从底行开始扫描
{
//判断第一个实心方块在面板上邻接的下方方格是否为实心,是就代表已经到达底部
for (x = 0; x < width_block; x++)
{
if (*(block + y * width_block + x))
{
if (cur_top + y + 1 < 0) return false;
if (g_panel[cur_top + y + 1][cur_left + x])
{
//判断是否gameover
if (cur_top <= 0)
{
if (timer_id)
{
KillTimer(hwnd, ID_TIMER);
timer_id = 0;
}
MessageBox(hwnd, TEXT("游戏结束"), TEXT("MSG"), MB_OK | MB_ICONEXCLAMATION);
SendMessage(hwnd, WM_CLOSE, 0, 0);
}
//
//固定方块
for (i = 0; i < height_block; i++)
{
for (j = 0; j < width_block; j++)
{
if (*(block + i * width_block + j)) g_panel[cur_top + i][cur_left + j] = 1;
}
}
return true;
}
}
}
}
return false;
}
void ClearRow(HDC hdc) //消行
{
int i, j, k;
int count = 0; //消行次数
bool isFilled;
//消行处理
for (i = ROWS - 1; i >= 0; i--)
{
isFilled = true;
for (j = 0; j < COLS; j++)
{
if (!g_panel[i][j])
{
isFilled = false;
break;
}
}
if (isFilled)
{
for (j = 0; j < COLS; j++)
{
g_panel[i][j] = 0;
}
//所有方块往下移
for (k = i - 1; k >= 0; k--)
{
for (j = 0; j < COLS; j++)
{
g_panel[k + 1][j] = g_panel[k][j];
}
}
i = i + 1;
count++;
}
}
//最高级别为9级,所以分数极限为(9+1)*SCORE_LEVEL_INC-1
if (score >= 10 * SCORE_LEVEL_INC - 1) return;
//加分规则:消除行数,1行加10分,2行加15分,3行加20分,4行加30分
switch (count)
{
case 1:
score += 10;
break;
case 2:
score += 15;
break;
case 3:
score += 20;
break;
case 4:
score += 30;
break;
}
int temp_level = score / SCORE_LEVEL_INC;
if (temp_level > level)
{
level = temp_level;
//撤销当前计时器,然后重设
if (timer_id) KillTimer(hwnd, ID_TIMER);
timer_id = SetTimer(hwnd, ID_TIMER, interval_base - level * interval_unit, NULL);
}
system("cls");
printf("score: %d, level: %d ", score, level);
}
void RefreshPanel(HDC hdc) //刷新面板
{
int x, y;
RECT rect;
HBRUSH h_bSolid = (HBRUSH)GetStockObject(GRAY_BRUSH),
h_bEmpty = (HBRUSH)GetStockObject(WHITE_BRUSH);
if (NULL == block) return;
//先刷屏
for (y = 0; y < ROWS; y++)
{
for (x = 0; x < COLS; x++)
{
//为避免刷掉方块的边框,rect范围必须比边框范围小1
rect.top = y * CELL + 2;
rect.bottom = (y + 1) * CELL - 2;
rect.left = x * CELL + 2;
rect.right = (x + 1) * CELL - 2;
if (g_panel[y][x])
FillRect(hdc, &rect, h_bSolid);
else
FillRect(hdc, &rect, h_bEmpty);
}
}
//再定位方块
for (y = 0; y < height_block; y++)
{
for (x = 0; x < width_block; x++)
{
if (*(block + y * width_block + x)) //实心
{
rect.top = (y + cur_top) * CELL + 2;
rect.bottom = (y + cur_top + 1) * CELL - 2;
rect.left = (x + cur_left) * CELL + 2;
rect.right = (x + cur_left + 1) * CELL - 2;
FillRect(hdc, &rect, h_bSolid);
}
}
}
}
bool ExportBlock() //输出方块
{
int sel;
if (block)
{
free(block); //释放之前分配的内存
block = NULL;
}
sel = rand() % 7;
switch (sel)
{
case 0: //水平条
width_block = 4;
height_block = 1;
block = (byte*)malloc(sizeof(byte) * width_block * height_block);
*(block + 0) = 1; //可以理解为*(block+0*width_block+0)=1,即第一行的第一个方格,下面同理
*(block + 1) = 1; //*(block+0*width_block+1)=1
*(block + 2) = 1; //*(block+0*width_block+2)=1
*(block + 3) = 1; //*(block+0*width_block+3)=1
cur_top = 0 - height_block;
cur_left = (COLS - width_block) / 2;
break;
case 1: //三角
width_block = 3;
height_block = 2;
block = (byte*)malloc(sizeof(byte) * width_block * height_block);
*(block + 0) = 0; //可以理解为*(block+0*width_block+0)=0,即第一行的第一个方格,下面同理
*(block + 1) = 1; //*(block+0*width_block+1)=1
*(block + 2) = 0; //*(block+0*width_block+2)=0
*(block + 3) = 1; //*(block+1*width_block+0)=1,第二行开始
*(block + 4) = 1; //*(block+1*width_block+1)=1
*(block + 5) = 1; //*(block+1*width_block+2)=1
cur_top = 0 - height_block;
cur_left = (COLS - width_block) / 2;
break;
case 2: //左横折
width_block = 3;
height_block = 2;
block = (byte*)malloc(sizeof(byte) * width_block * height_block);
*(block + 0) = 1; //可以理解为*(block+0*width_block+0)=1,下面同理
*(block + 1) = 0; //*(block+0*width_block+1)=0
*(block + 2) = 0; //*(block+0*width_block+2)=0
*(block + 3) = 1; //*(block+1*width_block+0)=1
*(block + 4) = 1; //*(block+1*width_block+1)=1
*(block + 5) = 1; //*(block+1*width_block+2)=1
cur_top = 0 - height_block;
cur_left = (COLS - width_block) / 2;
break;
case 3: //右横折
width_block = 3;
height_block = 2;
block = (byte*)malloc(sizeof(byte) * width_block * height_block);
*(block + 0) = 0; //可以理解为*(block+0*width_block+0)=0,下面同理
*(block + 1) = 0; //*(block+0*width_block+1)=0
*(block + 2) = 1; //*(block+0*width_block+2)=1
*(block + 3) = 1; //*(block+1*width_block+0)=1
*(block + 4) = 1; //*(block+1*width_block+1)=1
*(block + 5) = 1; //*(block+1*width_block+2)=1
cur_top = 0 - height_block;
cur_left = (COLS - width_block) / 2;
break;
case 4: //左闪电
width_block = 3;
height_block = 2;
block = (byte*)malloc(sizeof(byte) * width_block * height_block);
*(block + 0) = 1; //可以理解为*(block+0*width_block+0)=1,下面同理
*(block + 1) = 1; //*(block+0*width_block+1)=1
*(block + 2) = 0; //*(block+0*width_block+2)=0
*(block + 3) = 0; //*(block+1*width_block+0)=0
*(block + 4) = 1; //*(block+1*width_block+1)=1
*(block + 5) = 1; //*(block+1*width_block+2)=1
cur_top = 0 - height_block;
cur_left = (COLS - width_block) / 2;
break;
case 5: //右闪电
width_block = 3;
height_block = 2;
block = (byte*)malloc(sizeof(byte) * width_block * height_block);
*(block + 0) = 0; //可以理解为*(block+0*width_block+0)=0,下面同理
*(block + 1) = 1; //*(block+0*width_block+1)=1
*(block + 2) = 1; //*(block+0*width_block+2)=1
*(block + 3) = 1; //*(block+1*width_block+0)=1
*(block + 4) = 1; //*(block+1*width_block+1)=1
*(block + 5) = 0; //*(block+1*width_block+2)=0
cur_top = 0 - height_block;
cur_left = (COLS - width_block) / 2;
break;
case 6: //石头
width_block = 2;
height_block = 2;
block = (byte*)malloc(sizeof(byte) * width_block * height_block);
*(block + 0) = 1; //可以理解为*(block+0*width_block+0)=1,下面同理
*(block + 1) = 1; //*(block+0*width_block+1)=1
*(block + 2) = 1; //*(block+1*width_block+0)=1
*(block + 3) = 1; //*(block+1*width_block+1)=1
cur_top = 0 - height_block;
cur_left = (COLS - width_block) / 2;
break;
}
return block != NULL;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
//TCHAR szBuffer[1024];
switch (message)
{
case WM_CREATE:
MoveWindow(hwnd, 400, 10, CELL * COLS + 8, CELL * ROWS + 32, FALSE); //补齐宽度和高度
srand(time(NULL));
ExportBlock();
timer_id = SetTimer(hwnd, ID_TIMER, interval_base - level * interval_unit, NULL);
return 0;
case WM_TIMER:
hdc = GetDC(hwnd);
DoDownShift(hdc);
ReleaseDC(hwnd, hdc);
return 0;
case WM_KEYDOWN:
hdc = GetDC(hwnd);
switch (wParam)
{
case VK_LEFT: //左移
if (!isPause) DoLeftShift(hdc);
break;
case VK_RIGHT: //右移
if (!isPause) DoRightShift(hdc);
break;
case VK_UP: //转向
if (!isPause) DoRedirection(hdc);
break;
case VK_DOWN: //加速
if (!isPause) DoAccelerate(hdc);
break;
case VK_SPACE: //暂停
isPause = !isPause;
if (isPause)
{
if (timer_id) KillTimer(hwnd, ID_TIMER);
timer_id = 0;
}
else
{
timer_id = SetTimer(hwnd, ID_TIMER, interval_base - level * interval_unit, FALSE);
}
break;
}
ReleaseDC(hwnd, hdc);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
DrawPanel(hdc); //绘制面板
RefreshPanel(hdc); //刷新
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
if (block) free(block);
if (timer_id) KillTimer(hwnd, ID_TIMER);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
低配版(代码行数较少)
注意:C语言实现(放.c文件里)
#include
#include
#include
#include
#define WIDTH 10//x j
#define HIGTH 25//y i
//[y][x] [HIGTH][WIDTH] [i][j] [20][10]
#define TICK 1000
#define COOLDOWN 200
typedef enum ELEMENT
{
AIR, BLOCK, MOVING
}ELEMENT;
typedef enum FUNCTION_RESULT
{
FUNCTION_SUSSESS, FUNCTION_FAIL
}FUNCTION_RESULT;
typedef enum SHAPE_TYPE
{
O_SHAPE, J_SHAPE, L_SHAPE, T_SHAPE, I_SHAPE, S_SHAPE, Z_SHAPE
}SHAPE_TYPE;
char map[HIGTH][WIDTH];//显示区域为0,5到10,25 0为空 1为已下落的方块 2为正在移动的方块
COORD faller[4];
COORD next_faller[4];
ULONGLONG last;
ULONGLONG now;
int key;
SHAPE_TYPE now_shape;
int keyboard_flag;
HANDLE hdl;
//形状的初始位置,分别表示xy坐标,顺序是ojltisz
short o_shape[8] = { 4,3,5,3,4,4,5,4 };
short j_shape[8] = { 4,4,5,4,6,4,4,3 };
short l_shape[8] = { 5,4,4,4,3,4,5,3 };
short t_shape[8] = { 5,4,4,4,6,4,5,3 };
short i_shape[8] = { 4,4,5,4,3,4,6,4 };
short s_shape[8] = { 4,3,5,3,4,2,5,4 };
short z_shape[8] = { 4,3,5,3,5,2,4,4 };
short shape[7][8] =
{
{ 4,3,5,3,4,4,5,4 },
{ 4,4,5,4,6,4,4,3 },
{ 5,4,4,4,3,4,5,3 },
{ 5,4,4,4,6,4,5,3 },
{ 4,4,5,4,3,4,6,4 },
{ 4,3,5,3,4,2,5,4 },
{ 4,3,5,3,5,2,4,4 },
};
int is_legal(COORD test[4])//1为合法 0为不合法
{
for (int i = 0; i < 4; i++)
{
if (test[i].X < 0 || test[i].X >= WIDTH)return 0;
if (test[i].Y >= HIGTH)return 0;
}
for (int i = 0; i < 4; i++)
{
if (map[test[i].Y][test[i].X] == BLOCK)return 0;
}
return 1;
}
void update_screen()
{
//system("CLS");
COORD pos_start = { 0,0 };
SetConsoleCursorPosition(hdl, pos_start);
for (int i = 5; i < HIGTH; i++)
{
printf("
for (int j = 0; j < WIDTH; j++)
{
if (map[i][j] == AIR) printf(". ");
else printf("■");
}
printf("|>\n");
}
printf("");
}
void generate()
{
now_shape = rand() % 7;
memcpy(&faller, shape[now_shape], 4 * sizeof(COORD));
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = MOVING;
}
FUNCTION_RESULT try_move_down()
{
memcpy(next_faller, faller, sizeof(faller));
for (int i = 0; i < 4; i++)
{
next_faller[i].Y++;
if (next_faller[i].Y >= HIGTH)return FUNCTION_FAIL;
if (map[next_faller[i].Y][next_faller[i].X] == BLOCK)return FUNCTION_FAIL;
}
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = AIR;
memcpy(faller, next_faller, sizeof(faller));
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = MOVING;
return FUNCTION_SUSSESS;
}
void clear_row()
{
COORD temp_map[HIGTH][WIDTH];
int flag;
for (int i = HIGTH - 1; i >= 5; i--)
{
flag = 1;
for (int j = 0; j < WIDTH; j++)
{
if (map[i][j] != BLOCK)
{
flag = 0;
break;
}
}
if (flag)
{
memcpy(temp_map, map, i * sizeof(map[0]));
memcpy(map + 1, temp_map, i * sizeof(map[0]));
continue;
}
}
}
//向右输入1,向左输入-1
FUNCTION_RESULT try_move_horizontal(int direction)
{
memcpy(next_faller, faller, sizeof(faller));
for (int i = 0; i < 4; i++)
{
next_faller[i].X += direction;
if (next_faller[i].X >= WIDTH || next_faller[i].X < 0) return FUNCTION_FAIL;
if (map[next_faller[i].Y][next_faller[i].X] == BLOCK)return FUNCTION_FAIL;
}
keyboard_flag = 1;
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = AIR;
memcpy(faller, next_faller, sizeof(faller));
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = MOVING;
return FUNCTION_SUSSESS;
}
FUNCTION_RESULT try_fall()
{
FUNCTION_RESULT result = FUNCTION_FAIL;
while (try_move_down() == FUNCTION_SUSSESS)result = FUNCTION_SUSSESS;
return result;
}
//以中心点旋转
//以所有点旋转后向下
//以其他点旋转
FUNCTION_RESULT t_spin(int direction)
{
for (int j = 0; j < 4; j++)
{
next_faller[j].X = faller[0].X + direction * (faller[0].Y - faller[j].Y);
next_faller[j].Y = faller[0].Y + direction * (faller[j].X - faller[0].X);
}
if (is_legal(next_faller))
{
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = AIR;
memcpy(faller, next_faller, sizeof(faller));
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = MOVING;
return FUNCTION_SUSSESS;
}
for (int round = 1; round >= 0; round--)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
next_faller[j].X = faller[i].X + direction * (faller[i].Y - faller[j].Y);
next_faller[j].Y = faller[i].Y + direction * (faller[j].X - faller[i].X) + round;
}
if (is_legal(next_faller))
{
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = AIR;
memcpy(faller, next_faller, sizeof(faller));
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = MOVING;
return FUNCTION_SUSSESS;
}
}
}
return FUNCTION_FAIL;
}
//以中心点旋转
//以其他点旋转
//检查以中心点旋转后能否向下移动一格
//检查以其他点旋转后能否向下移动一格
FUNCTION_RESULT try_rotate(int direction)
{
if (now_shape == O_SHAPE)return FUNCTION_FAIL;
if (now_shape == T_SHAPE)return t_spin(direction);
for (int round = 0; round <= 1; round++)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
next_faller[j].X = faller[i].X + direction * (faller[i].Y - faller[j].Y);
next_faller[j].Y = faller[i].Y + direction * (faller[j].X - faller[i].X) + round;
}
if (is_legal(next_faller))
{
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = AIR;
memcpy(faller, next_faller, sizeof(faller));
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = MOVING;
return FUNCTION_SUSSESS;
}
}
}
return FUNCTION_FAIL;
}
int main()
{
//清除光标
hdl = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci = { 1,0 };
SetConsoleCursorInfo(hdl, &cci);
SetConsoleTitle("TETRIS!!!");
//随机数种子
srand((unsigned)time(NULL));
//地图初始化
memset(map, 0, WIDTH * HIGTH * sizeof(char));
//计时开始
last = GetTickCount64();
keyboard_flag = 0;
//生成第一个方块
generate();
update_screen();
while (1)//主循环
{
now = GetTickCount64();
//说明该向下移动了
if (keyboard_flag)
{
keyboard_flag = 0;
last = GetTickCount64() + COOLDOWN;
update_screen();
}
if (now > last)
{
last += TICK;
if (try_move_down() == FUNCTION_FAIL)//向下移动失败,创建一个新的形状
{
for (int i = 0; i < 4; i++) map[faller[i].Y][faller[i].X] = BLOCK;
clear_row();
generate();
}
update_screen();
}
while (_kbhit())
{
key = _getch();
switch (key)
{
case 'E':case 'e':
if (try_rotate(1) == FUNCTION_SUSSESS)keyboard_flag = 1;
break;
case 'Q':case 'q':
if (try_rotate(-1) == FUNCTION_SUSSESS)keyboard_flag = 1;
break;
case 'S':case 's':
if (try_move_down() == FUNCTION_SUSSESS)keyboard_flag = 1;
break;
case 'W':case 'w':
if (try_fall() == FUNCTION_SUSSESS)keyboard_flag = 1;
break;
case 'D':case 'd':
if (try_move_horizontal(1) == FUNCTION_SUSSESS)keyboard_flag = 1;
break;
case 'A':case 'a':
if (try_move_horizontal(-1) == FUNCTION_SUSSESS)keyboard_flag = 1;
break;
}
}
}
return 0;
}
#include
#include
#include
#include
#include
#define A1 0//A代表长条型,B为方块,C为L型,D为闪电型
#define A2 1
#define B 2
#define C11 3
#define C12 4
#define C13 5
#define C14 6
#define C21 7
#define C22 8
#define C23 9
#define C24 10
#define D11 11
#define D12 12
#define D21 13
#define D22 14
using namespace std;
class Box
{
private:
int map[23][12];//画面坐标,记录有方块的点,也是游戏界面
int hotpoint[2];//当前活动的点,所有图形都是以此为基准绘制的
int top;//当前最高位置
int point;//分数
int level;//等级
int ID;//当前活动图形的ID号
int colorID;//图形的颜色ID。
public:
Box()//初始化
{
int i,j;
for(i=0;i<23;i++)
for(j=0;j<12;j++)
map[i][j]=0;
hotpoint[0]=0;
hotpoint[1]=5;
point=0;
level=1;
top=99;
ID=0;
}
void SetColor(int color);//颜色
void DrawMap();//画游戏的大界面
bool Judge(int x,int y);//判断当前位置能否绘制图形
void Welcome();//欢迎界面
void DrawBox(int x,int y,int num);//绘制图形
void Redraw(int x,int y,int num);//擦除图形
void Run();//运行
void Turn();//转动方块
void UpdataMap();//更新画面
void Pause();//暂停
};
void SetPos(int i,int j)//设定光标位置
{
COORD pos={i,j};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
const int sharp[15][8]=
{
{0,0,1,0,2,0,3,0},{0,0,0,1,0,2,0,3},
{0,0,1,0,0,1,1,1},
{0,0,1,0,1,1,1,2},{0,1,1,1,2,0,2,1},{0,0,0,1,0,2,1,2},{0,0,0,1,1,0,2,0},
{1,0,1,1,1,2,0,2},{0,0,0,1,1,1,2,1},{0,0,0,1,0,2,1,0},{0,0,1,0,2,0,2,1},
{0,0,0,1,1,1,1,2},{0,1,1,0,1,1,2,0},
{0,1,0,2,1,0,1,1},{0,0,1,0,1,1,2,1}
};//形状点的各个坐标,先纵后横
const int high[15]={4,1,2,2,3,2,3,2,3,2,3,2,3,2,3};//这个数组是用来保存各个形状高度的,以上面的坐标相对应
void Box::SetColor(int colorID)
{
int n_color;
switch(colorID)
{
case 0: n_color = 0x08;break;
case 1: n_color = 0x0C;break;
case 2: n_color = 0x0D;break;
case 3: n_color = 0x0E;break;
case 4: n_color = 0x0A;break;
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n_color);
}
void Box::DrawMap()//画界面
{
int i;
SetColor(0);//界面颜色
for(i=0;i<14;i++)
{
SetPos(i*2,0);
cout<
}
for(i=1;i<=24;i++)
{
SetPos(0,i);
cout<
SetPos(13*2,i);
cout<
}
for(i=0;i<14;i++)
{
SetPos(i*2,24);
cout<
}
i=15;
for(i=15;i<=25;i++)
{
SetPos(i*2,0);
cout<
}
for(i=1;i<=8;i++)
{
SetPos(15*2,i);
cout<
SetPos(25*2,i);
cout<
}
for(i=15;i<=25;i++)
{
SetPos(i*2,9);
cout<
}
SetPos(16*2,16);
cout<
SetPos(16*2,17);
cout<
SetPos(16*2,18);
cout<
}
void Box::DrawBox(int x,int y,int num)//绘制图形
{
int i;
int nx,ny;
if (num<2)SetColor(1);//0、1是长条
else if(num<3) SetColor(2);//2 方块
else if(num<11) SetColor(3);//3、4、5、6、7、8、9、10
else SetColor(4);
for(i=0;i<4;i++)
{
nx=x+sharp[num][i*2];
ny=y+sharp[num][i*2+1];
SetPos((ny+1)*2,nx+1);//利用sharp数组相对于点x,y绘制形状
//SetColor(i+1);
cout<
}
}
void Box::Redraw(int x,int y,int num)//擦除图形,原理同上
{
int i;
int nx,ny;
for(i=0;i<4;i++)
{
nx=x+sharp[num][i*2];
ny=y+sharp[num][i*2+1];
SetPos((ny+1)*2,nx+1);
cout<
}
}
void Box::Turn()//转动图形,单纯的该ID而已
{
switch(ID)
{
case A1: ID=A2; break;
case A2: ID=A1; break;
case B: ID=B; break;
case C11: ID=C12; break;
case C12: ID=C13; break;
case C13: ID=C14; break;
case C14: ID=C11; break;
case C21: ID=C22; break;
case C22: ID=C23; break;
case C23: ID=C24; break;
case C24: ID=C21; break;
case D11: ID=D12; break;
case D12: ID=D11; break;
case D21: ID=D22; break;
case D22: ID=D21; break;
}
}
void Box::Welcome()//欢迎界面
{
char x;
while(1)
{
system("cls");
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
cout<
SetPos(16,9);
x=getch();
if(x<='9'&&x>='1')//设置等级
{
level=x-'0';
break;
}
}
}
void Box::UpdataMap()//更新画面(关键)
{
int clear;
int i,j,k;
int nx,ny;
int flag;
for(i=0;i<4;i++)//更新map数组的信息
{
nx=hotpoint[0]+sharp[ID][i*2];
ny=hotpoint[1]+sharp[ID][i*2+1];
map[nx][ny]=1;
}
if(hotpoint[0]
top=hotpoint[0];
clear=0;//消除的格数
for(i=hotpoint[0];i
{
flag=0;
for(j=0;j<12;j++)//检测是否可以消除此行
{
if(map[i][j]==0)//代表有空格,不能消除
{
flag=1;//1表示不能消除
break;
}
}
if(flag==0)//可以消除
{
for(k=i;k>=top;k--)//从当前位置向上所有的点下移一行
{
if(k==0)//最高点特殊处理
for(j=0;j<12;j++)
{
map[k][j]=0;
SetPos((j+1)*2,k+1);
cout<
}
else
{
for(j=0;j<12;j++)
{
map[k][j]=map[k-1][j];
SetPos((j+1)*2,k+1);
if(map[k][j]==0)
cout<
else
cout<
}
}
}
top++;//消除成功,最高点下移
clear++;
point+=clear*10*level;
}
}
SetColor(0);
SetPos(16*2,17);
cout<
}
void Box::Run()//运行游戏
{
int i=0;
char x;
int Count;//计数器
int nextID;
int temp;
srand((int)time(0));//将随机数的起点设置为time(0):不带秒
ID=rand()%15;//随机生成ID和下一个ID
nextID=rand()%15;//这里为了方便,其实每个形状不是等概率生成的
DrawBox(hotpoint[0],hotpoint[1],ID);//绘制图形
DrawBox(3,17,nextID);
Count=1000-level*100;//等级决定计数,这里是用Count控制时间,来控制下落的速度
while(1)
{
if(i>=Count)
{
i=0;//计数器清零
if(Judge(hotpoint[0]+1,hotpoint[1]))//如果下个位置无效(即到底)
{
UpdataMap();//更新画面
ID=nextID;//生成新ID,用原等待ID替换为当前ID
hotpoint[0]=0;//热点更新
hotpoint[1]=5;
Redraw(3,17,nextID);
nextID=rand()%15;
DrawBox(hotpoint[0],hotpoint[1],ID);
DrawBox(3,17,nextID);
if(Judge(hotpoint[0],hotpoint[1]))//无法绘制开始图形,游戏结束
{
//getch();
system("cls");
SetPos(25,15);
cout<
system("pause");//就是在命令行上输出一行类似于“Press any key to exit”
exit(0);//关闭所有文件,退出正在执行的程序,返回0代表正常结束
}
}
else
{
Redraw(hotpoint[0],hotpoint[1],ID);//没有到底,方块下移一位
hotpoint[0]++;//热点下移
DrawBox(hotpoint[0],hotpoint[1],ID);
}
}
if(kbhit())//读取键盘信息
{
x=getch();
if(x=='a'||x=='A')//左移
{
if(Judge(hotpoint[0],hotpoint[1]-1)==0)
{
Redraw(hotpoint[0],hotpoint[1],ID);
hotpoint[1]-=1;
DrawBox(hotpoint[0],hotpoint[1],ID);
}
}
if(x=='d'||x=='D')//右移
{
if(Judge(hotpoint[0],hotpoint[1]+1)==0)
{
Redraw(hotpoint[0],hotpoint[1],ID);
hotpoint[1]+=1;
DrawBox(hotpoint[0],hotpoint[1],ID);
}
}
if(x=='s'||x=='S')//向下加速!!!!!!!!此处可以改进,可以改进加速效果。改成+3之后,会出现BUG,最后几个无法加速
{
if(Judge(hotpoint[0]+3,hotpoint[1])==0)
{
Redraw(hotpoint[0],hotpoint[1],ID);
hotpoint[0]+=1;
DrawBox(hotpoint[0],hotpoint[1],ID);
}
}
if(x=='w'||x=='W')//转动方块
{
temp=ID;
Turn();
if(!Judge(hotpoint[0],hotpoint[1]))
{
Redraw(hotpoint[0],hotpoint[1],temp);
DrawBox(hotpoint[0],hotpoint[1],ID);
}
else
ID=temp;
}
if(x=='p'||x=='P')
{
//getch();
//system("cls");
Pause();
}
if(x=='q'||x=='Q')
{
system("cls");
SetPos(25,15);
cout<
system("pause");
exit(0);
}
while(kbhit())//读掉剩下的键盘信息
getch();
}
Sleep(1);//等待1毫秒
i++;//计数器加1
}
}
bool Box::Judge(int x,int y)//判断当前是否可以绘制方块
{
int i;
int nx,ny;
for(i=0;i<4;i++)
{
nx=x+sharp[ID][i*2];
ny=y+sharp[ID][i*2+1];
if(nx<0||nx>=23||ny<0||ny>=12||map[nx][ny]==1)//不能,返回1
return 1;
}
return 0;
}
void Box::Pause()
{
system("cls");
while(1)
{
SetPos(30,13);
cout<
if(getch()=='p'||getch()=='P')
break;
}
SetPos(30,13);
cout<
DrawMap();
int i ,j;
for(i=0;i<23;i++)
for(j=0;j<12;j++)
if(map[i][j]==1)
{
SetPos((j+1)*2,i+1);
cout<
}
}
int main()//主函数
{
Box game;
game.Welcome();
system("cls");
game.DrawMap();
game.Run();
}