| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2501 人关注过本帖
标题:怎么实现双缓冲双缓冲
只看楼主 加入收藏
观海听潮
Rank: 1
等 级:新手上路
帖 子:14
专家分:5
注 册:2016-8-28
结帖率:50%
收藏
已结贴  问题点数:9 回复次数:1 
怎么实现双缓冲双缓冲
求一个小的案例: 用c++实现
可以实现双缓冲,不用很长,我对window.h库函数不了解 所以希望 有些注释。。。

或者帮忙看一下 下面的俄罗斯方块 代码
我设计的是在某一行满了后,将这一行消除掉,用的是重新打印整个操作区的页面,因为是重新一行一行的打印,所以会有闪动,
想用双缓冲实现一下图形界面重新打印的问题。。。
#include<iostream>
#include<Windows.h>
#include<conio.h>
#include<time.h>
using namespace std;

int     score = 0;            //分数
bool check = true;        //检查方块还能不能下落
int  point_X, point_Y;    //操作区的数组的位置坐标
int  time1 = 0;            //睡眠时间
int     scope[32][36] = { 0 };        //操作范围 这里注意一个方格是占两个横坐标的 29-4 为25行
int  block[4][4] = { 0 };        //提示区的块数组
int  Block[4][4] = { 0 };        //显示区的数组
int  tmp[4][4] = { 0 };            //临时变量 用于旋转等操作时 的替代变量
int  block0[4][4] = {{0,1,1,0},{0,0,1,0},{0,0,1,0},{0,0,0,0}};// 7 个方块 用数组表示 正“7”
int  block1[4][4] = {{0,1,1,0},{0,1,0,0},{0,1,0,0},{0,0,0,0}};// 反“7”
int  block2[4][4] = {{0,0,0,0},{0,0,1,1},{0,1,1,0},{0,0,0,0}};// 反“z”
int  block3[4][4] = {{0,0,0,0},{1,1,0,0},{0,1,1,0},{0,0,0,0}};// 正“z”
int  block4[4][4] = {{0,0,0,0},{0,1,0,0},{1,1,1,0},{0,0,0,0}};// 倒“T”
int  block5[4][4] = {{0,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}};// 正方形
int  block6[4][4] = {{0,0,0,0},{0,0,0,0},{1,1,1,1},{0,0,0,0}};// 直条
//-----------函数声明------开始-------------
void console();                //设置窗口位置和大小,为了让程序运行得更好看
void gotoxy(int x, int y);        //设置光标输出的位置函数 坐标不能为 负数
void my_print();            //设置页面
void Appear_random();            //产生随机块 并打印在 提示区
void Print();                //打印函数 根据 point_X 和point_Y点的位置就可以打印出来 该点在小方格的左上角
void DownBlock();            //向下移动 一位
void UpBblock();            //顺时针旋转 90度
void LeftBlock();            //向左移动一位
void RightBlock();            //向右移动一位
void OperAreaPrint();            //重新打印整个墙内部的所有小块
int clear();                //清除满的行
//-----------函数声明------开始-------------
//设置窗口位置和大小,为了让程序运行得更好看
void console()
{
    //获取标准设备输出句柄
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO bInfo;//窗口缓冲区信息
    GetConsoleScreenBufferInfo(hOut, &bInfo );    // 获取窗口缓冲区信息
   
    SetConsoleTitle("俄罗斯方块 C版");//设置窗口的标题
    COORD size = {180, 120};            //不能小于默认的(80, 25)
    SetConsoleScreenBufferSize(hOut,size); // 重新设置缓冲区大小*/   
    SMALL_RECT rc = {0,0, 150, 100}; //不能大于缓冲区大小 上下左右的点
    SetConsoleWindowInfo(hOut,true ,&rc);    // 重置窗口大小
}

//设置光标输出的位置函数 坐标不能为 负数
void gotoxy(int x, int y)//x为 横坐标 y为纵坐标
{
    HANDLE app;
    COORD pos;
    pos.X = x;
    pos.Y = y;
    app = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(app, pos);
   
}

//设置页面
void my_print()
{
    system("color 70");//白底黑字
    for(int i = 1; i < 30; i++)//共 29 行
        cout<<"■\t\t\t\t■ |                    |"<< endl;//用tab键对齐 所以如开头的 "■\t"占8个字节
    cout<<"■■■■■■■■■■■■■■■■■ |--------------------------------------|";//框架
    gotoxy(36, 0);
    cout<<"------------------右面--------------------"<< endl;

    gotoxy(40, 3);
    cout<<"分 数: "<< score<< endl;
    gotoxy(36,6);
    printf("下一个方块:");
    gotoxy(36,14);
    printf("操作方法:");
    gotoxy(40,16);
    printf("↑:旋转 ↓:沉淀");
    gotoxy(40,18);
    printf("→:右移 ←:左移");

}
//产生随机块 并打印在 提示区
void Appear_random()
{
    srand((unsigned int)time(0));
    if(rand()%7 == 0)
        for(int i = 0; i < 4; i ++)
            for(int j = 0; j < 4; j++)
                block[i][j] = block0[i][j];
    else if(rand()%7 == 1)
        for(int i = 0; i < 4; i ++)
            for(int j = 0; j < 4; j++)
                block[i][j] = block1[i][j];
    else if(rand()%2 == 0)
        for(int i = 0; i < 4; i ++)
            for(int j = 0; j < 4; j++)
                block[i][j] = block2[i][j];
    else if(rand()%7 == 3)
        for(int i = 0; i < 4; i ++)
            for(int j = 0; j < 4; j++)
                block[i][j] = block3[i][j];
    else if(rand()%7 == 4)
        for(int i = 0; i < 4; i ++)
            for(int j = 0; j < 4; j++)
                block[i][j] = block4[i][j];
    else if(rand()%7 == 5)
        for(int i = 0; i < 4; i ++)
            for(int j = 0; j < 4; j++)
                block[i][j] = block5[i][j];
    else
        for(int i = 0; i < 4; i ++)
            for(int j = 0; j < 4; j++)
                block[i][j] = block6[i][j];                           

    for(int i = 0; i < 4; i++)                //打印出块
    {
        //gotoxy(44, 8+i);                    //将光标移动到 要打印的位置
        int a = 44;
        int b = 8+i;
        for(int j = 0; j < 4; j++)   
            if(block[i][j] == 1)
            {
                gotoxy(a + j*2, b);
                cout<<"■";        
            }
            else
            {
                gotoxy(a + j*2, b);
                cout<<" ";                    //将原来的块 覆盖
            }
    }
}

//打印函数 根据 point_X 和point_Y点的位置就可以打印出来 该点在小方格的左上角
void Print()
{
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
            {
                gotoxy(point_X + j*2, point_Y + i);//因为 一个小块占两个横坐标 所以要使 j*2
                cout<<"■";
            }
}



void DownBlock()
{
    if(check  == true)
        return;

    for(int i = 0; i < 4; i++)                //将原来的小方块覆盖掉
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
            {
                gotoxy(point_X + j*2, point_Y + i);
                cout<<" ";                                //将原来的小方块覆盖掉
            }
    for(int i = 0; i < 4; i++)                //在其下面输出新的方块
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
            {
                gotoxy(point_X + j*2, point_Y + i + 1);
                cout<<"■";                                //在其下面输出新的方块
            }
    point_Y++;            //注意:光标一定要在 块的左上角 跟踪 块落到那里了
    //判断下落后 是否到底部
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
                if(scope[point_Y + i + 1][point_X + j*2]==1 || point_Y + i > 27)
                {
                    check = true;        //到达底部
                    return ;
                }
}

void UpBblock()//向右旋转 90度
{
    //先将原来位置上的块覆盖掉
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
            {
                gotoxy(point_X + j*2, point_Y + i);
                cout<<" ";                //覆盖
            }
    //旋转
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            tmp[j][3-i] = Block[i][j];
    //判断旋转后 是否出界
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(tmp[i][j] == 1)
            {
                if(point_X + j*2 < 2 || point_X+ j*2 > 30 ||
                    (!Block[i][j] && scope[point_Y+j*2][point_X+i]))
                    return;
            }


    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            Block[i][j] = tmp[i][j];
   
   
   
    Print();
}

void LeftBlock()
{
    //判断是否出界
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
                if(point_X + j*2 < 4 || scope[point_Y + i][point_X + j*2 -2]==1)//左面的空间不够向左移动的
                    return;
    //左移动一位
    //将原来的覆盖掉
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
            {
                gotoxy(point_X + j*2, point_Y + i);
                cout<<" ";
            }
    //移动
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
            {
                gotoxy(point_X + j*2 - 2, point_Y + i);
                cout<<"■";
            }
    point_X  -= 2;
}

void RightBlock()
{
    //判断是否出界
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(Block[i][j] ==1)
            if(point_X + j*2 > 28 || scope[point_Y + i][point_X+j*2+2] == 1)    //右面的空间不够向右移动的(注意边界 从32开始 到32结束)
                return;
    //右移动一位
    //将原来的覆盖掉
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
            {
                gotoxy(point_X + j*2, point_Y + i);
                cout<<" ";
            }
    //移动
    for(int i = 0; i < 4; i++)
        for(int j = 0; j < 4; j++)
            if(Block[i][j] == 1)
            {
                gotoxy(point_X + j*2 + 2, point_Y + i);
                cout<<"■";
            }
    point_X  += 2;
}

void OperAreaPrint()
{
    //遍历整个操作区 进行 打印
    for(int i = 0; i < 29; i++)//行
    {
        for(int j = 2; j < 30; j += 2)
        {
            if (scope[i][j] == 1)
            {
                gotoxy(j, i);
                cout<<"■";     
            }
            else if(scope[i][j] != 1)
            {
                gotoxy(j, i);
                cout<<" "; //将原来的 小方块 覆盖掉
            }
        }
    }
    gotoxy(40, 3);
    cout<<"分 数: "<< score<< endl;
}
int clear()                //清除满的行
{
    int flag = 0;            //标记 若为 1 代表需要清除 重新打印
    //循环整个块 看是否都满了
    for(int i = 0; i < 4; i++)        //四行都要判断
    {
        for(int j = 4; j < 30; j += 2)    //判断该行的所有空间 是否都有 块
        {
            if(scope[point_Y + i][j] == 0)    //操作区没块存在
            {
                break;
            }

            else if(j == 28)                //这一行 都有块
            {
                flag = 1;
                score ++;    //分数 加一
                //清除这一行
                for(int tmp = 2; tmp < 30; tmp++)
                {
                    scope[point_Y + i][tmp] = 0;    //将操作区的数组 置为 0
                }

                //这一行上面的 都向下移动一位
                for(int a1 = point_Y + i; a1 > 0; a1--)
                {
                    for(int a2 = 2; a2 < 30; a2 += 2)
                        scope[a1][a2] = scope[a1-1][a2];
                }
                break;
            }

        }
        //重新打印操作区的 块
    if(flag == 1)
        OperAreaPrint();
    }

   
    return 0;
}

int main()
{
    //设置页面
    console();
    my_print();

    //产生随机块 并打印在 提示区
    Appear_random();

    //----开始游戏---进行循环----
    while(1)                    //无限循环
    {
        //若没有正在下落的随机块时 产生随机块 并打印
        if(check == true)        //没有方块下落
        {
            check = false;        //将标记值置为 false
            //初始化每次 块开始下落时的操作区数组的坐标位置
            point_X = 14;        //横坐标从 14开始 注意 横坐标 两个字符位置代表一个小方格的位置
            point_Y = 0;        //纵坐标从 0 开始
            //将提示区的块赋值给操作块 并在操作区打印出块
            for(int i = 0; i < 4; i++)
                for(int j = 0; j < 4; j++)
                    Block[i][j] = block[i][j];
            Print();                    //在操作区打印出 块
            Appear_random();            //产生随机块
        }

        //若有输入键 就执行 输入键的操作
        if(kbhit())                        //检测是否有按键 若有 就执行
        {
            char key = getch();            //捕获按键
            //判断按键 执行不同的操作
            switch (key)
            {
            case 72:    //上
                UpBblock();
                break;
            case 75:    //左
                LeftBlock();
                break;
            case 77:    //右
                RightBlock();
                break;
            case 80:    //下
                DownBlock();
                break;
            default:
                break;
            }
        }
        //间隔一段时间 自动下移一位
        Sleep(30);            //间隔 30ms
        if(++time1%30 == 0)    //每隔30 个30ms就自动 下移一位
            DownBlock();

        //若没有正在下落的随机块 就把下落的方格块赋值给操作区的数组
        if(check == true)
        {
            for(int i = 0; i < 4; i ++)
                for(int j = 0; j < 4; j++)
                    if(Block[i][j] == 1)
                        scope[point_Y + i][point_X + 2*j] = Block[i][j];//将操作区的该点的值赋 为 1 代表已经有 块了
        
            int k = clear();        //清除满的行
            //if(k == 9)
            //    return -1;
            OperAreaPrint();//打印操作区的块
        }
        
    }
    return 0;
}


[此贴子已经被作者于2017-3-2 13:36编辑过]

2017-03-02 09:07
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9007
专家分:53942
注 册:2011-1-18
收藏
得分:9 
不知所云
2017-03-02 10:04
快速回复:怎么实现双缓冲双缓冲
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017916 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved