C++小游戏-俄罗斯方块

zyl 2025-11-20 19:47:29 2025-11-20 21:35:44 23
#include<iostream>
#include<stdio.h>
#include<conio.h>
#include<windows.h>
#include<time.h>
using namespace std;

#define W 10
#define H 20
const int ROWS = H + 2;
const int COLS = W + 2;
const int Btype = 7;

// 方块颜色
const int BlockColors[Btype] = {
	4,  // T - 红色
	14, // O - 黄色
	6,  // J - 棕色/橙色
	1,  // I - 蓝色
	2,  // S - 绿色
	13, // Z - 紫色
	11  // L - 青色
};

int mp[ROWS][COLS] = {0};
int x, y, Bid, Bir, NextBid, NextBir;
bool Flag = 0;
int score = 0;
// 下落的间隔时间
int INTERVAL = 500;
// 暂停
bool paused = 0;

bool Blocks[Btype][4][4][4] = {
{{{0,1,0,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}},{{0,1,0,0},{0,1,1,0},{0,1,0,0},{0,0,0,0}},{{0,0,0,0},{1,1,1,0},{0,1,0,0},{0,0,0,0}},{{0,1,0,0},{1,1,0,0},{0,1,0,0},{0,0,0,0}}},
{{{0,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}},{{0,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}},{{0,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}},{{0,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}}},
{{{0,1,0,0},{0,1,0,0},{0,1,1,0},{0,0,0,0}},{{0,0,0,0},{1,1,1,0},{1,0,0,0},{0,0,0,0}},{{1,1,0,0},{0,1,0,0},{0,1,0,0},{0,0,0,0}},{{0,0,1,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}}},
{{{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0}},{{0,0,0,0},{1,1,1,1},{0,0,0,0},{0,0,0,0}},{{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0}},{{0,0,0,0},{1,1,1,1},{0,0,0,0},{0,0,0,0}}},
{{{0,1,0,0},{0,1,1,0},{0,0,1,0},{0,0,0,0}},{{0,0,0,0},{0,1,1,0},{1,1,0,0},{0,0,0,0}},{{0,1,0,0},{0,1,1,0},{0,0,1,0},{0,0,0,0}},{{0,0,0,0},{0,1,1,0},{1,1,0,0},{0,0,0,0}}},
{{{0,0,1,0},{0,1,1,0},{0,1,0,0},{0,0,0,0}},{{0,0,0,0},{1,1,0,0},{0,1,1,0},{0,0,0,0}},{{0,0,1,0},{0,1,1,0},{0,1,0,0},{0,0,0,0}},{{0,0,0,0},{1,1,0,0},{0,1,1,0},{0,0,0,0}}},
{{{0,0,1,0},{0,0,1,0},{0,1,1,0},{0,0,0,0}},{{0,1,0,0},{0,1,1,1},{0,0,0,0},{0,0,0,0}},{{0,1,1,0},{0,1,0,0},{0,1,0,0},{0,0,0,0}},{{0,0,0,0},{1,1,1,0},{0,0,1,0},{0,0,0,0}}}
};

// 隐藏光标
void HideCursor(){ 
	CONSOLE_CURSOR_INFO cursor_info = {1, 0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); 
}

// 设置光标位置
void setPos(int x,int y)  {
	CONSOLE_SCREEN_BUFFER_INFO csbiInfo;                            
	HANDLE hConsoleOut;
	hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleScreenBufferInfo(hConsoleOut,&csbiInfo);
	csbiInfo.dwCursorPosition.X = x;                                    
	csbiInfo.dwCursorPosition.Y = y;                                    
	SetConsoleCursorPosition(hConsoleOut,csbiInfo.dwCursorPosition);
}

// 带颜色的输出
void cprintf(const char* s, int color){
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | color);
	printf(s);
	SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | 7);
}

// 游戏提示
void tips(){
	setPos(W*2+6, 7);
	printf("游戏说明:\n");
	setPos(W*2+6, 9);
	printf("按 WASD 和 ↑ ↓ ← → 操控游戏\n");
	setPos(W*2+6, 11);
	printf("按↑和W旋转,按AD和← →左右移动,长按S加速下落\n");
	setPos(W*2+6, 13);
	printf("当前得分:%d\n", score);
}

// 初始化
void init(){
	x = W/2-1, y = 1;
	Bid = rand()%Btype;
	Bir = rand()%4;
	NextBid = rand()%Btype;
	NextBir = rand()%4;
	for(int i=0;i<ROWS;i++){
		for(int j=0;j<COLS;j++){
			if(i==0 || j==0 || i==ROWS-1 || j==COLS-1) mp[i][j] = 1;
			else mp[i][j] = 0;
		}
	}
}

void draw() {
	setPos(0, 0); // 从屏幕左上角开始绘制
	for (int i = 0; i < ROWS; i++) {
		// 绘制游戏区域(每格占2字符)
		for (int j = 0; j < COLS; j++) {
			// 先判断是否是当前下落方块的位置
			bool isCurrent = false;
			for (int bi = 0; bi < 4 && !isCurrent; bi++) {
				for (int bj = 0; bj < 4; bj++) {
					if (Blocks[Bid][Bir][bi][bj] && y + bi == i && x + bj == j) {
						isCurrent = true;
						break;
					}
				}
			}
			if (isCurrent) {
				cprintf("", BlockColors[Bid]);
			} else if (mp[i][j]) {
				if (i == 0 || j == 0 || i == ROWS - 1 || j == COLS - 1)
					cprintf("", 7);
				else
					cprintf("", BlockColors[mp[i][j] - 1]);
			} else {
				printf("  ");
			}
		}
		// 右侧信息区
		if (i == 7) {
			printf("    游戏说明:");
		} else if (i == 9) {
			printf("    WASD / 方向键 控制,Q 暂停");
		} else if (i == 11) {
			printf("    ↑/W: 旋转,←→/AD: 移动");
		} else if (i == 13) {
			printf("    当前得分:%d", score);
		} else if (paused && i == 15) {
			HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
			SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_INTENSITY);
			printf("    游戏已暂停");
			SetConsoleTextAttribute(h, FOREGROUND_INTENSITY | 7);
		} else if (paused && i == 16) {
			HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
			SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_INTENSITY);
			printf("    按 Q 继续");
			SetConsoleTextAttribute(h, FOREGROUND_INTENSITY | 7);
		} else if (i >= 1 && i <= 4) {
			// 绘制“下一个方块”预览(第1~4行右侧)
			printf("    ");
			for (int j = 0; j < 4; j++) {
				if (Blocks[NextBid][NextBir][i-1][j])
					cprintf("", BlockColors[NextBid]);
				else
					printf("  ");
			}
		} else {
			printf("                    "); // 清空右侧(20个空格)
		}
		printf("\n");
	}
	// 把光标移到底部,避免干扰游戏画面
	setPos(0, ROWS + 2);
}
// 判断这个位置能不能放下对应的方块
bool IsPlace(int tx, int ty, int tid, int tir){
	if(tx<0) return 0;
	for(int i=0; i<4; i++){
		for(int j=0; j<4; j++){
			if(Blocks[tid][tir][i][j]){
				// mp[ty+i][tx+j]
				if(ty+i<0 || ty+i>=ROWS || tx+j<0 || tx+j>=COLS) return 0;
				if(mp[ty+i][tx+j]) return 0;
			}
		}
	}
	return 1;
}

void DelLine() {
	// 1. 标记哪些行是满行
	bool vis[ROWS] = {0}; // 初始化为 false
	int cnt = 0;
	for (int i = 1; i <= H; i++) {
		bool isFull = true;
		for (int j = 1; j <= W; j++) {
			if (!mp[i][j]) {
				isFull = false;
				break;
			}
		}
		if (isFull) {
			vis[i] = true;
			cnt++;
		}
	}
	if (cnt == 0) return;
	// 从底部向上重建地图
	int L = H;
	for (int i = H; i >= 1; i--) {
		if (!vis[i]) { // 不是满行才复制
			if (L != i) {
				for (int j = 0; j < COLS; j++) {
					mp[L][j] = mp[i][j];
				}
			}
			L--;
		}
	}
	// 清空顶部
	for (int i = 1; i <= L; i++) {
		for (int j = 1; j <= W; j++) {
			mp[i][j] = false;
		}
		mp[i][0] = mp[i][COLS-1] = true; // 保持墙
	}
	// 更新分数
	if(cnt == 1) score += 100;
	else if(cnt==2) score += 200;
	else if(cnt==3) score += 400;
	else score += 800;
	
	INTERVAL = max(150, 500-score/100);
} 

void Move(){
	// 可以往下移动
	if(IsPlace(x, y+1, Bid, Bir)) y++;
	// 不能往下移动,写入mp中(锁定方块)
	else{
		for(int i=0; i<4; i++){
			for(int j=0; j<4; j++){
				if(Blocks[Bid][Bir][i][j]) mp[y+i][x+j] = Bid + 1;
			}
		}
		DelLine();
		Flag = 1;
	}
}

void Create(){
	Bid = NextBid, Bir = NextBir;
	NextBid = rand()%Btype, NextBir = rand()%4, x = W/2-1, y = 1;
}

void KeyInput(){
	// 检查左移(A / ←)
	if (GetAsyncKeyState('A') & 0x8000 || GetAsyncKeyState(VK_LEFT) & 0x8000) {
		static DWORD lastMoveLeft = 0;
		DWORD now = GetTickCount();
		if (now - lastMoveLeft > 100) { // 每50ms响应一次(可调)
			if (IsPlace(x-1, y, Bid, Bir)) x--;
			lastMoveLeft = now;
		}
	}
	// 检查右移(D / →)
	if (GetAsyncKeyState('D') & 0x8000 || GetAsyncKeyState(VK_RIGHT) & 0x8000) {
		static DWORD lastMoveRight = 0;
		DWORD now = GetTickCount();
		if (now - lastMoveRight > 100) {
			if (IsPlace(x+1, y, Bid, Bir)) x++;
			lastMoveRight = now;
		}
	}
	// 检查旋转(W / ↑)
	static bool rotated = false;
	if (GetAsyncKeyState('W') & 0x8000 || GetAsyncKeyState(VK_UP) & 0x8000) {
		if (!rotated) {
			if (IsPlace(x, y, Bid, (Bir+1)%4)) Bir = (Bir+1)%4;
			rotated = true;
		}
	} 
	else rotated = false; 
	// 检查瞬降(S / ↓)
	if (GetAsyncKeyState('S') & 0x8000 || GetAsyncKeyState(VK_DOWN) & 0x8000) {
		if(IsPlace(x, y+1, Bid, Bir)) y++;
		Sleep(10);
	}
	
	static bool ispause = false;
	if (GetAsyncKeyState('Q') & 0x8000) {
		if (!ispause) {
			paused = !paused;
			ispause = true;
		}
	} 
	else ispause = false;
}

int main(){
	HideCursor();
	srand(time(0));
	init();
	DWORD LastTime = GetTickCount();
	while(1){
		KeyInput();
		if(!paused){
			DWORD NowTime = GetTickCount();
			if(NowTime-LastTime >= INTERVAL){
				Move();
				LastTime = NowTime;
			}
			if(Flag){
				Create();
				if(!IsPlace(x, y, Bid, Bir)) break;
				Flag = 0;
			}
		}
		draw();
		Sleep(50);
	}
	setPos((W+1)/2,(H-1)/2);
	cprintf("游戏结束!", 4);
	setPos(0,H+2);
	system("pause");
	return 0;
}
{{ vote && vote.total.up }}