gusucode.com > VC++连连看游戏源码-源码程序 > VC++连连看游戏源码-源码程序\code\skyblue_LLK\skyblue_LLKDlg.cpp
//Download by http://www.NewXing.com /*++ Copyright (c) AFE(Active-Free-Elegance) Module Name: skyblue_LLKDlg.cpp Abstract: LLK-Game's kernal-solving Dialog Author: Weijian Luo (Arthur Luo) 15-Jun-2005 E-mail: skybluehacker@yahoo.com.cn Revision History: 1.0 --*/ #include "stdafx.h" #include "skyblue_LLK.h" #include "skyblue_LLKDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // C_LLK_Dlg dialog #define BKCOLOR RGB(128,128,128) //背景颜色 #define FRONTWIDTH (39+2) //前面方块的宽度 #define FRONTHEIGHT (39+12) //前面方块的高度 #define BKWIDTH 46 //背景方块的宽度 #define BKHEIGHT 56 //背景方块的高度 #define ROWCOUNT 7 //行数 #define COLCOUNT 12 //列数 #define BLANK_STATE -1 //空方块(没有任何动物) ///////////////////////////////////////////////////////////////////////////// // C_LLK_Dlg dialog C_LLK_Dlg::C_LLK_Dlg(CWnd* pParent /*=NULL*/) : CDialog(C_LLK_Dlg::IDD, pParent) { //{{AFX_DATA_INIT(C_LLK_Dlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); //记录方块置为无效状态 m_nY1= BLANK_STATE; m_nX1= BLANK_STATE; //初始化行列数 m_nRow=ROWCOUNT; m_nCol=COLCOUNT; //根据行列数动态分配内核数据数组空间 m_map=new int[m_nRow*m_nCol]; } C_LLK_Dlg::~C_LLK_Dlg() { //释放动态数组空间 delete[] m_map; } void C_LLK_Dlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(C_LLK_Dlg) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(C_LLK_Dlg, CDialog) //{{AFX_MSG_MAP(C_LLK_Dlg) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_LBUTTONDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // C_LLK_Dlg message handlers BOOL C_LLK_Dlg::OnInitDialog() { CDialog::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon //获取程序框架的设备环境 CDC *pWinDC = GetDC(); //内存设备环境以及内存位图的创建,初始化,关联 //3D方块边框图样内存位图 m_mem3DBkDC.CreateCompatibleDC(pWinDC); m_mem3DBkBmp.LoadBitmap(IDB_BITMAP_3D_FRAMES); m_mem3DBkDC.SelectObject(&m_mem3DBkBmp); //动物图样内存位图 m_memAnimalDC.CreateCompatibleDC(pWinDC); m_memAnimalBmp.LoadBitmap(IDB_BMP_ANIMAL); m_memAnimalDC.SelectObject(&m_memAnimalBmp); //整个游戏区域内存位图 m_MemDC.CreateCompatibleDC(pWinDC); m_memBitmap.CreateCompatibleBitmap(pWinDC, m_nCol*FRONTWIDTH+5, m_nRow*FRONTHEIGHT+5); m_MemDC.SelectObject(&m_memBitmap); //开始一个新的游戏 StartNewGame(); //放在最桌面的前面显示 HWND hWnd = ::AfxGetMainWnd()->m_hWnd; ::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); return TRUE; // return TRUE unless you set the focus to a control } void C_LLK_Dlg::StartNewGame() { //初始化地图,将地图中所有方块区域位置置为空方块状态 for(int iNum=0;iNum<(m_nCol*m_nRow);iNum++) { m_map[iNum] = BLANK_STATE; } //部下随机种子 srand(time(NULL)); //生成随机地图 //将所有匹配成对的动物物种放进一个临时的地图中 CDWordArray tmpMap; for(int i=0;i<(m_nCol*m_nRow)/4;i++) for(int j=0;j<4;j++) tmpMap.Add(i); //每次从上面的临时地图中取走(获取后并在临时地图删除) //一个动物放到地图的空方块上 for(i=0;i<m_nRow*m_nCol;i++) { //随机挑选一个位置 int nIndex=(int(rand()*0.1+rand()*0.01+rand()))%tmpMap.GetSize(); //获取该选定物件放到地图的空方块 m_map[i]=tmpMap.GetAt(nIndex); //在临时地图除去该动物 tmpMap.RemoveAt(nIndex); } //更新显示 Invalidate(TRUE); } // // 游戏区域的绘制 // void C_LLK_Dlg::GameDraw(CDC * pDC) { //绘制背景颜色 pDC->FillSolidRect(0,0,m_nCol*FRONTWIDTH+5,m_nRow*FRONTHEIGHT+5,BKCOLOR); for(int i=0;i<m_nRow;i++) { for(int j=0;j<m_nCol;j++) { if(m_map[i*m_nCol+j]==BLANK_STATE) { continue; } //绘制方块边框 pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT, BKWIDTH,BKHEIGHT, &m_mem3DBkDC, 0,BKHEIGHT, SRCCOPY); //绘制方块 //因为要使得效果透明,所以由图样的底色以及表面两部分构成 pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT, FRONTWIDTH-2,FRONTHEIGHT-12, &m_memAnimalDC, FRONTWIDTH-2,m_map[i*m_nCol+j]*(FRONTHEIGHT-12), SRCAND); pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT, FRONTWIDTH-2,FRONTHEIGHT-12, &m_memAnimalDC, 0,m_map[i*m_nCol+j]*(FRONTHEIGHT-12), SRCPAINT); } } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR C_LLK_Dlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void C_LLK_Dlg::OnPaint() { CPaintDC dc(this); // device context for painting //先将整个游戏区域的图像绘制到内存位图 GameDraw(&m_MemDC); //将内存位图中绘制好的图像一次性拷贝到屏幕 dc.BitBlt(0,0,m_nCol*FRONTWIDTH,m_nCol*FRONTHEIGHT,&m_MemDC,0,0,SRCCOPY); } // // 鼠标左键消息处理 // void C_LLK_Dlg::OnLButtonDown(UINT nFlags, CPoint point) { //1.计算鼠标点击方块的的位置 int x=point.x/FRONTWIDTH+(point.x%FRONTWIDTH?1:0)-1; int y=point.y/FRONTHEIGHT+(point.y%FRONTHEIGHT?1:0)-1; //2.在游戏区域内并且该区域还有该区域不是空的区域 if(x<m_nCol&&y<m_nRow&&m_map[y*m_nCol+x]!= BLANK_STATE) { //3.假设尚未记录第一个方块 if(m_nX1==BLANK_STATE) { //4.记录第一个方块的位置 m_nX1=x; m_nY1=y; //获取程序框架的设备环境 CDC *pWinDC = GetDC(); //临时绘制点中的方块外框 //只绘屏幕不载入内存位图 CPen myPen; CPen *pOldPen; myPen.CreatePen(PS_SOLID, 4, RGB(255,0,0)); pOldPen = pWinDC->SelectObject(&myPen); //方块外框绘制,线条环绕绘制框架 pWinDC->MoveTo(x*FRONTWIDTH,y*FRONTHEIGHT); pWinDC->LineTo(x*FRONTWIDTH,(y+1)*FRONTHEIGHT); pWinDC->LineTo((x+1)*FRONTWIDTH,(y+1)*FRONTHEIGHT); pWinDC->LineTo((x+1)*FRONTWIDTH,y*FRONTHEIGHT); pWinDC->LineTo(x*FRONTWIDTH,y*FRONTHEIGHT); //现场恢复 pWinDC->SelectObject(pOldPen); } else { //5.判断是否点击的方块非本身, 是否点击同一种动物 if((m_nX1!=x||m_nY1!=y)&& m_map[m_nY1*m_nCol+m_nX1]==m_map[y*m_nCol+x] ) { //6.检测是否可以消除 if(IsLink(m_nX1,m_nY1,x,y)) { //7.数据清理 m_map[m_nY1*m_nCol+m_nX1]=BLANK_STATE; m_map[y*m_nCol+x]=BLANK_STATE; } } //8.清空记录方块的值 m_nX1=BLANK_STATE; m_nY1=BLANK_STATE; //通知重绘 Invalidate(FALSE); } } //察看是否已经胜利 if(IsWin()) { MessageBox("恭喜您胜利闯关,即将开始新局"); StartNewGame(); } } // //X直接连通 // BOOL C_LLK_Dlg::X1_Link_X2(int x, int y1,int y2) { //保证y1的值小于y2 if(y1>y2) { //数据交换 int n=y1; y1=y2; y2=n; } //直通 for(int i=y1+1;i<=y2;i++) { if(i==y2) return TRUE; if(m_map[i*m_nCol+x]!=BLANK_STATE) break; } //左通 if(XThrough(x-1,y1,FALSE)&&XThrough(x-1,y2,FALSE)) return TRUE; //右通 if(XThrough(x+1,y1,TRUE)&&XThrough(x+1,y2,TRUE)) return TRUE; return FALSE; } // //Y直接连通 // BOOL C_LLK_Dlg::Y1_Link_Y2(int x1,int x2,int y) { if(x1>x2) { int x=x1; x1=x2; x2=x; } //直通 for(int i=x1+1;i<=x2;i++) { if(i==x2) return TRUE; if(m_map[y*m_nCol+i]!=BLANK_STATE) break; } //上通 if(YThrough(x1,y-1,FALSE)&&YThrough(x2,y-1,FALSE)) return TRUE; //下通 if(YThrough(x1,y+1,TRUE)&&YThrough(x2,y+1,TRUE)) return TRUE; return FALSE; } // // 是否同一直线通 // BOOL C_LLK_Dlg::LineX(int x,int y1,int y2) { if(y1>y2) { int y=y1; y1=y2; y2=y; } for(int y=y1;y<=y2;y++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) return FALSE; if(y==y2) return TRUE; } return FALSE; } // // 是否同一直线通 // BOOL C_LLK_Dlg::LineY(int x1,int x2,int y) { if(x1>x2) { int x=x1; x1=x2; x2=x; } for(int x=x1;x<=x2;x++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) return FALSE; if(x==x2) return TRUE; } return FALSE; } // // 1直角接口连通 // BOOL C_LLK_Dlg::OneCornerLink(int x1, int y1,int x2, int y2) { if(x1>x2) { int n=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } if(y2<y1) { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2+1)) return TRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1-1)) return TRUE; return FALSE; } else { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2-1)) return TRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1+1)) return TRUE; return FALSE; } return FALSE; } // // 2直角接口连通 // BOOL C_LLK_Dlg::TwoCornerLink(int x1, int y1, int x2, int y2) { if(x1>x2) { int n=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } //右通 if(XThrough(x1+1,y1,TRUE)&&XThrough(x2+1,y2,TRUE)) return TRUE; //左通 if(XThrough(x1-1,y1,FALSE)&&XThrough(x2-1,y2,FALSE)) return TRUE; //上通 if(YThrough(x1,y1-1,FALSE)&&YThrough(x2,y2-1,FALSE)) return TRUE; //下通 if(YThrough(x1,y1+1,TRUE)&&YThrough(x2,y2+1,TRUE)) return TRUE; //右 for(int x=x1+1;x<m_nCol;x++) { if(m_map[y1*m_nCol+x]>-1) break; if(OneCornerLink(x,y1,x2,y2)) return TRUE; } //左 for(x=x1-1;x>-1;x--) { if(m_map[y1*m_nCol+x]!=BLANK_STATE) break; if(OneCornerLink(x,y1,x2,y2)) return TRUE; } //上 for(int y=y1-1;y>-1;y--) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) return TRUE; } //下 for(y=y1+1;y<m_nRow;y++) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) return TRUE; } return FALSE; } BOOL C_LLK_Dlg::XThrough(int x, int y, BOOL bAdd) { if(bAdd) { for(int i=x;i<m_nCol;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) return FALSE; } else { for(int i=0;i<=x;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) return FALSE; } return TRUE; } BOOL C_LLK_Dlg::YThrough(int x, int y,BOOL bAdd) { if(bAdd) { for(int i=y;i<m_nRow;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) return FALSE; } else { for(int i=0;i<=y;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) return FALSE; } return TRUE; } // // 判断选中的两个方块是否可以消除 // BOOL C_LLK_Dlg::IsLink(int x1, int y1, int x2, int y2) { //X直连方式 if(x1==x2) { if(X1_Link_X2(x1,y1,y2)) return TRUE; } //Y直连方式 else if(y1==y2) { if(Y1_Link_Y2(x1,x2,y1)) return TRUE; } //一个转弯直角的联通方式 if(OneCornerLink(x1,y1,x2,y2)) { return TRUE; } //两个转弯直角的联通方式 else if(TwoCornerLink(x1,y1,x2,y2)) { return TRUE; } return FALSE; } // // 截获键盘消息 F2 (用于新游戏开始) // BOOL C_LLK_Dlg::PreTranslateMessage(MSG* pMsg) { if(pMsg->message==WM_KEYDOWN) { if(pMsg->wParam==VK_F2) { StartNewGame(); } } return CDialog::PreTranslateMessage(pMsg); } // // 检测是否已经赢得了游戏 // BOOL C_LLK_Dlg::IsWin(void) { //检测所有是否尚有非未被消除的方块 // (非BLANK_STATE状态) for(int i=0;i<m_nRow*m_nCol;i++) { if(m_map[i] != BLANK_STATE) { return FALSE; } } return TRUE; }