C++ 萌新试手—俄罗斯方块

 第二个编程作品——俄罗斯方块

借鉴了很多大神的程序算法,最终完成了这个

用一个4*4数组表示每个类型方块

并用4位十六进制   每一位表示每个数组的一行

 

然后运用一个二维数组旋转的算法 运用到四位十六进制数上形成方块的旋转,详见BlockRotate()函数

学生一枚  拿着俄罗斯方块练练手

 

game_data.h 

#pragma once

//界面相关参数

//游戏板方块数
#define x_GAMEBOARD_NUM 15
#define y_GAMEBOARD_NUM 25

//方块大小
#define BLOCK_SQUARE 20

//游戏板长宽
#define GAMEBOARD_WIDTH x_GAMEBOARD_NUM*20
#define GAMEBOARD_HEIGHT y_GAMEBOARD_NUM*20

//帮助栏长宽
#define HELPBOARD_WIDTH 150
#define HELPBOARD_HEIGHT GAMEBOARD_HEIGHT

//界面窗口大小
#define WINDOWS_WIDTH GAMEBOARD_WIDTH + HELPBOARD_WIDTH + 60
#define WINDOWS_HEIGHT GAMEBOARD_HEIGHT + 40

//控制按键
#define KB_UP 'w'
#define KB_DOWN 's'
#define KB_LEFT 'a'
#define KB_RIGHT 'd'
#define KB_PAUSE ' '

typedef int BlockTypeIdx;


int game_score = 0;//游戏分数
int BlockShapeType = 0;//方块类型数
bool Game_Board[y_GAMEBOARD_NUM][x_GAMEBOARD_NUM] = { false };//游戏板 false为无方块 true为有
char Key_Hit;//键盘输入
bool HighSpeed = false;
#define MaxTypeNum 10 //最大类型数存储数量

//方块形状表示
typedef struct BlockShape
{
	unsigned short BlockShapeBits;
}BlockArray;
BlockArray BlockShapeArray[MaxTypeNum];

//4*4方块左上角的坐标
typedef struct LOCATE
{
	int left;
	int top;
}Block_Location;

//方块位置初始化
Block_Location InitBlockLocation = { 20 + 7 * BLOCK_SQUARE,-40 };



 

 game_init.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<easyx.h>
#include<graphics.h>
#include<iostream>
#include"game_data.h"

//帮助栏显示
void Init_Help()
{
	setbkcolor(BLACK);
	settextstyle(20, 0, _T("宋体"));
	outtextxy(WINDOWS_WIDTH - 40 - HELPBOARD_WIDTH / 2, 50, _T("预览"));
	outtextxy(WINDOWS_WIDTH - 40 - HELPBOARD_WIDTH / 2, 200, _T("分数"));
	outtextxy(WINDOWS_WIDTH - 60 - HELPBOARD_WIDTH / 2, 300, _T("操作说明"));
	outtextxy(WINDOWS_WIDTH - 60 - HELPBOARD_WIDTH / 2, 340, _T("wsad方向"));
	outtextxy(WINDOWS_WIDTH - 60 - HELPBOARD_WIDTH / 2,380, _T("空格暂停"));
	TCHAR s[5];
	_stprintf(s, _T("%d"), game_score);
	settextcolor(LIGHTBLUE);
	outtextxy(WINDOWS_WIDTH - 30 - HELPBOARD_WIDTH / 2, 240, s);
}


//方块形状存入
/*
0100	0110	0110	0100	0010	0000	0000
0100	0100	0010	0110	0110	0110	0010
0100	0100	0010	0010	0100	0110	0111
0100	0000	0000	0000	0000	0000	0000
*/
void BlockShape_Recorder()
{
	BlockShapeArray[BlockShapeType++].BlockShapeBits = 0x4444;
	BlockShapeArray[BlockShapeType++].BlockShapeBits = 0x6440;
	BlockShapeArray[BlockShapeType++].BlockShapeBits = 0x6220;
	BlockShapeArray[BlockShapeType++].BlockShapeBits = 0x4620;
	BlockShapeArray[BlockShapeType++].BlockShapeBits = 0x2640;
	BlockShapeArray[BlockShapeType++].BlockShapeBits = 0x0660;
	BlockShapeArray[BlockShapeType++].BlockShapeBits = 0x0270;
}


//界面加载 边框绘制
void Init_Game()
{
	initgraph(WINDOWS_WIDTH, WINDOWS_HEIGHT);
	setbkcolor(LIGHTGRAY);;
	cleardevice();
	setfillcolor(BLACK);
	solidrectangle(20, 20, GAMEBOARD_WIDTH + 20, GAMEBOARD_HEIGHT + 20);
	solidrectangle(WINDOWS_WIDTH-20-HELPBOARD_WIDTH,20,WINDOWS_WIDTH-20,WINDOWS_HEIGHT-20);
	Init_Help();
	BlockShape_Recorder();
}




//绘制方块
//true为显示方块 false为清除原来方块
void Block_Display (BlockShape BlockType, Block_Location& BlockLocation, bool Display)
{

		unsigned short mask;
		int xRock = BlockLocation.left;
		int yRock = BlockLocation.top;
		if (Display)
		{
			setfillcolor(RED);
			setlinecolor(WHITE);
		}
		else
		{
			setfillcolor(BLACK);
			setlinecolor(BLACK);
		}
		if (BlockLocation.top >= 20)
		{
			mask = 1 << 15;
			for (int i = 1; i <= 16; i++)
			{
				if (mask & BlockType.BlockShapeBits)
					fillrectangle(xRock, yRock, xRock + BLOCK_SQUARE, yRock + BLOCK_SQUARE);
				i % 4 == 0 ? (xRock = BlockLocation.left, yRock += BLOCK_SQUARE) : xRock += BLOCK_SQUARE;
				mask >>= 1;
			}
		}
		else//如果top为0 从第2行开始显示 // -20 3 //-40 4 
		{
			int Row = 2 - BlockLocation.top / BLOCK_SQUARE;//第2行移动11位 //3  7 //4 3
			mask = 1 << (19 - 4 * Row);
			{
				for (int i = 1; i <= 4 * (5 - Row); i++)//从第4行 有1行需要打印 //3 2 //2 3
				{
					if (mask & BlockType.BlockShapeBits)
						fillrectangle(xRock, yRock + BLOCK_SQUARE * (Row - 1), xRock + BLOCK_SQUARE, yRock + BLOCK_SQUARE * (Row - 1) + BLOCK_SQUARE);
					i % 4 == 0 ? (xRock = BlockLocation.left, yRock += BLOCK_SQUARE) : xRock += BLOCK_SQUARE;
					mask >>= 1;
				}
			}
		}
	
}

game_play.h 

#pragma once
#include"game_init.h"
#include<conio.h>
#include<ctime>


bool JudgeMove(BlockShape &BlockShape, Block_Location &BlockLocation,char Direction);
void UserKeyBoardControl(BlockShape &TypeIdx, Block_Location &BlockLocation);
BlockShape BlockRotate(BlockShape &BlockType);
void JudgeLineFull();
void DeleteLine(int Idx);
void BoardFlagSet(BlockShape &BlockShape, Block_Location &BlockLocation);
void UpdateScore();
bool IsGameOver();

//游戏运行
void PlayGame()
{
	BlockShape TmpBlock;
	int CurrentBlockIdx, NextBlockIdx;
	srand((unsigned)time(NULL));
	CurrentBlockIdx = rand() % BlockShapeType;
	NextBlockIdx = rand() % BlockShapeType;
	Block_Location CurrentLocation;
	Block_Location VisitLocation = { WINDOWS_WIDTH - 60 - HELPBOARD_WIDTH / 2, 80 };
	CurrentLocation.left = InitBlockLocation.left;
	CurrentLocation.top = InitBlockLocation.top;
	Block_Display(BlockShapeArray[NextBlockIdx], VisitLocation, true);
	Block_Display(BlockShapeArray[CurrentBlockIdx], CurrentLocation, true);
	TmpBlock = BlockShapeArray[CurrentBlockIdx];
	while (true)
	{
		

		Block_Display(TmpBlock, CurrentLocation, true);
		HighSpeed = false;
		for (int i = 0; i < 300; i++)
		{
			UserKeyBoardControl(TmpBlock, CurrentLocation);
			if (HighSpeed)
				break;
			Sleep(1);
		}
		if (!JudgeMove(TmpBlock, CurrentLocation, KB_DOWN))
		{
			BoardFlagSet(TmpBlock, CurrentLocation);
			JudgeLineFull();
			if (IsGameOver())
			{
				MessageBox(NULL, _T("游戏结束"), _T("GAME OVER"), MB_OK);
				exit(0);
			}
			Block_Display(BlockShapeArray[NextBlockIdx], VisitLocation, false);
			CurrentBlockIdx = NextBlockIdx;
			NextBlockIdx = rand() % BlockShapeType;
			CurrentLocation.left = InitBlockLocation.left;
			CurrentLocation.top = InitBlockLocation.top;
			Block_Display(BlockShapeArray[NextBlockIdx], VisitLocation, true);
			Block_Display(BlockShapeArray[CurrentBlockIdx], InitBlockLocation, true);
			TmpBlock = BlockShapeArray[CurrentBlockIdx];
		}
		Block_Display(TmpBlock, CurrentLocation, false);
		CurrentLocation.top += BLOCK_SQUARE;

	}
}

//判定游戏是否结束
bool IsGameOver()
{
	for (int i = 0; i < x_GAMEBOARD_NUM; i++)
		if (Game_Board[0][i])return true;
	return false;
}

//分数更新
void UpdateScore()
{
	TCHAR s[10];
	_stprintf(s, _T("%d"), game_score);
	settextcolor(LIGHTBLUE);
	outtextxy(WINDOWS_WIDTH - 30 - HELPBOARD_WIDTH / 2, 240, s);
}

//删除整行,并使上边的下移
void DeleteLine(int Row)
{
//将满行这一行的以上全部全都清空
	setfillcolor(BLACK);
	solidrectangle(20, 20, 20 + BLOCK_SQUARE*x_GAMEBOARD_NUM, 20 + BLOCK_SQUARE * Row + BLOCK_SQUARE);

//将原来上面的行下移
	int count = 0;
	while (count != x_GAMEBOARD_NUM)
	{
		count = 0;
		for (int i = 0; i < x_GAMEBOARD_NUM; i++)
		{
			Game_Board[Row][i] = Game_Board[Row - 1][i];
			if (Game_Board[Row][i])
			{
				setfillcolor(RED);
				setlinecolor(WHITE);
				fillrectangle(20 + i * 20, 20 + Row * 20, 20 + i * 20 + BLOCK_SQUARE, 20 + Row * 20 + BLOCK_SQUARE);
			}
			else
				count++;
		}
		Row--;
	}
}

//判断是否存在整行被占用
void JudgeLineFull()
{
	bool LineFull = true;
	int Idx = y_GAMEBOARD_NUM - 1;
	int count = 0;
	while (count != x_GAMEBOARD_NUM)
	{
		LineFull = true;
		count = 0;
		for (int i = 0; i < x_GAMEBOARD_NUM; i++)
		{
			if (!(Game_Board[Idx][i]))
			{
				LineFull = false;
				count++;
			}
		}
		if (LineFull)
		{
			DeleteLine(Idx);
			game_score += 10;
			UpdateScore();
			Idx++;
		}
		Idx--;
	}
}


//在有方块的位置设置为1
void BoardFlagSet(BlockShape &BlockShape, Block_Location &BlockLocation)
{
	int xRock = BlockLocation.left;
	int yRock = BlockLocation.top;
	unsigned short mask = 1 << 15;
	for (int i = 1; i <= 16; i++)
	{
		if (BlockShape.BlockShapeBits & mask)
		{
			Game_Board[(yRock - 20) / BLOCK_SQUARE][(xRock - 20) / BLOCK_SQUARE] = true;
		}
		i % 4 == 0 ? (xRock = BlockLocation.left, yRock += BLOCK_SQUARE) : xRock += BLOCK_SQUARE;
		mask >>= 1;
	}
}

//方块旋转
BlockShape BlockRotate(BlockShape &BlockType)
{

	unsigned short mask;
	unsigned short NextBlock;
	for (int i = 3; i >= 0; i--)
	{
		for (int j = i; j < 16; j += 4)
		{
			mask = ((1 << j)&BlockType.BlockShapeBits) >> j;
			NextBlock = (NextBlock << 1) | mask;

		}
	}
	BlockShape Type = {NextBlock};
	return Type;
}


//判定能否移动
bool JudgeMove(BlockShape &BlockType, Block_Location &CurrentLocation, char Direction)
{
	unsigned short mask = 1 << 15;
	int xRock = CurrentLocation.left;
	int yRock = CurrentLocation.top;
	for (int i = 1; i <= 16; i++)
	{

		if (BlockType.BlockShapeBits & mask)
		{
			switch (Direction)
			{
			case KB_UP:
				if (Game_Board[(yRock - 20) / BLOCK_SQUARE][(xRock - 20) / BLOCK_SQUARE] || xRock <= 0 || xRock >= BLOCK_SQUARE*x_GAMEBOARD_NUM+20 || yRock >= 20 * y_GAMEBOARD_NUM)
					return false;
				break;
			case KB_DOWN:
				if (Game_Board[(yRock - 20) / BLOCK_SQUARE+1][(xRock - 20) / BLOCK_SQUARE] || yRock ==20 * y_GAMEBOARD_NUM)
					return false;
				break;
			case KB_LEFT:
				if (Game_Board[(yRock - 20) / BLOCK_SQUARE][(xRock - 20) / BLOCK_SQUARE - 1] || xRock == 20)
					return false;
				break;
			case KB_RIGHT:
				if (Game_Board[(yRock - 20) / BLOCK_SQUARE][(xRock - 20) / BLOCK_SQUARE + 1] || xRock == BLOCK_SQUARE*x_GAMEBOARD_NUM)
					return false;
				break;
			default:
				break;
			}
		}
		i % 4 == 0 ? (xRock = CurrentLocation.left, yRock += BLOCK_SQUARE) : xRock += BLOCK_SQUARE;
		mask >>= 1;
	}
	return true;
}

//按键操控
void UserKeyBoardControl(BlockShape& BlockType, Block_Location &BlockLocation)
{
	if (_kbhit())
	{
		Key_Hit = _getch();
		switch (Key_Hit)
		{
		case KB_UP:
			if (JudgeMove(BlockRotate(BlockType), BlockLocation, Key_Hit))
			{
				Block_Display(BlockType, BlockLocation, false);
				BlockType = BlockRotate(BlockType);
				Block_Display(BlockType, BlockLocation, true);
			}
			break;
		case KB_DOWN:
			if (JudgeMove(BlockType, BlockLocation, Key_Hit))
			{
				HighSpeed = true;
			}
			break;
		case KB_LEFT:
			if (JudgeMove(BlockType, BlockLocation, Key_Hit))
			{
				Block_Display(BlockType, BlockLocation, false);
				BlockLocation.left -= BLOCK_SQUARE;
				Block_Display(BlockType, BlockLocation, true);
			}
			break;
		case KB_RIGHT:
			if (JudgeMove(BlockType, BlockLocation, Key_Hit))
			{
				Block_Display(BlockType, BlockLocation, false);
				BlockLocation.left += BLOCK_SQUARE;
				Block_Display(BlockType, BlockLocation, true);
			}
			break;
		case KB_PAUSE:
			while (true)
			{
				Key_Hit = _getch();
				if (Key_Hit == ' ')
					break;
			}
		default:
			break;
		}
	}
}

main.cpp 


#include"game_init.h"
#include"game_play.h"

int main()
{

	Init_Game();
	PlayGame();
	closegraph();
}

 

全部评论
无法运行 缺少<easyx.h>头文件
点赞 回复 分享
发布于 2020-04-15 16:45

相关推荐

1 1 评论
分享
牛客网
牛客企业服务