gusucode.com > 基于VC++编程war3连连看源码程序 > war3连连看/源代码/linkView.cpp

    // linkView.cpp : implementation of the CLinkView class
//


#include "stdafx.h"
#include "link.h"

#include "linkDoc.h"
#include "linkView.h"
#include "windows.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// CLinkView

IMPLEMENT_DYNCREATE(CLinkView, CView)

BEGIN_MESSAGE_MAP(CLinkView, CView)
	//{{AFX_MSG_MAP(CLinkView)
	ON_WM_LBUTTONDOWN()
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_MOUSEMOVE()
	ON_WM_CHAR()
	ON_WM_CANCELMODE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CLinkView construction/destruction

CLinkView::CLinkView()
{
	// TODO: add construction code here

}

CLinkView::~CLinkView()
{
}

BOOL CLinkView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CLinkView drawing

void CLinkView::OnDraw(CDC* pDC)
{
	CLinkDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
}

/////////////////////////////////////////////////////////////////////////////
// CLinkView diagnostics

#ifdef _DEBUG
void CLinkView::AssertValid() const
{
	CView::AssertValid();
}

void CLinkView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CLinkDoc* CLinkView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CLinkDoc)));
	return (CLinkDoc*)m_pDocument;
}
#endif //_DEBUG


//声明外部变量theApp
extern CLinkApp theApp;


//进入新的关卡
void NewStage( CDC * pDC ) 
{
	srand(time(0));
	int i , j  ;
	for( i = 0 ;i<leny ; ++i )
		for( j =0 ; j<lenx ; ++j )
			theApp.PicArray[i][j].visible = false ;

	int x , y ; 
	//每关出现lenx种图形,每种图形各有leny个 ,本程序中lenx=10 ,leny = 8 
	for( i=0; i<lenx-1 ; ++i )
	{
		for( j =0 ; j<leny ; ++j )
		{
			bool re = true ;
			while( re ) 
			{
				y = rand()%leny  ;
				x = rand()%lenx  ;
				if( theApp.PicArray[y][x].visible == false )
				{

					theApp.PicArray[y][x].type = i ; 
					theApp.PicArray[y][x].visible = true ;
					theApp.PicArray[y][x].x = x ; 
					theApp.PicArray[y][x].y = y ;
					re = false ;
				}
			}
		}
	}

	for( i = 0; i<leny ; ++i ) //剩下最后一种图片就不用随机了
		for( j =0 ; j<lenx ; ++j )
			if( theApp.PicArray[i][j].visible == false )
			{	
				theApp.PicArray[i][j].type = lenx-1 ; 
				theApp.PicArray[i][j].visible = true ;
				theApp.PicArray[i][j].x = j ;   //千万注意对应关系!!
				theApp.PicArray[i][j].y = i ;
			}

	
	CString str  ; 
	str.Format( "您的得分是 %u ,共%d关,现在是第 %d 关",  theApp.score ,totalStage,theApp.stage) ;
	pDC->TextOut( 150 , 15 , str) ;

	theApp.PaintPicture(pDC);  

}


/*在图片a与图片b间画线
* CClientDC & dc为当前的dc
*/
void draw_line( picture & a , picture & b , CClientDC & dc ) //CClientDC类不能作按值传递参数
{
	CPoint p1( theApp.margin + a.x * 64 + 64 / 2 , theApp.margin + a.y * 64 + 64 / 2 ) ;
	CPoint p2(  theApp.margin + b.x * 64 + 64/ 2 , theApp.margin + b.y * 64 + 64 / 2 ) ;
	dc.MoveTo( p1 );
	dc.LineTo( p2 ) ;
}

//将图片a从当前窗口中抹去
void paint_black( picture a  , CDC *pDC ) 
{
	CBrush backBrush(RGB(0, 0, 0));
	
	CBrush* pOldBrush = pDC->SelectObject(&backBrush);
	CRect rect;
	pDC->GetClipBox(&rect);
	
	pDC->PatBlt(theApp.margin + width * a.x , theApp.margin + width * a.y, width , width , PATCOPY);

	pDC->SelectObject(pOldBrush);
}

//判断图片a与图片b能否直接相连(a、b间连线的转角数为0 )
bool match_direct( picture a , picture b , CClientDC & dc )
{
	//a、b的x或y坐标必须有且只有一个相同才能直接相连
	if (! (  a.x==b.x  || a.y == b.y  ) )
		return false ;

	//判断a、b间是否有其他图片阻隔
	int i ;
	bool match_x = false ;
	if( a.x == b.x )
	{
		match_x = true ;
		if( a.y > b.y ) 
			for( i=a.y-1 ; i>b.y ; --i )
				if( theApp.PicArray[ i][ a.x ].visible == true )
					match_x = false ;
		if(  b.y > a.y ) 
			for( i = b.y -1 ; i>a.y ; --i )
				if( theApp.PicArray[ i][ a.x ].visible == true )
					match_x = false ;
	}

	bool match_y = false ;
	if( a.y == b.y )
	{
		match_y = true ;
	
		if( a.x > b.x ) 
			for( i = a.x - 1  ; i>b.x ; --i ) 
				if(  theApp.PicArray[ a.y ][ i ].visible == true )
					match_y = false ;
		if( b.x > a.x )
			for( i = b.x -1 ; i>a.x ; --i ) 
				if( theApp.PicArray[ a.y ][ i ].visible == true )
					match_y = false ;
	}

	if( match_x || match_y )
	{
	//	draw_line(  a ,  b ,  dc ) ;   //不能写在这里,否则match_one_corner会不正常
		return true ;
	}

	return false ;
}

//判断a、b间能否通过只有一个转角的折线相连
bool match_one_corner( picture a , picture b , CClientDC & dc) 
{	
	if( theApp.PicArray[ b.y ][ a.x ].visible == false &&\
		match_direct( a , theApp.PicArray[ b.y ][ a.x ]  , dc) && \
		match_direct( b , theApp.PicArray[ b.y ][ a.x ] ,dc) )
	{
		draw_line( a , theApp.PicArray[ b.y ][ a.x ] ,dc ) ;  
		draw_line( b , theApp.PicArray[ b.y ][ a.x ] ,dc) ;

		return true ;
	}

	if( theApp.PicArray[ a.y ][ b.x ].visible == false &&\
		match_direct( a , theApp.PicArray[ a.y ][ b.x ] ,dc ) && \
		match_direct( b , theApp.PicArray[ a.y ][ b.x ] ,dc) )
	{
		draw_line( a , theApp.PicArray[ a.y ][ b.x ] ,dc ) ;  
		draw_line( b , theApp.PicArray[ a.y ][ b.x ] ,dc) ;

		return true ;
	}
	return false ;
}

//判断a、b能否通过有2个转角的折线相连
bool match_two_corner( picture a , picture b , CClientDC  & dc  ) 
{
	int i ; 

	//转化为a与c能直接相连,而c与b可以通过有一个转角的折线相连的情况
	for( i=a.x -1 ; i>=0 ; --i )
		if( theApp.PicArray[a.y][i].visible == true )
			break;
		else
			if( match_one_corner( theApp.PicArray[a.y][i] , b ,dc) )
			{
				draw_line( a , theApp.PicArray[a.y][i] ,dc ) ;
				return true ;
			}

	for( i = a.x +1 ; i<lenx ; ++i )
		if( theApp.PicArray[a.y][i].visible == true )
			break;
		else
			if( match_one_corner( theApp.PicArray[a.y][i] , b ,dc ) )
			{
				draw_line( a , theApp.PicArray[a.y][i] ,dc ) ;
				return true ;
			}

	for( i = a.y - 1 ; i>=0 ; --i )
		if( theApp.PicArray[i][a.x].visible == true )
			break;
		else
			if( match_one_corner( theApp.PicArray[i][a.x] ,b ,dc) )
			{
				draw_line( a , theApp.PicArray[i][a.x] ,dc ) ;
				return true ;
			}

	for( i = a.y + 1 ; i<leny ; ++i )
		if( theApp.PicArray[i][a.x].visible == true )
			break;
		else
			if( match_one_corner( theApp.PicArray[i][a.x] ,b ,dc) )
			{
				draw_line( a , theApp.PicArray[i][a.x] ,dc ) ;
				return true ;
			}

	return false ;

}

//判断a与b能否相连(条件:a与b类型相同,且能用转角不超过3个的折线相连
bool match( picture a , picture b , CClientDC & dc ) 
{
	if( a.type != b.type )
		return false ;
	
	//直接相连
	if( match_direct( a, b , dc )  )
	{
		draw_line(  a ,  b ,  dc ) ;
		Sleep(500) ;    //连线在窗口中显示0.5 s 后消失
		for( int i=0 ;i<leny ; ++i )
			for( int j =0 ;j<lenx ; ++j )
				if( theApp.PicArray[i][j].visible == false )
					paint_black( theApp.PicArray[i][j]  , &dc ) ;

		return true ;
	}

	//通过一个或两个转角相连的情况
	if( match_one_corner( a , b ,dc )  || match_two_corner( a, b ,dc) )
	{
		Sleep(500) ;
		for( int i=0 ;i<leny ; ++i )
			for( int j =0 ;j<lenx ; ++j )
				if( theApp.PicArray[i][j].visible == false )
					paint_black( theApp.PicArray[i][j]  , &dc ) ;

		return true ;
	}

	return false ;
}


//点击左键时判断前后点击的图片能否消去
void CLinkView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if( point.x <=theApp.margin || point.y<=theApp.margin ||\
		point.x >= theApp.margin +lenx*width || point.y >= theApp.margin +leny*width )
		return ;

	int x = ( point.x - theApp.margin ) / width ;
	int y = ( point.y - theApp.margin ) / width ; 
	int Px = ( theApp.PreClick.x - theApp.margin) / width ; 
	int Py =  ( theApp.PreClick.y - theApp.margin ) / width ;

	//设置画笔的属性,并关联到dc
	CClientDC dc(this) ;
	int penWidth  =  5;   
	CPen   pen(PS_SOLID,   penWidth,  RGB(255,   0,   0));   
	dc.SelectObject(&pen);  

	if( x == Px && y == Py ) //前后两次点击的是同一张图片
		return ;
	else
		if( Px <0 || Py <0 ) //这是第一次点击的情况
			return ;
		else
		if( theApp.PicArray[ y ][ x ].visible == true && \
			theApp.PicArray[ Py ][ Px ].visible == true &&\
			theApp.PicArray[ y ][ x ].type == theApp.PicArray[ Py ][ Px ].type &&\
			match( theApp.PicArray[ y ][ x ] , theApp.PicArray[ Py ][ Px ] , dc ) 
			)
		{
			
			theApp.PicArray[ y ][ x ].visible = false ;
			theApp.PicArray[ Py ][ Px ].visible = false ;

			CDC* pDC=GetDC();
			paint_black( theApp.PicArray[ y ][ x ] , pDC );
			paint_black( theApp.PicArray[ Py ][ Px ] ,pDC ) ;

			theApp.score += 10 ;

			CString str  ; 
			str.Format( "您的得分是 %u ,共%d关,现在是第 %d 关",  theApp.score ,totalStage,theApp.stage) ;
				
			pDC->TextOut( 150 , 15 , str) ;
			
			theApp.remain_num -= 2 ; 
			if( theApp.remain_num == 0 )  //剩余图片数为0,则通关
			{
				theApp.score += theApp.stage * 100 ; 

				CString str  ; 
				str.Format( "您的得分是 %u ,共%d关,现在是第 %d 关",  theApp.score ,totalStage,theApp.stage) ;
				
				pDC->TextOut( 150 , 15 , str) ;
				if( theApp.stage == totalStage )  
					MessageBox( "你已经成功完成所有关卡!!","恭喜!!",MB_OK ) ;
				else
				{
					MessageBox("成功完成游戏!下面进行下一关!","恭喜!!",MB_OK );
					theApp.remain_num = lenx * leny ;
					theApp.stage ++ ; 
					NewStage( pDC ) ;
				}

			}

			ReleaseDC( pDC ) ;
		}

	theApp.PreClick = point ; 
}

//重画黑色的背景
BOOL CLinkView::OnEraseBkgnd(CDC* pDC) 
{

	//设置brush为希望的背景颜色
	CBrush backBrush( RGB(0, 0, 0) );
	
	//保存旧的brush
	CBrush* pOldBrush = pDC->SelectObject(&backBrush);
	CRect rect;
	pDC->GetClipBox(&rect);
	
	//画需要的区域
	pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
	pDC->SelectObject(pOldBrush);
	
	return TRUE;
}


//最小化后再次恢复窗口时,需要重画窗口
void CLinkView::OnPaint() 
{
	CPaintDC dc(this);
	CDC* pDC = GetDC();
	theApp.PaintPicture( pDC );
	ReleaseDC( pDC ) ;
}

//鼠标移动时,经过的的图片要变色
void CLinkView::OnMouseMove(UINT nFlags, CPoint point ) 
{

	//在图片范围内
	if( point.x > theApp.margin && point.y > theApp.margin &&\
		point.x < theApp.margin + width * lenx && point.y <theApp.margin + width * leny )
	{
		CDC* pDC = GetDC();

		//重画所有图片,主要是为了将上次经过的变色的图片恢复正常状态
		theApp.PaintPicture( pDC );

		int i = ( point.x - theApp.margin )/width ;
		int j = ( point.y - theApp.margin )/width ;

		
		if( theApp.PicArray[j][i].visible == true )
		{
			//鼠标经过的图片要变色
			CBitmap bitmap3 ;
			bitmap3.LoadBitmap( 171 + theApp.stage ) ;	//171是第一张变色图片的资源号
			CDC dcCompatible3 ;
			dcCompatible3.CreateCompatibleDC( pDC) ;
			dcCompatible3.SelectObject( &bitmap3 ) ;
			
			pDC->BitBlt( theApp.margin + i*width, theApp.margin + j*width,width,width,&dcCompatible3,0,theApp.PicArray[j][i].type*width,SRCCOPY ) ;
			
			//将鼠标指向的图片画到右边的空白处,图片下面显示说明文字
			CBitmap bitmap4 ;
			bitmap4.LoadBitmap( 191 + theApp.stage ) ;	//191是第一张正常图片的资源号
			CDC dcCompatible4 ;
			dcCompatible4.CreateCompatibleDC( pDC) ;
			dcCompatible4.SelectObject( &bitmap4 ) ;
			pDC->BitBlt( theApp.margin + width*lenx + width , theApp.margin  + width ,width,width,&dcCompatible4,0,theApp.PicArray[j][i].type*width,SRCCOPY ) ;
			
			pDC->TextOut( theApp.margin + width*lenx + width , theApp.margin  + width *2 , theApp.pic_info[theApp.stage -1 ][theApp.PicArray[j][i].type] ) ;
			
		}

		ReleaseDC( pDC ) ;
	}
}


void CLinkView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	if( nChar == 1 )
	{
		CDC * pDC = GetDC() ;
		CString str  ; 
		str.Format( "您的得分是 %u ,共%d关,现在是第 %d 关",  theApp.score ,totalStage,theApp.stage) ;
		pDC->TextOut( 150 , 15 , str) ;
		

		if( theApp.stage > totalStage )
			MessageBox( "你已经成功完成所有关卡!!","恭喜!!",MB_OK ) ;
		else
		{
			MessageBox("您使用了秘籍,直接进入下一关!","提示",MB_OK ) ;
			theApp.remain_num = lenx * leny ;
			theApp.stage ++ ; 
			NewStage( pDC ) ;
			str.Format( "您的得分是 %u ,共%d关,现在是第 %d 关",  theApp.score ,totalStage,theApp.stage) ;
			pDC->TextOut( 150 , 15 , str) ;
		}
		ReleaseDC( pDC ) ;
	}
}

void CLinkView::OnCancelMode() 
{
	CView::OnCancelMode();
	
}