游戏编程入门(9):开发 Henway(小鸡过马路) 游戏

应用前面学到的子画面知识,开发一个小鸡过马路游戏。

接上文 游戏编程入门(8):管理子画面


Henway 游戏的玩法

Henway 游戏的主角是一只小鸡,它急需从一条繁忙的高速公路的一边到达另一边。Henway 的游戏方向是水平的,这意味着小鸡要从屏幕的左边到右边。

这里写图片描述

Henway 游戏,小鸡的数量是有限的3只。当所有小鸡都死掉时,游戏就结束了。当小鸡成功的穿越了高速公路或者玩家失去了一只小鸡,都会计入积分系统中,最后显示玩家所得的分数。

Henway 游戏,以键盘的上下左右键,控制小鸡。

设计Henway 游戏

Henway 游戏有5个子画面:一个小鸡子画面和4辆汽车子画面,有7个位图图像:1个背景高速公路图像,1个小鸡图像,4个汽车图像,很小的鸡头图像。

很小的鸡头图像显示在右下角,提示玩家还剩下多少只小鸡。在高速公路上损失小鸡时,鸡头就会消失,直到没有剩下任何鸡头位置,这时游戏就结束了。

现在,读者已经对游戏中涉及的图像对象有了一定的了解,下面考虑游戏必须维护的其他数据。首先,很显然需要记录剩余多少个小鸡,还需要维护一个连续的积分,在每次小鸡安全穿过高速公路时都加分,还需要一个布尔变量,用来记录游戏是否结束了。

还有最后一个变量,如果读者没有真正开发这个程序并彻底测试它,那么很难预见到这个变量。我是指一个输入延迟变量,它有助于改变键盘的输入响应,以便改进游戏的可玩性。

如果在每一个游戏循环里都直接响应键盘,那么小鸡在游戏屏幕上的移动就会太快了,这就产生了太多的游戏周期,过多的注意了输入设备。为了稍微放慢输入,可以使用一个延迟变量,每三个游戏循环才检查一次键盘输入。确定合适的延迟是一个不断尝试的过程,因此可以随意修改它并查看最合适的延迟。

总结一下,Henway 游戏的设计使我们了解到游戏必须管理以下信息:

  • 剩下的小鸡数量
  • 得分
  • 确定游戏是否结束的布尔变量
  • 输入延迟变量

开发Henway 游戏

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

Henway 目录结构与效果图

Henway 目录结构:

这里写图片描述

Henway 效果图:

这里写图片描述

这里写图片描述

这里写图片描述

Henway 游戏源代码

Henway.h 源代码

#pragma once

//-----------------------------------------------------------------
// 包含的文件
//-----------------------------------------------------------------
#include <windows.h>
#include "Resource.h"
#include "GameEngine.h"
#include "Bitmap.h"
#include "Sprite.h"

//-----------------------------------------------------------------
// 全局变量
//-----------------------------------------------------------------
HINSTANCE   g_hInstance;         //程序实例句柄
GameEngine* g_pGame;             //游戏引擎指针
HDC         g_hOffscreenDC;      //屏幕外设备
HBITMAP     g_hOffscreenBitmap;  //屏幕外缓冲区的位图
Bitmap*     g_pHighwayBitmap;    //背景高速公路位图
Bitmap*     g_pChickenBitmap;    //小鸡位图
Bitmap*     g_pCarBitmaps[4];    //4个汽车位图
Bitmap*     g_pChickenHeadBitmap;//鸡头位图
Sprite*     g_pChickenSprite;    //小鸡子画面
int         g_iInputDelay;       //输入延迟
int         g_iNumLives;         //剩下的小鸡
int         g_iScore;            //得分
BOOL        g_bGameOver;         //游戏是否结束

//-----------------------------------------------------------------
// 根据用户输入事件移动小鸡子画面
//-----------------------------------------------------------------
void MoveChicken(int iXDistance, int iYDistance);

Henway.cpp 源代码

//-----------------------------------------------------------------
// 包含的文件
//-----------------------------------------------------------------
#include "Henway.h"

//-----------------------------------------------------------------
// 游戏事件函数
//-----------------------------------------------------------------

// 初始化游戏
BOOL GameInitialize(HINSTANCE hInstance)
{
  // Create the game engine
  g_pGame = new GameEngine(hInstance, TEXT("Henway"),
    TEXT("Henway"), IDI_HENWAY, IDI_HENWAY_SM, 465, 400);
  if (g_pGame == NULL)
    return FALSE;

  // Set the frame rate
  g_pGame->SetFrameRate(30);

  // Store the instance handle
  g_hInstance = hInstance;

  return TRUE;
}

// 开始游戏
void GameStart(HWND hWindow)
{
  // 生成随机数种子
  srand(GetTickCount());

  // 创建屏幕外的设备环境,然后使用它创建一个屏幕外位图
  g_hOffscreenDC = CreateCompatibleDC(GetDC(hWindow));
  g_hOffscreenBitmap = CreateCompatibleBitmap(GetDC(hWindow),
    g_pGame->GetWidth(), g_pGame->GetHeight());
  SelectObject(g_hOffscreenDC, g_hOffscreenBitmap);

  // 创建并加载位图
  HDC hDC = GetDC(hWindow);
  g_pHighwayBitmap = new Bitmap(hDC, IDB_HIGHWAY, g_hInstance);
  g_pChickenBitmap = new Bitmap(hDC, IDB_CHICKEN, g_hInstance);
  g_pCarBitmaps[0] = new Bitmap(hDC, IDB_CAR1, g_hInstance);
  g_pCarBitmaps[1] = new Bitmap(hDC, IDB_CAR2, g_hInstance);
  g_pCarBitmaps[2] = new Bitmap(hDC, IDB_CAR3, g_hInstance);
  g_pCarBitmaps[3] = new Bitmap(hDC, IDB_CAR4, g_hInstance);
  g_pChickenHeadBitmap = new Bitmap(hDC, IDB_CHICKENHEAD, g_hInstance);

  // 创建小鸡和汽车的子画面(汽车的z顺序比小鸡高,这样小鸡被汽车压的时候,小鸡显示在车下面)
  Sprite* pSprite;
  RECT    rcBounds = { 0, 0, 465, 400 };
  g_pChickenSprite = new Sprite(g_pChickenBitmap, rcBounds, BA_STOP);
  g_pChickenSprite->SetPosition(4, 175);
  g_pChickenSprite->SetVelocity(0, 0);
  g_pChickenSprite->SetZOrder(1);
  g_pGame->AddSprite(g_pChickenSprite);
  pSprite = new Sprite(g_pCarBitmaps[0], rcBounds, BA_WRAP);
  pSprite->SetPosition(70, 0);
  pSprite->SetVelocity(0, 7);
  pSprite->SetZOrder(2);
  g_pGame->AddSprite(pSprite);
  pSprite = new Sprite(g_pCarBitmaps[1], rcBounds, BA_WRAP);
  pSprite->SetPosition(160, 0);
  pSprite->SetVelocity(0, 3);
  pSprite->SetZOrder(2);
  g_pGame->AddSprite(pSprite);
  pSprite = new Sprite(g_pCarBitmaps[2], rcBounds, BA_WRAP);
  pSprite->SetPosition(239, 400);
  pSprite->SetVelocity(0, -5);
  pSprite->SetZOrder(2);
  g_pGame->AddSprite(pSprite);
  pSprite = new Sprite(g_pCarBitmaps[3], rcBounds, BA_WRAP);
  pSprite->SetPosition(329, 400);
  pSprite->SetVelocity(0, -10);
  pSprite->SetZOrder(2);
  g_pGame->AddSprite(pSprite);

  // 初始化其余全局变量
  g_iInputDelay = 0;
  g_iNumLives = 3;
  g_iScore = 0;
  g_bGameOver = FALSE;
}

// 结束游戏
void GameEnd()
{
  // 清除屏幕外设备环境和位图
  DeleteObject(g_hOffscreenBitmap);
  DeleteDC(g_hOffscreenDC);  

  // 清除位图
  delete g_pHighwayBitmap;
  delete g_pChickenBitmap;
  for (int i = 0; i < 4; i++)
    delete g_pCarBitmaps[i];
  delete g_pChickenHeadBitmap;

  // 清除子画面
  g_pGame->CleanupSprites();

  // 清除游戏引擎
  delete g_pGame;
}

void GameActivate(HWND hWindow)
{

}

void GameDeactivate(HWND hWindow)
{

}

// 绘制游戏
void GamePaint(HDC hDC)
{
  // 绘制高速公路背景
  g_pHighwayBitmap->Draw(hDC, 0, 0);

  // 绘制游戏子画面
  g_pGame->DrawSprites(hDC);

  // 绘制剩余小鸡生命的数量
  for (int i = 0; i < g_iNumLives; i++)
    g_pChickenHeadBitmap->Draw(hDC,
      406 + (g_pChickenHeadBitmap->GetWidth() * i), 382, TRUE);
}

// 游戏循环
void GameCycle()
{
  if (!g_bGameOver)
  {
    // 更新子画面
    g_pGame->UpdateSprites();

    // 获得用来绘制游戏的设备环境
    HWND  hWindow = g_pGame->GetWindow();
    HDC   hDC = GetDC(hWindow);

    // 在屏幕外设备环境上绘制游戏
    GamePaint(g_hOffscreenDC);

    // 将屏幕外位图位块传送到游戏屏幕
    BitBlt(hDC, 0, 0, g_pGame->GetWidth(), g_pGame->GetHeight(),
      g_hOffscreenDC, 0, 0, SRCCOPY);

    // 清理
    ReleaseDC(hWindow, hDC);
  }
}

// 键盘响应事件
void HandleKeys()
{
  if (!g_bGameOver && (++g_iInputDelay > 2))
  {
    // 根据按键移动小鸡
    if (GetAsyncKeyState(VK_LEFT) < 0)
      MoveChicken(-20, 0);
    else if (GetAsyncKeyState(VK_RIGHT) < 0)
      MoveChicken(20, 0);
    if (GetAsyncKeyState(VK_UP) < 0)
      MoveChicken(0, -20);
    else if (GetAsyncKeyState(VK_DOWN) < 0)
      MoveChicken(0, 20);

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

// 按下鼠标
void MouseButtonDown(int x, int y, BOOL bLeft)
{
  // 开始一个新游戏
  if (g_bGameOver)
  {
    g_iNumLives = 3;
    g_iScore = 0;
    g_bGameOver = FALSE;
  }
}

void MouseButtonUp(int x, int y, BOOL bLeft)
{
}

void MouseMove(int x, int y)
{
}


// 碰撞检测
BOOL SpriteCollision(Sprite* pSpriteHitter, Sprite* pSpriteHittee)
{
  // 查看是否撞上了小鸡
  if (pSpriteHittee == g_pChickenSprite)
  {
    // 将小鸡移回开始位置,给人一种新小鸡开始的错觉
    g_pChickenSprite->SetPosition(4, 175);

    // 查看游戏是否结束
    if (--g_iNumLives > 0)
      MessageBox(g_pGame->GetWindow(), TEXT("Ouch!"), TEXT("Henway"), MB_OK);
    else
    {
      // 显示游戏结束消息
      TCHAR szText[64];
      wsprintf(szText, "Game Over! You scored %d points.", g_iScore);
      MessageBox(g_pGame->GetWindow(), szText, TEXT("Henway"), MB_OK);
      g_bGameOver = TRUE;
    }

    return FALSE;
  }

  return TRUE;
}

//-----------------------------------------------------------------
// 移动小鸡子画面
//-----------------------------------------------------------------
void MoveChicken(int iXDistance, int iYDistance)
{
  // 将小鸡移动到新位置
  g_pChickenSprite->OffsetPosition(iXDistance, iYDistance);

  // 查看小鸡是否成功通过
  if (g_pChickenSprite->GetPosition().left > 400)
  {
    // 将小鸡移回开始位置并增加得分
    g_pChickenSprite->SetPosition(4, 175);
    g_iScore += 150;
    MessageBox(g_pGame->GetWindow(), TEXT("You made it!"), TEXT("Henway"),
      MB_OK);
  }
}

源代码 下载

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

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值