首页 资讯 论坛 我的社区 搜索 用户

[C/C++]使用c控制台写一个俄罗斯方块

无闻风
发表于 2019-06-27 13:00:30
0
810

 界面很丑旦问题不大,主要还是为了实现功能。

需要用到的头文件:

#include "pch.h"            //这是vs里默认添加的   如果在别的编译器报错就把这句删掉
#include 
#include 
#include "windows.h"
#include  

一些定义:

模型的数量与颜色数量

#define mod_max 7
#define colo_max 8

#define random(x) (rand()%x)//定义随机数范围

定义颜色值

#define blue              0x01
#define green             0x02
#define red               0x04
#define hig               0x08
#define yellow            red|green
#define lightblue         blue|green
#define purple            red|blue
#define white             blue|green|red

定义按键键值

#define dd 80
#define ll 75
#define rr 77
#define uu 72

#define esc 27
#define space 32

获得控制台资源句柄

HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);

颜色表

char colo_tab[colo_max] =
{
	blue,
	green,
	red,
	hig,
	yellow,
	lightblue,
	purple,
	white,
};

7个模型 每个模型4个方向  每个方向5行

char mod[mod_max][4][5] =
{
	//mod0
	{
		{
			0x80,
			0xc0,
			0x80,
		},
		{
			0x40,
			0xe0,
		},
		{
			0x40,
			0xc0,
			0x40,
		},
		{
			0xe0,
			0x40,
		},
	},
	//mod1
	{
		{
			0xc0,
			0x60,
		},
		{
			0x40,
			0xc0,
			0x80,
		},
		{
			0xc0,
			0x60,
		},
		{
			0x40,
			0xc0,
			0x80,
		},
	},
	//mod2
	{
		{
			0xc0,
			0xc0,
		},
		{
			0xc0,
			0xc0,
		},
		{
			0xc0,
			0xc0,
		},
		{
			0xc0,
			0xc0,
		},
	},
	//mod3
	{
		{
			0x80,
			0x80,
			0x80,
			0x80,
		},
		{
			0xf0,
		},
		{
			0x80,
			0x80,
			0x80,
			0x80,
		},
		{
			0xf0,
		},
	},
	//mod4
	{
		{
			0x20,
			0xe0,
		},
		{
			0xc0,
			0x40,
			0x40,
		},
		{
			0xe0,
			0x80,
		},
		{
			0x80,
			0x80,
			0xc0,
		},
	},
	//mod5
	{
		{
			0x60,
			0xc0,
		},
		{
			0x80,
			0xc0,
			0x40,
		},
		{
			0x60,
			0xc0,
		},
		{
			0x80,
			0xc0,
			0x40,
		},
	},
	//mod6
	{
		{
			0xe0,
			0x20,
		},
		{
			0x40,
			0x40,
			0xc0,
		},
		{
			0x80,
			0xe0,
		},
		{
			0xc0,
			0x80,
			0x80,
		},
	},
};

棋盘的缓存

char map[25][25];
void set_colo(char colo)//用于设置字体颜色
{
	SetConsoleTextAttribute(hOut, colo | hig);
}

void colo_print(char colo,const char *p)/可以设置颜色的显示
{
	SetConsoleTextAttribute(hOut,colo|hig);
	printf(p);
	SetConsoleTextAttribute(hOut, white | hig);
}
void set_y_x(int y, int x)//设置光标位置
{
	COORD pos = { x,y };
	SetConsoleCursorPosition(hOut, pos);
}
void y_x_colo_print(int y,int x,char colo,const char *p)//可以设置坐标以及颜色的文件显示
{
	set_y_x(y,x);
	colo_print(colo,p);
}

到这里驱动部分已经完成了 现在要做的就是写逻辑部分

下面是核心代码:

棋盘显示函数 放在主函数中循环调用棋盘大小是20*20 用两个for循环扫描整个棋盘 如果棋盘中有数据就将它显示出来 如果没有就显示空格将之前的缓存刷掉这里要注意"█"这个字符占用两个字节所以把x轴*2,填充空格的时候也要填充两个。整个棋盘并不是从0,0开始的所以要加偏移量也就是y+3,x+1.

void dis_map()
{
	int y, x;
	for (y = 0; y < 20; y++)
	{
		for (x = 0; x < 20; x++)
		{
			if (map[y][x] != 0)
			{
				y_x_colo_print(y+3, (x+1)*2, map[y][x], "█");
			}
			else
			{
				y_x_colo_print(y + 3, (x + 1) * 2, map[y][x], "  ");
			}
		}
	}
}

把模型放到棋盘里,参数有y,x也就是位置,m是模型,d是方向,最后就是颜色

char dis_mod_in_map(char y,char x,char m,char d,char colo)//返回1正常  2碰壁  4到底
{
	char a,b,c,e=1;
        //这里是把每个模型放在5*5的空间里  如果自己添加模型不能大于这个值
	for (a = 0; a < 5; a++)//扫描模型的每一行
	{	
		c = mod[m][d][a];//获取模型的每一行的数据
		for (b = 0; b < 5; b+=1)
		{
			if (c & 0x80)//通过与最高位的方式获得列数据
			{
				if (colo != 0)//如果是有数据的
				{
                                        //判断有没有超过两边的边界
					if (((b + x) < 0) || ((b + x) > 19)|| (map[a + y][b + x] != 0))					{
						e = e & ~0x01;
						e = e|2;
					}
                                        //判断有没有到底,到底和碰壁是可以同时存在的
					if (((a + y) == 20) || (map[a + y][b + x] != 0))
					{
						e = e & ~0x01;
						e = e | 4;

					}
				}			
			}
			c <<= 1;
		}
	}
        //如果到底了就讲模型固定到棋盘
	if (e & 1)
	{
		for (a = 0; a < 5; a++)
		{
			c = mod[m][d][a];
			for (b = 0; b < 5; b += 1)
			{
				if (c & 0x80)
				{
					if (colo == 0)
					{
						map[a + y][b + x] = 0;
					}
					else
					{
						map[a + y][b + x] = colo;
					}
				}
				c <<= 1;
			}
		}

	}
	return e;
}

如果单用_getch()会导致程序阻塞,程序会一直等待按键输入,所以在这之前用_kbhit()检查是否有按键按下,这个函数如果有按键被按下会返回1而且不会造成程序阻塞.

char get_key()
{
	char a;
	if (_kbhit() == 1)
	{
		a = _getch();
		return a;
	}
	return 0;

}

检查是否满一行,程序从最下面一行也就是第19行开始往上扫描(19到0)扫描每一行中每一列是否都有数据,每一行的开始都给flag置1然后开始扫描行的内容只要有一个单位是空(0)就说明这行没满flag置0,如果这行一行扫描完flag还是1说明这行满了 从这行开始把上面的内容往下移然后y+1再扫描一次这一行 这样就可以连续消除满行,最后没消除一行分数加100,分数满1000提升一个等级下落速度加快.

void charackwin()
{
	char y, x,flag=0,y2;
	for (y = 19; y > 0; y--)
	{
		flag = 1;
		for (x = 0; x < 20; x++)
		{
			if (map[y][x] == 0)
			{
				flag = 0;
			}
		}
		if (flag == 1)
		{

			for (y2 = y; y2 > 1; y2--)
			{
				for (x = 0; x < 20; x++)
				{
					map[y2][x] = map[y2 - 1][x];
				}
			}
			score += 100;
			if (score >= 1000)
			{
				score = 0;
				level += 1;
				speed -= 20;
			}
			y += 1;

		}
	}
}

有了这些核心代码 剩下的功能随便写

下面是完整代码:

// 1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include 
#include 
#include "windows.h"
#include

#define mod_max 7
#define colo_max 8

#define random(x) (rand()%x)//定义随机数范围

#define blue              0x01
#define green             0x02
#define red               0x04
#define hig               0x08
#define yellow            red|green
#define lightblue         blue|green
#define purple            red|blue
#define white             blue|green|red

#define dd 80
#define ll 75
#define rr 77
#define uu 72

#define esc 27
#define space 32

HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);

char colo_tab[colo_max] =
{
	blue,
	green,
	red,
	hig,
	yellow,
	lightblue,
	purple,
	white,
};
char mod[mod_max][4][5] =
{
	//mod0
	{
		{
			0x80,
			0xc0,
			0x80,
		},
		{
			0x40,
			0xe0,
		},
		{
			0x40,
			0xc0,
			0x40,
		},
		{
			0xe0,
			0x40,
		},
	},
	//mod1
	{
		{
			0xc0,
			0x60,
		},
		{
			0x40,
			0xc0,
			0x80,
		},
		{
			0xc0,
			0x60,
		},
		{
			0x40,
			0xc0,
			0x80,
		},
	},
	//mod2
	{
		{
			0xc0,
			0xc0,
		},
		{
			0xc0,
			0xc0,
		},
		{
			0xc0,
			0xc0,
		},
		{
			0xc0,
			0xc0,
		},
	},
	//mod3
	{
		{
			0x80,
			0x80,
			0x80,
			0x80,
		},
		{
			0xf0,
		},
		{
			0x80,
			0x80,
			0x80,
			0x80,
		},
		{
			0xf0,
		},
	},
	//mod4
	{
		{
			0x20,
			0xe0,
		},
		{
			0xc0,
			0x40,
			0x40,
		},
		{
			0xe0,
			0x80,
		},
		{
			0x80,
			0x80,
			0xc0,
		},
	},
	//mod5
	{
		{
			0x60,
			0xc0,
		},
		{
			0x80,
			0xc0,
			0x40,
		},
		{
			0x60,
			0xc0,
		},
		{
			0x80,
			0xc0,
			0x40,
		},
	},
	//mod6
	{
		{
			0xe0,
			0x20,
		},
		{
			0x40,
			0x40,
			0xc0,
		},
		{
			0x80,
			0xe0,
		},
		{
			0xc0,
			0x80,
			0x80,
		},
	},
};

char map[25][25];

void set_colo(char colo)
{
	SetConsoleTextAttribute(hOut, colo | hig);
}

void colo_print(char colo,const char *p)
{
	SetConsoleTextAttribute(hOut,colo|hig);
	printf(p);
	SetConsoleTextAttribute(hOut, white | hig);
}
void set_y_x(int y, int x)
{
	COORD pos = { x,y };
	SetConsoleCursorPosition(hOut, pos);
}
void y_x_colo_print(int y,int x,char colo,const char *p)
{
	set_y_x(y,x);
	colo_print(colo,p);
}

void title()
{
	char a;
	y_x_colo_print(0,8,white,"趣  味  俄  罗  斯  方  块");
	y_x_colo_print(2, 2, lightblue, "█");
	y_x_colo_print(3, 2, lightblue, "█");
	y_x_colo_print(3, 4, lightblue, "█");
	y_x_colo_print(4, 2, lightblue, "█");

	y_x_colo_print(3, 10, yellow, "█");
	y_x_colo_print(3, 12, yellow, "█");
	y_x_colo_print(4, 12, yellow, "█");
	y_x_colo_print(4, 14, yellow, "█");

	y_x_colo_print(3, 20, green, "█");
	y_x_colo_print(4, 20, green, "█");
	y_x_colo_print(3, 22, green, "█");
	y_x_colo_print(4, 22, green, "█");

	y_x_colo_print(2, 28, purple, "█");
	y_x_colo_print(3, 28, purple, "█");
	y_x_colo_print(4, 28, purple, "█");
	y_x_colo_print(5, 28, purple, "█");

	y_x_colo_print(3, 38, red, "█");
	y_x_colo_print(4, 34, red, "█");
	y_x_colo_print(4, 36, red, "█");
	y_x_colo_print(4, 38, red, "█");

	for (a = 6; a < 20; a++)
	{
		if (a == 6 || a == 19)
		{
			y_x_colo_print(a, 0, yellow, "============================================");
		}
		else
		{
			y_x_colo_print(a, 0, yellow, "||                                        ||");
		}
	}

	y_x_colo_print(10, 10, red, "1.开始游戏    2.按键说明");
	y_x_colo_print(16, 10, red, "3.游戏规则    4.退出");



}
void flower()
{
	y_x_colo_print(6, 44, purple, "                 (_)");
	y_x_colo_print(7, 44, purple, "               (_) (_)");
	y_x_colo_print(8, 44, purple, "                 (_)");

	y_x_colo_print(8, 44, red,  "        (_)");
	y_x_colo_print(9, 44, red,  "      (_) (_)");
	y_x_colo_print(10, 44, red, "        (_)");

	y_x_colo_print(7, 62, yellow, "@");
	y_x_colo_print(9, 53, yellow, "@");
	y_x_colo_print(8, 59, yellow, "/");
	y_x_colo_print(9, 58, yellow, "|");
	y_x_colo_print(10, 58, yellow, "|");
	y_x_colo_print(10, 57, yellow, "");
	y_x_colo_print(11, 58, yellow, "|");
	y_x_colo_print(11, 59, yellow, "/");
	y_x_colo_print(12, 58, yellow, "|");
	y_x_colo_print(12, 57, yellow, "");
	y_x_colo_print(13, 58, yellow, "|");
	y_x_colo_print(13, 59, yellow, "/");
	y_x_colo_print(14, 58, yellow, "|");

	y_x_colo_print(14, 54, green, "");
	y_x_colo_print(14, 60, green, "//");
	y_x_colo_print(15, 54, green, "^^^^^^^^");


}

void welcome()
{
	y_x_colo_print(21, 8, lightblue, "请选择[1 2 3 4]:[]");
}


void draw_game_frame()
{
	char a;
	y_x_colo_print(0, 10, lightblue, "趣味俄罗斯方块");

	for (a = 0; a < 22; a++)
	{
		if (a == 0||a==21)
		{
			y_x_colo_print(a+2, 0, red,   " = = = = = = = = = = = = = = = = = = = = = ");
		}
		else
		{
			y_x_colo_print(a + 2, 0, red, "|                                         |");
		}
	}

}

void dis_map()
{
	int y, x;

	//map[0][0] = blue;
	//map[19][39] = blue;
	for (y = 0; y < 20; y++)
	{
		for (x = 0; x < 20; x++)
		{
			if (map[y][x] != 0)
			{
				y_x_colo_print(y+3, (x+1)*2, map[y][x], "█");
			}
			else
			{
				y_x_colo_print(y + 3, (x + 1) * 2, map[y][x], "  ");
			}
		}
	}
}

char dis_mod_in_map(char y,char x,char m,char d,char colo)//返回1正常  2碰壁  4到底
{
	char a,b,c,e=1;
	for (a = 0; a < 5; a++)
	{	
		c = mod[m][d][a];
		for (b = 0; b < 5; b+=1)
		{
			if (c & 0x80)
			{
				if (colo != 0)
				{
					if (((b + x) < 0) || ((b + x) > 19)|| (map[a + y][b + x] != 0))
					{
						e = e & ~0x01;
						e = e|2;
					}
					if (((a + y) == 20) || (map[a + y][b + x] != 0))
					{
						e = e & ~0x01;
						e = e | 4;

					}
				}			
			}
			c <<= 1;
		}
	}
	if (e & 1)
	{
		for (a = 0; a < 5; a++)
		{
			c = mod[m][d][a];
			for (b = 0; b < 5; b += 1)
			{
				if (c & 0x80)
				{
					if (colo == 0)
					{
						map[a + y][b + x] = 0;
					}
					else
					{
						map[a + y][b + x] = colo;
					}
				}
				c <<= 1;
			}
		}

	}
	return e;
}
char get_key()
{
	char a;
	if (_kbhit() == 1)
	{
		a = _getch();
		return a;
	}
	return 0;

}

char ch;         //按键的状态
char state = 0;  //游戏状态
char yy=0, xx=10;//全局坐标
char mm = 0;    //全局模型
char cc = blue;   //全局颜色
char dir= 0;    //全局方向

char next_mm = 0;    //下一个模型
char next_cc = blue;   //下一个颜色
char next_dir = 0;    //下一个方向

int level = 1;
int score = 0;
int speed = 300;
int speed_js = 300;
long move_time;
char zt_flag = 0;
int move_js = 0;

char d_move()
{
	char e=0;
	speed_js = speed;
	if (ch == dd)
	{
		speed_js = 0;
	}

	if (ch == space)
	{
		if (zt_flag == 0)
		{
			zt_flag = 1;
		}
		else
		{
			zt_flag = 0;
		}
	}
	if (ch == uu)
	{
		dis_mod_in_map(yy, xx, mm, dir, 0);
		dir = (dir == 3) ? dir = 0 : ++dir;
		dis_mod_in_map(yy, xx, mm, dir, cc);
	}

	if (ch == rr)
	{
		dis_mod_in_map(yy, xx, mm, dir, 0);
		xx++;		
		if (dis_mod_in_map(yy, xx, mm, dir, cc) & 2)
		{
			//dis_mod_in_map(yy, xx, mm, dir, 0);
			xx--;
			dis_mod_in_map(yy, xx, mm, dir, cc);
		}
	}
	if (ch == ll)
	{
		dis_mod_in_map(yy, xx, mm, dir, 0);
		xx--;
		if (dis_mod_in_map(yy, xx, mm, dir, cc) & 2)
		{
			//dis_mod_in_map(yy, xx, mm, dir, 0);
			xx++;
			dis_mod_in_map(yy, xx, mm, dir, cc);
		}
	}

	if (zt_flag == 0)
	{
		if (clock() > move_time)
		{
			move_time = clock() + speed_js;
			dis_mod_in_map(yy, xx, mm, dir, 0);
			yy += 1;
			if (dis_mod_in_map(yy, xx, mm, dir, cc) & 4)
			{
				if (move_js == 0)
				{
					e = 2;
				}
				else
				{
					e = 1;
					move_js = 0;
				}
				yy--;
				dis_mod_in_map(yy, xx, mm, dir, cc);

			}
			else
			{
				move_js += 1;
			}
		}
	}

	return e;
}

void dis_next_mod()
{
	char map_buff[5][5];
	char y, x, c;
	for (y = 0; y < 5; y++)
	{
		for (x = 0; x < 5; x++)
		{
			map_buff[y][x] = 0;
		}
	}
	for (y = 0; y < 5; y++)
	{
		c = mod[next_mm][next_dir][y];
		for (x = 0; x < 5; x++)
		{
			if (c & 0x80)
			{
				map_buff[y][x] = next_cc;
			}
			c <<= 1;
		}
	}
	for (y = 0; y < 5; y++)
	{
		for (x = 0; x < 5; x++)
		{
			y_x_colo_print(10 + y, (25 + x) * 2, map_buff[y][x], "  ");
			if (map_buff[y][x] != 0)
			{
				y_x_colo_print(10 + y, (25 + x) * 2, map_buff[y][x], "█");
			}
		}
	}
}
void dis_data()
{
	set_colo(red);
	set_y_x(3,48);
	printf("level:%d", level);
	set_y_x(5, 48);
	printf("score:%d", score);
	set_y_x(7, 48);
	printf("speed:%dms", speed);
	y_x_colo_print(9,48,green,"**********");
	y_x_colo_print(9, 58, lightblue, "下一个出现方块:");

	y_x_colo_print(15, 48, green, "**********");

	y_x_colo_print(17, 48, yellow, "Esc:退出游戏");
	y_x_colo_print(19, 48, yellow, "↑键旋转");
	y_x_colo_print(21, 48, yellow, "空格:暂停游戏");

	dis_next_mod();

}

void end()
{
	y_x_colo_print(0, 0, red, "           ████    █      █    ██");
	y_x_colo_print(1, 0, red, "           █          ██    █    █  █");
	y_x_colo_print(2, 0, red, "           ████    █  █  █    █   █");
	y_x_colo_print(3, 0, red, "           █          █    ██    █  █");
	y_x_colo_print(4, 0, red, "           ████    █      █    ██");

	y_x_colo_print(20, 0, yellow, "我想重新玩一局--------1    不玩了,退出吧--------2");

}

void charackwin()
{
	char y, x,flag=0,y2;
	for (y = 19; y > 0; y--)
	{
		flag = 1;
		for (x = 0; x < 20; x++)
		{
			if (map[y][x] == 0)
			{
				flag = 0;
			}
		}
		if (flag == 1)
		{

			for (y2 = y; y2 > 1; y2--)
			{
				for (x = 0; x < 20; x++)
				{
					map[y2][x] = map[y2 - 1][x];
				}
			}
			score += 100;
			if (score >= 1000)
			{
				score = 0;
				level += 1;
				speed -= 20;
			}
			y += 1;

		}
	}
}
int main()
{
	//系统初始化
	char game_mod = 0;
	char d_flag;
	char y, x;
	title();
	flower();
	welcome();
	srand((int)time(0));					//设置随机数种子
	while (1)
	{
		//游戏初始化
		ch = _getch();
		if (ch == 49)
		{
			game_mod = 1;
			printf("starn");
			system("cls");
			draw_game_frame();
		}
		ch = 0;
		while(game_mod)
		{
			ch=get_key();
			if (ch == esc)
			{
				return 0;
			}
			switch (state)
			{
			case 0:
				yy = 0;
				xx = 10;

				mm = next_mm;
				cc = next_cc;
				dir = next_dir;
				next_mm = random(mod_max);
				next_cc = colo_tab[random(colo_max)];
				next_dir= random(4);
				draw_game_frame();
				charackwin();
				dis_mod_in_map(yy, xx, mm, dir, cc);

				state = 1;
				break;
			case 1:   //下落状态
				d_flag = d_move();
				dis_data();
				if (d_flag ==1)
				{
					state = 0;
				}
				dis_map();						
				if (d_flag == 2)
				{
					system("cls");
					state = 2;
				}			
				break;
			case 2:
				end();
				ch = _getch();
				if (ch == 49)
				{
					for (y = 0; y < 25; y++)
					{
						for (x = 0; x < 25; x++)
						{
							map[y][x] = 0;
						}
					}
					level = 1;
					score = 0;
					speed = 300;
					system("cls");
					state = 0;
				}
				else
				{
					return 0;
				}
				break;
			default:
				break;
			}


		}

		//return 0;
	}
}

最后修改 2019-09-21 22:07:37
0
810
用户评论
一起折腾