又开了一个分组,里面才一篇写数独游戏的文章,怪空的。再写一个吧。
写什么好呢,我想起大一写的第一个游戏:俄罗斯方块。
都是条件分支和循环,没有什么算法知识,比较适合再水一篇
一、俄罗斯方块的初始化
1、头文件包:
#include <windows.h>
#include <ctime>
#include <conio.h>
#include <cstdio>
#include <math.h>
2、俄罗斯方块的坐标和颜色控制:
当初的一大难点(哭),不知道有没有人和我一样
上网查了一下也是看得云里雾里的,不知道如何操作。
感谢一位叫张祺的大佬提供的源代码,才让我明白如何控制坐标和颜色,
下面两个函数都是人家的:
void gotoxy(int x, int y){
COORD pos;//表示一个字符在控制台屏幕上的坐标
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);//是API中定位光标位置的函数。
}//光标控制模块
void color(int b){
HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)) ;
SetConsoleTextAttribute(hConsole, b) ;//颜色控制
}//颜色控制模块
3、俄罗斯方块结构体:
还是张祺大哥的方法,用结构体存放俄罗斯方块的横纵坐标,然后将7大类19小类的俄罗斯方块的相对坐标存入其中
("I Shape"两种,"J Shape"
注意的是横纵坐标长度是不一样的
如俄罗斯方块 "O shape "坐标可以用二维数组表示为 {{0,0,2,2},{1,0,1,0}}, 前一个一维数组是x坐标,后一个是y坐标
二、俄罗斯方块的运行与判断:
1、运行:
设置一个 while(俄罗斯方块能运行==true) 的结构体,每循环一次,检测键盘一次,移动方块一次
(1)方块的移动:显示方块→暂停→清除方块→按操作改变方块坐标→再次显示。。。
当方块停止移动时,不必清除方块
△新建两个参数X,Y,表示对俄罗斯方块横纵坐标的修正,
俄罗斯方块初始化坐标+修正=俄罗斯方块新坐标
(2)方块下落:没有检测到键盘输入,方块下面没有阻挡,直接++Y即可
(3)方块旋转(kbhit检测到“↑”且有地方旋转):删除方块→修改到指定的类→显示修改类过后的方块
比如 T Shape大类按顺时针方向有四种旋转状态(四种小类),被记为类10,类11,类12,类13,
如果当前状态为类12,检测到“↑”时则把类12修改为类13;再检测到“↑”,把类13修改为类10。。。
(4)方块左右移(检测到“←”或“→”,且移动方向没有障碍):X+=2(x与y的长度是不同的),同时停止++Y。
为了做出加速的效果,我缩短了方块移动的暂停时间
(5)方块向下加速(检测到“↓”且方块下面没有障碍):缩短方块移动的暂停时间即可
2、方块的障碍判断
先设置一个二维数组a,数组编号与俄罗斯方块游戏界面的每一个方格坐标一一对应
比如坐标(6,8)对应a[4][5],坐标(8,8)对应a[4][6]
当俄罗斯方块停止运行时,将对应数组上的数字记为1。
循环读取俄罗斯方块四个方格坐标,单个方格坐标记为(x,y),对应数组a[m][n]
(1)、下方障碍判断:
四个方格其中一个满足a[m+1][n]=1,表示该方块下面有障碍,俄罗斯方块停止移动
ps:当无法向下移动,但是还能往左右移动时,怎么办?
当俄罗斯方块无法向下移动时,不用急于设置俄罗斯方块能运行=false。
首先禁止Y++,然后设置一个计时器,比如设置3,表示再循环三次while语句
如果没有检测到键盘输入,计时-1,;当计时为0时,设置俄罗斯方块能运行=false
(2)、左右判断
四个方格其中一个满足a[m][n-1]=1或超出左边界,锁死左移动,即使检测到"←"也不能往左移
右判断同理
(3)、当俄罗斯方块不再运行时,设置其四个方块坐标对应的数组值为1
3、俄罗斯方块的结算:
当一个方块不再运行,我们要做一些结算,才能继续产生下一个方块
(1)、行满判断:检测数组,如果a旗下某些一维数组中的元素全为1,表示这些一维数组对应的行满了,进一步进行结算;
没有,则生成下一个俄罗斯方块
(2)、进一步结算:行满清除等:
至行满的行开始交换数据。比如第Y行满了,对应数组M,
则
a[M][n]=a[M-1][n],a[M][n-1]=a[M-1][n-1] 。。。a[M-1][0]=a[M-1][0]
a[M-1][n]=a[M-2][n],a[M-1][n-1]=a[M-2][n-1] 。。。a[M-1][0]=a[M-2][0]
。
。
。
a[1][n]=a[0][n],a[1][n-1]=a[0][n-1] 。。。 a[1][0]=a[0][0]
将上面这些数组对应的方格都清掉,再重新检查上面这些数组
如果a[m][n]=1,则在对应坐标显示方格,反之不显示
ps:如果给方格设置颜色,可以将数组a改为三维数组
a[m][n][0]存储0和1,表示有没有方格,a[m][n][1]存储方格颜色
三、代码
#include <windows.h>
#include <ctime>
#include <conio.h>
#include <cstdio>
#include <math.h>
#define Speed 500 //下落速度
#define buffer 2 //触底缓冲
int board[30][30][2];
int sort[7]={0,1,3,5,7,11,15};//俄罗斯方块分为7大类19小类
int mark=0;
int amend_x=10,amend_y=4,speed=Speed;
time_t seed;
int kind=0,next_kind;
int key;//水平锁
int win=1;
struct before{
int x[4];
int y[4];
}before;
struct now{
int x[4];
int y[4];
int color;
}now[19]={ //□□
{{0,2,0,2},{-1,-1,-2,-2},10},//□□系列 num:0
{{0,6,4,2},{-1,-1,-1,-1},11},{{2,2,2,2},{-1,-2,-3,-4},11},//□□□□系列 num:1-2
//□□
{{0,4,2,2},{-2,-1,-1,-2},12},{{0,2,0,2},{-1,-2,-2,-3},12},// □□系列 num:3-4;
// □□
{{0,4,2,2},{-1,-2,-1,-2},13},{{0,2,2,0},{-2,-1,-2,-3},13},//□□ 系列 num:5-6;
// □
{{0,4,2,2},{-1,-1,-1,-2},14},{{0,2,0,0},{-1,-2,-2,-3},14},{{0,4,2,2},{-2,-2,-1,-2},14},{{0,2,2,2},{-2,-1,-2,-3},14},//□□□系列 num:7-10
//□
{{0,4,2,0},{-1,-1,-1,-2},9},{{0,2,0,0},{-1,-3,-2,-3},9},{{0,4,2,4},{-2,-1,-2,-2},9},{{0,2,2,2},{-1,-1,-2,-3},9},//□□□系列 num:11-14
// □
{{0,4,2,4},{-1,-1,-1,-2},5},{{0,2,0,0},{-1,-1,-2,-3},5},{{0,4,2,0},{-1,-2,-2,-2},5},{{0,2,2,2},{-3,-1,-2,-3},5},//□□□系列 num:15-18
};//方块形态结构体;
void gotoxy(int x, int y){
COORD pos;//表示一个字符在控制台屏幕上的坐标
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);//是API中定位光标位置的函数。
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(hOut,&cci);//获取光标信息
cci.bVisible = FALSE;//隐藏光标
SetConsoleCursorInfo(hOut,&cci);//设置光标信息
}//光标控制模块
void color(int b){
HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)) ;
SetConsoleTextAttribute(hConsole, b) ;//颜色控制
}//颜色控制模块
void boundary(){
color(7);
int i=0,j=0;
gotoxy(2,1);
for(i=0;i<26;i++){
printf("□");
}
gotoxy(2,27);
for(i=0;i<26;i++){
printf("□");
}
for(i=0;i<25;i++){
gotoxy(2,2+i);
printf("□");
gotoxy(34,2+i);
if(i==7||i==13){
printf("□□□□□□□□□");
}else{
printf("□");
}
gotoxy(52,2+i);
printf("□");
}
int t=100;
color(7);
gotoxy(37,11);
printf("最高分数:%d",t);
color(7);
gotoxy(37,13);
printf("当前得分:%d",mark);
gotoxy(37,17);
printf("↑:旋转");
gotoxy(37,19);
printf("↓:加速");
gotoxy(37,21);
printf("←:左移 ");
gotoxy(37,23);
printf("→:右移");
gotoxy(37,25);
printf("空格:停止");
color(12);
gotoxy(23,29);
printf("俄罗斯方块");
gotoxy(14,31);
printf("哈蒙森软件工业公司 于1898年出品");
color(7);
for(int i=0;i<30;++i){
board[26][i][0]=1;
}
}//界面生成模块
void next(){
srand(time(&seed));
next_kind=sort[rand()%7];
gotoxy(37,3);
printf("下一个");
color(now[next_kind].color);
for(int i=0;i<4;++i){
gotoxy(now[kind].x[i]+37,now[kind].y[i]+7);
printf(" ");
}
for(int i=0;i<4;++i){
gotoxy(now[next_kind].x[i]+37,now[next_kind].y[i]+7);
printf("■");
}
color(7);
}
void left_and_rigth(int dir){
if(now[kind].x[0]+amend_x>=6 && now[kind].x[1]+amend_x<=30){
if(dir==3){
for(int i=0;i<4;++i){
int x=now[kind].x[i]+amend_x;
int y=now[kind].y[i]+amend_y;
if(board[y-1][x/2-3][0]==1){
key=0;
}
}
}
if(dir==4 || dir==1){
for(int i=0;i<4;++i){
int x=now[kind].x[i]+amend_x;
int y=now[kind].y[i]+amend_y;
if(board[y-1][x/2-1][0]==1){
key=0;
}
}
}
}
if(now[kind].x[0]+amend_x<6 && dir==3){
key=0;
}
if(now[kind].x[1]+amend_x>30 && (dir==4 || dir==1)){
key=0;
}
}//左右障碍判断
void game_over(){
for(int i=25;i>=0;i--)
{
for(int j=0;j<15;j++){
color(7);
gotoxy(32-j*2,2+i);
printf("□");
Sleep(10);
board[i][j][0]=0;
}
}
for(int j=0;j<25;j++)
{
for(int i=0;i<15;i++)
{
gotoxy(4+2*i,j+2);
printf(" ");
Sleep(10);
}
}
gotoxy(37,13);
printf("当前得分:%d ",mark);
mark=0;
}//界面清除模块
int input(){
int ch1=0;
int ch2=0;
if (ch1=getch()){
ch2=getch();//第一次调用getch(),返回值224
if(kbhit()){
ch2=getch();
}
switch (ch2)//第二次调用getch()
{
//↑↓←→键
case 72: return 1;
case 80: return 2;
case 75: return 3;
case 77: return 4;
}
}
}
void move(int fall){
for(int i=0;i<2;++i){
for(int j=0;j<4;++j){
int x=now[kind].x[j]+amend_x;
int y=now[kind].y[j]+amend_y;
if(i==0 && y>1){
gotoxy(x,y);
color(now[kind].color);
printf("■");
gotoxy(x,y+1);
}
if(i==1 && fall==1 && y>1){
gotoxy(x,y);
printf(" ");
}
}
color(7);
Sleep(speed*(1-i));
}
gotoxy(37,13);
printf("当前得分:%d ",mark);
}//方块的移动
bool fall_or_not(){
for(int i=0;i<4;++i){
int x=now[kind].x[i]+amend_x;
int y=now[kind].y[i]+amend_y;
if(board[y-1][x/2-2][0]==1){
return false;
}
}
return true;
}//垂直障碍模块
void rotate(){
if(kind>0 && kind<3){
kind==1?kind=2:kind=1;
}
if(kind>2 && kind<5){
kind==3?kind=4:kind=3;
}
if(kind>4 && kind<7){
kind==5?kind=6:kind=5;
}
if(kind>6 && kind<11){
kind==10?kind=7:kind++;
}
if(kind>10 && kind<15){
kind==14?kind=11:kind++;
}
if(kind>14){
kind==18?kind=15:kind++;
}
}//方块旋转模块
void line_clear(int n){
for(n;n>1;--n){
for(int i=0;i<15;++i){
gotoxy(4+2*i,n+1);
color(0);
printf(" ");
board[n][i][0]=board[n-1][i][0];
board[n][i][1]=board[n-1][i][1];
if(board[n][i][0]==1){
gotoxy(4+2*i,n+1);
color(board[n][i][1]);
printf("■");
}
}
}
}//行满清除
void full_or_not(){
int line=0;
for(int i=1;i<26;++i){
int k=0;
for(int j=0;j<15;++j){
if(board[i][j][0]==1){
++k;
}
}
if(k==15){
++line;
line_clear(i);
}
}
if(line>0){
mark+=pow(3,line-1);
color(7);
for(int i=0;i<line*2;++i){
gotoxy(10,3);
i%2==0?color(7):color(12);
if(line==1){
printf("为不列颠人欢呼!");
}
if(line==2){
printf("维多利亚女王万岁!");
}
if(line==3){
printf("为黄金时代干杯!");
}
if(line==4){
printf("上帝保佑大英帝国!");
}
Sleep(100);
if(i%2==1){
Sleep(2000);
}
}
gotoxy(10,3);
printf(" ");
color(7);
}
}//判断行满
void game(){
int fall=1,dir,time=buffer,stop=0;
amend_x=10,amend_y=3;
if(kind==1){
--amend_y;
}
while(fall==1){
dir=5;
key=1;
if(kbhit()){
dir=input();
left_and_rigth(dir);
gotoxy(2,0);
if(dir==1 && key==1 && amend_y>4 && stop==0){
rotate();
time=2;
}
if(dir==2){
speed=30;
}
if(dir==3 && key==1){
amend_x-=2;
if(stop==0){
--amend_y;
}
speed=30;
time=2;
}
if(dir==4 && key==1){
amend_x+=2;
if(stop==0){
--amend_y;
}
speed=30;
time=2;
}
}
++amend_y;
if(fall_or_not()==false){
stop=1;
for(int i=0;i<4;++i){
if(now[kind].y[i]+amend_y<4){
win=0;
}
}
}
if(fall_or_not()==true){
stop=0;
time=buffer;
}
if(stop==1 && time>0){
--time;
--amend_y;
}
if(time==0){
fall=0;
}
move(fall);
speed=Speed;
gotoxy(10,0);
}
for(int i=0;i<4;++i){
int x=now[kind].x[i]+amend_x;
int y=now[kind].y[i]+amend_y;
board[y-1][x/2-2][0]=1;
board[y-1][x/2-2][1]=now[kind].color;
}
full_or_not();
}//控制一个俄罗斯方块的运行
int main(){
srand(time(&seed));
kind=sort[rand()%7];
boundary();
int again=1;
while(again==1){
while(win==1){
next();
game();
kind=next_kind;
}
game_over();
boundary();
gotoxy(5,15);
printf("Enter 1 begin next game:");
scanf("%d",&again);
gotoxy(5,15);
printf(" ");
win=1;
}
gotoxy(0,40);
return 0;
}