变量声明:
// elsblocksDlg.h : 头文件 // #define BLOCK_X 10 //总游戏区x格子 #define BLOCK_Y 16 //总游戏区y格子 #define CELL_LEN 30 //单个格子的宽度 #define SCELL_LEN 20 //小格子的宽度 #pragma once // CelsblocksDlg 对话框 class CelsblocksDlg : public CDialog { // 构造 public: CelsblocksDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 enum { IDD = IDD_ELSBLOCKS_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; int m_level; //等级 int m_Map[(BLOCK_X+1)][BLOCK_Y+1]; //地图 int m_Speed; //下落速度 bool m_Model[7][4][4]; //各个Block的模型 CPoint m_MoldeChange[4][4]; //Block改变的对应坐标 bool m_BlockNext[4][4]; //下一个Block bool m_BlockShow[4][4]; //当前游戏的Block CPoint m_CurrPosi; //当前的m_BlockShow的(0,0)在client的坐标 int m_Score; //得分 bool m_IsStart; //游戏是否开始 bool m_IsPause; //游戏是否暂停 //CRect m_ShowNext; //下一个Block显示区坐标 // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: void NextBlock(); //创建下一个Block void DrawNextBlock(); //画出下一个Block void DrawCell(CRect rect); //画单元格 //定时器 void GoDown(); //往下 void GoLeft(); //向左移动 void GoRight(); //向右移动 void ChangeBlock(bool Block[4][4],bool flag); //改变Block的姿势 void GameStart(); //开始游戏 bool CanMoveLR(int flag); //判断是否能左右移动 bool CanMoveDown(); //判断是否向下移动 void DeletLines(); //消行 void UpdateAll(); //刷新游戏区 void GameResule(); //游戏得分情况 BOOL CelsblocksDlg::PreTranslateMessage(MSG* pMsg); //按键响应 afx_msg void OnTimer(UINT_PTR nIDEvent); // afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnAbout(); afx_msg void OnGameStart(); afx_msg void OnGamePause(); };
主要实现代码:
// elsblocksDlg.cpp : 实现文件 // #include "stdafx.h" #include "elsblocks.h" #include "elsblocksDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialog { public: CAboutDlg(); // 对话框数据 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedOk(); }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) ON_BN_CLICKED(IDOK, &CAboutDlg::OnBnClickedOk) END_MESSAGE_MAP() // CelsblocksDlg 对话框 CelsblocksDlg::CelsblocksDlg(CWnd* pParent /*=NULL*/) : CDialog(CelsblocksDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CelsblocksDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CelsblocksDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_WM_TIMER() // ON_WM_KEYDOWN() ON_COMMAND(ID_ABOUT, &CelsblocksDlg::OnAbout) ON_COMMAND(ID_GAME_START, &CelsblocksDlg::OnGameStart) ON_COMMAND(ID_GAME_PAUSE, &CelsblocksDlg::OnGamePause) END_MESSAGE_MAP() // CelsblocksDlg 消息处理程序 BOOL CelsblocksDlg::OnInitDialog() { CDialog::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 ShowWindow(SW_NORMAL); // TODO: 在此添加额外的初始化代码 SetWindowPos(GetDlgItem(IDD_ELSBLOCKS_DIALOG), 0, 0,BLOCK_X*CELL_LEN+4*CELL_LEN, BLOCK_Y*CELL_LEN+CELL_LEN+SCELL_LEN-5, SWP_NOZORDER | SWP_NOMOVE); / / /模子 / memset(m_Model,0,sizeof(m_Model)); /** /** /** /***** /***** m_Model[0][2][1]=1; m_Model[0][3][1]=1; m_Model[0][3][2]=1; m_Model[0][3][3]=1; /**** m_Model[1][3][0]=1; m_Model[1][3][1]=1; m_Model[1][3][2]=1; m_Model[1][3][3]=1; //**** //**** //**** m_Model[2][2][2]=1; m_Model[2][2][3]=1; m_Model[2][3][2]=1; m_Model[2][3][3]=1; //** //**** ** m_Model[3][2][1]=1; m_Model[3][2][2]=1; m_Model[3][3][2]=1; m_Model[3][3][3]=1; ** //**** //** m_Model[4][3][1]=1; m_Model[4][3][2]=1; m_Model[4][2][2]=1; m_Model[4][2][3]=1; //** ****** m_Model[5][1][2]=1; m_Model[5][2][1]=1; m_Model[5][2][2]=1; m_Model[5][2][3]=1; ** ** ** /***** /***** m_Model[6][3][1]=1; m_Model[6][3][2]=1; m_Model[6][3][3]=1; m_Model[6][2][3]=1; ///转换对应位置 m_MoldeChange[0][0]=CPoint(0,0); m_MoldeChange[0][1]=CPoint(1,0); m_MoldeChange[0][2]=CPoint(2,0); m_MoldeChange[0][3]=CPoint(3,0); m_MoldeChange[1][0]=CPoint(0,3); m_MoldeChange[1][1]=CPoint(1,3); m_MoldeChange[1][2]=CPoint(2,3); m_MoldeChange[1][3]=CPoint(3,3); m_MoldeChange[2][0]=CPoint(0,2); m_MoldeChange[2][1]=CPoint(1,2); m_MoldeChange[2][2]=CPoint(2,2); m_MoldeChange[2][3]=CPoint(3,2); m_MoldeChange[3][0]=CPoint(0,1); m_MoldeChange[3][1]=CPoint(1,1); m_MoldeChange[3][2]=CPoint(2,1); m_MoldeChange[3][3]=CPoint(3,1); memset(m_BlockShow,0,sizeof(m_BlockShow)); memset(m_BlockNext,0,sizeof(m_BlockNext)); memset(m_Map,0,sizeof(m_Map)); m_IsStart=false; m_level=1; m_Score=0; //MessageBox(LPCTSTR("sdfs"),0,0); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CelsblocksDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CelsblocksDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast
这个程序的思路是这样的:
用以个矩阵来存储游戏区,游戏区中已经落下的标记为1其余清0
当然还有一个活动的 方块 ,这个方块我没有放到地图矩阵中来
在画图时,我开始尝试的是整体刷新( Invalidate)
发现闪的厉害,我就改用局部刷新( InvalidateRect)。
我尝试了,当把方块画的小于格子,局部刷新闪屏好一些
但我在这个程序的实现过程中并没有全部用上面的方法,因为效果还是不好,总有闪屏
最重要的是很难控制,出现内存错误了!!!
建议在画动态图时还是使用双缓冲好
什么是双缓冲呢?
就是把地图先画成图,然后再把图插入到界面。
还有个是哪个变换的问题,我是使用了一个变换矩阵来转换坐标(如果能计算的方法也不错,本人愚笨,当时怎么算都没算出来,不过我还是找到了变换的公式了,呵呵)
在写键盘按键反应时,在DLG类中不能用OnKeyDown
而应用PreTranslateMessage来截取键盘消息
不过不知道何时出现一个奇怪现象,我本想用空格来暂停游戏的,结果一按就退出游戏了,不解。。。