当前位置:   article > 正文

2D游戏引擎(五)——添加子画面类_2d游戏引擎种类

2d游戏引擎种类

 子画面的主要目的是模拟游戏中能够随时间移动的图形对象,它具有以下属性:

Bitmap*       m_pBitmap;    //位图指针
  RECT          m_rcPosition;   //子画面位置
  POINT         m_ptVelocity;   //速度
  int           m_iZOrder;    //z顺序
  RECT          m_rcBounds;    //边界矩形
  BOUNDSACTION  m_baBoundsAction; //边界动作
  BOOL          m_bHidden;    //可见/隐藏

基于以上属性,子画面(Sprite)类程序清单如下:

//-----------------------------------------------------------------
// Sprite Object
// C++ Header - Sprite.h
//-----------------------------------------------------------------

#pragma once

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include 
 
 
  
  
#include "Bitmap.h"

//-----------------------------------------------------------------
// 自定义数据类型(边界动作)
//-----------------------------------------------------------------
typedef WORD        BOUNDSACTION;
const BOUNDSACTION  BA_STOP   = 0,
                    BA_WRAP   = 1,
                    BA_BOUNCE = 2,
                    BA_DIE    = 3;

//-----------------------------------------------------------------
// Sprite Class
//-----------------------------------------------------------------
class Sprite
{
protected:
  // Member Variables
  Bitmap*       m_pBitmap;		  //位图指针
  RECT          m_rcPosition;	  //子画面位置
  POINT         m_ptVelocity;	  //速度
  int           m_iZOrder;		  //z顺序
  RECT          m_rcBounds;		  //边界矩形
  BOUNDSACTION  m_baBoundsAction; //边界动作
  BOOL          m_bHidden;		  //可见/隐藏

public:
  // Constructor(s)/Destructor
  Sprite(Bitmap* pBitmap);
  Sprite(Bitmap* pBitmap, RECT& rcBounds,
    BOUNDSACTION baBoundsAction = BA_STOP);
  Sprite(Bitmap* pBitmap, POINT ptPosition, POINT ptVelocity, int iZOrder,
    RECT& rcBounds, BOUNDSACTION baBoundsAction = BA_STOP);
  virtual ~Sprite();

  // General Methods
  virtual void  Update();
  void          Draw(HDC hDC);
  BOOL          IsPointInside(int x, int y);

  // 访问方法
  RECT&   GetPosition()             { return m_rcPosition; };
  void    SetPosition(int x, int y);
  void    SetPosition(POINT ptPosition);
  void    SetPosition(RECT& rcPosition)
    { CopyRect(&m_rcPosition, &rcPosition); };
  void    OffsetPosition(int x, int y);
  POINT   GetVelocity()             { return m_ptVelocity; };
  void    SetVelocity(int x, int y);
  void    SetVelocity(POINT ptVelocity);
  BOOL    GetZOrder()               { return m_iZOrder; };
  void    SetZOrder(int iZOrder)    { m_iZOrder = iZOrder; };
  void    SetBounds(RECT& rcBounds) { CopyRect(&m_rcBounds, &rcBounds); };
  void    SetBoundsAction(BOUNDSACTION ba) { m_baBoundsAction = ba; };
  BOOL    IsHidden()                { return m_bHidden; };
  void    SetHidden(BOOL bHidden)   { m_bHidden = bHidden; };
  int     GetWidth()                { return m_pBitmap->GetWidth(); };
  int     GetHeight()               { return m_pBitmap->GetHeight(); };
};

//-----------------------------------------------------------------
// Sprite Inline General Methods
//-----------------------------------------------------------------
inline BOOL Sprite::IsPointInside(int x, int y)
{
  POINT ptPoint;
  ptPoint.x = x;
  ptPoint.y = y;
  return PtInRect(&m_rcPosition, ptPoint);
}

//-----------------------------------------------------------------
// Sprite Inline Accessor Methods
//-----------------------------------------------------------------
inline void Sprite::SetPosition(int x, int y)
{
  OffsetRect(&m_rcPosition, x - m_rcPosition.left, y - m_rcPosition.top);
}

inline void Sprite::SetPosition(POINT ptPosition)
{
  OffsetRect(&m_rcPosition, ptPosition.x - m_rcPosition.left,
    ptPosition.y - m_rcPosition.top);
}

inline void Sprite::OffsetPosition(int x, int y)
{
  OffsetRect(&m_rcPosition, x, y);
}

inline void Sprite::SetVelocity(int x, int y)
{
  m_ptVelocity.x = x;
  m_ptVelocity.y = y;
}

inline void Sprite::SetVelocity(POINT ptVelocity)
{
  m_ptVelocity.x = ptVelocity.x;
  m_ptVelocity.y = ptVelocity.y;
}

  
  

 
 
//-----------------------------------------------------------------
// Sprite Object
// C++ Source - Sprite.cpp
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "Sprite.h"

//-----------------------------------------------------------------
// Sprite Constructor(s)/Destructor
//-----------------------------------------------------------------
Sprite::Sprite(Bitmap* pBitmap)
{
  //初始化成员变量
  m_pBitmap = pBitmap;
  SetRect(&m_rcPosition, 0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
  m_ptVelocity.x = m_ptVelocity.y = 0;
  m_iZOrder = 0;
  SetRect(&m_rcBounds, 0, 0, 640, 480);
  m_baBoundsAction = BA_STOP;
  m_bHidden = FALSE;
}

Sprite::Sprite(Bitmap* pBitmap, RECT& rcBounds, BOUNDSACTION baBoundsAction)
{
  // 计算一个随机位置
  int iXPos = rand() % (rcBounds.right - rcBounds.left);
  int iYPos = rand() % (rcBounds.bottom - rcBounds.top);

  // 初始化成员变量
  m_pBitmap = pBitmap;
  SetRect(&m_rcPosition, iXPos, iYPos, iXPos + pBitmap->GetWidth(),
    iYPos + pBitmap->GetHeight());
  m_ptVelocity.x = m_ptVelocity.y = 0;
  m_iZOrder = 0;
  CopyRect(&m_rcBounds, &rcBounds);
  m_baBoundsAction = baBoundsAction;
  m_bHidden = FALSE;
}

Sprite::Sprite(Bitmap* pBitmap, POINT ptPosition, POINT ptVelocity, int iZOrder,
    RECT& rcBounds, BOUNDSACTION baBoundsAction)
{
  //初始化成员变量
  m_pBitmap = pBitmap;
  SetRect(&m_rcPosition, ptPosition.x, ptPosition.y,
    ptPosition.x + pBitmap->GetWidth(), ptPosition.y + pBitmap->GetHeight());
  m_ptVelocity = ptVelocity;
  m_iZOrder = iZOrder;
  CopyRect(&m_rcBounds, &rcBounds);
  m_baBoundsAction = baBoundsAction;
  m_bHidden = FALSE;
}

Sprite::~Sprite()
{
}

//-----------------------------------------------------------------
// Sprite General Methods
//-----------------------------------------------------------------
void Sprite::Update()
{
  // 更新位置
  POINT ptNewPosition, ptSpriteSize, ptBoundsSize;
  ptNewPosition.x = m_rcPosition.left + m_ptVelocity.x;
  ptNewPosition.y = m_rcPosition.top + m_ptVelocity.y;
  ptSpriteSize.x = m_rcPosition.right - m_rcPosition.left;
  ptSpriteSize.y = m_rcPosition.bottom - m_rcPosition.top;
  ptBoundsSize.x = m_rcBounds.right - m_rcBounds.left;
  ptBoundsSize.y = m_rcBounds.bottom - m_rcBounds.top;

  // 检查边界动作
  // 环绕
  if (m_baBoundsAction == BA_WRAP)
  {
    if ((ptNewPosition.x + ptSpriteSize.x) < m_rcBounds.left)
      ptNewPosition.x = m_rcBounds.right;
    else if (ptNewPosition.x > m_rcBounds.right)
      ptNewPosition.x = m_rcBounds.left - ptSpriteSize.x;
    if ((ptNewPosition.y + ptSpriteSize.y) < m_rcBounds.top)
      ptNewPosition.y = m_rcBounds.bottom;
    else if (ptNewPosition.y > m_rcBounds.bottom)
      ptNewPosition.y = m_rcBounds.top - ptSpriteSize.y;
  }
  // 弹开
  else if (m_baBoundsAction == BA_BOUNCE)
  {
    BOOL bBounce = FALSE;
    POINT ptNewVelocity = m_ptVelocity;
    if (ptNewPosition.x < m_rcBounds.left)
    {
      bBounce = TRUE;
      ptNewPosition.x = m_rcBounds.left;
      ptNewVelocity.x = -ptNewVelocity.x;
    }
    else if ((ptNewPosition.x + ptSpriteSize.x) > m_rcBounds.right)
    {
      bBounce = TRUE;
      ptNewPosition.x = m_rcBounds.right - ptSpriteSize.x;
      ptNewVelocity.x = -ptNewVelocity.x;
    }
    if (ptNewPosition.y < m_rcBounds.top)
    {
      bBounce = TRUE;
      ptNewPosition.y = m_rcBounds.top;
      ptNewVelocity.y = -ptNewVelocity.y;
    }
    else if ((ptNewPosition.y + ptSpriteSize.y) > m_rcBounds.bottom)
    {
      bBounce = TRUE;
      ptNewPosition.y = m_rcBounds.bottom - ptSpriteSize.y;
      ptNewVelocity.y = -ptNewVelocity.y;
    }
    if (bBounce)
      SetVelocity(ptNewVelocity);
  }
  // 停止(默认)
  else
  {
    if (ptNewPosition.x  < m_rcBounds.left ||
      ptNewPosition.x > (m_rcBounds.right - ptSpriteSize.x))
    {
      ptNewPosition.x = max(m_rcBounds.left, min(ptNewPosition.x,
        m_rcBounds.right - ptSpriteSize.x));
      SetVelocity(0, 0);
    }
    if (ptNewPosition.y  < m_rcBounds.top ||
      ptNewPosition.y > (m_rcBounds.bottom - ptSpriteSize.y))
    {
      ptNewPosition.y = max(m_rcBounds.top, min(ptNewPosition.y,
        m_rcBounds.bottom - ptSpriteSize.y));
      SetVelocity(0, 0);
    }
  }
  SetPosition(ptNewPosition);
}

void Sprite::Draw(HDC hDC)
{
  // 如果没有隐藏,使用子画面
  if (m_pBitmap != NULL && !m_bHidden)
    m_pBitmap->Draw(hDC, m_rcPosition.left, m_rcPosition.top, TRUE);
}

当然附上一个相应的实例程序:创建几个行星子画面,并让它们在游戏屏幕上飞来飞去,分别带有一种边界动作。

程序清单:

 

//-----------------------------------------------------------------
// Planets Application
// C++ Header - Planets.h
//-----------------------------------------------------------------

#pragma once

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include 
 
 
  
  
#include "Resource.h"
#include "GameEngine.h"
#include "Bitmap.h"
#include "Sprite.h"

//-----------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------
HINSTANCE   g_hInstance;
GameEngine* g_pGame;
Bitmap*     g_pGalaxyBitmap;	//背景
Bitmap*     g_pPlanetBitmap[3];	//行星位图
Sprite*     g_pPlanetSprite[3];	//行星子画面
BOOL        g_bDragging;		//拖动标志
int         g_iDragPlanet;		//拖动行星号

  
  

 
 

 

 

//-----------------------------------------------------------------
// Planets Application
// C++ Source - Planets.cpp
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "Planets.h"

//-----------------------------------------------------------------
// Game Engine Functions
//-----------------------------------------------------------------
BOOL GameInitialize(HINSTANCE hInstance)
{
  // Create the game engine
  g_pGame = new GameEngine(hInstance, TEXT("Planets"),
    TEXT("Planets"), IDI_PLANETS, IDI_PLANETS_SM, 600, 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)
{
  // Seed the random number generator
  srand(GetTickCount());

  //创建并加载位图
  HDC hDC = GetDC(hWindow);
  g_pGalaxyBitmap = new Bitmap(hDC, IDB_GALAXY, g_hInstance);
  g_pPlanetBitmap[0] = new Bitmap(hDC, IDB_PLANET1, g_hInstance);
  g_pPlanetBitmap[1] = new Bitmap(hDC, IDB_PLANET2, g_hInstance);
  g_pPlanetBitmap[2] = new Bitmap(hDC, IDB_PLANET3, g_hInstance);

  //创建行星子画面
  RECT rcBounds = { 0, 0, 600, 400 };
  g_pPlanetSprite[0] = new Sprite(g_pPlanetBitmap[0], rcBounds);
  g_pPlanetSprite[1] = new Sprite(g_pPlanetBitmap[1], rcBounds, BA_WRAP);
  g_pPlanetSprite[2] = new Sprite(g_pPlanetBitmap[2], rcBounds, BA_BOUNCE);
  g_pPlanetSprite[0]->SetPosition(0, 0);
  g_pPlanetSprite[0]->SetVelocity(1, 1);
  g_pPlanetSprite[1]->SetVelocity(2, -1);
  g_pPlanetSprite[2]->SetVelocity(3, -2);

  //设置初始拖动信息
  g_bDragging = FALSE;
  g_iDragPlanet = -1;
}

void GameEnd()
{
  // Cleanup the bitmaps
  delete g_pGalaxyBitmap;
  for (int i = 0; i < 3; i++)
    delete g_pPlanetBitmap[i];

  // Cleanup the sprites
  for (i = 0; i < 3; i++)
    delete g_pPlanetSprite[i];

  // Cleanup the game engine
  delete g_pGame;
}

void GameActivate(HWND hWindow)
{
}

void GameDeactivate(HWND hWindow)
{
}

void GamePaint(HDC hDC)
{
  // 绘制星系背景
  g_pGalaxyBitmap->Draw(hDC, 0, 0);

  // 绘制行星子画面
  for (int i = 0; i < 3; i++)
    g_pPlanetSprite[i]->Draw(hDC);
}

void GameCycle()
{
  // 更新行星子画面
  for (int i = 0; i < 3; i++)
    g_pPlanetSprite[i]->Update();

  // Force a repaint to redraw the planets
  InvalidateRect(g_pGame->GetWindow(), NULL, FALSE);
}

void HandleKeys()
{
}

void MouseButtonDown(int x, int y, BOOL bLeft)
{
  //查看是否使用鼠标左键单击了一颗行星
  if (bLeft && !g_bDragging)
  {
    for (int i = 0; i < 3; i++)
      if (g_pPlanetSprite[i]->IsPointInside(x, y))
      {
        // 捕获鼠标
        SetCapture(g_pGame->GetWindow());

        // Set the drag state and the drag planet
        g_bDragging = TRUE;
        g_iDragPlanet = i;

        //开始模拟鼠标移动
        MouseMove(x, y);

        // 不检查其他行星
        break;
      }
  }
}

void MouseButtonUp(int x, int y, BOOL bLeft)
{
  // 释放鼠标
  ReleaseCapture();

  // 停止拖动
  g_bDragging = FALSE;
}

void MouseMove(int x, int y)
{
  if (g_bDragging)
  {
    //将子画面移动到鼠标指针位置
    g_pPlanetSprite[g_iDragPlanet]->SetPosition(
      x - (g_pPlanetBitmap[g_iDragPlanet]->GetWidth() / 2),
      y - (g_pPlanetBitmap[g_iDragPlanet]->GetHeight() / 2));

    // Force a repaint to redraw the planets
    InvalidateRect(g_pGame->GetWindow(), NULL, FALSE);
  }
}

void HandleJoystick(JOYSTATE jsJoystickState)
{
}

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/103405
推荐阅读
相关标签
  

闽ICP备14008679号