⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 board.cpp

📁 一款自已开发的贪吃蛇游戏
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// ************************************************************
// The main board to display the game, it is a dynamic method
// to create the board by the Create(), 
//
// Author: Flowstar
// Date:   2002.12.09
//
// ************************************************************
// Board.cpp : implementation file
//

#include "stdafx.h"
#include "SnakeGame.h"
#include "Board.h"

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

const int SNAKE_COUNT = 36;  // the total snake cell count
const int BORDER_WIDTH = 5;
const int BTN_TOP = 175;
const int BTN_HEIGHT = 32;

const int GAME_SUM = 3;		// total game round + 1

int CBoard::m_nMidState = 0; // the background music is playing

/////////////////////////////////////////////////////////////////////////////
// CBoard

CBoard::CBoard():m_nSpeedLevel(0)
				,m_nScores(0)
				,m_nSnakeCount(0)
				,m_nDeadSum(0)
				,m_bSound(true)
				,m_nFlag(0)
				,m_nState(GAME_READY)
				,m_mtCurrent(MOVE_DOWN)
				,m_bBootGame(true)
				,m_bWinGame(true)
				,m_bReadyGame(false)
				,m_ptFlashCell(-1, -1)
				,m_picForeground(NULL)
				,m_picBackground(NULL)
				,m_pbmpPlayer(NULL)
				,m_nSpeed((10 - m_nSpeedLevel) * TIME_SPAN)
				,m_rtClientLeft(0, 0, COLS * WIDTH, ROWS * WIDTH)
{
//	m_nSpeedLevel	= 0;
//	m_nSpeed		= (10 - m_nSpeedLevel) * TIME_SPAN;
//	m_nScores		= 0;
//	m_nSnakeCount	= 1;
//	m_nDeadSum		= 0;
//	m_bSound		= true;
//	m_nFlag         = 0;
//	m_nState		= GAME_READY;
//	m_mtCurrent		= MOVE_DOWN;
//	m_bBootGame		= true;
//	m_bWinGame		= true;
//	m_bReadyGame	= false;
//	m_ptFlashCell.x = -1;
//	m_ptFlashCell.y = -1;
//
//	m_picForeground = NULL;
//	m_picBackground = NULL;
//	m_pbmpPlayer	= NULL;
//
//	m_Snake.RemoveAll();
//	m_rtClientLeft.SetRect(0, 0, COLS * WIDTH, ROWS * WIDTH);

	srand((unsigned)time(NULL));
	for (int nRow = 0; nRow < ROWS; nRow ++)
		for (int nCol = 0; nCol < COLS; nCol ++)
		{
			m_bData[nRow][nCol] = 0;
		}
}

CBoard::~CBoard()
{
	delete [] m_picForeground;
	delete [] m_picBackground;
	m_picForeground = NULL;
	m_picBackground = NULL;

	m_MidBk.Stop(false);
}


BEGIN_MESSAGE_MAP(CBoard, CStatic)
	//{{AFX_MSG_MAP(CBoard)
	ON_WM_TIMER()
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDD_BTN_SOUND, OnBtnSound)
	ON_BN_CLICKED(IDD_BTN_START, OnBtnStart)
	ON_BN_CLICKED(IDD_BTN_PAUSE, OnBtnPause)
	ON_BN_CLICKED(IDD_BTN_RESTART, OnBtnRestart)
	ON_BN_CLICKED(IDD_BTN_END, OnBtnEnd)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBoard message handlers

void CBoard::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	CDC *pDC = GetDC();
	int nRow, nCol;
	CPoint pt;

	switch (nIDEvent)
	{
	case TIMER_SNAKE:
		Move(m_mtCurrent);
		break;
	case TIMER_CELL:
		FlashCell(pDC, m_ptFlashCell);
		break;
	case TIMER_READY:
		{
			for (nRow = 0; nRow < ROWS; nRow ++)
				for (nCol = 0; nCol < COLS; nCol ++)
				{
					pt.x = nCol;
					pt.y = nRow;
					if (m_bData[nRow][nCol] == 1)
						DrawCell(pDC, pt, m_bReadyGame);
					else if ( m_bData[nRow][nCol] == 2)
						DrawCell(pDC, pt, !m_bReadyGame);
				}
				m_bReadyGame = !m_bReadyGame;
				break;
		}
	case TIMER_WIN:
		break;
	case TIMER_OVER:
		break;
	default:
		break;
	}
	ReleaseDC(pDC);

	CStatic::OnTimer(nIDEvent);
}

void CBoard::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	if (m_bBootGame)   // Draw only once
	{	
		CRect rtBoard;
		CBitmap bm;
		// Get background DC
		GetClientRect(&rtBoard);
		ClientToScreen(&rtBoard);
		m_dcBk.CreateCompatibleDC((CDC*)&dc);
		bm.CreateCompatibleBitmap((CDC*)&dc, rtBoard.Width(), rtBoard.Height());
		m_dcBk.SelectObject(&bm);
		m_dcBk.BitBlt(0, 0, rtBoard.Width(), rtBoard.Height(), (CDC*)&dc, 0, 0, SRCCOPY);
		m_bBootGame = false;

		// Get ForeGround DC
		CBitmap bmFr;
		m_picForeground->Render((CDC*)&dc, m_rtClient);
		m_dcFr.CreateCompatibleDC((CDC*)&dc);
		bmFr.CreateCompatibleBitmap((CDC*)&dc, rtBoard.Width(), rtBoard.Height());
		m_dcFr.SelectObject(&bmFr);
		m_dcFr.BitBlt(0, 0, rtBoard.Width(), rtBoard.Height(), (CDC*)&dc, 0, 0, SRCCOPY);
	}

	if (GetGameState() == GAME_READY)
	{
		CRect rtBoard;
		GetClientRect(&rtBoard);
		ClientToScreen(&rtBoard);
		dc.BitBlt(0, 0, rtBoard.Width(), rtBoard.Height(), &m_dcFr, 0, 0, SRCCOPY);
		ReadyGame();

		CRect rtReady(3 * WIDTH, (ROWS/3+1) * WIDTH, \
			(COLS-3) * WIDTH - 2, (ROWS/3+3) * WIDTH);
		CString sReady("Ready");
		DrawMyText(&dc, sReady, rtReady, 11);

		m_btnPause.SetWindowText("PAUSE");
	}

	if (GetGameState() == GAME_PAUSE)
	{
		m_btnPause.SetWindowText("CONTINUE");
	}

	if (GetGameState() == GAME_PLAYING)
	{
		m_btnPause.SetWindowText("PAUSE");
	}
		

	// -------------------------------------
	// Set the right view content
	CPen	penRed( PS_SOLID, 1, RGB(255,0,0) );
	CPen	penGreen( PS_SOLID, 1, RGB(0,255,0) );
	CPen	penBlue( PS_SOLID, 1, RGB(0,0,255) );
	CPen	*pOld = NULL;

	pOld = dc.SelectObject( &penRed );
	dc.MoveTo( WIDTH * COLS, 0 );
	dc.LineTo( WIDTH * COLS, WIDTH * ROWS);
	dc.SelectObject(&penGreen);
	dc.MoveTo( WIDTH * COLS + 1, 0 );
	dc.LineTo( WIDTH * COLS + 1, WIDTH * ROWS);
	dc.SelectObject( &penBlue );
	dc.MoveTo( WIDTH * COLS + 2, 0 );
	dc.LineTo( WIDTH * COLS + 2, WIDTH * ROWS);

	dc.SelectObject( pOld );
	penRed.DeleteObject();
	penGreen.DeleteObject();
	penBlue.DeleteObject();

	CRect rtScore(COLS * WIDTH, 5, (COLS+COL_CTL) * WIDTH, 25);
	CString sScore = "SCORE";
	DrawMyText((CDC*)&dc, sScore, rtScore);

	CRect rtSpeed(COLS * WIDTH, 55, (COLS+COL_CTL) * WIDTH, 75);
	CString sSpeed = "SPEED";
	DrawMyText((CDC*)&dc, sSpeed, rtSpeed);

	m_dpScore.SetNumber(m_nScores);
	m_dpSpeed.SetNumber(m_nSpeedLevel);

	//m_btnSound.DrawTransparent(true);
}

BOOL CBoard::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
{
	// TODO: Add your specialized code here and/or call the base class
	m_picForeground = new CPicture;
	m_picBackground = new CPicture;
	m_pbmpPlayer	= new CBitmap;
	if (m_picForeground == NULL || m_picBackground == NULL
		|| m_pbmpPlayer == NULL)
		return false;

	m_picForeground->Load(IDP_BACKGROUND);
	m_picBackground->Load(IDP_FOREGROUND);
	m_pbmpPlayer->LoadBitmap(IDB_PLAYER);
	
	m_dpScore.Create(this, (COLS+1) * WIDTH, 1*WIDTH+8, 0, 6);
	m_dpSpeed.Create(this, (COLS+2) * WIDTH+10, 4*WIDTH, 0, 2);

	
	return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}

int CBoard::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CStatic::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// TODO: Add your specialized creation code here
	// Draw the button list
	CRect rtSound((COLS + 1) * WIDTH-8, BTN_TOP, (COLS + 5) * WIDTH+12, BTN_TOP + BTN_HEIGHT);
	m_btnSound.Create("SOUND", WS_VISIBLE , rtSound, this, IDD_BTN_SOUND);
	m_btnSound.SetIcon(IDI_SOUND);
	m_btnSound.SetColor(3, RGB(255, 0, 253));
	m_btnSound.SetColor(1, RGB(  0,255,  0));
	m_btnSound.DrawTransparent();

	CRect rtStart((COLS + 1) * WIDTH-8, BTN_TOP + BTN_HEIGHT + BORDER_WIDTH, (COLS + 5) * WIDTH+12, BTN_TOP + BORDER_WIDTH + BTN_HEIGHT * 2 );
	m_btnStart.Create("START", WS_VISIBLE , rtStart, this, IDD_BTN_START);
	m_btnStart.SetIcon(IDI_START);
	m_btnStart.SetColor(3, RGB(255, 0, 253));
	m_btnStart.SetColor(1, RGB(  0,255,  0));
	m_btnStart.DrawTransparent();

	CRect rtPause((COLS + 1) * WIDTH-8, BTN_TOP + (BTN_HEIGHT + BORDER_WIDTH) * 2, (COLS + 5) * WIDTH+12, BTN_TOP + (BTN_HEIGHT + BORDER_WIDTH) * 3 - BORDER_WIDTH);
	m_btnPause.Create("PAUSE", WS_VISIBLE , rtPause, this, IDD_BTN_PAUSE);
	m_btnPause.SetIcon(IDI_PAUSE);
	m_btnPause.SetColor(3, RGB(255, 0, 253));
	m_btnPause.SetColor(1, RGB(  0,255,  0));
	m_btnPause.DrawTransparent();

	CRect rtRestart((COLS + 1) * WIDTH-8, BTN_TOP + (BTN_HEIGHT + BORDER_WIDTH) * 3, (COLS + 5) * WIDTH+12, BTN_TOP + (BTN_HEIGHT + BORDER_WIDTH) * 4 - BORDER_WIDTH);
	m_btnRestart.Create("RESTART", WS_VISIBLE , rtRestart, this, IDD_BTN_RESTART);
	m_btnRestart.SetIcon(IDI_RESTART);
	m_btnRestart.SetColor(3, RGB(255, 0, 253));
	m_btnRestart.SetColor(1, RGB(  0,255,  0));
	m_btnRestart.DrawTransparent();

	CRect rtEnd((COLS + 1) * WIDTH-8, BTN_TOP + (BTN_HEIGHT + BORDER_WIDTH) * 4, (COLS + 5) * WIDTH+12, BTN_TOP + (BTN_HEIGHT + BORDER_WIDTH) * 5 - BORDER_WIDTH);
	m_btnEnd.Create("END", WS_VISIBLE , rtEnd, this, IDD_BTN_END);
	m_btnEnd.SetIcon(IDI_END);
	m_btnEnd.SetColor(3, RGB(255, 0, 253));
	m_btnEnd.SetColor(1, RGB(  0,255,  0));
	m_btnEnd.DrawTransparent();
	
	m_MidBk.Create(IDR_MIDI_BK);
	//PlayBkMusic();
	//m_hMusic = AfxBeginThread((AFX_THREADPROC)PlayBkMusic, this, THREAD_PRIORITY_NORMAL);
	/*m_hMusic = */
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlayBkMusic, this, 0, NULL);
	return 0;
}

BOOL CBoard::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	GetClientRect(&m_rtClient);
	
	//pDC->FillRect(m_rtClient, &CBrush(GetSysColor(COLOR_3DFACE)));	
	if (m_bBootGame)
	{
		m_picBackground->Render(pDC,m_rtClient);
	}
	else
	{
		CRect rtBoard;
		GetClientRect(&rtBoard);
		ClientToScreen(&rtBoard);
		pDC->BitBlt(0, 0, rtBoard.Width(), rtBoard.Height(), &m_dcFr, 0, 0, SRCCOPY);
	}
		
	return CStatic::OnEraseBkgnd(pDC);
}


// ************************************************************
//				 Flowstar's Operation for the game 
// ************************************************************

void CBoard::DrawCell(CDC *pDC, CPoint ptCell, bool bErase)
{
	CPoint	ptTL, ptBR;  // the point of top and left, bottom and right
	
	// a fixed cell, asif a rectangle
	ptTL.x	= ptCell.x    *  WIDTH;
	ptTL.y	= ptCell.y    *  WIDTH;
	ptBR.x	= ptTL.x      +  WIDTH - 1;
	ptBR.y	= ptTL.y      +  WIDTH - 1;
	
	if( bErase ) // Draw background cell 
	{
		pDC->BitBlt(ptTL.x, ptTL.y, WIDTH, WIDTH, &m_dcBk, ptCell.x*WIDTH, ptCell.y*WIDTH, SRCCOPY);
		
		// =======================================================
		// Draw the 3D Face Border
		// =======================================================
		
		CPen	pnWhite( PS_SOLID, 1, RGB(255,255,255) );
		CPen	pnGray( PS_SOLID, 1, RGB(0,0,0) );
		CPen	*pOldPen = NULL;
		
		// draw top and left line 
		pOldPen = pDC->SelectObject( &pnWhite );
		pDC->MoveTo( ptTL.x, ptBR.y);
		pDC->LineTo( ptTL.x, ptTL.y);
		pDC->LineTo( ptBR.x, ptTL.y);
		
		// draw bottom and right line
		pDC->SelectObject( &pnGray );
		pDC->LineTo( ptBR.x, ptBR.y);
		pDC->LineTo( ptTL.x, ptBR.y);
		pDC->SelectObject( pOldPen );
	}
	else		 // Draw foreground cell
	{
		pDC->BitBlt(ptTL.x, ptTL.y, WIDTH, WIDTH, &m_dcFr, ptCell.x*WIDTH, ptCell.y*WIDTH, SRCCOPY);
	}

}

void CBoard::DrawCellF(CDC *pDC, CPoint ptCell, UINT nID, bool bErase)
{
	CPoint	ptTL, ptBR;  // the point of top and left, bottom and right
	CBrush	br(m_pbmpPlayer);
	CRect	rt;

	// a fixed cell, asif a rectangle
	ptTL.x	= ptCell.x    *  WIDTH;
	ptTL.y	= ptCell.y    *  WIDTH;
	ptBR.x	= ptTL.x      +  WIDTH - 1;
	ptBR.y	= ptTL.y      +  WIDTH - 1;
	rt.SetRect(ptTL, ptBR);

	if( bErase ) // Draw background cell 
	{
		//pDC->BitBlt(ptTL.x, ptTL.y, WIDTH, WIDTH, &m_dcBk, ptCell.x*WIDTH, ptCell.y*WIDTH, SRCCOPY);
		pDC->FillRect(&rt, &br);

		// =======================================================
		// Draw the 3D Face Border
		// =======================================================
		
		CPen	pnWhite( PS_SOLID, 1, RGB(255,255,255) );
		CPen	pnGray( PS_SOLID, 1, RGB(0,0,0) );
		CPen	*pOldPen = NULL;
		
		// draw top and left line 
		pOldPen = pDC->SelectObject( &pnWhite );
		pDC->MoveTo( ptTL.x, ptBR.y);
		pDC->LineTo( ptTL.x, ptTL.y);
		pDC->LineTo( ptBR.x, ptTL.y);
		
		// draw bottom and right line
		pDC->SelectObject( &pnGray );
		pDC->LineTo( ptBR.x, ptBR.y);
		pDC->LineTo( ptTL.x, ptBR.y);
		pDC->SelectObject( pOldPen );
	}
	else		 // Draw foreground cell
	{
		pDC->BitBlt(ptTL.x, ptTL.y, WIDTH, WIDTH, &m_dcFr, ptCell.x*WIDTH, ptCell.y*WIDTH, SRCCOPY);
	}

}

void CBoard::DrawSnake(CDC *pDC, bool bErase /*= true */, bool bAll /*= false*/)
{
	CPoint pt;
	POSITION pos;

	if (bAll)  // Draw the all snake
	{
		for (int i = 0; i < m_nSnakeCount; i ++)
		{
			pos = m_Snake.FindIndex(i);
			pt = m_Snake.GetAt(pos);
			DrawCell(pDC, pt, bErase);
		}
		return;
	}

	if (bErase) // Draw the head and tail cell
	{
		pos = m_Snake.FindIndex(0);
		pt = m_Snake.GetAt(pos);
	}
	else
	{
		pos = m_Snake.FindIndex(m_nSnakeCount-1);
		pt  = m_Snake.GetAt(pos);
	}
	DrawCell(pDC, pt, bErase);
}

void CBoard::DrawPlayers(int nPlayer, bool bErase)
{
	int nPlayers;
	CPoint pt(COLS + 1, 6);
	CDC *pDC = GetDC();
	
	if (nPlayer > 4)
		nPlayers = 4;
	else
		nPlayers = nPlayer;
	
	// Draw the players
	for (int i = 0; i < nPlayers; i ++){
		DrawCellF(pDC, pt, IDB_PLAYER, bErase);
		pt.x ++;
	}
	ReleaseDC(pDC);
}

void CBoard::FlashCell(CDC *pDC, CPoint pt)
{
	if (pt.x == -1 && pt.y == -1)
		return;
	m_nFlag = (m_nFlag + 1) % 2;
	if (m_nFlag == 0)
	{
		DrawCell(pDC, pt, true);
		if (m_nState == GAME_PAUSE)
			DrawCell(pDC, m_ptHead, false);
	}
	else
	{
		DrawCell(pDC, pt , false);
		if (m_nState == GAME_PAUSE)
			DrawCell(pDC, m_ptHead, true);
	}

}

void CBoard::SetScores(int nScore) 
{
	m_dpScore.SetNumber(nScore);
}

void CBoard::SetSpeed(int nSpeed, bool bRestart /*= true*/)
{
	for (int i = 0; i < nSpeed; i ++)
	{
		SpeedUp(bRestart);
	}
}

//int	CBoard::GetGameState() const
//{
//	return m_nState;


// =============================================================
// 根据参数 MOVETYPE 来进行相应的移动
// =============================================================
void CBoard::Move(MOVETYPE movetype)
{
	m_mtPrevious = m_mtCurrent;
	m_mtCurrent = movetype;

	// protect backword to dead
	switch (movetype)
	{
	case MOVE_LEFT:
		if (m_mtPrevious == MOVE_RIGHT)
			MoveBackword();
		break;
	case MOVE_RIGHT:
		if (m_mtPrevious == MOVE_LEFT)
			MoveBackword();
		break;
	case MOVE_UP:
		if (m_mtPrevious == MOVE_DOWN)
			MoveBackword();
		break;
	case MOVE_DOWN:
		if (m_mtPrevious == MOVE_UP)
			MoveBackword();
		break;
	default:
		break;
	}

	CPoint ptLocal;
	ptLocal.x = m_ptHead.x;
	ptLocal.y = m_ptHead.y;
	CDC *pDC = GetDC();

	switch (m_mtCurrent)
	{
	case MOVE_LEFT:
		ptLocal.x --;
		if (EatAgg(ptLocal)){ // judge the foreward cell is or not the egg
			DrawSnake(pDC, true, true);
			return;
		}
			
		if (ValidateMoving(ptLocal))
		{
			DrawSnake(pDC, false);
			SwapSnakeCell(ptLocal);
			DrawSnake(pDC, true);
		}
		else
			EndGame();
		break;
	case MOVE_RIGHT:
		ptLocal.x ++;
		if (EatAgg(ptLocal)){
			DrawSnake(pDC, true, true);
			return;
		}
		
		if (ValidateMoving(ptLocal))
		{
			DrawSnake(pDC, false);
			SwapSnakeCell(ptLocal);
			DrawSnake(pDC, true);
		}
		else
			EndGame();
		break;
	case MOVE_UP:
		ptLocal.y --;
		if (EatAgg(ptLocal)){
			DrawSnake(pDC, true, true);
			return;
		}
		
		if (ValidateMoving(ptLocal))
		{
			DrawSnake(pDC, false);
			SwapSnakeCell(ptLocal);
			DrawSnake(pDC, true);
		}
		else
			EndGame();
		break;
	case MOVE_DOWN:
		ptLocal.y ++;
		if (EatAgg(ptLocal)){
			DrawSnake(pDC, true, true);
			return;
		}
		
		if (ValidateMoving(ptLocal))
		{
			DrawSnake(pDC, false);
			SwapSnakeCell(ptLocal);
			DrawSnake(pDC, true);
		}
		else
			EndGame();
		break;
	default:
		break;
	}
	ReleaseDC(pDC);
}

bool CBoard::ValidateMoving(CPoint pt)
{
	if (pt.x < 0 || pt.y < 0 || pt.x > COLS-1 || pt.y > ROWS-1)
		return false;

	m_nSnakeCount = m_Snake.GetCount();
	CPoint ptLocal;
	POSITION pos;

	for (int i = 0; i < m_nSnakeCount; i ++)
	{
		pos = m_Snake.FindIndex(i);
		ptLocal = m_Snake.GetAt(pos);
		if (pt.x == ptLocal.x && pt.y == ptLocal.y){
			return false;
		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -