65.9K
CodeProject 正在变化。 阅读更多。
Home

Nura Tritris - 一款基于 WTL 的杀时间电脑游戏

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (11投票s)

2007年2月12日

CPOL

20分钟阅读

viewsIcon

40620

downloadIcon

3260

Nura Tritris 是一款电脑游戏,用户需要堆叠球,并使至少三个相同颜色的球在水平、垂直或对角线上匹配。当用户匹配到相同颜色的球时,堆叠的球会消失。

目录

  1. 引言
    1. Nura Tritris 的名字
    2. Nura Tritris 的规则
    3. Nura Tritris 的特点
    4. Nura Tritris 的使用
  2. 背景
  3. 源代码
  4. 环境
  5. 使用代码
    1. 整体结构
    2. CMainFrame 和 CTritrisWTLView 类
    3. TritrisWindowWTL 类
    4. TritrisWindowWTL 的用户定义消息 NM_TRITRIS (= UM_TRITRIS)
    5. NextWindow 类
    6. TritrisCore 类
  6. 关注点
  7. Tritris 定制器
  8. 致谢

引言

Nura Tritris 的名字

Nura Tritris 是一款电脑游戏,用户需要堆叠球,并使至少三个相同颜色的球在水平、垂直或对角线上匹配。当用户匹配到相同颜色的球时,堆叠的球会消失。然后,原来堆叠在消失的球上面的球会落到剩余的堆叠球上。Nura 是我妻子的名字。所以我将我的程序命名为 Nura Tritris。Nur 在阿拉伯语中是“光”的意思,而 -a 是一个女性后缀,所以 Nura 可以表示“明亮的女士”。这是中东地区非常流行的女性阿拉伯名字。

Nura Tritris 的规则

Nura Tritris 的规则与普通 Tritris 游戏的规则相同。规则如下:

  1. 一块砖由三个球组成。
  2. 当一块砖落下时,你必须改变颜色的顺序和/或向左或向右移动砖块,以便在它落在堆叠的砖块之前,其颜色与堆叠的砖块的颜色匹配。
  3. 当它落在堆叠的砖块上时,如果至少有三个相同颜色的球在垂直、水平或对角线上匹配,相同颜色的球将消失。然后,原来堆叠在消失的球上面的球会落到剩余的球或地面上。如果这时再次有至少三个相同颜色的球在垂直、水平或对角线上匹配,相同颜色的球将再次消失。这个过程会重复进行,直到没有至少三个相同颜色的球在垂直、水平或对角线上匹配为止。
  4. 然后,一块新的砖会落下。

Nura Tritris 的特点

  1. 它会自动检测 Windows 的语言,并以韩语或英语显示所有说明。如果您的 Windows 是韩语 Windows,它将处于韩语模式;如果是其他语言的 Windows,它将处于英语模式。但是,您可以使用 NuraTritris.ini 将 Nura Tritris 定制为您自己的语言。您可以使用 TritrisCustomizer.exe 生成 NuraTritris.ini。稍后我将介绍 TritrisCustomizer.exe
  2. 它有一个选项可以显示帮助网格。默认是不显示网格。
  3. 它有一个选项可以发出声音。默认是发出声音。
  4. 它有一个选项可以提前显示下一块砖。默认是提前显示下一块砖。
  5. 游戏开始时有 5 种颜色,如果分数超过 50 分则有 6 种颜色,如果分数超过 100 分则有 7 种颜色。
  6. 如果您的分数超过 150 分,下落速度每 50 分会加快。
  7. 如果您的分数超过 250 分,堆叠球的颜色会随机改变。
  8. 如果您按下“F1”键,会弹出一个“关于”消息框。您可以在其中看到关于 Nura Tritris 的简单信息。

Nura Tritris 的使用

  1. 要开始游戏,点击“开始”按钮。
  2. 游戏过程中,如果您想取消游戏,点击“取消”按钮。
  3. 游戏过程中,如果您想暂停游戏,点击“暂停”按钮。然后,如果您想再次继续游戏,点击“继续”按钮。
  4. 如果您需要帮助网格,请勾选“网格”选项。
  5. 如果您不需要声音,请取消勾选“声音”选项。
  6. 按下向上箭头键可以改变砖块的颜色顺序。
  7. 按下向左箭头键可以将砖块向左移动。
  8. 按下向右箭头键可以将砖块向右移动。
  9. 按下向下箭头键可以将砖块向下移动。
  10. 按下空格键可以将砖块快速落到底部。

背景

它包含五个部分:一个 Tritris 引擎、一个类似控件的窗口、一个下一个窗口、一个视图窗口和一个皮肤窗口。我将在本文中对这些部分进行简要描述。我使用了 桥接模式(确切地说,是桥接模式的修改版本),但我不会在这里解释设计模式。如果您对桥接模式好奇,可以在这里了解它。

源代码

此源代码使用 WTL 库。源代码包括四个项目:TritrisCore、TritrisWindowWTL、NuraTritris(在 TritrisWTL 文件夹中)和 TritrisCustomizer。TritrisCore 项目是 Tritris 引擎的库。TritrisWindowWTL 项目是 Tritris 窗口的类似控件的 WTL 库。NuraTritris 项目是可执行项目,它实际上是 Tritris 游戏程序。但是,它不使用 Tritris 窗口库,而是直接使用 Tritris 窗口和 Tritris 核心的源代码。最后,TritrisCustomizer 项目是可执行项目,它是 NuraTritris 的语言定制器。

环境

Nura Tritris 是使用 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++ .NET 2005 Express Edition(以下简称 VC++ 8.0X)进行编译。当然,在编译之前您需要采取一些步骤。关于使用 VC++ 8.0X 进行 Windows 编程,这里有介绍;关于 VC++ 8.0X 的 WTL 安装,这里有介绍。为了使其能够使用 ATL 3.0 的 VC++ 8.0X 进行编译,我创建了 ATLVersion.h 并将其包含在 stdafx.h 中。Tritris.sln 用于 VC++ 7.1,而 Tritris2005.sln 用于 VC++ 8.0X。TritrisWTL.vcproj 用于 VC++ 7.1,而 TritrisWTL2005.vcproj 用于 VC++ 8.0X。所有解决方案文件(*.sln)和项目文件(*.vcproj)的文件命名约定都与上述示例相同。

Using the Code

整体结构

我提到过 Nura Tritris 由五个部分组成:一个 Tritris 引擎、一个类似控件的窗口、一个下一个窗口、一个视图窗口和一个皮肤窗口。皮肤窗口本身是一个 SDI 应用程序框架,并包含视图窗口作为其子窗口。皮肤窗口由类 CMainFrame 实现。视图窗口包含类似控件的窗口和下一个窗口作为其子窗口,并由类 CTritrisWTLView 实现。类似控件的窗口是 Tritris 游戏窗口本身,并由类 TritrisWindowWTL 实现。我称这个窗口为类似控件的窗口的原因是,这个窗口实际上不是一个控件,但它具有控件的功能。类似控件的窗口包含 Tritris 引擎。Tritris 引擎由类 TritrisCore 实现。下一个窗口是在 Tritris 游戏进行时提前显示下一个砖块的窗口,并由类 NextWindow 实现。

CMainFrame 和 CTritrisWTLView 类

CMainFrameCTritrisWTLView 由 WTL 应用程序向导提供,我在此基础上进行了编码。CTritrisWTLViewTritrisWindowWTL 接收用户定义消息 NM_TRITRIS(在本例中为 UM_TRITRIS)。其成员函数 OnTritrisMessage 将处理消息 UM_TRITRIS。以下代码与用户定义消息 UM_TRITRIS 的处理有关。

LRESULT CTritrisWTLView::OnTritrisMessage (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;
    //case TN_SHOWNEXT:     break;
    //case TN_CLEAR:        break;
    }

    return 0;
}

void CTritrisWTLView::OnPurge (int lines)
{
    TCHAR    str[STRINGMAX];
    _stprintf(str, m_strScore, m_pTritris->GetScore());
    m_Score.SetWindowText(str);
}

void CTritrisWTLView::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_TRITRIS, TN_FINISH, 
                         (LPARAM) score);
}

void CTritrisWTLView::OnNext (LPARAM lParam)
{
    m_pNext->PostMessage(UM_TRITRIS, TN_NEXT, lParam);
}

它还通过按钮和复选框接收用户的指令。如果您希望将语言设置为英语,无论您的 Windows 系统语言是什么,请取消注释 TritrisWTL 文件夹中 stdafx.h 文件第 29 行的语句,如下所示:

#define TRITRIS_LANG   LANG_ENGLISH

TritrisWindowWTL 类

它使用一个用户定义消息:NM_TRITRIS(确切地说,在本例中是 m_MessageUM_TRITRIS)。每当有新砖块落下、或相同颜色的球被清除、或球被清除时,TritrisWindowWTL 都会向 TritrisWTLView 发送 NM_TRITRIS。当游戏结束时,它也会向 TritrisWTLView 发送 NM_TRITRIS。为了避免 TritrisWTLView 中的消息冲突,TritrisWindowWTL 的构造函数可以接收一个不同的 NM_TRITRIS 用户定义消息值作为参数,并将其保存到 m_Message 中。TritrisWindowWTL 独立于 TritrisWTLView,就像 CProgressBarCtrl 独立于 TritrisWTLView 一样。TritrisWindowWTL 的公共成员函数如下:

class TritrisWindowWTL : public CWindowImpl <TritrisWindowWTL>
{
    ...
public:
    TritrisWindowWTL (UINT message = NM_TRITRIS, 
                      bool bAuto = true);
    TritrisWindowWTL (UINT message, int lang, bool bAuto);
    virtual ~TritrisWindowWTL (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) const { 
        return m_pTritris-> GetScore(); }
    inline int GetLevel (void) const { 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) const { 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);
    ...
}

TritrisWindowWTL (UINT message = NM_TRITRIS, bool bAuto = true);

  • 这是一个构造函数。
  • 第一个参数 messageTritrisWindowWTL 将发送给父窗口的消息。为了避免消息冲突,您可以为该消息指定一个不同的值。默认值是 NM_TRITRIS
  • 第二个参数是它是否自行处理结束过程。如果第二个参数 bAuto 设置为 true,它将自行控制球的速度和颜色数量,并处理结束过程。默认值是 true
  • 语言将根据 Windows 的默认系统语言自动选择。

TritrisWindowWTL (UINT message, int lang, bool bAuto);

  • 这是另一个构造函数。
  • 第一个和第三个参数与上述相同。
  • 第二个参数 lang 用于指定语言。如果将其设置为 LANG_KOREAN,它将使用韩语,无论 Windows 的默认语言是什么。

inline bool Start (void);

  • 它使 Tritris 游戏开始。
  • 当游戏开始时,返回值为 true,失败时为 false

inline bool Stop (void);

  • 它使 Tritris 游戏停止。
  • 当游戏停止时,返回值为 true,失败时为 false

inline bool Pause (void);

  • 它使 Tritris 游戏暂停。
  • 当游戏暂停时,返回值为 true,失败时为 false

inline bool Continue (void);

  • 它使 Tritris 游戏继续。
  • 当游戏继续时,返回值为 true,失败时为 false

inline int GetScore (void) const;

  • 它提供 Tritris 游戏的当前分数。
  • 返回值为当前分数。

inline int GetLevel (void) const;

  • 它提供 Tritris 游戏的当前等级。
  • 返回值为当前等级。

inline void SetGrid (bool bGrid = true);

  • 它决定 Tritris 窗口是否具有辅助网格。
  • 如果参数 bGridtrue,Tritris 窗口将具有辅助网格。如果参数 bGridfalse,Tritris 窗口将不具有辅助网格。

inline void SetSound (bool bSound = true);

  • 它决定 Tritris 窗口是否发出音效。
  • 如果参数 bSoundtrue,Tritris 窗口将发出音效。如果参数 bSoundfalse,Tritris 窗口将不发出音效。

inline int GetSpeed (void) const;

  • 它提供 Tritris 游戏的当前速度。
  • 返回值为用于 SetTimer 的计时器间隔,单位为毫秒。

bool SetSpeed (int interval);

  • 它设置速度。
  • 参数 interval 是移动之间的间隔。单位是毫秒。

HWND Create (HWND hParentWnd, const RECT& rect, DWORD dwStyle, DWORD dwExStyle, UINT nID);

  • 它创建 Tritris 类似控件的窗口。其窗口类名为 TRITRIS_CLASS,对于 ASCII 码定义为 "Tritris",对于 UNICODE 定义为 L"Tritris"。
  • 返回值为 Tritris 窗口的窗口句柄。
  • 第一个参数 hParentWnd 是其父窗口的窗口句柄。
  • 第二个参数 rect 是 Tritris 窗口矩形的引用。
  • 第三个参数 dwStyle 是 Tritris 窗口的窗口样式。
  • 第四个参数 dwExStyle 是 Tritris 窗口的扩展窗口样式。
  • 第五个参数 nID 是赋予 Tritris 窗口的 ID。

HWND Create (HWND hParentWnd, const POINT& pt, DWORD dwStyle, DWORD dwExStyle, UINT nID);

  • 它创建 Tritris 类似控件的窗口。其窗口类名为 TRITRIS_CLASS,对于 ASCII 码定义为 "Tritris",对于 UNICODE 定义为 L"Tritris"。
  • 返回值为 Tritris 窗口的窗口句柄。
  • 第一个参数 hParentWnd 是其父窗口的窗口句柄。
  • 第二个参数 pt 是 Tritris 窗口左上角的引用。其宽度和高度将分别确定为 400 像素和 640 像素。
  • 第三个参数 dwStyle 是 Tritris 窗口的窗口样式。
  • 第四个参数 dwExStyle 是 Tritris 窗口的扩展窗口样式。
  • 第五个参数 nID 是赋予 Tritris 窗口的 ID。
HWND Create (HWND hParentWnd, const RECT& rect, UINT nID);
  • 它创建 Tritris 类似控件的窗口。其窗口类名为 TRITRIS_CLASS,对于 ASCII 码定义为 "Tritris",对于 UNICODE 定义为 L"Tritris"。
  • 返回值为 Tritris 窗口的窗口句柄。
  • 第一个参数 hParentWnd 是其父窗口的窗口句柄。
  • 第二个参数 rect 是 Tritris 窗口矩形的引用。
  • 第三个参数 nID 是赋予 Tritris 窗口的 ID。
  • Tritris 窗口的样式和扩展样式都默认为 NULL

HWND Create (HWND hParentWnd, const POINT& pt, UINT nID);

  • 它创建 Tritris 类似控件的窗口。其窗口类名为 TRITRIS_CLASS,对于 ASCII 码定义为 "Tritris",对于 UNICODE 定义为 L"Tritris"。
  • 返回值为 Tritris 窗口的窗口句柄。
  • 第一个参数 hParentWnd 是其父窗口的窗口句柄。
  • 第二个参数 pt 是 Tritris 窗口左上角的引用。其宽度和高度将分别确定为 400 像素和 640 像素。
  • 第三个参数 nID 是赋予 Tritris 窗口的 ID。
  • Tritris 窗口的样式和扩展样式都默认为 NULL

BOOL Move (int x, int y, BOOL bRepaint = TRUE);

  • 它将窗口移动到指定位置。
  • 如果成功,返回值为 true;如果失败,返回值为 false
  • 第一个和第二个参数 xy 是 Tritris 窗口的左上角位置。
  • 第三个参数 bRepaint 与 Tritris 窗口移动时是否重绘有关。如果 bRepaint 为 true,Tritris 窗口将被重绘。如果 bRepaint 为 false,Tritris 窗口将不会被重绘。bRepaint 的默认值为 true
  • Tritris 窗口的宽度和高度将保持不变。

BOOL Move (POINT& pt, BOOL bRepaint = TRUE);

  • 它将窗口移动到指定位置。
  • 如果成功,返回值为 true;如果失败,返回值为 false
  • 第一个参数 pt 是 Tritris 窗口的左上角位置。
  • 第二个参数 bRepaint 与 Tritris 窗口移动时是否重绘有关。如果 bRepainttrue,Tritris 窗口将被重绘。如果 bRepaintfalse,Tritris 窗口将不会被重绘。bRepaint 的默认值为 true
  • Tritris 窗口的宽度和高度将保持不变。

BOOL Move (int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE);

  • 它将窗口移动到指定位置。
  • 如果成功,返回值为 true;如果失败,返回值为 false
  • 第一个、第二个、第三个和第四个参数 xynWidthnHeight 是 Tritris 窗口的位置。
  • 第五个参数 bRepaint 与 Tritris 窗口移动时是否重绘有关。如果 bRepainttrue,Tritris 窗口将被重绘。如果 bRepaintfalse,Tritris 窗口将不会被重绘。bRepaint 的默认值为 true

BOOL Move (RECT& rect, BOOL bRepaint = TRUE);

  • 它将窗口移动到指定位置。
  • 如果成功,返回值为 true;如果失败,返回值为 false
  • 第一个参数 rect 是 Tritris 窗口位置的引用。
  • 第二个参数 bRepaint 与 Tritris 窗口移动时是否重绘有关。如果 bRepainttrue,Tritris 窗口将被重绘。如果 bRepaintfalse,Tritris 窗口将不会被重绘。bRepaint 的默认值为 true

Create(...)Move(...) 的模式与 Nura Othello 或 Nura Tetris 的模式相同。Nura Othello 发布在这里,Nura Tritris 发布在这里。我更喜欢 Create(...)Move(...) 函数的这些模式。

TritrisWindowWTL 的用户定义消息 NM_TRITRIS (= UM_TRITRIS)

用户定义消息 NM_TRITRIS (本例中为 UM_TRITRIS )将 WPARAM 作为通知代码,将 LPARAM 作为与通知代码相关的信息。通知代码在 TritrisWindowWTL.h 中定义。通知代码如下:

用户定义消息 NM_TRITRIS (= UM_TRITRIS) 表

WPARAM (通知代码)

LPARAM

描述

TN_FINISH

分数

通知游戏结束

TN_NEXT

用于 Next 窗口进行双缓冲的 HDC

通知下一个砖块

TN_PURGE

清除的球的数量

通知已清除的球

TN_LEVEL

新等级

留作将来使用

TN_START

尚未确定

留作将来使用

TN_STOP

尚未确定

留作将来使用

TN_PAUSE

尚未确定

留作将来使用

TN_CONTINUE

尚未确定

留作将来使用

TN_GRID

尚未确定

留作将来使用

TN_SOUND

尚未确定

留作将来使用

TN_SHOWNEXT

尚未确定

留作将来使用

TN_CLEAR

清除球的数量

留作将来使用

NextWindow 类

它是显示下一个砖块的窗口。它接收一个用户定义消息:NM_TRITRIS(确切地说,在本例中是 m_MessageUM_TRITRIS)。如果 TritrisWindowWTL 以通知代码 TN_NEXTTN_FINISH 作为 WPARAM TritrisWTLView 发送 NM_TRITRISTritrisWTLView 会将它们发送给 NextWindow。这就是 TritrisWindowWTLNextWindow 这两个不同窗口相互通信的方式。NextWindow 通过 StretchBlt 使用通过 LPARAM 传递的设备上下文句柄(HDC)来显示下一个砖块。请参阅 LRESULT NextWindow::OnPaint。NextWindow 的相关源代码如下:

LRESULT NextWindow::OnTritrisMessage (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, TRITRIS_NEXTBMWIDTH, 
                  TRITRIS_NEXTBMHEIGHT, SRCCOPY);

    return 0;
}

通过 LPARAM 传递的设备上下文句柄(HDC)已经由 TritrisWindowWTL::DrawNext(void) 准备好。函数 CreateMove 具有与 TritrisWindowWTL 相同的模式。

TritrisCore 类

Tritris 按照以下状态运行。我将解释这些状态。

状态图

  • 新建(New):当 Tritris 开始时,会生成一个新砖块。
  • 下落(Fall):当新砖块生成后,新生成的砖块会下落。
  • 更新(Update):当砖块落在地面或堆叠的球上时,它会被堆叠到球上。
  • 清除(Clear):如果垂直、水平或对角线上至少有三个相同颜色的球,它们将被清除。
  • 清除(Purge):球被清除后,堆叠在被清除的球上的球会落到剩余的球上。
  • 再次清除(Clear Again):球下落后,如果垂直、水平或对角线上至少有三个相同颜色的球,它们将被再次清除。

我不会解释所有成员函数。相反,我将介绍 TritrisCore 公共成员函数的用法。

class TritrisCore
{
    ...
public:
    TritrisCore (int width, int height, int colors);
    ~TritrisCore (void);

    inline char GetBoard (int x, int y) const {
            return Board(x, y);}
    inline LOCATION GetCurLoc (void) const { return m_Pos;}
    inline int GetScore (void) const { return m_Score; }
    inline int GetLoopStep (void) const { 
            return (int) m_LoopStep; }
    inline BLOCK* GetCurBrick (void) const { 
            return (BLOCK*) &m_Brick[m_CurBrick]; }
    inline BLOCK* GetNextBrick (void) const { 
            return (BLOCK*) &m_Brick[m_NextBrick]; }
    inline void SetColors (int colors)
        { m_Colors    = ((0 < colors) && 
        (colors < COLORS)) ? colors : COLORS; }

    void InitGame (int colors = 0);
    bool RotateBrick (bool bUp = true);
    bool ShiftLeft (void);
    bool ShiftRight (void);
    bool ShiftDown (void);
    void PullDown (void);
    unsigned short Shuffle (void);
    int Loop ();
};
  

TritrisCore (int width, int height, int colors);

  • 这是一个构造函数。
  • 第一个参数 width 是 Tritris 板内部的宽度。
  • 第二个参数 height 是 Tritris 板内部的高度。
  • 第三个参数 colors 是球的颜色数量。

inline char GetBoard (int x, int y);

  • 它返回 Tritris 板的一个单元格。
  • 第一个参数 x 是 x 坐标。
  • 第二个参数 y 是 y 坐标。
  • 返回值为 WALL (= -1)、BLANK (= 0) 和 BALL (= 1, 2, ...) 之一。

inline LOCATION GetCurLoc (void) const;

  • 它返回下落砖块的当前位置。
  • 返回值为 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 (void) const ;

  • 它提供当前分数。

inline int GetLoopStep (void) const;

  • 它提供当前的循环步骤。
  • 返回值为 TRITRIS_LOOPNEWTRITRIS_LOOPFALLTRITRIS_LOOPUPDATETRITRIS_LOOPCLEARTRITRIS_LOOPCLEARAGAINTRITRIS_LOOPPURGETRITRIS_LOOPEND 之一。

inline BLOCK* GetCurBrick (void) const;

  • 它返回当前下落砖块的四个块的集合。
  • 返回值为包含四个 struct BLOCK 元素的数组。struct BLOCK 如下:
  • struct BLOCK : public LOCATION
    {
        char    col;
    
        BLOCK (void) : LOCATION()  {}
        BLOCK (char xx, char yy, char cc = 0) : LOCATION(xx, 
                                                yy), col(cc) {}
        operator LOCATION () { return LOCATION(x, y); }
    };
    

inline BLOCK* GetNextBrick (void) const;

  • 它返回下一个等待砖块的四个块的集合。
  • 返回值为包含四个 struct BLOCK 元素的数组。

void InitGame (int colors = 0);

  • 它初始化所有变量并启动 Tritris 游戏。
  • 参数 colors 是球的颜色数量。如果 colors 小于 1 或大于构造函数参数 colors 的值,它将与构造函数参数 colors 的值相同。

bool RotateBrick (bool bUp = true);

  • 它改变当前砖块的颜色顺序。
  • 参数 bUp 决定旋转方向。如果 bUp 为 true,它会向上旋转颜色。如果 bUp 为 false,它会向下旋转颜色。
  • 如果砖块的颜色旋转了,返回值为 true;如果砖块的颜色没有旋转,返回值为 false。

bool ShiftLeft (void);

  • 它将砖块向左移动。
  • 如果砖块向左移动了,返回值为 true;如果砖块没有向左移动,返回值为 false。

bool ShiftRight (void);

  • 它将砖块向右移动。
  • 如果砖块向右移动了,返回值为 true;如果砖块没有向右移动,返回值为 false。

bool ShiftDown (void);

  • 它将砖块向右移动。
  • 如果砖块向下移动了,返回值为 true;如果砖块没有向下移动,返回值为 false。如果返回值为 false,则表示砖块已经着陆。

void PullDown (void);

  • 它快速将砖块下落到底部。

unsigned short Shuffle (void);

  • 它交换堆叠球的颜色。
  • 如果交换了颜色,返回值为 true。如果未交换颜色,返回值为 false。

int Loop (void);

  • 它使 Tritris 前进一个步骤。
  • 返回值为下一个步骤状态。它是 TRITRIS_LOOPNEWTRITRIS_LOOPFALLTRITRIS_LOOPUPDATETRITRIS_LOOPCLEARTRITRIS_LOOPCLEARAGAINTRITRIS_LOOPPURGETRITRIS_LOOPEND 之一。

关注点

VC++ 8.0X 使用 ATL 3.0,而 VC++ 7.1 使用 ATL 7.1。尽管两者都使用相同的 WTL 8.0,但 VC++ 7.1 的源代码与 VC++ 8.0X 不兼容。因此,为了使其能够用 VC++ 8.0X 编译,尽管它是用 VC++ 7.1 (ATL 7.1) 开发的,我还是创建了 ATLVersion.h 并将其包含在 stdafx.h 中。ATLVersion.hNura OthelloNura Tetris 的文件相同。在这个项目中,ATLVersion.h 运行良好,但我认为它不能很好地适用于所有为 VC++ 7.1 编写的项目,使其能够用 VC++ 8.0X 编译。如果有人对 ATL 的向下兼容性感兴趣,我鼓励他或她改进 ATLVersion.h

Tritris 定制器

我不会解释 TritrisCustomizer 的源代码。相反,我将介绍如何使用这个实用程序。如果您运行此程序并在相应的编辑窗口中将所有消息翻译成您的语言并保存,您将得到一个 NuraTritris.ini 文件。如果您将其放在 NuraTritris.exe 所在的同一文件夹中,NuraTritris.exe 将使用 NuraTritris.ini 以您的语言显示所有消息。此外,您可以将其保存为不同的名称,例如 NuraTritrisRussian.ini。它本身不能作为 NuraTritris.exe 使用,但您可以将其保留为 NuraTritris 的特定语言包。

致谢

我要感谢 Michael Dunn 撰写了关于 WTL for MFC 程序员的优秀文章。我从他的文章中学到了很多关于 WTL 的知识。他的文章可以在这里找到。我还要感谢 Sergey Solozhentsev 在 WTL Helper 和 WTL Wizards 方面所做的出色工作。您可以从这里这里获取他的 WTL Helper,以及从这里这里获取其手册。请不要混淆。他的 WTL Wizards 与普通的 WTL App Wizard 不同,例如后者可以通过 setup71.js 安装。他的 WTL Wizards 也支持分屏窗口框架。您还可以从这里获取他的 WTL Wizards,以及从这里获取其手册。它为我在使用 WTL 编码时提供了很多便利。最重要的是,我真心感谢上帝和我的妻子 Nura。他将她赐予我,她永远在我身边,是我坚定的支持者。

© . All rights reserved.