www.gusucode.com > 潜艇大战游戏VC++源代码-源码程序 > 潜艇大战游戏VC++源代码-源码程序\code\ChildView.cpp

    //Download by http://www.NewXing.com
// ChildView.cpp : implementation of the CChildView class
//

#include "stdafx.h"
#include "ShipDemo.h"
#include "ChildView.h"

#include "Explosion.h"
#include "MyObject.h"
#include "Score.h"
#include "MyShip.h"
#include "Submarine.h"
#include "Bomb.h"
#include "Torpedo.h"

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

#define SHIP_VERT_POS		20
#define SKY_COLOR			RGB(0, 255, 255)
#define SEA_COLOR			RGB(0, 128, 255)
#define MAX_BOMBNUM 10
//indicate m_Objects[]     
//Fox example: use 'm_Objects[MYSHIP]' to handle "my ship"
#define MYSHIP		0
#define SUBMARINE	1
#define MY_BOMB		2
#define	ENEMY_BOMB	3
#define	EXPLOSION	4
#define	SCORE		5




/////////////////////////////////////////////////////////////////////////////
// CChildView

CChildView::CChildView()
{
// load image list;
	CExplosion::LoadImage();
	CMyShip::LoadImage();
	CSubmarine::LoadImage();
	CBomb::LoadImage();
	CTorpedo::LoadImage();


// create my ship object, this is the 1st object in object list
	m_Objects[MYSHIP].AddTail(new CMyShip(CPoint((GAME_WIDTH-SHIP_WIDTH)*1/3, SHIP_VERT_POS),0 ));
	m_Objects[MYSHIP].AddTail(new CMyShip(CPoint((GAME_WIDTH-SHIP_WIDTH)*2/3, SHIP_VERT_POS),1 ));
	m_bGamePause = false;
}

CChildView::~CChildView()
{
// free memory

// delete all objects
	POSITION pos = m_Objects[MYSHIP].GetHeadPosition();
	int i;
	for(i=0;i<6;i++)
	{
		while(pos!=NULL)
		{
			delete m_Objects[i].GetNext(pos);
		}
		m_Objects[i].RemoveAll();
	}

// clear image lists
	CExplosion::DeleteImage();
	CMyShip::DeleteImage();
	CSubmarine::DeleteImage();
	CBomb::DeleteImage();
	CTorpedo::DeleteImage();
	
}


BEGIN_MESSAGE_MAP(CChildView,CWnd )
	//{{AFX_MSG_MAP(CChildView)
	ON_WM_PAINT()
	ON_WM_CREATE()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_COMMAND(IDM_GAMEPAUSE, OnGamepause)
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CChildView message handlers

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) 
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

//	cs.dwExStyle |= WS_EX_CLIENTEDGE;  // Wanghaitao remove this line
	cs.style &= ~WS_BORDER;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL);

	return TRUE;
}

void CChildView::OnPaint() 
{
	// TODO: Add your message handler code here
	CPaintDC dc(this); // device context for painting

// repaint window so easily
	dc.BitBlt(0, 0, GAME_WIDTH, GAME_HEIGHT, &m_VirtualDC, 0, 0, SRCCOPY);

	// Do not call CWnd::OnPaint() for painting messages
}


int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd ::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here

// create virtual back buffer 
	CClientDC dc(this);
	m_VirtualBitmap.CreateCompatibleBitmap(&dc, GAME_WIDTH, GAME_HEIGHT);
	m_VirtualDC.CreateCompatibleDC(&dc);
	m_VirtualDC.SelectObject(&m_VirtualBitmap);

// create loop
	SetTimer(100, 30, NULL);
	srand( (unsigned)time( NULL ) );
	return 0;
}

void CChildView::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	static int nCreator = random(15) +15 ;
	CClientDC dc(this);

	int i,j,k;
	CRect l_Rect;
	CMyObject* pObject;

	if(m_bGamePause)
		return;

// create new sub
	if(nCreator==0)
	{
		m_Objects[SUBMARINE].AddTail(new CSubmarine(random(2)%2?true:false, random(GAME_HEIGHT-SHIP_VERT_POS-SHIP_HEIGHT*2-30)+SHIP_VERT_POS+SHIP_HEIGHT+30, random(4), random(4)+3));
		nCreator = random(15) + 15;
	}

// Draw sky and see
	m_VirtualDC.FillSolidRect(0, 0, GAME_WIDTH, SHIP_VERT_POS+SHIP_HEIGHT-5, SKY_COLOR);
	m_VirtualDC.FillSolidRect(0, SHIP_VERT_POS+SHIP_HEIGHT-5, GAME_WIDTH, GAME_HEIGHT, SEA_COLOR);

// Draw all objects on the virtual dc, Be careful using "POSITION"
	POSITION pos1, pos2, pos3, pos4;
	CSubmarine* pSub;
	CMyShip* pMyShip;
	if(m_Objects[MYSHIP].GetCount()!=0)
		pMyShip=(CMyShip*)m_Objects[MYSHIP].GetHead();//Get my ship

	for(j=0;j<6;j++)
	for(i=0,pos1=m_Objects[j].GetHeadPosition(); (pos2=pos1)!=NULL; i++)
   	{
		pObject=(CMyObject*)m_Objects[j].GetNext(pos1);

		if(pObject->Draw(&m_VirtualDC, m_bGamePause))  // object terminated
		{
			m_Objects[j].RemoveAt(pos2);
			delete pObject;
		}
	//submarine throw torpedo
		else if(m_Objects[MYSHIP].GetCount()!=0 && j==SUBMARINE ) 
		{
			//double "my ship"
			for(k=0;k<m_Objects[MYSHIP].GetCount();k++)
			{
				if(0 == k)
					pMyShip=(CMyShip*)m_Objects[MYSHIP].GetHead();
				if(1 == k)
					pMyShip=(CMyShip*)m_Objects[MYSHIP].GetTail();
				//if "my ship" is above
				if( pObject->GetPos().x+SUBMARINE_WIDTH/2 > pMyShip->GetPos().x &&
				pObject->GetPos().x+SUBMARINE_WIDTH/2 < pMyShip->GetPos().x+SHIP_WIDTH )
				{
				//reduce the torpedo number
					if( ((CSubmarine*)pObject)->GetFireFlag() && random(10)==2)
					{
					CTorpedo *pTorpedo=new CTorpedo( CPoint(pObject->GetPos().x+SUBMARINE_WIDTH/2-TORPEDO_WIDTH/2, pObject->GetPos().y) );
					m_Objects[ENEMY_BOMB].AddTail(pTorpedo);
					((CSubmarine*)pObject)->SetFireFlag();
					}
				}//if
			}//for(i=0;i<2;i++)
		}
	}//for

//Find collision between explosion and submarine
//Notice that an explosion can trigger an explosion of the submarines nearby

	for(pos1=m_Objects[EXPLOSION].GetHeadPosition(); (pos2=pos1)!=NULL;)
	{
			pObject=(CMyObject*)m_Objects[EXPLOSION].GetNext(pos1);
		
			for(pos3=m_Objects[SUBMARINE].GetHeadPosition(); (pos4=pos3)!=NULL;)
   			{
					pSub = (CSubmarine*)m_Objects[SUBMARINE].GetNext(pos3);  
					l_Rect=pObject->GetRect();

					//if there is collision between explosion and submarine
					if( (l_Rect.IntersectRect(pSub->GetRect(), l_Rect )) )
					{
						// here we first create explosion object to make score always above that explosion
						CExplosion *pExplosion=new CExplosion(pSub->GetPos());

						// when an explosion trigger another explosion, the score should multiple
						pExplosion->SetMulti( ((CExplosion*)pObject)->GetMulti()+1 );

						m_Objects[EXPLOSION].AddTail(pExplosion);
						m_Objects[SCORE].AddTail(new CScore(pSub->GetPos(), pExplosion->GetMulti(), pSub->GetType()+1, RGB(random(255), random(255), random(255))));
						
						m_Objects[SUBMARINE].RemoveAt(pos4);
						delete pSub;
						break;
											
					}//if
			}//for
						
	}//for

//Find bombs which shoot on submarine
	for(pos1=m_Objects[MY_BOMB].GetHeadPosition(); (pos2=pos1)!=NULL;)
	{
			pObject=(CMyObject*)m_Objects[MY_BOMB].GetNext(pos1);
			
			for(pos3=m_Objects[SUBMARINE].GetHeadPosition(); (pos4=pos3)!=NULL;)
   			{
					pSub = (CSubmarine*)m_Objects[SUBMARINE].GetNext(pos3);  // save for deletion
					l_Rect=((CBomb*)pObject)->GetRect();

					//if there is collision between this bomb and submarine
					if( (l_Rect.IntersectRect(pSub->GetRect(), l_Rect )) )
					{
						// here we first create explosion object to make score always above that explosion
						m_Objects[EXPLOSION].AddTail(new CExplosion(pSub->GetPos()));
						m_Objects[SCORE].AddTail(new CScore(pSub->GetPos(),1,pSub->GetType()+1, RGB(random(255), random(255), random(255))));
						
						m_Objects[SUBMARINE].RemoveAt(pos4);
						delete pSub;
						m_Objects[MY_BOMB].RemoveAt(pos2);					
						delete pObject;
						// break is important! to avoid next recycle use a bomb not exist
						break;
											
					}//if
			}//for
						
	}//for
	
//Find enemy bombs which shoot on "my ship"
	if(m_Objects[MYSHIP].GetCount()!=0)
	for(pos1=m_Objects[ENEMY_BOMB].GetHeadPosition(); (pos2=pos1)!=NULL;)
	{
			pObject=(CMyObject*)m_Objects[MY_BOMB].GetNext(pos1);
		
			
			for(pos3=m_Objects[MYSHIP].GetHeadPosition(); (pos4=pos3)!=NULL;)
   			{
					pMyShip = (CMyShip*)m_Objects[MYSHIP].GetNext(pos3);  
					l_Rect=pObject->GetRect();

					//if there is collision between this torpedo and "my ship"
					if( (l_Rect.IntersectRect(pMyShip->GetRect(), l_Rect )) )
					{
						// here we first create explosion object to make score always above that explosion
						m_Objects[EXPLOSION].AddTail(new CExplosion(pMyShip->GetPos()));
						
						m_Objects[MYSHIP].RemoveAt(pos4);
						delete pMyShip;
						m_Objects[ENEMY_BOMB].RemoveAt(pos2);					
						delete pObject;

						// break is important! to avoid next recycle use a bomb not exist
						break;
											
					}//if
			}//for
						
	}//for
// Game over
	if(m_Objects[MYSHIP].GetCount()==0)
	{
		m_VirtualDC.SetTextColor(RGB(255, 0, 0));
		m_VirtualDC.SetTextAlign(TA_CENTER);
		m_VirtualDC.TextOut(GAME_WIDTH/2, GAME_HEIGHT/2,"GAME OVER");
	}
// restore old text align
	m_VirtualDC.SetTextAlign(TA_LEFT);
// sample: calculate objects numbers
	m_VirtualDC.SetBkMode(TRANSPARENT);
	m_VirtualDC.SetTextColor(RGB(255, 0, 0));
	CString string;
	string.Format("Total Enemy: %d , Total Bomb: %d", m_Objects[SUBMARINE].GetCount(),m_Objects[MY_BOMB].GetCount() );
	m_VirtualDC.TextOut(10, 10, string);
// sample: calculate total score
	string.Format("Your score: %d",CScore::GetTotalScore() );
	m_VirtualDC.TextOut(300, 10, string);


// blt the virtual dc on client dc
	dc.BitBlt(0, 0, GAME_WIDTH, GAME_HEIGHT, &m_VirtualDC, 0, 0, SRCCOPY);

	nCreator--;

//	CWnd ::OnTimer(nIDEvent);  // no use, safely remove it
}

void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	if(m_bGamePause)
		return;
	if(m_Objects[MYSHIP].GetCount()==0)//my ship is not exist
		return;
//double "my ship"
	CMyShip* pShip1 = (CMyShip*)m_Objects[MYSHIP].GetHead(); // remember that our ship1 is the first object[MYSHIP] in object list
	CMyShip* pShip2 = (CMyShip*)m_Objects[MYSHIP].GetTail(); // remember that our ship2 is the last object[MYSHIP] in object list

	switch(nChar)
	{
	case VK_LEFT:       // turn left
		pShip1->SetMotion(-1);
		break;
	
	case VK_RIGHT: // turn right
		pShip1->SetMotion(1);
		break;
	case 'a':
	case 'A':       // turn left
		pShip2->SetMotion(-1);
		break;
	case 'd':
	case 'D':		// turn right
		pShip2->SetMotion(1);
		break;
	
	case VK_SPACE: // throw bomb from middle
		if( m_Objects[MY_BOMB].GetCount()<MAX_BOMBNUM )
		m_Objects[MY_BOMB].AddTail(new CBomb(pShip2->GetPos().x+SHIP_WIDTH/2-BOMB_WIDTH/2, 3));
		break;

	case VK_RETURN: // throw bomb from middle
		if( m_Objects[MY_BOMB].GetCount()<MAX_BOMBNUM )
		m_Objects[MY_BOMB].AddTail(new CBomb(pShip1->GetPos().x+SHIP_WIDTH/2-BOMB_WIDTH/2, 3));
		break;
	case 'o':
	case 'O':	// throw bomb on left side
		if( m_Objects[MY_BOMB].GetCount()<MAX_BOMBNUM )
		m_Objects[MY_BOMB].AddTail(new CBomb(pShip1->GetPos().x-BOMB_WIDTH/2, 3));
		break;
	
	case 'p':
	case 'P':	// throw bomb on right side
		if( m_Objects[MY_BOMB].GetCount()<MAX_BOMBNUM )
		m_Objects[MY_BOMB].AddTail(new CBomb(pShip1->GetPos().x+SHIP_WIDTH-BOMB_WIDTH/2, 3));
		break;
	
	case 'b':
	case 'B':	// throw bomb on left side
		if( m_Objects[MY_BOMB].GetCount()<MAX_BOMBNUM )
		m_Objects[MY_BOMB].AddTail(new CBomb(pShip2->GetPos().x-BOMB_WIDTH/2, 3));
		break;
	
	case 'n':
	case 'N':	// throw bomb on right side
		if( m_Objects[MY_BOMB].GetCount()<MAX_BOMBNUM )
		m_Objects[MY_BOMB].AddTail(new CBomb(pShip2->GetPos().x+SHIP_WIDTH-BOMB_WIDTH/2, 3));
		break;
	}//switch

//	CWnd ::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CChildView::OnDestroy() 
{
	CWnd ::OnDestroy();
	
	// TODO: Add your message handler code here
	KillTimer(100);
}

void CChildView::OnGamepause() 
{
	// TODO: Add your command handler code here
	m_bGamePause = !m_bGamePause;  // toggle pause status
	CString strTitle;
	strTitle.LoadString(AFX_IDS_APP_TITLE);
	AfxGetMainWnd()->SetWindowText(m_bGamePause ? strTitle+_T(" - 暂停") : strTitle);
}

void CChildView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	if(m_bGamePause)
		return;
	if(m_Objects[MYSHIP].GetCount()==0)
		return;
//double "my ship"
	CMyShip* pShip1 = (CMyShip*)m_Objects[MYSHIP].GetHead();
	CMyShip* pShip2 = (CMyShip*)m_Objects[MYSHIP].GetTail();
	switch(nChar)
	{
	case 'a':
	case 'A':       // turn left
		if( pShip2->GetMotion() == -1 )       // turn left
			pShip2->SetMotion(0);
		break;
	case 'd':
	case 'D':		// turn right
		if( pShip2->GetMotion()==1 ) // turn right
			pShip2->SetMotion(0);
		break;
	case VK_LEFT:
		if( pShip1->GetMotion() == -1 )       // turn left
			pShip1->SetMotion(0);
		
		break;
	case VK_RIGHT:
		if( pShip1->GetMotion()==1 ) // turn right
			pShip1->SetMotion(0);
		
		break;
	}
	//	CWnd ::OnKeyUp(nChar, nRepCnt, nFlags);
}