俄罗斯方块(三)C语言

第四天效果图如下
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#ifndef _DAY4_H
#define _DAY4_H
#include<windows.h>
#include<time.h>
#include<stdbool.h>
//游戏区域位置设计
#define COL_BEGIN 2
#define COL_END 14
#define ROW_BEGIN 4
#define ROW_END 26

HANDLE Output;//控制台输出句柄

//存储游戏相关数据的结构体
typedef struct TetrisManager//俄罗斯管理
{
    unsigned int pool[28];//游戏池
    int x;//当前方块的x坐标,左上角坐标
    int y;//
    int type[3];//当前,下一个,下下一个方块的类型
    int orientation[3];//当前,下一个,下下一个方块的旋转状态

    //左边栏
    unsigned score;//得分
    unsigned erasedTotal;//消行总数
    unsigned erasedCount[4];//消几行数
    unsigned tetrisTotal;//目前出现方块总数
    unsigned tetrisCount[7];//目前出现各种方块数

    bool dead;//挂
}Manager;//结构体别名

//构造存储游戏控制相关数据的结构体
typedef struct  TetrisControl
{

    bool pause;//暂停
    bool clockwise;//旋转方向;顺时针方向为ture
    int direction;//移动方向:0向左移动 1向右移动
    //游戏池内每格的颜色
    //此版本是彩色的,仅用游戏池数据无法存储颜色
    int color[28][16];
}Control;//Control是结构体别名

//初始状态的游戏池
//每个元素表示游戏池的一行
//两端各置两个1,底部两行全部为1,便于进行碰撞
//这样一来游戏池的宽度为12列 共16列
//当某个元素为OXFFFF时,说明该行已经填满
//顶部4行用于给方块,不显示
//底部2行不显示,显示出来的游戏池高度为22行
static const unsigned int gs_uInitialTetrisPool[28]=
{
    0XC003,0XC003,0XC003,0XC003,0XC003,0XC003,0XC003,
    0XC003,0XC003,0XC003,0XC003,0XC003,0XC003,0XC003,
    0XC003,0XC003,0XC003,0XC003,0XC003,0XC003,0XC003,
    0XC003,0XC003,0XC003,0XC003,0XC003,0XC003,0XFFFF
    //C003 1100 0000 0000 0011

};

//7种方块的4种旋转状态(4位一行)
static const unsigned int TetrisTable[7][4]=
{
    { 0x00f0, 0x2222,0x00f0,0x2222 },//I
    { 0x0072, 0x0262,0x0270,0x0232 },//T
    { 0x0223, 0x0074,0x0622,0x0170 },//L
    { 0x0226, 0x0470,0x0322,0x0071 },//J
    { 0x0063, 0x0264,0x0063,0x0264 },//Z
    { 0x006c, 0x0462,0x006c,0x0462 },//S
    { 0x0660, 0x0660,0x0660,0x0660 },//O
};

//函数声明
void printPoolBorder();//显示游戏池边界
void gotoxyWithFullwidth(short x,short y);//全角显示鼠标定位函数
void printPrompting();//显示按键提示信息
void printScore(const Manager *manager);

void intiGame(Manager* manager,Control*control);//初始化游戏
void startGame(Manager *manager,Control *control);
void printNextTetris(const Manager *manager);
void printTetrisPool(const Manager *manager,Control *control);//显示游戏池
void initTetris(Manager *manager);//初始化方块
void insertTetris(Manager *manager);//插入方块
bool checkCollision(const Manager *manager);//检测碰撞
void setPoolColor(const Manager *manager,Control *control);//设置游戏池颜色
void printCurrentTetris(const  Manager *manager,Control *control);

#endif // _DAY4_H

#include <stdio.h>
#include <stdlib.h>
#include"day4.h"

int main()
{
    Manager manager;
    Control control;
    intiGame(&manager,&control);//初始化游戏
    printNextTetris(&manager);
    do
    {
        printPrompting();
        printPoolBorder();
        printScore(&manager);//显示得分
        printTetrisPool(&manager,&control);
        insertTetris(&manager);//插入方块
        setPoolColor(&manager,&control);
    }while(1);
    return 0;
}

//初始化游戏
void intiGame(Manager* manager,Control*control)
{
   Output=GetStdHandle(STD_OUTPUT_HANDLE);
   //定义光标隐藏变量并初始化
   CONSOLE_CURSOR_INFO info;
   info.bVisible=FALSE;//FAlse为光标隐藏
   info.dwSize=1;//光标亮度为1-100
   //设置光标隐藏
   SetConsoleCursorInfo(Output,&info);
   SetConsoleTitle("俄罗斯方块");//控制台句柄
   startGame(manager,control);//调用游戏
}


//游戏池
void printPoolBorder()
{
    int y;
    SetConsoleTextAttribute(Output,0xf0);

    for(y=4;y<26;y++)
    {
        //两条纵线
        gotoxyWithFullwidth(10,y-3);//鼠标定位
        printf("%2s"," ");
        gotoxyWithFullwidth(23,y-3);//鼠标定位
        printf("%2s"," ");
    }

        gotoxyWithFullwidth(10,y-3);//一条横线
        printf("%28s"," ");

}
//显示全角定位
void gotoxyWithFullwidth(short x,short y)
{
     static COORD cd;
     cd.X= x*2;//移动1个坐标乘以2,改变2个像素点的  距离
     cd.Y=y;
     //移动光标到指定位置
     SetConsoleCursorPosition(Output,cd);//输出句柄

}
//按键提示信息
void printPrompting()
{
    //设置文字颜色,高亮
      SetConsoleTextAttribute(Output,0x0B);
      //设置文字位置
      gotoxyWithFullwidth(26,10);
      printf("█控制:");
      gotoxyWithFullwidth(27,12);
      printf("□向左移动:← A 4");
      gotoxyWithFullwidth(27,13);
      printf("□向右移动:→ D 6");
      gotoxyWithFullwidth(27,14);
      printf("□向下移动:↓ S 2");
      gotoxyWithFullwidth(27,15);
      printf("□顺时针转:↑ W 8");
      gotoxyWithFullwidth(27,16);
      printf("□逆时针转:0 ");
      gotoxyWithFullwidth(27,17);
      printf("□直接落地:空格 ");
      gotoxyWithFullwidth(27,18);
      printf("□暂停游戏:回车 ");
      gotoxyWithFullwidth(26,23);
      printf("▉By:briup");
}
//显示得分信息
void printScore(const Manager *manager)
{
    static const char *tetrisName="ITLJZSO";
    int i;
    //初始化结构体内存空间
    //memset(manager,0,sizeof(Manager));
    //设置文字颜色 文字颜色 高亮红+绿=黄色
    SetConsoleTextAttribute(Output,0x0E);

    //得分
    gotoxyWithFullwidth(2,2);
    printf("█得分:%u",manager->score);

    //消行总数
    gotoxyWithFullwidth(1,6);
    printf("█消行总数:%u",manager->erasedTotal);

    //一次消1234行数纪录
    for(i=0;i<4;i++)
{
    gotoxyWithFullwidth(2,8+i);
    printf("□消%d:%u",i+1,manager->erasedCount[i]);

}
    //目前出现的方块总数
    gotoxyWithFullwidth(1,15);
    printf("█方块总数:%u",manager->tetrisTotal);

    //目前出现的ITLJZSO类型的方块数纪录
    for(i=0;i<7;i++)
{
   gotoxyWithFullwidth(2,17+i);
   printf("□%c形:%u",tetrisName[i],manager->tetrisCount[i]);

}

}
//开始游戏
void startGame(Manager *manager,Control *control)
{
    /*主要是初始化相关游戏值*/
    //初始化结构体内存空间
    memset(manager,0,sizeof(Manager));
    //初始化游戏池
    memcpy(manager->pool,gs_uInitialTetrisPool,sizeof(unsigned [28]) );
    //使用时间作为种子参数
    srand((unsigned)time(NULL));
    //初始化下一个方块
    manager->type[1]=rand()%7;
    manager->orientation[1]=rand()%4;
    manager->type[2]=rand()%7;
    manager->orientation[2]=rand()%4;
    memset(control,0,sizeof(Control));
    //初始化方块2017/6/8
    initTetris(manager);//给下一个方块
    setPoolColor(manager,control);//设置颜色
}

//显示下一个,下下一个
void printNextTetris(const Manager *manager)
{
    int i;
    unsigned int tetris;//存储下一个,下下一个类型
    //设置边框
    SetConsoleTextAttribute(Output,0X0f);//高亮白色
    gotoxyWithFullwidth(26,1);
    printf("┏━━━━━━━━━┓ ┏━━━━━━━━━┓");
    gotoxyWithFullwidth(26,2);
    printf("┃%8s ┃ ┃%8s ┃"," " ," ");
    gotoxyWithFullwidth(26,3);
    printf("┃%8s ┃ ┃%8s ┃"," " ," ");
    gotoxyWithFullwidth(26,4);
    printf("┃%8s ┃ ┃%8s ┃"," " ," ");
    gotoxyWithFullwidth(26,5);
    printf("┃%8s ┃ ┃%8s ┃"," " ," ");
    gotoxyWithFullwidth(26,6);
    printf("┗━━━━━━━━━┛ ┗━━━━━━━━━┛");
     //下一个方格用相应的颜色显示
    tetris=TetrisTable[manager->type[1]][manager->orientation[1]];
    SetConsoleTextAttribute(Output,manager->type[1]|8);//前景高亮

    for(i=0;i<16;i++)
    {   //x初始位置是27 (i&3)0—15的值为 0123 0123 0123 0123
        //y初始位置是2 (i>>2)右移两位0—15的值为0000111122223333
        gotoxyWithFullwidth((i&3)+27,(i>>2)+2);
        if((tetris>>i)&1)
            printf("■");
        else
            printf("%2s","");
    }
    tetris=TetrisTable[manager->type[2]][manager->orientation[2]];
    SetConsoleTextAttribute(Output,8);
    for(i=0;i<16;i++)
    {  //x初始位置是33 (i&3)0—15的值为 0123 0123 0123 0123
        //y初始位置是2 (i>>2)右移两位0—15的值为0000111122223333
        gotoxyWithFullwidth((i&3)+33,(i>>2)+2);
        if((tetris>>i)&1)
            printf("■");
        else
            printf("%2s","");
    }
}

#define gotoxyInPool(x,y)   gotoxyWithFullwidth(11,y-3);
//显示游戏池
void printTetrisPool(const Manager *manager,Control *control)
{
    int x,y;
    for(y=ROW_BEGIN;y<ROW_END;y++)//4,26
  {   gotoxyInPool(2,y);//游戏池中光标定位
   // gotoxyWithFullwidth(11,y-3);
   //定点到游戏池中的方格2 14
   for(x=COL_BEGIN;x<COL_END;x++)
  {
       if((manager->pool[y]>>x) &1)//1100 0000 0000 0011 >>2
       //用相应的颜色,显示一个实心的方块
        {
            SetConsoleTextAttribute(Output,control->color[y][x]);
            //control->color[y][x] 是一个数
            //一个方块如0X00f0 只有0和1组成 若想有特定的颜色 就要扩展成4*4的数组
            //有1的地方 就赋值为特定的数 也就是特定的颜色
            //也就是说这xy坐标所确定的地方 不是1 而是一个特定的颜色数manager->type[0]|8设置高亮
            printf("■");
        }
        else
        {
            //没有方块,显示空白
            SetConsoleTextAttribute(Output,0);
            printf("%2s","");
        }

  }
}
}
//初始化方块
void initTetris(Manager *manager)
{
     unsigned int tetris;//16当前方块存放
     manager->type[0]=manager->type[1];//下一个方块置为当前
     manager->orientation[0]=manager->orientation[1];//下一个方块旋转状态置为当前
     manager->type[1]=manager->type[2];//下下一个方块
     manager->orientation[1]=manager->orientation[2];
     manager->type[2]=rand()%7;//随机生成
     manager->orientation[2]=rand()%4;//
     tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
     //设置当前方块Y坐标,保证刚给出时只显示方块最下面一行 高位
     //这种方式使得玩家可以以很快的 速度将方块落在不显示出4行的位置
     if(tetris &0xf000)//俄罗斯方块最先显示最下面一行
     manager->y=0;
     else
     manager->y=(tetris &0x0f00)?1:2;
     manager->x=6;//设置当前方块x坐标
     manager->y=4;//设置当前方块y坐标 实际出现游戏池内方块出现坐标6,1
     if(checkCollision(manager)) //检测碰撞
     manager->dead=true;//标记游戏结束
     else
     insertTetris(manager); //将当前方块加入游戏池
     manager->tetrisTotal++;//方块总数加起来
     manager->tetrisCount[manager->type[0]]++;//相应方块数
     printNextTetris(manager);//显示下一个和下下一个方块
     printScore(manager);//显示得分信息

}
//插入方块
void insertTetris(Manager *manager)
{
    //插入当前方块
    unsigned int tetris;//16位
    tetris = TetrisTable[manager->type[0]][manager->orientation[0]];
    //(tetris >>0x0)&0x0f)当前方块每四位取出,<< manager->x 左移6位 再与0xc003或,最终移到游戏池中央
    manager->pool[manager->y+0]|=(((tetris >>0x0)&0x0f)<< manager->x);
    manager->pool[manager->y+1]|=(((tetris>>0x4)&0x0f)<<manager->x);
    manager->pool[manager->y+2]|=(((tetris >>0x8)&0x0f)<< manager->x);
    manager->pool[manager->y+3]|=(((tetris>>0xc)&0x0f)<<manager->x);
}
//设置游戏池内方块的颜色
void setPoolColor(const Manager *manager,Control *control)
{
    //只做设置颜色,不需要清除
    //当移动方块或给一个方块时候在调用
    int x,y,i;
    unsigned int tetris;
    tetris=TetrisTable[manager->type[0]][manager->orientation[0]];
    for(i=0;i<16;i++)
    {
        y=(i>>2)+manager->y;//0000 1111 2222 3333
        x=(i &3)+manager->x;//0123 0123 0123 0123 x=6 游戏池中间值
        if(y>ROW_END)//26
            break;
        if((tetris>>i) &1)
       //用相应的颜色,显示一个实心的方块
        control->color[y][x]=(manager->type[0]|8);//设置当前方块颜色
        //有四行0 1 2 3 每行有四列0123
    }
}
bool checkCollision(const Manager *manager)//空语句
{

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值