游戏编程入门(18):使用闪屏增添游戏的活力

到现在为止,我们开发的游戏都存在一个问题就是它们在初次运行的时候没有充分的标识自己,虽然窗口的标题栏包含了游戏的名称,但是在初次运行游戏时清楚地标识自己是很重要的。而且我们的游戏,总是一点进去就开始了,这也给人以不好的体验。

游戏很像是电影,应该在片头显示名字并且给人以缓冲的时间。在电影中,这种介绍和缓冲被称为片头,而游戏中的名称被称为闪屏,它们可以包含有用的信息,例如版权通知和游戏玩法的介绍等。本章将介绍如何通过添加闪屏来装饰 Space Out 游戏。

本章内容包括:

  • 为什么闪屏是所有游戏的一个重要部分
  • 将闪屏结合到游戏中需要哪些工作
  • 如何向 Space Out 游戏添加闪屏

接上文 游戏编程入门(17):开发 Space Out(逃离太空)游戏


闪屏的重要性

无论在游戏闪屏中显示的内容是多还是少,重要的是,至少要显示游戏的名称以及其他相关的信息,如游戏的版权。如果需要一个特定的动作才能开始游戏,那么在闪屏中提一下也不错。没有人喜欢游戏立即开始而不提醒玩家游戏将在何时开始,因此闪屏至少应该让玩家有机会准备好才开始玩游戏。

闪屏也是一个提供包括游戏的简短说明以及游戏玩法提示和技巧的位置。对于闪屏,要考虑的最后一点是高分列表。这个列表包含人们在游戏中获得的最高得分。在稍后的文章中,我们将介绍如何创建一个高分列表,将 Space Out 游戏的高分保存到一个文件中。

目前,许多商业游戏都不仅包含闪屏,还包括了介绍性的动画或者视频片断等。这种“闪动画”比简单的闪屏更加吸引人,但是创建它通常需要更多的动作,特别是当它是一个实际的视频时。另一方面,一些游戏只是显示直接来自于游戏的动画片断,这是作为游戏的一种演示。在稍后的文章中,我们也会介绍如何将闪屏转换为 Space Out 游戏的一个演示模式。

了解闪屏

实现闪屏最容易的方法就是创建屏幕的位图图像,然后在游戏开始之前将其显示在游戏屏幕上。闪屏的图像可以大到填满整个游戏屏幕,也可以稍微小一点,显示在现有的游戏背景之上。

下图显示了如何设计闪屏图像,以便覆盖在 Space Out 游戏中的背景之上。

这里写图片描述

从上面这幅图可以看得出来,显示闪屏没有什么难度。向游戏添加闪屏稍微有一点难度的地方是为闪屏创建一个单独的游戏模式。例如,之前创建的所有游戏都处于两种模式之中,“游戏结束”和“游戏未结束”。这两种模式直接由 g_bGameOver 全局变量控制,而这个变量有两个布尔值,TURE 或 FALSE。因此,我们将游戏扩展为以下3种模式:

  • 闪屏
  • 游戏结束
  • 游戏未结束

虽然在显示闪屏时,游戏是结束的。但是对于“游戏结束”模式,因为没有显示闪屏,所以它不同于“闪屏”模式。

开发 Space Out 2 游戏

带有一个闪屏的 Space Out 游戏命名为 Space Out 2。游戏玩法没有变,只是添加了一个闪屏来装饰游戏。

注意:若出现编译错误,请在项目设置->连接->对象/库模块中 加入 msimg32.lib winmm.lib

Space Out 2 目录结构和效果图

Space Out 2 目录结构:

这里写图片描述

Space Out 2 效果图:

这里写图片描述

编写游戏代码

向 Space Out 2 游戏添加闪屏的第一步是向游戏添加几个全局变量,以便存储闪屏的位图以及闪屏模式。 它们是在 SpaceOut.h 中声明的。

Bitmap*           g_pSplashBitmap;                      //闪屏位图
BOOL              g_bSplash;                            //是否处于闪屏

g_bSplash 处于 TRUE 则游戏处于闪屏模式。在游戏开始时将g_bSplash 设置为TRUE,然后用户在按 Enter键开始游戏时,将其设置为FALSE。

初始化全局变量非常重要,这项任务是在 GameStart( ) 函数中完成的, GameStart( ) 函数的第一个变化是创建闪屏位图。

g_pSplashBitmap = new Bitmap(hDC, IDB_SPLASH, g_hInstance);

另外还要初始化 g_bSplash ,如下所示:

 // 初始化全局变量
  g_bSplash = TRUE;
  g_bGameOver = TRUE;

GameActivate( ) 和 GameDeactivate( )

使闪屏正常的大部分工作是当游戏处于闪屏模式时禁用游戏的某些部分。

GameActivate( ) 和 GameDeactivate( ) 函数在继续活着暂停MIDI 背景音乐之前检查 g_bSplash 变量的值。

//激活游戏
void GameActivate(HWND hWindow)
{
  if (!g_bSplash)
    // 继续播放背景音乐
    g_pGame->PlayMIDISong(TEXT(""), FALSE);
}
// 游戏未被激活时
void GameDeactivate(HWND hWindow)
{
  if (!g_bSplash)
    // 暂停背景音乐
    g_pGame->PauseMIDISong();
}

GamePaint( )

与闪屏有关的最重要代码位于 GamePaint( ) 函数中,这里实际绘制闪屏的位置。

// 绘制游戏
void GamePaint(HDC hDC)
{
 // 绘制背景
  g_pBackground->Draw(hDC);

  // 绘制沙漠位图
  g_pDesertBitmap->Draw(hDC, 0, 371);

  if (g_bSplash)
  {
    // 绘制闪屏位图
    g_pSplashBitmap->Draw(hDC, 142, 100, TRUE);
  }
  else
  {
   // 绘制子画面
  g_pGame->DrawSprites(hDC);

  // 绘制得分
  TCHAR szText[64];
  RECT  rect = { 460, 0, 510, 30 };
  wsprintf(szText, "%d", g_iScore);
  SetBkMode(hDC, TRANSPARENT);
  SetTextColor(hDC, RGB(255, 255, 255));
  DrawText(hDC, szText, -1, &rect, DT_SINGLELINE | DT_RIGHT | DT_VCENTER);

  // 绘制剩余生命(小汽车)数量
  for (int i = 0; i < g_iNumLives; i++)
    g_pSmCarBitmap->Draw(hDC, 520 + (g_pSmCarBitmap->GetWidth() * i),
      10, TRUE);

  // 绘制游戏结束
  if (g_bGameOver)
    g_pGameOverBitmap->Draw(hDC, 190, 149, TRUE);
  }
}

HandleKeys( )

HandleKeys( ) 函数在游戏退出闪屏 以开始一个新游戏时更改 g_bSplash 的值。

// 监听键盘
void HandleKeys()
{
  if (!g_bGameOver)
  {
    // 按下左/右键移动汽车
    POINT ptVelocity = g_pCarSprite->GetVelocity();
    if (GetAsyncKeyState(VK_LEFT) < 0)
    {
      // 向左移动(因为是向左行驶时倒退,所以汽车左行的最大速度小于右行的最大速度)
      ptVelocity.x = max(ptVelocity.x - 1, -4);
      g_pCarSprite->SetVelocity(ptVelocity);
    }
    else if (GetAsyncKeyState(VK_RIGHT) < 0)
    {
      // 向右移动
      ptVelocity.x = min(ptVelocity.x + 2, 6);
      g_pCarSprite->SetVelocity(ptVelocity);
    }

    // 按下空格键发射导弹
    if ((++g_iFireInputDelay > 6) && GetAsyncKeyState(VK_SPACE) < 0)
    {
      // 创建一个新的导弹子画面
      RECT  rcBounds = { 0, 0, 600, 450 };
      RECT  rcPos = g_pCarSprite->GetPosition();
      Sprite* pSprite = new Sprite(g_pMissileBitmap, rcBounds, BA_DIE);
      pSprite->SetPosition(rcPos.left + 15, 400);
      pSprite->SetVelocity(0, -7);
      g_pGame->AddSprite(pSprite);

      // 播放导弹发射声音
      PlaySound((LPCSTR)IDW_MISSILE, g_hInstance, SND_ASYNC |
        SND_RESOURCE | SND_NOSTOP);

      // 重置输入延迟
      g_iFireInputDelay = 0;
    }
  }

  // 按下Enter键开始一个新游戏
  if (GetAsyncKeyState(VK_RETURN) < 0)
    if (g_bSplash)
    {
      // 开始一个没有闪屏的新游戏
      g_bSplash = FALSE;
      NewGame();
    }
    else if (g_bGameOver)
    {
      // 开始一个新游戏
      NewGame();
    }
}

源代码下载

http://pan.baidu.com/s/1ge2Vzr1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,如果使用Windows API函数编写小游戏,可能会出现闪屏问题。这是因为在每次重绘窗口时,窗口背景会被擦除,然后重新绘制。为了解决这个问题,可以使用双缓冲技术。 双缓冲技术的基本思路是:在内存中创建一个与屏幕大小相同的位图,先将所有的绘制操作都在位图上完成,然后再一次性将整个位图绘制到屏幕上,从而避免了闪屏问题。 以下是使用双缓冲技术解决闪屏问题的示例代码: ```c #include <Windows.h> #define WIDTH 80 #define HEIGHT 25 int main() { // 获取控制台句柄和屏幕缓冲区句柄 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hBuffer = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL ); // 设置控制台窗口大小和缓冲区大小 COORD size = { WIDTH, HEIGHT }; SetConsoleScreenBufferSize(hBuffer, size); SMALL_RECT rc = { 0, 0, WIDTH - 1, HEIGHT - 1 }; SetConsoleWindowInfo(hBuffer, TRUE, &rc); // 将缓冲区设置为活动缓冲区 SetConsoleActiveScreenBuffer(hBuffer); // 隐藏光标 CONSOLE_CURSOR_INFO cci; GetConsoleCursorInfo(hOut, &cci); cci.bVisible = FALSE; SetConsoleCursorInfo(hOut, &cci); // 在缓冲区中绘制游戏界面 while (1) { // 创建位图并获取设备上下文 HBITMAP hBitmap = CreateCompatibleBitmap(hOut, WIDTH, HEIGHT); HDC hdcBitmap = CreateCompatibleDC(hOut); SelectObject(hdcBitmap, hBitmap); // 绘制游戏界面到位图上 // ... // 将位图绘制到缓冲区上 BitBlt( GetStdHandle(STD_OUTPUT_HANDLE), 0, 0, WIDTH, HEIGHT, hdcBitmap, 0, 0, SRCCOPY ); // 释放设备上下文和位图资源 DeleteDC(hdcBitmap); DeleteObject(hBitmap); } return 0; } ``` 在这个示例代码中,我们首先创建了一个与屏幕大小相同的缓冲区,然后将其设置为活动缓冲区。在游戏循环中,我们先在内存中创建一个位图,并将游戏界面绘制到位图上,最后再将位图绘制到缓冲区上。这样就避免了每次重绘窗口时的闪屏问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值