📄 board.cpp
字号:
// ************************************************************
// 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 + -