📄 gamebo~1.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// This file is part of the completely free tetris clone "CGTetris".
//
// This is free software.
// You may redistribute it by any means providing it is not sold for profit
// without the authors written consent.
//
// No warrantee of any kind, expressed or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
/////////////////////////////////////////////////////////////////////////////
// GameBoard.cpp : implementation file
//
#include "stdafx.h"
#include "Tetris.h"
#include "GameBoard.h"
#include "Piece.h"
#include "MemDC.h"
#include "VolumeCtrl.h"
#include <stdlib.h>
#include <time.h>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static CGameBoard * gpGameBoard;
CGameBoard * TetrisGetGameBoard() { return gpGameBoard; }
static UINT guBoomArray[] = {
IDI_Boom_1,
IDI_Boom_2,
IDI_Boom_3,
IDI_Boom_4,
IDI_Boom_5,
IDI_Boom_6,
IDI_Boom_7,
IDI_Boom_8,
IDI_Boom_9,
IDI_Boom_10,
};
#define ENDVEC( vector ) (vector-1+sizeof(vector)/sizeof(vector[0]))
/////////////////////////////////////////////////////////////////////////////
// CGameBoard
BOOL CGameBoard :: m_bRegistered = Register();
IMPLEMENT_DYNAMIC(CGameBoard, CWnd);
CGameBoard::CGameBoard()
{
m_pCurPiece = m_pNextPiece = 0;
m_usLevel = 0;
m_clrCurPiece = RGB(0,0,0);
m_bShowGrid = TRUE;
m_nSquareWidth = 14;
m_nSquareHeight = 14;
m_clrBackground = RGB(255, 255, 255);
m_bExFigures = FALSE;
m_pMusic = 0;
m_uTimer = 0;
m_dwVolume = 100; // 100% music volume by default
gpGameBoard = this;
}
CGameBoard::~CGameBoard()
{
if(m_pCurPiece)
delete m_pCurPiece;
if(m_pNextPiece)
delete m_pNextPiece;
if( m_pMusic )
delete m_pMusic;
gpGameBoard = 0;
}
BOOL CGameBoard :: Register()
{
WNDCLASS wc;
wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = GameBoardWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = 0;
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = 0;
wc.lpszClassName = TEXT("TetrisGameBoard");
VERIFY(RegisterClass(&wc));
return TRUE;
}
BEGIN_MESSAGE_MAP(CGameBoard, CWnd)
//{{AFX_MSG_MAP(CGameBoard)
ON_WM_PAINT()
ON_WM_TIMER()
ON_WM_NCDESTROY()
ON_WM_CREATE()
ON_WM_ERASEBKGND()
ON_WM_KEYDOWN()
ON_WM_KEYUP()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_MIDI_VOLUMECHANGED, OnVolumeChanged)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGameBoard message handlers
void CGameBoard::ShowGrid(BOOL bShow)
{
m_bShowGrid = bShow;
}
void CGameBoard :: Paint()
{
Invalidate();
//UpdateWindow();
OnPaint(); // force an immediately paint
}
void CGameBoard :: OnPaint()
{
CPaintDC pdc(this); // device context for painting
CMemDC dc(&pdc);
COLORREF clrTopLeft = ::GetSysColor(COLOR_BTNHILIGHT);
COLORREF clrBottomRight = ::GetSysColor(COLOR_BTNSHADOW);
CRect rect;
GetClientRect(rect);
dc.FillSolidRect(0, 0, rect.Width(), rect.Height(), m_clrBackground);
register const UINT uWidth = Width(rect);
register const UINT uHeight = Height(rect);
// paint the board itself
for( register UINT i=0; i<uHeight; ++i )
for( register UINT j=0; j<uWidth; ++j ) {
if( m_Board[i][j] != m_clrBackground ) {
dc.FillSolidRect(j*m_nSquareWidth, i*m_nSquareHeight, m_nSquareWidth, m_nSquareHeight, m_Board[i][j]);
dc.Draw3dRect(j*m_nSquareWidth, i*m_nSquareHeight, m_nSquareWidth, m_nSquareHeight, clrTopLeft, clrBottomRight);
}
}
// now paint the current piece ...
if( m_pCurPiece != 0 ) {
register const int nLines = m_pCurPiece->GetLines();
register const int nCols = m_pCurPiece->GetColumns();
for( register int l = nLines-1 ; l >= 0 ; --l )
for( register int c = 0 ; c < nCols ; ++c ) {
int nL = m_nCurLine - ((nLines-1) & l);
int nC = m_nCurCol + c;
if( nL >= 0 && nL < Height() &&
nC >= 0 && nC < Width() )
if( m_pCurPiece->IsSquare(l, c) ) {
dc.FillSolidRect(nC*m_nSquareWidth, nL*m_nSquareHeight, m_nSquareWidth, m_nSquareHeight, m_clrCurPiece);
dc.Draw3dRect(nC*m_nSquareWidth, nL*m_nSquareHeight, m_nSquareWidth, m_nSquareHeight, clrTopLeft, clrBottomRight);
}
}
}
// draw the grid
if( m_bShowGrid ) {
// draw vertical lines
for( register h = m_nSquareWidth; h < rect.Width(); h += m_nSquareWidth ) {
dc.MoveTo(h, 0);
dc.LineTo(h, rect.bottom);
}
// draw horizontal lines
for( register v = m_nSquareHeight; v < rect.Height(); v += m_nSquareHeight ) {
dc.MoveTo(0, v);
dc.LineTo(rect.right, v);
}
}
}
void CGameBoard::SetDimension(int nWidth, int nHeight)
{
m_nSquareWidth = nWidth;
m_nSquareHeight = nHeight;
}
void CGameBoard::GetDimension(int & nWidth, int & nHeight)
{
nWidth = m_nSquareWidth;
nHeight = m_nSquareHeight;
}
int CGameBoard::Width(LPCRECT pRect) const
{
CRect rect(pRect ? pRect : CRect(0,0,0,0));
if( ! pRect )
GetClientRect(rect);
return rect.Width() / m_nSquareWidth;
}
int CGameBoard::Height(LPCRECT pRect) const
{
CRect rect(pRect ? pRect : CRect(0,0,0,0));
if( ! pRect )
GetClientRect(rect);
return rect.Height() / m_nSquareHeight;
}
void CGameBoard::InitBoard()
{
CRect rect;
GetClientRect(rect);
register const int nHeight = Height(rect);
register const int nWidth = Width(rect);
m_Board.resize(nHeight, vector<COLORREF>());
for( register int i=0; i<nHeight; ++i ) {
m_Board[i].resize(nWidth, m_clrBackground);
for( register int j=0; j<nWidth; ++j )
m_Board[i][j] = m_clrBackground;
}
m_ulCompleteLines = 0;
m_usLevel = 0;
m_ulPieces = 0;
m_uPoints = 0;
if( m_uTimer )
KillTimer(m_uTimer);
m_uTimer = 0;
if( m_pCurPiece )
delete m_pCurPiece;
m_pCurPiece = 0;
if( m_pNextPiece )
delete m_pNextPiece;
m_pNextPiece = SelectPiece();
NotifyParent();
Paint();
}
void CGameBoard::MoveLeft() {
ASSERT(m_pCurPiece); // make sure we're inside a game
if( CanPlace(m_nCurLine, m_nCurCol-1) ) {
--m_nCurCol;
m_SndKey.Play();
}
}
void CGameBoard::MoveRight() {
ASSERT(m_pCurPiece); // make sure we're inside a game
if( CanPlace(m_nCurLine, m_nCurCol+1) ) {
++m_nCurCol;
m_SndKey.Play();
}
}
void CGameBoard::Rotate() {
ASSERT(m_pCurPiece); // make sure we're inside a game
m_pCurPiece->Rotate();
if( ! CanPlace(m_nCurLine, m_nCurCol) )
m_pCurPiece->BackRotate();
else
m_SndKey.Play();
}
void CGameBoard::BackRotate() {
ASSERT(m_pCurPiece); // make sure we're inside a game
m_pCurPiece->BackRotate();
if( ! CanPlace(m_nCurLine, m_nCurCol) )
m_pCurPiece->Rotate();
else
m_SndKey.Play();
}
void CGameBoard::StartFall() {
if( m_uTimer ) {
m_SndKey.Play();
ResetTimer(TRUE); // increase speed to maximum
}
}
void CGameBoard::StopFall() {
if( m_uTimer )
ResetTimer(); // restore speed
}
void CGameBoard::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if( m_pCurPiece ) {
switch(nChar) {
case VK_LEFT:
case VK_NUMPAD4:
MoveLeft();
break;
case VK_RIGHT:
case VK_NUMPAD6:
MoveRight();
break;
case VK_UP:
case VK_NUMPAD8:
case VK_NUMPAD5:
Rotate();
break;
case VK_DOWN:
case VK_NUMPAD2:
BackRotate();
break;
case VK_SPACE:
case VK_NUMPAD0:
if( !(nFlags & (1<<14)) ) {
// the key was not down before
StartFall();
}
break;
case VK_ADD:
case VK_SUBTRACT:
case TCHAR('+'):
case TCHAR('-'):
if( m_pMusic ) {
CVolumeCtrl dlg(m_pMusic);
dlg.DoModal();
m_dwVolume = dlg.GetVolume();
}
break;
}
}
Paint();
CWnd::OnChar(nChar, nRepCnt, nFlags);
}
void CGameBoard::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if(nChar == VK_SPACE || nChar == VK_NUMPAD0) {
if( (nFlags & (1<<14)) ) {
// the key was down before
StopFall();
}
} else
CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}
bool CGameBoard::CanPlace(int nLine, int nCol)
{
ASSERT( m_pCurPiece != 0 );
register const int nCols = m_pCurPiece->GetColumns();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -