Nura Quadris – 杀时间电脑游戏






3.55/5 (7投票s)
对一款熟悉的游戏有不同的看法。

目录
- 引言
- 背景
- 源代码
- 环境
- 使用代码
- 整体结构
- CMainFrame 和 CQuadrisWTLView 类
- QuadrisWindowWTL 类
- QuadrisWindowWTL 的用户定义消息 NM_QUADRIS (= UM_QUADRIS)
- NextWindow 类
- QuadrisCore 类
- 如何支持 Win95、Win98、Win98SE 和 WinME
- 如何嵌入帮助功能
- 关注点
- Quadris 自定义工具
- 致谢
引言
Nura Quadris 的名称
Nura Quadris 是一款电脑游戏,用户必须堆叠砖块并填满一整行或多行来清除它们。当我们像打保龄球时一次击倒所有瓶子一样,一次清除四行时,我们称之为“Quadris”。Nura 是我妻子的名字。所以,我将我的程序命名为 Nura Quadris。Nur 在阿拉伯语中是光的意思,而 -a 是一个女性后缀,所以 Nura 可以指“明亮的女士”。这是中东地区非常流行的女性阿拉伯名字。
Nura Quadris 的规则
Nura Quadris 的规则与普通 Quadris 游戏的规则相同。规则如下:
- 一块砖由四个方块组成。
- 当一块砖落下时,你必须旋转它和/或左右移动它,使其在落在已堆叠的砖块上之前与它们吻合。
- 当它落在已堆叠的砖块上时,如果一整行或多行被完全填满,则已填满的行将被清除,堆叠在已清除行上的砖块将下落以填补空行。
- 然后,一块新砖将落下。
Nura Quadris 的功能
- 它会自动检测 Windows 的语言,并以韩语或英语显示所有说明。如果您的 Windows 是韩语 Windows,它将处于韩语模式;如果是非韩语 Windows,它将处于英语模式。但是,您可以使用 NuraQuadris.ini 将 Nura Quadris 自定义为您自己的语言。您可以使用 QuadrisCustomizer.exe 生成 NuraQuadris.ini。我稍后会介绍 QuadrisCustomizer.exe。
- 它具有显示辅助网格的选项。默认情况下不显示网格。
- 它具有发出声音的选项。默认情况下会发出声音。
- 它具有提前显示下一块砖的选项。默认情况下会提前显示下一块砖。
- 在开始游戏之前,如果您按下“F1”键,您可以获取帮助信息。如果您按下“F12”键,将弹出一个“关于”消息框。您可以在其中看到有关 Nura Quadris 的简单信息。
Nura Quadris 的使用
- 要开始游戏,点击“开始”按钮。
- 游戏过程中,如果您想取消游戏,点击“取消”按钮。
- 在游戏过程中,如果您想暂停游戏,请点击“暂停”按钮。然后,如果您想继续游戏,请点击“继续”按钮。
- 如果您想要辅助网格,请勾选“网格”选项。
- 如果您不想要声音,请勾选“静音”选项。
- 按向上箭头键旋转砖块。
- 按向左箭头键向左移动砖块。
- 按向右箭头键向右移动砖块。
- 按向下箭头键更快地向下移动砖块。
- 按空格键将砖块快速落到底部。
背景
它包含五部分:一个 Quadris 引擎、一个类似控件的窗口、一个下一个窗口、一个视图窗口和一个皮肤窗口。我将在本文中对这些部分进行简要描述。我使用了设计模式:桥接模式(确切地说,是桥接模式的修改版本),但我在这里不解释设计模式。
源代码
此源代码使用 WTL 库。源代码包含四个项目:QuadrisCore、QuadrisWindowWTL、NuraQuadris(在 QuadrisWTL 文件夹中)和 QuadrisCustomizer。项目 QuadrisCore 是 Quadris 引擎的库。QuadrisWindowWTL 是 WTL 的 Quadris 窗口的类似控件的窗口。项目 NuraQuadris 是可执行项目,它实际上是一个 Quadris 游戏程序。但是,它不使用 Quadris 窗口的库,而是为了简化问题,直接使用 Quadris 窗口和 Quadris 核心的源代码。最后,项目 QuadrisCustomizer 是一个可执行项目,它是 NuraQuadris 的语言自定义工具。
环境
Nura Quadris 是使用 VC++ .NET 2003 Standard Edition SP1(以下简称 VC++ 7.1)和 WTL 8.0 创建的。除非网站更改,您可以此处获取 WTL 8.0。它主要在 Windows XP SP2、Windows 2000 SP4 和 Windows 98 SE 下进行了测试。要编译源代码,您需要安装 WTL。此外,它可以使用 VC++ 2005 Express Edition(以下简称 VC++ 8.0X)或 VC++ 2008 Express Edition(以下简称 VC++ 9.0X)进行编译。当然,您在编译之前必须采取一些步骤。关于使用 VC++ 8.0X 进行 Windows 编程的信息此处,关于 VC++ 8.0X 的 WTL 安装信息此处。要在 VC++ 9.0X 中通过创建 WTL-App 向导使用 WTL 8.0,请将 setup90x.js 放入已安装的 WTL 8.0 的“AppWiz”文件夹并使用它,这是我通过修改 setup80x.js 创建的。为了使其能够与使用 ATL 3.0 的 VC++ 8.0X 或 VC++ 9.0X 进行编译,我创建了 ATLVersion.h 并将其包含在 stdafx.h 中。Quadris.sln 用于 VC++ 7.1,而 Quadris2008.sln 用于 VC++ 9.0X。QuadrisWTL.vcproj 用于 VC++ 7.1,而 QuadrisWTL2008.vcproj 用于 VC++ 9.0X。解决方案文件 (*.sln) 和项目文件 (*.vcproj) 的所有文件名约定与上述示例相同。
Using the Code
整体结构
我已经提到 Nura Quadris 由五部分组成:一个 Quadris 引擎、一个类似控件的窗口、一个下一个窗口、一个视图窗口和一个皮肤窗口。皮肤窗口本身是一个 SDI 应用程序框架,它包含一个视图窗口作为其子窗口。皮肤窗口由 CMainFrame
类实现。视图窗口包含类似控件的窗口和下一个窗口作为其子窗口,它由 CQuadrisWTLView
类实现。类似控件的窗口是 Quadris 游戏窗口本身,由 QuadrisWindowWTL
类实现。我之所以称此窗口为类似控件的窗口,是因为此窗口实际上不是一个控件,但它具有控件的功能。类似控件的窗口包含 Quadris 引擎。Quadris 引擎由 QuadrisCore
类实现。下一个窗口是显示下一个方块的窗口,在 Quadris 游戏进行时提前显示,由 NextWindow
类实现。
CMainFrame 和 CQuadrisWTLView 类
CMainFrame
和 CQuadrisWTLView
类由 WTL-App Wizard 提供,我在此基础上进行了编码。CQuadrisWTLView
从 QuadrisWindowWTL
接收用户定义消息 NM_QUADRIS
(在本例中为 UM_QUADRIS
)。其成员函数 OnQuadrisMessage
将处理消息 UM_QUADRIS
。以下代码与用户定义消息 UM_QUADRIS
的处理有关。
LRESULT CQuadrisWTLView::OnQuadrisMessage (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case TN_NEXT: OnNext(lParam); break;
case TN_PURGE: OnPurge((int) lParam); break;
case TN_FINISH: OnFinish((int) lParam); break;
//case TN_LEVEL: break;
//case TN_PAUSE: break;
//case TN_CONTINUE: break;
//case TN_START: break;
//case TN_STOP: break;
//case TN_GRID: break;
//case TN_SOUND: break;
}
return 0;
}
void CQuadrisWTLView::OnPurge (int lines)
{
TCHAR str[STRINGMAX];
_stprintf(str, m_strScore, m_pQuadris->GetScore());
m_Score.SetWindowText(str);
}
void CQuadrisWTLView::OnFinish (int score)
{
m_Start.ShowWindow(SW_SHOW);
m_Cancel.ShowWindow(SW_HIDE);
m_Pause.ShowWindow(SW_HIDE);
m_Continue.ShowWindow(SW_HIDE);
m_pNext->PostMessage(UM_QUADRIS, TN_FINISH, (LPARAM) score);
}
void CQuadrisWTLView::OnNext (LPARAM lParam)
{
m_pNext->PostMessage(UM_QUADRIS, TN_NEXT, lParam);
}
它还通过按钮和复选框接收用户的指令。如果您想将语言设置为英语,而不考虑 Windows 的系统语言,请取消注释 QuadrisWTL 文件夹中 stdafx.h 文件第 62 行的语句,如下所示:
#define Quadris_LANG LANG_ENGLISH
QuadrisWindowWTL 类
它使用了一个用户定义的消息:NM_QUADRIS
(确切地说,在本例中是 m_Message
或 UM_QUADRIS
)。每当有新方块落下和/或当完全填满的行被清除时,QuadrisWindowWTL
都会向 QuadrisWTLView
发送 NM_QUADRIS
。当游戏结束时,它也会向 QuadrisWTLView
发送 NM_QUADRIS
。为了避免 QuadrisWTLView
中的消息冲突,QuadrisWindowWTL
的构造函数可以接收 NM_QUADRIS
用户定义消息的不同值作为参数,并将其保存在 m_Message
中。QuadrisWindowWTL
与 QuadrisWTLView
的耦合非常松散。QuadrisWindowWTL
的公共成员函数如下:
class QuadrisWindowWTL : public CWindowImpl<QuadrisWindowWTL>
{
...
public:
QuadrisWindowWTL (UINT message = NM_QUADRIS, bool bAuto = true);
QuadrisWindowWTL (UINT message, int lang, bool bAuto);
virtual ~QuadrisWindowWTL (void);
...
inline bool Start (void) { return StartStop(true); }
inline bool Stop (void) { return StartStop(false); }
inline bool Pause (void) { return PauseContinue(true); }
inline bool Continue (void) { return PauseContinue(false); }
inline int GetScore (void) { return m_pQuadris->GetScore(); }
inline int GetLevel (void) { return m_Level; }
inline void SetGrid (bool bGrid = true) { m_bGrid = bGrid; }
inline void SetSound (bool bSound = true) { m_bSound = bSound; }
inline int GetSpeed (void) { return m_Interval; }
bool SetSpeed (int interval);
// The reason why there is no function Create (..., const RECT* pRect, ...)
// or Create (..., const POINT* pPt, ...) is to prevent a null pointer parameter.
HWND Create (HWND hParentWnd, int x, int y, UINT nID);
HWND Create (HWND hParentWnd, const POINT& pt, UINT nID);
HWND Create (HWND hParentWnd, int x, int y, int nWidth, int nHeight, UINT nID);
HWND Create (HWND hParentWnd, const RECT& rect, UINT nID);
HWND Create (HWND hParentWnd, int x, int y,
DWORD dwStyle, DWORD dwExStyle, UINT nID);
HWND Create (HWND hParentWnd, const POINT& pt,
DWORD dwStyle, DWORD dwExStyle, UINT nID);
HWND Create (HWND hParentWnd, int x, int y, int nWidth, int nHeight,
DWORD dwStyle, DWORD dwExStyle, UINT nID);
HWND Create (HWND hParentWnd, const RECT& rect,
DWORD dwStyle, DWORD dwExStyle, UINT nID);
// The reason why there is no function Move (..., const RECT* pRect, ...)
// or Move (..., const POINT* pPt, ...) is to prevent a null pointer parameter.
BOOL Move (int x, int y, BOOL bRepaint = TRUE);
BOOL Move (POINT& pt, BOOL bRepaint = TRUE);
BOOL Move (int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE);
BOOL Move (RECT& rect, BOOL bRepaint = TRUE);
...
}
QuadrisWindowWTL (UINT message = NM_QUADRIS, bool bAuto = true);
- 这是一个构造函数。
- 第一个参数
message
是QuadrisWindowWTL
将发送到父窗口的消息。为了避免消息冲突,您可以为该消息提供不同的值。默认值为NM_QUADRIS
。 - 第二个参数是它是否自行处理结束进程。如果第二个参数
bAuto
设置为true
,它将不会向父窗口发送NM_QUADRIS
(或您指定的消息),它将处理结束进程。默认值为true
。 - 语言将根据 Windows 的默认系统语言自动选择。
QuadrisWindowWTL (UINT message, int lang, bool bAuto);
- 这是另一个构造函数。
- 第一个和第三个参数与上述相同。
- 第二个参数
lang
用于语言。如果您将其设置为LANG_ENGLISH
,无论 Windows 的默认语言如何,它都将使用韩语。
inline bool Start (void);
- 它使 Quadris 游戏开始。
- 当游戏开始时返回值为
true
,失败时返回值为false
。
inline bool Stop (void);
- 它使 Quadris 游戏停止。
- 当游戏停止时返回值为
true
,失败时返回值为false
。
inline bool Pause (void);
- 它使 Quadris 游戏暂停。
- 当游戏暂停时返回值为
true
,失败时返回值为false
。
inline bool Continue (void);
- 它使 Quadris 游戏继续。
- 当游戏继续时返回值为
true
,失败时返回值为false
。
inline int GetScore (void);
- 它给出 Quadris 游戏的当前分数。
- 返回值为当前分数。
inline int GetLevel (void);
- 它给出 Quadris 游戏的当前级别。
- 返回值为当前级别。
inline void SetGrid (bool bGrid = true);
- 它决定 Quadris 窗口是否具有辅助网格。
- 如果参数
bGrid
为true
,Quadris 窗口将具有辅助网格。如果参数bGrid
为false
,Quadris 窗口将不具有辅助网格。
inline void SetSound (bool bSound = true);
- 它决定 Quadris 窗口是否发出音效。
- 如果参数
bSound
为true
,Quadris 窗口将发出音效。如果参数bSound
为false
,Quadris 窗口将不发出音效。
inline int GetSpeed (void);
- 它给出 Quadris 游戏的当前速度。
- 返回值为当前速度。
bool SetSpeed (int interval);
- 它设置速度。
- 参数
interval
是移动之间的间隔。单位是毫秒。
HWND Create (HWND hParentWnd, const RECT& rect, DWORD dwStyle, DWORD dwExStyle, UINT nID);
- 它创建 Quadris 类似控件的窗口。其窗口类名为
Quadris_CLASS
,ASCII 码定义为 "Quadris",UNICODE 定义为 L"Quadris"。 - 返回值为 Quadris 窗口的句柄。
- 第一个参数
hParentWnd
是其父窗口的窗口句柄。 - 第二个参数
rect
是 Quadris 窗口矩形的引用。 - 第三个参数
dwStyle
是 Quadris 窗口的窗口样式。 - 第四个参数
dwExStyle
是 Quadris 窗口的扩展窗口样式。 - 第五个参数
nID
是赋予 Quadris 窗口的 ID。
HWND Create (HWND hParentWnd, const POINT& pt, DWORD dwStyle, DWORD dwExStyle, UINT nID);
- 它创建 Quadris 类似控件的窗口。其窗口类名为
Quadris_CLASS
,ASCII 码定义为 "Quadris",UNICODE 定义为 L"Quadris"。 - 返回值为 Quadris 窗口的句柄。
- 第一个参数
hParentWnd
是其父窗口的窗口句柄。 - 第二个参数
pt
是 Quadris 窗口左上角的引用。其宽度和高度都将确定为 400 像素。 - 第三个参数
dwStyle
是 Quadris 窗口的窗口样式。 - 第四个参数
dwExStyle
是 Quadris 窗口的扩展窗口样式。 - 第五个参数
nID
是赋予 Quadris 窗口的 ID。
HWND Create (HWND hParentWnd, const RECT& rect, UINT nID);
- 它创建 Quadris 类似控件的窗口。其窗口类名为
Quadris_CLASS
,ASCII 码定义为 "Quadris",UNICODE 定义为 L"Quadris"。 - 返回值为 Quadris 窗口的句柄。
- 第一个参数
hParentWnd
是其父窗口的窗口句柄。 - 第二个参数
rect
是 Quadris 窗口矩形的引用。 - 第三个参数
nID
是赋予 Quadris 窗口的 ID。 - Quadris 窗口的样式和扩展样式默认都为
NULL
。
HWND Create (HWND hParentWnd, const POINT& pt, UINT nID);
- 它创建 Quadris 类似控件的窗口。其窗口类名为
Quadris_CLASS
,ASCII 码定义为 "Quadris",UNICODE 定义为 L"Quadris"。 - 返回值为 Quadris 窗口的句柄。
- 第一个参数
hParentWnd
是其父窗口的窗口句柄。 - 第二个参数
pt
是 Quadris 窗口左上角的引用。其宽度和高度都将确定为 400 像素。 - 第三个参数
nID
是赋予 Quadris 窗口的 ID。 - Quadris 窗口的样式和扩展样式默认都为
NULL
。
BOOL Move (int x, int y, BOOL bRepaint = TRUE);
- 它将窗口移动到指定位置。
- 如果成功,返回值为
true
;如果失败,返回值为false
。 - 第一个和第二个参数
x
和y
是 Quadris 窗口的左上角位置。 - 第三个参数
bRepaint
与 Quadris 窗口移动时是否重绘有关。如果bRepaint
为 true,则 Quadris 窗口将被重绘。如果bRepaint
为 false,则 Quadris 窗口将不被重绘。bRepaint
的默认值为true
。 - Quadris 窗口的宽度和高度将保持不变。
BOOL Move (POINT& pt, BOOL bRepaint = TRUE);
- 它将窗口移动到指定位置。
- 如果成功,返回值为
true
;如果失败,返回值为false
。 - 第一个参数
pt
是 Quadris 窗口的左上角位置。 - 第二个参数
bRepaint
与 Quadris 窗口移动时是否重绘有关。如果bRepaint
为true
,则 Quadris 窗口将被重绘。如果bRepaint
为false
,则 Quadris 窗口将不被重绘。bRepaint
的默认值为true
。 - Quadris 窗口的宽度和高度将保持不变。
BOOL Move (int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE);
- 它将窗口移动到指定位置。
- 如果成功,返回值为
true
;如果失败,返回值为false
。 - 第一个、第二个、第三个和第四个参数
x
、y
、nWidth
、nHeight
是 Quadris 窗口的位置。 - 第五个参数
bRepaint
与 Quadris 窗口移动时是否重绘有关。如果bRepaint
为true
,则 Quadris 窗口将被重绘。如果bRepaint
为false
,则 Quadris 窗口将不被重绘。bRepaint
的默认值为true
。
BOOL Move (RECT& rect, BOOL bRepaint = TRUE);
- 它将窗口移动到指定位置。
- 如果成功,返回值为
true
;如果失败,返回值为false
。 - 第一个参数
rect
是 Quadris 窗口位置的引用。 - 第二个参数
bRepaint
与 Quadris 窗口移动时是否重绘有关。如果bRepaint
为true
,则 Quadris 窗口将被重绘。如果bRepaint
为false
,则 Quadris 窗口将不被重绘。bRepaint
的默认值为true
。
Create(...) 和 Move(...) 的模式与 Nura Tritris 的模式相同。我更喜欢 Create(...) 和 Move(...) 函数的这些模式。
QuadrisWindowWTL 的用户定义消息 NM_QUADRIS (= UM_QUADRIS)
用户定义消息 NM_QUADRIS(在此例中为 UM_QUADRIS)以 WPARAM 作为通知码,LPARAM 作为与通知码相关的信息。通知码在 QuadrisWindowWTL.h 中定义。通知码如下:
<< 用户定义消息 NM_QUADRIS (= UM_QUADRIS) 表 >>
WPARAM (通知码) |
LPARAM |
描述 |
TN_FINISH |
分数 |
通知游戏结束 |
TN_NEXT |
用于下一个窗口进行双缓冲的 HDC |
通知下一个方块 |
TN_PURGE |
清除的行数 |
通知清除行 |
TN_LEVEL |
新级别 |
留作将来使用 |
TN_START |
尚未确定 |
留作将来使用 |
TN_STOP |
尚未确定 |
留作将来使用 |
TN_PAUSE |
尚未确定 |
留作将来使用 |
TN_CONTINUE |
尚未确定 |
留作将来使用 |
TN_GRID |
尚未确定 |
留作将来使用 |
TN_SOUND |
尚未确定 |
留作将来使用 |
TN_SHOWNEXT |
尚未确定 |
留作将来使用 |
NextWindow 类
它是显示下一个方块的窗口。它接收一个用户定义消息:NM_QUADRIS
(确切地说,在本例中是 m_Message
或 UM_QUADRIS
)。如果 QuadrisWindowWTL
将 WPARAM
设置为通知码 TN_NEXT
或 TN_FINISH
的 NM_QUADRIS
发送给 QuadrisWTLView
,则 QuadrisWTLView
将它们发送给 NextWindow
。这就是 QuadrisWindowWTL
和 NextWindow
这两个不同窗口之间通信的方式。NextWindow
通过 StretchBlt(...)
使用通过 LPARAM 传递的设备上下文句柄 (HDC) 来显示下一个方块。请参见 LRESULT NextWindow::OnPaint(...)
。NextWindow 的相关源代码如下:
LRESULT NextWindow::OnQuadrisMessage (UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case TN_NEXT: OnNext((HDC) lParam); break;
case TN_FINISH: OnFinish(); break;
}
return 0;
}
void NextWindow::OnNext (HDC hDC)
{
m_hDC = hDC;
Invalidate();
}
void NextWindow::OnFinish (void)
{
m_hDC = NULL;
Invalidate();
}
LRESULT NextWindow::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (!m_hDC)
{
SetMsgHandled(FALSE);
return 0;
}
CPaintDC dc(m_hWnd);
CRect rc;
GetClientRect(rc);
dc.StretchBlt(0, 0, rc.Width(), rc.Height(), m_hDC,
0, 0, Quadris_NEXTBMWIDTH, Quadris_NEXTBMHEIGHT, SRCCOPY);
return 0;
}
通过 LPARAM 传递的设备上下文句柄 (HDC) 已经由 QuadrisWindowWTL::DrawNext(void)
准备好。函数 Create(...)
和 Move(...)
具有与 QuadrisWindowWTL 相同的模式。
QuadrisCore 类
Quadris 算法是一个如此著名的算法,我不需要解释所有成员函数。相反,我将解释 QuadrisCore 公共成员函数的使用。
class QuadrisCore
{
...
public:
QuadrisCore (int width, int height, int colors);
~QuadrisCore (void);
inline char GetBoard (int x, int y) { return Board(x, y); }
inline LOCATION GetCurLoc () { return m_Pos; }
inline int GetScore () { return m_Score; }
inline int GetCurCol () { return m_CurCol; }
inline int GetNextCol () { return m_NextCol; }
inline int GetLoopStep () { return (int) m_LoopStep; }
inline BLOCK* GetCurBrick () { return (BLOCK*) &m_Brick[m_CurBrick]; }
inline BLOCK* GetNextBrick () { return (BLOCK*) &m_Brick[m_NextBrick]; }
void InitGame (void);
bool RotateBrick (bool bClockwise = true);
bool ShiftLeft (void);
bool ShiftRight (void);
bool ShiftDown (void);
void PullDown (void);
bool Shuffle (void);
int Loop ();
};
QuadrisCore (int width, int height, int colors);
- 这是一个构造函数。
- 第一个参数
width
是 Quadris 棋盘内部的宽度。 - 第二个参数
height
是 Quadris 棋盘内部的高度。 - 第三个参数
colors
是砖块的颜色数量。
inline char GetBoard (int x, int y);
- 它给出 Quadris 棋盘的一个单元格。
- 第一个参数
x
是 x 坐标。 - 第二个参数
y
是 y 坐标。 - 返回值为 WALL (= -1)、BLANK (= 0) 和 BRICK (= 1, 2, ...) 之一。
inline LOCATION GetCurLoc () ;
- 它给出下落方块的当前位置。
- 返回值为
struct LOCATION
形式的下落方块的当前位置。struct LOCATION
如下所示:
struct LOCATION
{
char x, y;
LOCATION (void) {}
LOCATION (char xx, char yy) : x(xx), y(yy) {}
LOCATION operator+ (LOCATION loc) { return LOCATION(x + loc.x, y + loc.y); }
LOCATION operator- (LOCATION loc) { return LOCATION(x - loc.x, y - loc.y); }
LOCATION operator+= (LOCATION loc) { x += loc.x; y += loc.y; return *this; }
LOCATION operator-= (LOCATION loc) { x -= loc.x; y -= loc.y; return *this; }
};
inline int GetScore ();
- 它给出当前分数。
inline int GetCurCol ();
- 它给出当前下落方块的颜色。
- 返回值为 1 到 colors 之间,即构造函数的第三个参数。
inline int GetNextCol ();
- 它给出下一个等待方块的颜色。
- 返回值为 1 到 colors 之间,即构造函数的第三个参数。
inline int GetLoopStep ();
- 它给出当前循环步骤。
- 返回值为
QUADRIS_LOOPNEW
、QUADRIS_LOOPFALL
、QUADRIS_LOOPUPDATE
、QUADRIS_LOOPCLEAR
、QUADRIS_LOOPPURGE
和QUADRIS_LOOPEND
之一。
inline BLOCK* GetCurBrick ();
- 它给出当前下落方块的四个方块组。
- 返回值为包含四个
struct BLOCK
元素的数组。struct BLOCK
如下所示:
typedef LOCATION BLOCK;
inline BLOCK* GetNextBrick ();
- 它给出下一个等待方块的四个方块组。
- 返回值为包含四个
struct BLOCK
元素的数组。
void InitGame (void);
- 它初始化所有变量并启动 Quadris 游戏。
bool RotateBrick (bool bClockwise = true);
- 它旋转当前方块。
- 参数
bClockwise
决定旋转方向。如果bClockwise
为 true,则顺时针旋转。如果bClockwise
为 false,则逆时针旋转。 - 如果方块旋转成功,返回值为 true;如果方块未旋转,返回值为 false。
bool ShiftLeft (void);
- 它将方块向左移动。
- 如果方块向左移动成功,返回值为 true;如果方块未向左移动,返回值为 false。
bool ShiftRight (void);
- 它将方块向右移动。
- 如果方块向右移动成功,返回值为 true;如果方块未向右移动,返回值为 false。
bool ShiftDown (void);
- 它将方块向右移动。
- 如果方块向下移动成功,返回值为 true;如果方块未向下移动,返回值为 false。如果返回值为 false,则表示方块已落地。
void PullDown (void);
- 它快速向下坠落方块。
bool Shuffle (void);
- 它将堆叠的砖块向左或向右移动。
- 如果移动成功,返回值为 true。如果未移动,返回值为 false。
int Loop ();
- 它使 Quadris 游戏向前一步。
- 返回值为下一步状态。它是
QUADRIS_LOOPNEW
、QUADRIS_LOOPFALL
、QUADRIS_LOOPUPDATE
、QUADRIS_LOOPCLEAR
、QUADRIS_LOOPPURGE
和QUADRIS_LOOPEND
之一。
如何支持 Win95、Win98、Win98SE 和 WinME
如果此项目以 UNICODE 字符集设置编译,它将无法在 Win95、Win98、Win98SE 和 WinME 下工作。然而,为了未来的可扩展性,最好使用 UNICODE 字符集设置进行编译。那么,我们如何才能利用 UNICODE 的优势并支持旧版本的 Windows 呢?我们可以使用 Windows 95/98/Me 系统上的 Microsoft Layer for Unicode。如果网站没有更改,您可以从此处下载 MSLU。要使用 MSLU,您需要通过点击 project > properties > configuration properties > linker > input > additional dependencies 并写入 "unicows.lib" 将 unicows.lib 链接到您的项目。当然,当 NuraQuadris.exe 在旧版本 Windows 下执行时,unicows.dll 应该与 NuraQuadris.exe 位于同一文件夹中。最后,您还需要在您的项目中包含 ForWin98.c 或者只需在 stdafx.cpp 中插入以下语句。
#include "ForWin98.c"
如何嵌入帮助功能
我使用了 HTML 帮助。如果网站没有更改,您可以从此处下载 HTML help 1.4 SDK。您需要通过点击 project > properties > configuration properties > linker > input > additional dependencies 并写入 "htmlhelp.lib" 将 htmlhelp.lib 链接到您的项目。当然,您需要事先制作编译好的 HTML 帮助文件,例如 Quadris.chm,并将其放在 NuraQuadris.exe 所在的同一文件夹中。我不会在这里解释如何制作编译好的 HTML 帮助文件,但您可以从您将从此处下载的文件中包含的 htmlhelp.chm 中学习。以下源代码展示了如何使用 HtmlHelp(...)
函数作为示例。不要忘记包含 htmlhelp.h,如下所示。
#include <htmlhelp.h>
...
LRESULT CQuadrisWTLView::OnHelp (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
{
// LPHELPINFO lpHelpInfo = (LPHELPINFO) lParam;
HWND help = HtmlHelp(m_hWnd, m_strHelp, HH_DISPLAY_TOPIC, NULL);
if (!help)
help = HtmlHelp(m_hWnd, m_strHelpDef, HH_DISPLAY_TOPIC, NULL);
if (help)
CWindow(help).CenterWindow(m_hWnd);
else
OnAppAbout();
return TRUE;
}
关注点
VC++ 8.0X 和 VC++ 9.0X 使用 ATL 3.0,而 VC++ 7.1 使用 ATL 7.1。尽管两者都使用相同的 WTL 8.0,但 VC++ 7.1 的源代码与 VC++ 8.0X 不兼容。因此,为了使其能够与 VC++ 8.0X 或 VC++ 9.0X 编译,尽管它是用 VC++ 7.1 (ATL 7.1) 开发的,我还是创建了 ATLVersion.h 并将其包含在 stdafx.h 中。ATLVersion.h 与 Nura Tritris 的文件相同。在这个项目中,ATLVersion.h 工作得很好,但我认为它并不适用于所有为 VC++ 7.1 编写的项目,使其能够很好地与 VC++ 8.0X 和 VC++ 9.0X 编译。如果有人对 ATL 的向下兼容性感兴趣,我鼓励他或她改进 ATLVersion.h。
我还制作了 ATLWinPlus.hpp 和 ATLCrackPlus.hpp 以提高消息映射的效率。如果您查看 ATLWinPlus.hpp 和 ATLCrackPlus.hpp 的源代码,您会很容易理解它们。如果您不信任 ATLWinPlus.hpp 和 ATLCrackPlus.hpp,请注释掉 QuadrisWTL 文件夹中 stdafx.h 文件第 54 行的语句,如下所示:
//#define ATL_PLUS_MSG
Quadris 自定义工具

我不会解释 QuadrisCustomizer 的源代码。相反,我将介绍如何使用这个实用程序。如果您运行此程序并在相应的编辑窗口中将所有消息翻译成您的语言并保存,您将获得一个 NuraQuadris.ini 文件。如果您将其放在 NuraQuadris.exe 所在的同一文件夹中,NuraQuadris.exe 将使用 NuraQuadris.ini 以您的语言显示所有消息。此外,您可以将其另存为不同的名称,例如 NuraQuadrisRussian.ini。它本身不会对 NuraQuadris.exe 起作用,但您可以将其保留为 NuraQuadris 的特定语言包。
致谢
我要感谢 Michael Dunn 为 MFC 程序员撰写的关于 WTL 的出色文章。我从他的文章中学到了很多关于 WTL 的知识。他的文章可以在这里找到。我还要感谢 Sergey Solozhentsev 在 WTL Helper 和 WTL Wizards 方面所做的出色工作。您可以在这里和这里获取他的 WTL Helper,以及在这里和这里获取其手册。不要混淆。他的 WTL Wizards 与可以通过例如 setup71.js 安装的普通 WTL App Wizard 不同。他的 WTL Wizards 也支持分屏窗口框架。您还可以在这里获取他的 WTL Wizards 及其手册,以及在这里获取。当我使用 WTL 编写代码时,它为我提供了很多便利。最重要的是,我非常感谢上帝和我的妻子 Nura。他把她赐给了我,她永远在我身边,是我坚定的支持者。