当前位置:威尼斯 > 威尼斯人登录网站 > 将本网站任何内容或服务用于其他用途时,将本

将本网站任何内容或服务用于其他用途时,将本

文章作者:威尼斯人登录网站 上传时间:2019-09-29

版权声明:访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。除此以外,将本网站任何内容或服务用于其他用途时,须征得本网站及相关权利人的书面许可,并支付报酬。转载需表明文章地址。

创意俄罗斯方块,俄罗斯方块创意设计

 

版权声明:访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。除此以外,将本网站任何内容或服务用于其他用途时,须征得本网站及相关权利人的书面许可,并支付报酬。转载需表明文章地址。

本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,予以删除。

作者QQ:1765813715

由于这个游戏倾入了我大量的时间和创意 所以写了个版权声明

这个游戏在基础的俄罗斯方块上面还添加了  两种方块

一种是幽灵方块 (可以在方块间任意移动 直到它所在的这一列下面没有空)

另一种是  炸弹方块  (他可以在激活和非激活中转换,激活时到达底部后会清除周围3*3的方块 非激活就和普通方块没有什么区别

第一次用WindowsApi写游戏  注释很多。 也查了很多资料

Windows窗口的创建以后我在写一个详细的 这里我就直接从CALLBACK WndProc 开始讲解我的程序结构了

 

 

图片 1

下面讲解每一个函数

void DrawPanel(HDC hdc);      绘制游戏面板

void RefreshPanel(HDC hdc); 刷新游戏面板
void creat();          创造方块 一共有9中方块
bool isbottom(HWND hwnd);    判断是否到达底部  幽灵方块判断方式不同  以及到达底部后的处理(即融入地图 或者炸弹方块的 爆炸) 以及检测游戏结束
bool drop(HDC hdc,HWND hwnd); 下降 其中调用 isbottom() 如果到达底部  调用clear(),creat(),refreshpanel()
void move_left();                      向左移动  检测碰撞(幽灵方块也是特殊处理)
void move_right();                    同上
void transform();        变形     变形时需要检测是否满足    炸弹方块的变形是 在激活和非激活状态之间转换
void clear(HDC hdc);      消行    内部还实现加分
void preview(HDC hdc);     图形预览框

 

 这里添加下 过程记录吧 也方便其他像学习的人有一条明确的路线

4月28日  下午6点—晚上12点    学习窗口的创建    如何绘画出图形界面
4月29日  上午8点—11.30   写出  已测试( 方块生成  碰撞检测  向下移动  时钟系统   暂停功能  检测游戏结束)
             未测试( 消行 )
            中午1点—1点40   完成左右移动   测试了消行  但是没有成功 还未发现原因(先睡觉)。。。。
将本网站任何内容或服务用于其他用途时,将本网站任何内容或服务用于其他用途时。              下午3点—4点   修改消行BUG  完成转换功能   到这里基本功能差不多就全部完成了
              现在基本的俄罗斯方块已经完成了   不过我的俄罗斯方块比较高级  还有两种方块就是幽灵方块 和 炸弹方块
      下午6点—7点  游戏测试 查找BUG(别说还真有)
       晚上11点—11.半  完成幽灵方块
4月30日  上午8点—11点  完成炸弹方块    图形预览
   晚上11点   完成BGM (找了几个小时)。。

 

 注意:我是在vs2017上面开发的  测试在dev上面无法编译   而且由于我这个添加BGM 所以有可能在你的电脑上也无法编译

      如果还缺少头文件请自行添加

    如果是这样,就删除播放BGM 的代码 或者自己从新加载资源文件

     在这里我把我的文件上传到百度网盘里   大家有需要的可以自己下载  其中bebug和release中的EXE文件 可以直接用来玩

    

#include "stdafx.h"
#include <windows.h>

// C 运行时头文件
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include<time.h>
#include<iostream>
#include "俄罗斯方块.h"
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")//知识就是财富啊  一个背景音乐搞了半天
#define CELL 20//方块大小
#define ROWS 25 //行数
#define COLS 15//列数
using namespace std;
TCHAR str[256];
int id; //记录当前方块种类
int next_id;//记录下一个方块的ID 达到预览
int len;
int score = 0;                //得分
int level = 0;                    //游戏等级
int speed = 500;                //游戏速率  初始化为1秒   后面的速率为  speed-min(level,7)*100;
UINT timer = 0;
bool ispause = 0;            //记录是否暂停
bool panel[25][15] = { 0 };    //记录游戏底层画面
bool active;                //记录炸弹方块是否被激活
int direction[8][2] = { 1,0,0,1,-1,0,0,-1,1,1,-1,-1,1,-1,-1,1 };//炸弹方块爆破的8个方向
COORD pre_peak;
bool pre_panel[2][4];        //预览面板

bool* block=NULL;            //通过记录方块组合 最左上角(我们后面称为顶点)的坐标  和组合的宽度高度 来确定这个组合的位置。   这样做有很大的好处
int block_top = 0;
int block_left = 0;
int block_height = 0;
int block_width = 0;

void DrawPanel(HDC hdc);
void RefreshPanel(HDC hdc);
void creat();
bool isbottom(HWND hwnd);
bool drop(HDC hdc,HWND hwnd);
void move_left();
void move_right();
void transform();
void clear(HDC hdc);
void preview(HDC hdc);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lparam);//回调函数

//建立窗口需要经过5个步骤  设计窗口类型  注册窗口类型 创建 显示 消息循环
int APIENTRY WinMain(HINSTANCE hInstance,   //程序当前运行的实例句柄
    HINSTANCE hPrevInstance,                //当前实例的前一个实例 w32下不再起作用
    LPSTR lpCmdLine,                        //表示传给程序的命令行参数
    int nCmdShow)                          //指定程序窗口如何显示,如 最大化最小化等
{
    WNDCLASS wndclass;                    //下面都是注册的内容。。。。。(好多。。)
    HWND hwnd;
    MSG msg;
    TCHAR lpszClassName[] = TEXT("俄罗斯方块");
    wndclass.style = CS_HREDRAW | CS_VREDRAW;           //窗口样式
    wndclass.lpfnWndProc = WndProc;                     //指向窗口函数的指针
    wndclass.cbClsExtra = 0;                            //窗口类附加字节, 为该类窗口共享,一般置0
    wndclass.cbWndExtra = 0;                            //窗口字节 一般值0
    wndclass.hInstance = hInstance;                        //当前应用程序的实例句柄
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);    //指定窗口图标
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);        //指定窗口光标
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//设置背景色
    wndclass.lpszMenuName = NULL;                                //窗口菜单资源名
    wndclass.lpszClassName = lpszClassName;                        //窗口类名
    if (!RegisterClass(&wndclass))                                //注册
        return FALSE;
    hwnd = CreateWindow(lpszClassName, TEXT("俄罗斯方块"),        //创建
        WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, CW_USEDEFAULT, 
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, 
        hInstance, NULL);
    ShowWindow(hwnd, nCmdShow);                                    //显示
    UpdateWindow(hwnd);                                            //上传
    while (GetMessage(&msg, NULL, 0, 0))                        //消息循环
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)//回掉函数
{
    switch (message)
    {
    case WM_CREATE:
        PlaySound(                        //BGM
            MAKEINTRESOURCE(130),        //不知道为什么 这里不能直接写 IDR_WAVE1 而是要写他的数字id
            GetModuleHandle(NULL),
            SND_RESOURCE | SND_ASYNC | SND_LOOP);
        MoveWindow(hwnd, 200, 200, COLS*CELL+300, ROWS*CELL+40, FALSE);//16.40
        pre_peak.X = 16; pre_peak.Y = 2; //确定预览框 顶点坐标
        srand(int(time(0)));
        next_id = rand() % 9;
        creat();
        timer = SetTimer(hwnd, 1, speed - min(7, level) * 50, NULL);  //创建一个时钟
        return 0;
    case WM_PAINT:
        HDC hdc;
        PAINTSTRUCT ps;
        hdc = BeginPaint(hwnd, &ps);
        DrawPanel(hdc);
        RefreshPanel(hdc);
        preview(hdc);
        TextOutW(hdc, 350+100, 370-330, TEXT("得分:"), 3);
        TextOutW(hdc, 350+100, 390-330, TEXT("等级:"), 3);
        TextOut(hdc, 350, 480, TEXT("Made by LYON"), strlen("Made by LYON"));
        len = wsprintf(str, TEXT("%d"),  score);  //。。。为了找这个    找了  一个小时。。。 怎么把整数转换为字符串
        TextOutW(hdc, 390+100, 370-330, str, len);            //其实也可以自己写一个转换函数的 ,,,不过。。。怎么能光用会的知识呢。。
        len = wsprintf(str, TEXT("%d"), level);
        TextOutW(hdc, 390+100, 390-330, str, len);

        EndPaint(hwnd, &ps);
        return 0;
    case WM_TIMER:                        //时钟发来的消息 这个时候就应该下落一个了
        if (!ispause)
        {
            hdc = GetDC(hwnd);
            drop(hdc, hwnd);
            ReleaseDC(hwnd, hdc);
        }
        return 0;
    case WM_KEYDOWN:                //有按键按下了
        hdc = GetDC(hwnd);                //获取设备上下文
        switch (wParam)
        {
        case VK_SPACE:
            if (ispause)
            {
                ispause = !ispause;
                timer = SetTimer(hwnd, 1, speed - min(7, level) * 50, NULL);
            }
            else
            {
                ispause = !ispause;
                KillTimer(hwnd, timer);            //销毁时钟
            }
            break;
        case VK_UP:
            if (ispause) break;
            transform();
            RefreshPanel(hdc);
            break;
        case VK_LEFT:
            if (ispause) break;
            if (block_left == 0) break;    //这一句也可以去掉   但是如果写在move 里面判断的话 还是会重绘界面  长按LEFT就会导致  方块 一闪一闪的
            move_left();
            RefreshPanel(hdc);
            break;
        case VK_RIGHT:
            if (ispause) break;
            if (block_left + block_width == 15) break;   //同上
            move_right();
            RefreshPanel(hdc);
            break;
        case VK_DOWN:
            if (!ispause)
            {
                hdc = GetDC(hwnd);
                drop(hdc, hwnd);
                ReleaseDC(hwnd, hdc);
            }
            break;
        default:
            break;
        }
        ReleaseDC(hwnd, hdc);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

bool isbottom(HWND hwnd)                //检测是否到达底部
{
    if (block == NULL) return 0;
    bool flag = 0;
    if (id == 7)            //幽灵方块需要特殊判断
    {
        flag = 1;
        for (int i = 1; block_top + i < 25; i++) //判断这一列 下面还有没有空 
        {
            if (!panel[block_top + i][block_left])
            {
                flag = 0; break;
            }
        }
    }
    else
    {
        for (int i = block_height - 1; i >= 0 && !flag; i--)
        {
            for (int j = 0; j < block_width && !flag; j++)
            {
                if (*(block + i*block_width + j))                               //判断每一个方块下面又没有方块了
                {
                    if (block_top + i + 1 < 0)continue;          //还没有进入地图
                    if (panel[block_top + i + 1][block_left + j] || block_top + i + 1 == 25)
                    {
                        flag = 1; break;

                    }
                }
            }
        }
    }
    if (flag)            //如果到达底部了 
    {
        if (id == 8 && active)            //炸弹方块到达底部后的处理方式不同
        {
            for (int i = 0; i < 8; i++)
            {
                if (block_top + direction[i][0] < 0 || block_top + direction[i][0] == 25 || block_left + direction[i][1] < 0 || block_left + direction[i][1] >= 15)
                    continue;
                panel[block_top + direction[i][0]][block_left + direction[i][1]] = FALSE;
            }
            return flag;
        }
        if (block_top < 0)//游戏结束 ,方块无法进入地图  说明下面已经满了 Gameover
        {
            if (timer)
            {
                KillTimer(hwnd,timer);
            }
            if (block) delete[] block;
            MessageBox(hwnd, TEXT("游戏结束"), TEXT("MSG"), MB_OK | MB_ICONEXCLAMATION);
            SendMessage(hwnd, WM_CLOSE, 0, 0);
        }
        else                        //将方块融入地图中
        {
            for (int i = 0; i < block_height; i++)
            {
                for (int j = 0; j < block_width; j++)
                {
                    if (*(block + i*block_width + j))
                    {
                        panel[block_top + i][block_left + j] = TRUE;
                    }
                }
            }
        }
    }
    return flag;
}
void clear(HDC hdc)                                //有问题
{
    bool flag; int number=0;
    for (int i = 0; i < block_height; i++)
    {
        flag = 1;
        for (int j = 0; j < 15; j++)
        {
            if (!panel[block_top + i][j])
            {
                flag = 0; break;
            }
        }
        if (flag)
        {
            number++;
            MessageBeep(1);//消行时会有声音
            for (int k = block_top+i; k > 0; k--)
            {
                for (int j = 0; j < 15; j++)
                {
                    panel[k][j] = panel[k - 1][j];
                }
            }
            for (int j = 0; j < 15; j++)
                panel[0][j] = FALSE;
        }
    }

    switch (number)
    {
    case 1:score += 5;  break;
    case 2:score += 13; break;
    case 3:score += 20; break;
    case 4:score += 28; break;
    default: break;
    }
    level = score / 50;
    len = wsprintf(str, TEXT("%d"), score);  
    TextOutW(hdc, 390+100, 370-330, str, len);
    len = wsprintf(str, TEXT("%d"), level);
    TextOutW(hdc, 390+100, 390-330, str, len);
} 
bool drop(HDC hdc,HWND hwnd)                    //下落
{
    if (!isbottom(hwnd))        //还没有到达底部
        block_top++;
    else                    //已经到达了底部
    {
        clear(hdc);//消行
        creat();//创建一个新组合
        preview(hdc);
        RefreshPanel(hdc);
    }
    RefreshPanel(hdc);
    return 0;
}
void DrawPanel(HDC hdc)          //绘制游戏面板
{
    int x, y;
    RECT rect;//矩形类

    for (y = 0; y<ROWS; y++)
    {
        for (x = 0; x<COLS; x++)
        {
            //计算方块的边框范围
            rect.top = y*CELL + 1;
            rect.bottom = (y + 1) *CELL - 1;
            rect.left = x*CELL + 1;
            rect.right = (x + 1) *CELL - 1;
            FrameRect(hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));//绘画矩形边框
        }
    }
    rect.top = pre_peak.Y*CELL-1;
    rect.bottom = (pre_peak.Y + 2)*CELL+1;
    rect.left = pre_peak.X*CELL-1;
    rect.right = (pre_peak.X + 4)*CELL+1;
    FrameRect(hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
    TextOut(hdc, pre_peak.X*CELL, pre_peak.Y*CELL - 30, TEXT("图形预览"), 4);
}
void RefreshPanel(HDC hdc)              //刷新面板
{
    int x, y;
    RECT rect;
    HBRUSH h_bSolid = (HBRUSH)GetStockObject(GRAY_BRUSH),          //设置笔刷颜色
        h_bEmpty = (HBRUSH)GetStockObject(WHITE_BRUSH),
        h_bomb_active = CreateSolidBrush(RGB(255, 0, 0)),
        h_bomb_nactive= CreateSolidBrush(RGB(100, 0, 0)),
    h_ghost = (HBRUSH)GetStockObject(BLACK_BRUSH); 
    //先刷屏
    for (y = 0; y<ROWS; y++)
    {
        for (x = 0; x<COLS; x++)
        {
            //为避免刷掉方块的边框,rect范围必须比边框范围小1
            rect.top = y*CELL + 2;
            rect.bottom = (y + 1) *CELL - 2;
            rect.left = x*CELL + 2;
            rect.right = (x + 1) *CELL - 2;
            if (panel[y][x])
                FillRect(hdc, &rect, h_bSolid);                    //绘画矩形内部
            else
                FillRect(hdc, &rect, h_bEmpty);
        }
    }
    if (block == NULL) return;
    if (id == 7)  //幽灵方块为黑色
    {
        rect.top = block_top*CELL + 2;
        rect.bottom = (block_top + 1)*CELL - 2;
        rect.left = block_left*CELL + 2;
        rect.right = (block_left + 1)*CELL - 2;
        FillRect(hdc, &rect, h_ghost);
    }
    else if (id == 8)
    {
        rect.top = block_top*CELL + 2;
        rect.bottom = (block_top + 1)*CELL - 2;
        rect.left = block_left*CELL + 2;
        rect.right = (block_left + 1)*CELL - 2;
        if(active)
        FillRect(hdc, &rect, h_bomb_active);
        else
        FillRect(hdc, &rect, h_bomb_nactive);
    }
    else
    {
        for (int i = 0; i < block_height; i++)                    //画出方块组合
        {
            for (int j = 0; j < block_width; j++)
            {
                if (*(block + i*block_width + j))
                {
                    rect.top = (block_top + i)*CELL + 2;
                    rect.bottom = (block_top + i + 1)*CELL - 2;
                    rect.left = (block_left + j)*CELL;
                    rect.right = (block_left + j + 1)*CELL - 2;
                    FillRect(hdc, &rect, h_bSolid);
                }
            }
        }
    }
}
void creat()
{
    srand(int(time(0)));
    id = next_id;
    next_id = rand() % 9;
    if (block != NULL)
    {
        delete[] block;
    }
    switch (id)
    {
    case 0:                                    //直线型
        block_height = 1;
        block_width = 4;
        block_top = -block_height;
        block_left = (COLS - block_width) / 2 + block_width / 2;//定位到中间上面
        block = new bool[block_height*block_width];                //分配足够的空间储存组合
        *(block) = TRUE;   *(block + 1) = TRUE;   *(block + 2) = TRUE;  *(block + 3) = TRUE;
        break;
    case 1:                                    //正方形
        block_height = 2;
        block_width = 2;
        block_top = -block_height;
        block_left = (COLS - block_width) / 2 + block_width /2;
        block = new bool[block_height*block_width];        
        *(block) = TRUE;      *(block + 1) = TRUE;   
        *(block + 2) = TRUE;  *(block + 3) = TRUE;
        break;
    case 2:                                    //倒T型
        block_height = 2;
        block_width = 3;
        block_top = -block_height;
        block_left = (COLS - block_width) / 2 + block_width /2;
        block = new bool[block_height*block_width];
        *(block) = FALSE;       *(block + 1) = TRUE;    *(block + 2) = FALSE;
        *(block + 3) = TRUE;    *(block + 4) = TRUE;    *(block + 5) = TRUE;
        break;
    case 3:                                    //左L型
        block_height = 2;
        block_width = 3;
        block_top = -block_height;
        block_left = (COLS - block_width) / 2 + block_width / 2;
        block = new bool[block_height*block_width];
        *(block) = TRUE;        *(block + 1) = FALSE;   *(block + 2) = FALSE;
        *(block + 3) = TRUE;    *(block + 4) = TRUE;    *(block + 5) = TRUE;
        break;
    case 4:                                //右L型
        block_height = 2;
        block_width = 3;
        block_top = -block_height;
        block_left = (COLS - block_width) / 2 + block_width / 2;
        block = new bool[block_height*block_width];
        *(block) = FALSE;        *(block + 1) = FALSE;    *(block + 2) = TRUE;
        *(block + 3) = TRUE;    *(block + 4) = TRUE;    *(block + 5) = TRUE;
        break;
    case 5:                            //正Z型
        block_height = 2;
        block_width = 3;
        block_top = -block_height;
        block_left = (COLS - block_width) / 2 + block_width / 2;
        block = new bool[block_height*block_width];
        *(block) = TRUE;        *(block + 1) = TRUE;    *(block + 2) = FALSE;
        *(block + 3) = FALSE;    *(block + 4) = TRUE;    *(block + 5) = TRUE;
        break;
    case 6:                        //倒Z型
        block_height = 2;
        block_width = 3;
        block_top = -block_height;
        block_left = (COLS - block_width) / 2 + block_width / 2;
        block = new bool[block_height*block_width];
        *(block) = FALSE;        *(block + 1) = TRUE;    *(block + 2) = TRUE;
        *(block + 3) = TRUE;    *(block + 4) = TRUE;    *(block + 5) = FALSE;
        break;
    case 7:                        //幽灵方块
        block_height = 1;
        block_width = 1;
        block_top = -block_height;
        block_left = (COLS - block_width) / 2 + block_width / 2;
        block = new bool[block_height*block_width];
        *(block) = TRUE;
    case 8:                                //炸弹方块
        block_height = 1;
        block_width = 1;
        block_top = -block_height;
        block_left = (COLS - block_width) / 2 + block_width / 2;
        block = new bool[block_height*block_width];
        *(block) = TRUE;
        active = TRUE;
        break;
    }
}
void move_left()                                    //判断 方块的左边又没有方块 ,没有就可以过去
{
    if (id == 7)
    {
        if (block_left == 0) return;
    }
    else
    {
        for (int i = 0; i < block_height; i++)
        {
            for (int j = 0; j < block_width; j++)
            {
                if (*(block + block_width*i + j))
                {
                    if (panel[block_top + i][block_left + j - 1] || block_left == 0)
                        return;
                }
            }
        }
    }
    block_left--;                                        //没有就移动顶点坐标
}
void move_right()                                    //判断方块的右边有没有方块  
{
    if (id == 7)
    {
        if (block_left ==14)
            return;
    }
    else
    {
        for (int i = 0; i < block_height; i++)
        {
            for (int j = block_width - 1; j >= 0; j--)
            {
                if (*(block + i*block_width + j))
                {
                    if (panel[block_top + i][block_left + j + 1] || block_left + block_width == 15)
                        return;
                }
            }
        }
    }
    block_left++;
}
void transform()//变形
{
    if (id == 7 || id == 1) return;//幽灵方块和 正方形方块转换后没差
    if (id == 8)                //炸弹方块直接转换激活状态
    {
        active = !active; return;
    }
    bool* zz = new bool[block_height*block_width];      //先建立一个缓存 表示转换后方块的位置
    for (int i = 0; i < block_width; i++)
    {
        for (int j = 0; j < block_height; j++)
        {
            //zz[i][j]=block[block_height-j-1][i]   转换公式
            *(zz + i*block_height + j) = *(block + (block_height-1-j)*block_width + i);  //转换
        }
    }
    //开始不重新定位 顶点 感觉转换特别死板  不是中心旋转 所以这里要改 一下顶点左边
    //嗯  改了一下感觉好多了
    int zz_top = block_top + (block_height - block_width) / 2;
    int zz_left = block_left + (block_width - block_height) / 2;
    if (zz_top + block_width >= 25 || zz_left + block_height > 15||zz_left<0) return;   //判断方块是否越界
    for (int i = 0; i < block_width; i++)                                            //判断该位置是否已经存在方块
    {
        for (int j = 0; j < block_height; j++)
        {
            if (panel[zz_top + j][zz_left + j])
                return;
        }
    }

    for (int i = 0; i < block_width; i++)                                      //前面都达标了 说明可以转换 ,
    {
        for (int j = 0; j < block_height; j++)
            *(block + i*block_height + j) = *(zz + i*block_height + j);
    }
    delete[] zz;                                                                //删除缓存
    int a;
    block_top = zz_top;
    block_left = zz_left;
    a = block_width; block_width = block_height; block_height = a;
}
void preview(HDC hdc)        //图形预览
{
    memset(pre_panel, 0, sizeof(pre_panel));
    RECT rect;
    HBRUSH h_brush = (HBRUSH)GetStockObject(GRAY_BRUSH);
    switch (next_id)
    {
    case 0:
        pre_panel[0][0] = TRUE; pre_panel[0][1] = TRUE; pre_panel[0][2] = TRUE; pre_panel[0][3] = TRUE;
        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("直线          "), 7);
        break;
    case 1:
        pre_panel[0][1] = TRUE; pre_panel[0][2] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;
        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("正方          "), 7);
        break;
    case 2:
        pre_panel[0][1] = TRUE; pre_panel[1][0] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;
        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("倒T           "), 7);
        break;
    case 3:
        pre_panel[0][0] = TRUE; pre_panel[1][0] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;
        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("左L           "), 7);
        break;
    case 4:
        pre_panel[0][2] = TRUE; pre_panel[1][0] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;
        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("右L           "), 7);
        break;
    case 5:
        pre_panel[0][0] = TRUE; pre_panel[0][1] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;
        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("左闪电        "), 7);
        break;
    case 6:
        pre_panel[0][2] = TRUE; pre_panel[0][1] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][0] = TRUE;
        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("右闪电        "), 7);
        break;
    case 7:
        pre_panel[0][1] = TRUE;
        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("幽灵          "), 7);
        h_brush = (HBRUSH)GetStockObject(BLACK_BRUSH);
        break;
    case 8:
        h_brush = CreateSolidBrush(RGB(255, 0, 0));
        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("炸弹          "), 7);
        pre_panel[0][1] = TRUE;
        break;
    }
    rect.top = pre_peak.Y*CELL;
    rect.bottom = (pre_peak.Y + 2)*CELL;
    rect.left = pre_peak.X*CELL;
    rect.right = (pre_peak.X + 4)*CELL;
    FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            if (pre_panel[i][j])
            {
                rect.top = (pre_peak.Y + i)*CELL + 2;
                rect.bottom = (pre_peak.Y + i + 1)*CELL - 2;
                rect.left = (pre_peak.X + j)*CELL + 2;
                rect.right = (pre_peak.X + j + 1)*CELL - 2;
                FillRect(hdc, &rect, h_brush);
            }
        }
    }
}

 

将本网站任何内容或服务用于其他用途时,将本网站任何内容或服务用于其他用途时。 回顾总结:编写过程中遇到了很多困难,很多知识都不懂 只有自己到处找问人,   而且没有抽象为类  可扩展性  和 代码重用能力太差 (一个图形预览 我还额外的编写了一个构造的函数  完全可以用creat()里面的, 但是就是由于开始考虑不完全导致后面修改起来麻烦)

 

版权声明:访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非...

本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,予以删除。

作者QQ:1765813715

由于这个游戏倾入了我大量的时间和创意 所以写了个版权声明

这个游戏在基础的俄罗斯方块上面还添加了 两种方块

一种是幽灵方块 (可以在方块间任意移动 直到它所在的这一列下面没有空)

另一种是 炸弹方块 (他可以在激活和非激活中转换,激活时到达底部后会清除周围3*将本网站任何内容或服务用于其他用途时,将本网站任何内容或服务用于其他用途时。3的方块 非激活就和普通方块没有什么区别

第一次用WindowsApi写游戏 注释很多。 也查了很多资料

Windows窗口的创建以后我在写一个详细的 这里我就直接从CALLBACK WndProc 开始讲解我的程序结构了

图片 2

下面讲解每一个函数

void DrawPanel; 绘制游戏面板

void RefreshPanel; 刷新游戏面板
void creat();          创造方块 一共有9中方块
bool isbottom(HWND hwnd); 判断是否到达底部 幽灵方块判断方式不同 以及到达底部后的处理(即融入地图 或者炸弹方块的 爆炸) 以及检测游戏结束
bool drop(HDC hdc,HWND hwnd); 下降 其中调用 isbottom() 如果到达底部 调用clear,refreshpanel()
void move_left(); 向左移动 检测碰撞(幽灵方块也是特殊处理)
void move_right(); 同上
void transform();        变形 变形时需要检测是否满足 炸弹方块的变形是 在激活和非激活状态之间转换
void clear;      消行 内部还实现加分
void preview;     图形预览框

这里添加下 过程记录吧 也方便其他像学习的人有一条明确的路线

4月28日 下午6点—晚上12点 学习窗口的创建 如何绘画出图形界面
4月29日 上午8点—11.30 写出 已测试( 方块生成 碰撞检测 向下移动 时钟系统 暂停功能 检测游戏结束)
未测试
中午1点—1点40 完成左右移动 测试了消行 但是没有成功 还未发现原因。。。。
下午3点—4点修改消行BUG 完成转换功能 到这里基本功能差不多就全部完成了
现在基本的俄罗斯方块已经完成了 不过我的俄罗斯方块比较高级 还有两种方块就是幽灵方块 和 炸弹方块
下午6点—7点 游戏测试 查找BUG
晚上11点—11.半 完成幽灵方块
4月30日 上午8点—11点 完成炸弹方块 图形预览
晚上11点 完成BGM 。。

注意:我是在vs2017上面开发的 测试在dev上面无法编译 而且由于我这个添加BGM 所以有可能在你的电脑上也无法编译

      如果还缺少头文件请自行添加

    如果是这样,就删除播放BGM 的代码 或者自己从新加载资源文件

     在这里我把我的文件上传到百度网盘里 大家有需要的可以自己下载其中bebug和release中的EXE文件可以直接用来玩

    

#include "stdafx.h"#include <windows.h>// C 运行时头文件#include <stdlib.h>#include <malloc.h>#include <memory.h>#include <tchar.h>#include<time.h>#include<iostream>#include "俄罗斯方块.h"#include<mmsystem.h>#pragma comment(lib,"winmm.lib")//知识就是财富啊  一个背景音乐搞了半天#define CELL 20//方块大小#define ROWS 25 //行数#define COLS 15//列数using namespace std;TCHAR str[256];int id; //记录当前方块种类int next_id;//记录下一个方块的ID 达到预览int len;int score = 0;                //得分int level = 0;                    //游戏等级int speed = 500;                //游戏速率  初始化为1秒   后面的速率为  speed-min*100;UINT timer = 0;bool ispause = 0;            //记录是否暂停bool panel[25][15] = { 0 };    //记录游戏底层画面bool active;                //记录炸弹方块是否被激活int direction[8][2] = { 1,0,0,1,-1,0,0,-1,1,1,-1,-1,1,-1,-1,1 };//炸弹方块爆破的8个方向COORD pre_peak;bool pre_panel[2][4];        //预览面板bool* block=NULL;            //通过记录方块组合 最左上角的坐标  和组合的宽度高度 来确定这个组合的位置。   这样做有很大的好处int block_top = 0;int block_left = 0;int block_height = 0;int block_width = 0;void DrawPanel;void RefreshPanel;void creat();bool isbottom(HWND hwnd);bool drop(HDC hdc,HWND hwnd);void move_left();void move_right();void transform();void clear;void preview;LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lparam);//回调函数//建立窗口需要经过5个步骤  设计窗口类型  注册窗口类型 创建 显示 消息循环int APIENTRY WinMain(HINSTANCE hInstance,   //程序当前运行的实例句柄    HINSTANCE hPrevInstance,                //当前实例的前一个实例 w32下不再起作用    LPSTR lpCmdLine,                        //表示传给程序的命令行参数    int nCmdShow)                          //指定程序窗口如何显示,如 最大化最小化等{    WNDCLASS wndclass;                    //下面都是注册的内容。。。。。    HWND hwnd;    MSG msg;    TCHAR lpszClassName[] = TEXT("俄罗斯方块");    wndclass.style = CS_HREDRAW | CS_VREDRAW;           //窗口样式    wndclass.lpfnWndProc = WndProc;                     //指向窗口函数的指针    wndclass.cbClsExtra = 0;                            //窗口类附加字节, 为该类窗口共享,一般置0    wndclass.cbWndExtra = 0;                            //窗口字节 一般值0    wndclass.hInstance = hInstance;                        //当前应用程序的实例句柄    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);    //指定窗口图标    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);        //指定窗口光标    wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);//设置背景色    wndclass.lpszMenuName = NULL;                                //窗口菜单资源名    wndclass.lpszClassName = lpszClassName;                        //窗口类名    if (!RegisterClass(&wndclass))                                //注册        return FALSE;    hwnd = CreateWindow(lpszClassName, TEXT("俄罗斯方块"),        //创建        WS_OVERLAPPEDWINDOW,         CW_USEDEFAULT, CW_USEDEFAULT,         CW_USEDEFAULT, CW_USEDEFAULT,        NULL, NULL,         hInstance, NULL);    ShowWindow(hwnd, nCmdShow);                                    //显示    UpdateWindow;                                            //上传    while (GetMessage(&msg, NULL, 0, 0))                        //消息循环    {        TranslateMessage(&msg);        DispatchMessage(&msg);    }    return msg.wParam;}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)//回掉函数{    switch     {    case WM_CREATE:        PlaySound(                        //BGM            MAKEINTRESOURCE(130),        //不知道为什么 这里不能直接写 IDR_WAVE1 而是要写他的数字id            GetModuleHandle,            SND_RESOURCE | SND_ASYNC | SND_LOOP);        MoveWindow(hwnd, 200, 200, COLS*CELL+300, ROWS*CELL+40, FALSE);//16.40        pre_peak.X = 16; pre_peak.Y = 2; //确定预览框 顶点坐标        srand(int(time(0)));        next_id = rand() % 9;        creat();        timer = SetTimer(hwnd, 1, speed - min(7, level) * 50, NULL);  //创建一个时钟        return 0;    case WM_PAINT:        HDC hdc;        PAINTSTRUCT ps;        hdc = BeginPaint(hwnd, &ps);        DrawPanel;        RefreshPanel;        preview;        TextOutW(hdc, 350+100, 370-330, TEXT("得分:"), 3);        TextOutW(hdc, 350+100, 390-330, TEXT("等级:"), 3);        TextOut(hdc, 350, 480, TEXT("Made by LYON"), strlen("Made by LYON"));        len = wsprintf(str, TEXT("%d"),  score);  //。。。为了找这个    找了  一个小时。。。 怎么把整数转换为字符串        TextOutW(hdc, 390+100, 370-330, str, len);            //其实也可以自己写一个转换函数的 ,,,不过。。。怎么能光用会的知识呢。。        len = wsprintf(str, TEXT("%d"), level);        TextOutW(hdc, 390+100, 390-330, str, len);        EndPaint(hwnd, &ps);        return 0;    case WM_TIMER:                        //时钟发来的消息 这个时候就应该下落一个了        if (!ispause)        {            hdc = GetDC;            drop(hdc, hwnd);            ReleaseDC(hwnd, hdc);        }        return 0;    case WM_KEYDOWN:                //有按键按下了        hdc = GetDC;                //获取设备上下文        switch         {        case VK_SPACE:            if             {                ispause = !ispause;                timer = SetTimer(hwnd, 1, speed - min(7, level) * 50, NULL);            }            else            {                ispause = !ispause;                KillTimer(hwnd, timer);            //销毁时钟            }            break;        case VK_UP:            if  break;            transform();            RefreshPanel;            break;        case VK_LEFT:            if  break;            if (block_left == 0) break;    //这一句也可以去掉   但是如果写在move 里面判断的话 还是会重绘界面  长按LEFT就会导致  方块 一闪一闪的            move_left();            RefreshPanel;            break;        case VK_RIGHT:            if  break;            if (block_left + block_width == 15) break;   //同上            move_right();            RefreshPanel;            break;        case VK_DOWN:            if (!ispause)            {                hdc = GetDC;                drop(hdc, hwnd);                ReleaseDC(hwnd, hdc);            }            break;        default:            break;        }        ReleaseDC(hwnd, hdc);        return 0;    case WM_DESTROY:        PostQuitMessage(0);        return 0;    default:        return DefWindowProc(hwnd, message, wParam, lParam);    }    return 0;}bool isbottom(HWND hwnd)                //检测是否到达底部{    if (block == NULL) return 0;    bool flag = 0;    if (id == 7)            //幽灵方块需要特殊判断    {        flag = 1;        for (int i = 1; block_top + i < 25; i++) //判断这一列 下面还有没有空         {            if (!panel[block_top + i][block_left])            {                flag = 0; break;            }        }    }    else    {        for (int i = block_height - 1; i >= 0 && !flag; i--)        {            for (int j = 0; j < block_width && !flag; j++)            {                if (*(block + i*block_width + j))                               //判断每一个方块下面又没有方块了                {                    if (block_top + i + 1 < 0)continue;          //还没有进入地图                    if (panel[block_top + i + 1][block_left + j] || block_top + i + 1 == 25)                    {                        flag = 1; break;                    }                }            }        }    }    if             //如果到达底部了     {        if (id == 8 && active)            //炸弹方块到达底部后的处理方式不同        {            for (int i = 0; i < 8; i++)            {                if (block_top + direction[i][0] < 0 || block_top + direction[i][0] == 25 || block_left + direction[i][1] < 0 || block_left + direction[i][1] >= 15)                    continue;                panel[block_top + direction[i][0]][block_left + direction[i][1]] = FALSE;            }            return flag;        }        if (block_top < 0)//游戏结束 ,方块无法进入地图  说明下面已经满了 Gameover        {            if             {                KillTimer(hwnd,timer);            }            if  delete[] block;            MessageBox(hwnd, TEXT("游戏结束"), TEXT("MSG"), MB_OK | MB_ICONEXCLAMATION);            SendMessage(hwnd, WM_CLOSE, 0, 0);        }        else                        //将方块融入地图中        {            for (int i = 0; i < block_height; i++)            {                for (int j = 0; j < block_width; j++)                {                    if (*(block + i*block_width + j))                    {                        panel[block_top + i][block_left + j] = TRUE;                    }                }            }        }    }    return flag;}void clear                                //有问题{    bool flag; int number=0;    for (int i = 0; i < block_height; i++)    {        flag = 1;        for (int j = 0; j < 15; j++)        {            if (!panel[block_top + i][j])            {                flag = 0; break;            }        }        if         {            number++;            MessageBeep(1);//消行时会有声音            for (int k = block_top+i; k > 0; k--)            {                for (int j = 0; j < 15; j++)                {                    panel[k][j] = panel[k - 1][j];                }            }            for (int j = 0; j < 15; j++)                panel[0][j] = FALSE;        }    }    switch     {    case 1:score += 5;  break;    case 2:score += 13; break;    case 3:score += 20; break;    case 4:score += 28; break;    default: break;    }    level = score / 50;    len = wsprintf(str, TEXT("%d"), score);      TextOutW(hdc, 390+100, 370-330, str, len);    len = wsprintf(str, TEXT("%d"), level);    TextOutW(hdc, 390+100, 390-330, str, len);} bool drop(HDC hdc,HWND hwnd)                    //下落{    if (!isbottom        //还没有到达底部        block_top++;    else                    //已经到达了底部    {        clear;//消行        creat();//创建一个新组合        preview;        RefreshPanel;    }    RefreshPanel;    return 0;}void DrawPanel          //绘制游戏面板{    int x, y;    RECT rect;//矩形类    for (y = 0; y<ROWS; y++)    {        for (x = 0; x<COLS; x++)        {            //计算方块的边框范围            rect.top = y*CELL + 1;            rect.bottom = (y + 1) *CELL - 1;            rect.left = x*CELL + 1;            rect.right = (x + 1) *CELL - 1;            FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));//绘画矩形边框        }    }    rect.top = pre_peak.Y*CELL-1;    rect.bottom = (pre_peak.Y + 2)*CELL+1;    rect.left = pre_peak.X*CELL-1;    rect.right = (pre_peak.X + 4)*CELL+1;    FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));    TextOut(hdc, pre_peak.X*CELL, pre_peak.Y*CELL - 30, TEXT("图形预览"), 4);}void RefreshPanel              //刷新面板{    int x, y;    RECT rect;    HBRUSH h_bSolid = GetStockObject(GRAY_BRUSH),          //设置笔刷颜色        h_bEmpty = GetStockObject(WHITE_BRUSH),        h_bomb_active = CreateSolidBrush(RGB(255, 0, 0)),        h_bomb_nactive= CreateSolidBrush(RGB(100, 0, 0)),    h_ghost = GetStockObject(BLACK_BRUSH);     //先刷屏    for (y = 0; y<ROWS; y++)    {        for (x = 0; x<COLS; x++)        {            //为避免刷掉方块的边框,rect范围必须比边框范围小1            rect.top = y*CELL + 2;            rect.bottom = (y + 1) *CELL - 2;            rect.left = x*CELL + 2;            rect.right = (x + 1) *CELL - 2;            if (panel[y][x])                FillRect(hdc, &rect, h_bSolid);                    //绘画矩形内部            else                FillRect(hdc, &rect, h_bEmpty);        }    }    if (block == NULL) return;    if (id == 7)  //幽灵方块为黑色    {        rect.top = block_top*CELL + 2;        rect.bottom = (block_top + 1)*CELL - 2;        rect.left = block_left*CELL + 2;        rect.right = (block_left + 1)*CELL - 2;        FillRect(hdc, &rect, h_ghost);    }    else if (id == 8)    {        rect.top = block_top*CELL + 2;        rect.bottom = (block_top + 1)*CELL - 2;        rect.left = block_left*CELL + 2;        rect.right = (block_left + 1)*CELL - 2;        if        FillRect(hdc, &rect, h_bomb_active);        else        FillRect(hdc, &rect, h_bomb_nactive);    }    else    {        for (int i = 0; i < block_height; i++)                    //画出方块组合        {            for (int j = 0; j < block_width; j++)            {                if (*(block + i*block_width + j))                {                    rect.top = (block_top + i)*CELL + 2;                    rect.bottom = (block_top + i + 1)*CELL - 2;                    rect.left = (block_left + j)*CELL;                    rect.right = (block_left + j + 1)*CELL - 2;                    FillRect(hdc, &rect, h_bSolid);                }            }        }    }}void creat(){    srand(int(time(0)));    id = next_id;    next_id = rand() % 9;    if (block != NULL)    {        delete[] block;    }    switch     {    case 0:                                    //直线型        block_height = 1;        block_width = 4;        block_top = -block_height;        block_left = (COLS - block_width) / 2 + block_width / 2;//定位到中间上面        block = new bool[block_height*block_width];                //分配足够的空间储存组合        * = TRUE;   *(block + 1) = TRUE;   *(block + 2) = TRUE;  *(block + 3) = TRUE;        break;    case 1:                                    //正方形        block_height = 2;        block_width = 2;        block_top = -block_height;        block_left = (COLS - block_width) / 2 + block_width /2;        block = new bool[block_height*block_width];                * = TRUE;      *(block + 1) = TRUE;           *(block + 2) = TRUE;  *(block + 3) = TRUE;        break;    case 2:                                    //倒T型        block_height = 2;        block_width = 3;        block_top = -block_height;        block_left = (COLS - block_width) / 2 + block_width /2;        block = new bool[block_height*block_width];        * = FALSE;       *(block + 1) = TRUE;    *(block + 2) = FALSE;        *(block + 3) = TRUE;    *(block + 4) = TRUE;    *(block + 5) = TRUE;        break;    case 3:                                    //左L型        block_height = 2;        block_width = 3;        block_top = -block_height;        block_left = (COLS - block_width) / 2 + block_width / 2;        block = new bool[block_height*block_width];        * = TRUE;        *(block + 1) = FALSE;   *(block + 2) = FALSE;        *(block + 3) = TRUE;    *(block + 4) = TRUE;    *(block + 5) = TRUE;        break;    case 4:                                //右L型        block_height = 2;        block_width = 3;        block_top = -block_height;        block_left = (COLS - block_width) / 2 + block_width / 2;        block = new bool[block_height*block_width];        * = FALSE;        *(block + 1) = FALSE;    *(block + 2) = TRUE;        *(block + 3) = TRUE;    *(block + 4) = TRUE;    *(block + 5) = TRUE;        break;    case 5:                            //正Z型        block_height = 2;        block_width = 3;        block_top = -block_height;        block_left = (COLS - block_width) / 2 + block_width / 2;        block = new bool[block_height*block_width];        * = TRUE;        *(block + 1) = TRUE;    *(block + 2) = FALSE;        *(block + 3) = FALSE;    *(block + 4) = TRUE;    *(block + 5) = TRUE;        break;    case 6:                        //倒Z型        block_height = 2;        block_width = 3;        block_top = -block_height;        block_left = (COLS - block_width) / 2 + block_width / 2;        block = new bool[block_height*block_width];        * = FALSE;        *(block + 1) = TRUE;    *(block + 2) = TRUE;        *(block + 3) = TRUE;    *(block + 4) = TRUE;    *(block + 5) = FALSE;        break;    case 7:                        //幽灵方块        block_height = 1;        block_width = 1;        block_top = -block_height;        block_left = (COLS - block_width) / 2 + block_width / 2;        block = new bool[block_height*block_width];        * = TRUE;    case 8:                                //炸弹方块        block_height = 1;        block_width = 1;        block_top = -block_height;        block_left = (COLS - block_width) / 2 + block_width / 2;        block = new bool[block_height*block_width];        * = TRUE;        active = TRUE;        break;    }}void move_left()                                    //判断 方块的左边又没有方块 ,没有就可以过去{    if (id == 7)    {        if (block_left == 0) return;    }    else    {        for (int i = 0; i < block_height; i++)        {            for (int j = 0; j < block_width; j++)            {                if (*(block + block_width*i + j))                {                    if (panel[block_top + i][block_left + j - 1] || block_left == 0)                        return;                }            }        }    }    block_left--;                                        //没有就移动顶点坐标}void move_right()                                    //判断方块的右边有没有方块  {    if (id == 7)    {        if (block_left ==14)            return;    }    else    {        for (int i = 0; i < block_height; i++)        {            for (int j = block_width - 1; j >= 0; j--)            {                if (*(block + i*block_width + j))                {                    if (panel[block_top + i][block_left + j + 1] || block_left + block_width == 15)                        return;                }            }        }    }    block_left++;}void transform()//变形{    if (id == 7 || id == 1) return;//幽灵方块和 正方形方块转换后没差    if (id == 8)                //炸弹方块直接转换激活状态    {        active = !active; return;    }    bool* zz = new bool[block_height*block_width];      //先建立一个缓存 表示转换后方块的位置    for (int i = 0; i < block_width; i++)    {        for (int j = 0; j < block_height; j++)        {            //zz[i][j]=block[block_height-j-1][i]   转换公式            *(zz + i*block_height + j) = *(block + (block_height-1-j)*block_width + i);  //转换        }    }    //开始不重新定位 顶点 感觉转换特别死板  不是中心旋转 所以这里要改 一下顶点左边    //嗯  改了一下感觉好多了    int zz_top = block_top + (block_height - block_width) / 2;    int zz_left = block_left + (block_width - block_height) / 2;    if (zz_top + block_width >= 25 || zz_left + block_height > 15||zz_left<0) return;   //判断方块是否越界    for (int i = 0; i < block_width; i++)                                            //判断该位置是否已经存在方块    {        for (int j = 0; j < block_height; j++)        {            if (panel[zz_top + j][zz_left + j])                return;        }    }    for (int i = 0; i < block_width; i++)                                      //前面都达标了 说明可以转换 ,    {        for (int j = 0; j < block_height; j++)            *(block + i*block_height + j) = *(zz + i*block_height + j);    }    delete[] zz;                                                                //删除缓存    int a;    block_top = zz_top;    block_left = zz_left;    a = block_width; block_width = block_height; block_height = a;}void preview        //图形预览{    memset(pre_panel, 0, sizeof(pre_panel));    RECT rect;    HBRUSH h_brush = GetStockObject(GRAY_BRUSH);    switch     {    case 0:        pre_panel[0][0] = TRUE; pre_panel[0][1] = TRUE; pre_panel[0][2] = TRUE; pre_panel[0][3] = TRUE;        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("直线          "), 7);        break;    case 1:        pre_panel[0][1] = TRUE; pre_panel[0][2] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("正方          "), 7);        break;    case 2:        pre_panel[0][1] = TRUE; pre_panel[1][0] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("倒T           "), 7);        break;    case 3:        pre_panel[0][0] = TRUE; pre_panel[1][0] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("左L           "), 7);        break;    case 4:        pre_panel[0][2] = TRUE; pre_panel[1][0] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("右L           "), 7);        break;    case 5:        pre_panel[0][0] = TRUE; pre_panel[0][1] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][2] = TRUE;        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("左闪电        "), 7);        break;    case 6:        pre_panel[0][2] = TRUE; pre_panel[0][1] = TRUE; pre_panel[1][1] = TRUE; pre_panel[1][0] = TRUE;        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("右闪电        "), 7);        break;    case 7:        pre_panel[0][1] = TRUE;        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("幽灵          "), 7);        h_brush = GetStockObject(BLACK_BRUSH);        break;    case 8:        h_brush = CreateSolidBrush(RGB(255, 0, 0));        TextOut(hdc, pre_peak.X*CELL+20, pre_peak.Y*CELL + 50, TEXT("炸弹          "), 7);        pre_panel[0][1] = TRUE;        break;    }    rect.top = pre_peak.Y*CELL;    rect.bottom = (pre_peak.Y + 2)*CELL;    rect.left = pre_peak.X*CELL;    rect.right = (pre_peak.X + 4)*CELL;    FillRect(hdc, &rect, GetStockObject(WHITE_BRUSH));    for (int i = 0; i < 2; i++)    {        for (int j = 0; j < 4; j++)        {            if (pre_panel[i][j])            {                rect.top = (pre_peak.Y + i)*CELL + 2;                rect.bottom = (pre_peak.Y + i + 1)*CELL - 2;                rect.left = (pre_peak.X + j)*CELL + 2;                rect.right = (pre_peak.X + j + 1)*CELL - 2;                FillRect(hdc, &rect, h_brush);            }        }    }}

回顾总结:编写过程中遇到了很多困难,很多知识都不懂 只有自己到处找问人, 而且没有抽象为类 可扩展性 和 代码重用能力太差 (一个图形预览 我还额外的编写了一个构造的函数 完全可以用creat()里面的, 但是就是由于开始考虑不完全导致后面修改起来麻烦)

本文由威尼斯发布于威尼斯人登录网站,转载请注明出处:将本网站任何内容或服务用于其他用途时,将本

关键词: