2D游戏引擎(六)——添加子画面管理器

 子画面管理器集成在游戏引擎类里面,对子画面对象进行一些操作处理,例如把子画面集中在一个vector类中,对其进行批量更新和绘制。因为修改的东西较多,我也懒得写了,贴下代码吧。另外此次修改也顺便解决下游戏画面的闪烁问题,自然采用双重缓存技术。

代码清单:

//-----------------------------------------------------------------
// Game Engine Object
// C++ Header - GameEngine.h
//-----------------------------------------------------------------

#pragma once

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include 
 
 
  
  
#include 
  
  
   
   
#include 
   
   
    
    
using namespace std;
#include "Sprite.h"

//-----------------------------------------------------------------
// Joystick Flags
//-----------------------------------------------------------------
typedef WORD    JOYSTATE;
const JOYSTATE  JOY_NONE  = 0x0000L,
                JOY_LEFT  = 0x0001L,
                JOY_RIGHT = 0x0002L,
                JOY_UP    = 0x0004L,
                JOY_DOWN  = 0x0008L,
                JOY_FIRE1 = 0x0010L,
                JOY_FIRE2 = 0x0020L;

//-----------------------------------------------------------------
// Windows Function Declarations
//-----------------------------------------------------------------
int WINAPI        WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow);
LRESULT CALLBACK  WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

//-----------------------------------------------------------------
// Game Engine Function Declarations
//-----------------------------------------------------------------
BOOL GameInitialize(HINSTANCE hInstance);
void GameStart(HWND hWindow);
void GameEnd();
void GameActivate(HWND hWindow);
void GameDeactivate(HWND hWindow);
void GamePaint(HDC hDC);
void GameCycle();
void HandleKeys();
void MouseButtonDown(int x, int y, BOOL bLeft);
void MouseButtonUp(int x, int y, BOOL bLeft);
void MouseMove(int x, int y);
void HandleJoystick(JOYSTATE jsJoystickState);
BOOL SpriteCollision(Sprite* pSpriteHitter, Sprite* pSpriteHittee);	//新增的游戏方法,定义了游戏对碰撞的处理

//-----------------------------------------------------------------
// GameEngine Class
//-----------------------------------------------------------------
class GameEngine
{
protected:
  // Member Variables
  static GameEngine*  m_pGameEngine;
  HINSTANCE           m_hInstance;
  HWND                m_hWindow;
  TCHAR               m_szWindowClass[32];
  TCHAR               m_szTitle[32];
  WORD                m_wIcon, m_wSmallIcon;
  int                 m_iWidth, m_iHeight;
  int                 m_iFrameDelay;
  BOOL                m_bSleep;
  UINT                m_uiJoystickID;
  RECT                m_rcJoystickTrip;
  vector
    
    
     
          m_vSprites;		//增加了一个vector类,记录子画面列表

  // Helper Methods
  BOOL                CheckSpriteCollision(Sprite* pTestSprite);

public:
  // Constructor(s)/Destructor
          GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass, LPTSTR szTitle,
            WORD wIcon, WORD wSmallIcon, int iWidth = 640, int iHeight = 480);
  virtual ~GameEngine();

  // General Methods
  static GameEngine*  GetEngine() { return m_pGameEngine; };
  BOOL                Initialize(int iCmdShow);
  LRESULT             HandleEvent(HWND hWindow, UINT msg, WPARAM wParam,
                        LPARAM lParam);
  void                ErrorQuit(LPTSTR szErrorMsg);
  BOOL                InitJoystick();
  void                CaptureJoystick();
  void                ReleaseJoystick();
  void                CheckJoystick();
  //以下常规方法为子画面管理器的一组方法
  void                AddSprite(Sprite* pSprite);
  void                DrawSprites(HDC hDC);
  void                UpdateSprites();
  void                CleanupSprites();
  Sprite*             IsPointInSprite(int x, int y);

  // Accessor Methods
  HINSTANCE GetInstance() { return m_hInstance; };
  HWND      GetWindow() { return m_hWindow; };
  void      SetWindow(HWND hWindow) { m_hWindow = hWindow; };
  LPTSTR    GetTitle() { return m_szTitle; };
  WORD      GetIcon() { return m_wIcon; };
  WORD      GetSmallIcon() { return m_wSmallIcon; };
  int       GetWidth() { return m_iWidth; };
  int       GetHeight() { return m_iHeight; };
  int       GetFrameDelay() { return m_iFrameDelay; };
  void      SetFrameRate(int iFrameRate) { m_iFrameDelay = 1000 /
              iFrameRate; };
  BOOL      GetSleep() { return m_bSleep; };
  void      SetSleep(BOOL bSleep) { m_bSleep = bSleep; };
};

     
     
 
//-----------------------------------------------------------------
// Game Engine Object
// C++ Source - GameEngine.cpp
//-----------------------------------------------------------------

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

//-----------------------------------------------------------------
// Static Variable Initialization
//-----------------------------------------------------------------
GameEngine *GameEngine::m_pGameEngine = NULL;

//-----------------------------------------------------------------
// Windows Functions
//-----------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  PSTR szCmdLine, int iCmdShow)
{
  MSG         msg;
  static int  iTickTrigger = 0;
  int         iTickCount;

  if (GameInitialize(hInstance))
  {
    // Initialize the game engine
    if (!GameEngine::GetEngine()->Initialize(iCmdShow))
      return FALSE;

    // Enter the main message loop
    while (TRUE)
    {
      if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
      {
        // Process the message
        if (msg.message == WM_QUIT)
          break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      else
      {
        // Make sure the game engine isn't sleeping
        if (!GameEngine::GetEngine()->GetSleep())
        {
          // Check the tick count to see if a game cycle has elapsed
          iTickCount = GetTickCount();
          if (iTickCount > iTickTrigger)
          {
            iTickTrigger = iTickCount +
              GameEngine::GetEngine()->GetFrameDelay();
            HandleKeys();
            GameEngine::GetEngine()->CheckJoystick();
            GameCycle();
          }
        }
      }
    }
    return (int)msg.wParam;
  }

  // End the game
  GameEnd();

  return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
{
  // Route all Windows messages to the game engine
  return GameEngine::GetEngine()->HandleEvent(hWindow, msg, wParam, lParam);
}

//-----------------------------------------------------------------
// Game Engine Helper Methods
//-----------------------------------------------------------------
BOOL GameEngine::CheckSpriteCollision(Sprite* pTestSprite)
{
  // See if the sprite has collided with any other sprites
  vector
 
 
  
  ::iterator siSprite;
  for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
  {
    // Make sure not to check for collision with itself
    if (pTestSprite == (*siSprite))
      continue;

    // Test the collision
    if (pTestSprite->TestCollision(*siSprite))
      // Collision detected
      return SpriteCollision((*siSprite), pTestSprite);
  }

  // No collision
  return FALSE;
}

//-----------------------------------------------------------------
// GameEngine Constructor(s)/Destructor
//-----------------------------------------------------------------
GameEngine::GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass,
  LPTSTR szTitle, WORD wIcon, WORD wSmallIcon, int iWidth, int iHeight)
{
  // Set the member variables for the game engine
  m_pGameEngine = this;
  m_hInstance = hInstance;
  m_hWindow = NULL;
  if (lstrlen(szWindowClass) > 0)
    lstrcpy(m_szWindowClass, szWindowClass);
  if (lstrlen(szTitle) > 0)
    lstrcpy(m_szTitle, szTitle);
  m_wIcon = wIcon;
  m_wSmallIcon = wSmallIcon;
  m_iWidth = iWidth;
  m_iHeight = iHeight;
  m_iFrameDelay = 50;   // 20 FPS default
  m_bSleep = TRUE;
  m_uiJoystickID = 0;
  m_vSprites.reserve(100);	  //可以容纳100个子画面指针对象
}

GameEngine::~GameEngine()
{
}

//-----------------------------------------------------------------
// Game Engine General Methods
//-----------------------------------------------------------------
BOOL GameEngine::Initialize(int iCmdShow)
{
  WNDCLASSEX    wndclass;

  // Create the window class for the main window
  wndclass.cbSize         = sizeof(wndclass);
  wndclass.style          = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc    = WndProc;
  wndclass.cbClsExtra     = 0;
  wndclass.cbWndExtra     = 0;
  wndclass.hInstance      = m_hInstance;
  wndclass.hIcon          = LoadIcon(m_hInstance,
    MAKEINTRESOURCE(GetIcon()));
  wndclass.hIconSm        = LoadIcon(m_hInstance,
    MAKEINTRESOURCE(GetSmallIcon()));
  wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  wndclass.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  wndclass.lpszMenuName   = NULL;
  wndclass.lpszClassName  = m_szWindowClass;

  // Register the window class
  if (!RegisterClassEx(&wndclass))
    return FALSE;

  // Calculate the window size and position based upon the game size
  int iWindowWidth = m_iWidth + GetSystemMetrics(SM_CXFIXEDFRAME) * 2,
      iWindowHeight = m_iHeight + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 +
        GetSystemMetrics(SM_CYCAPTION);
  if (wndclass.lpszMenuName != NULL)
    iWindowHeight += GetSystemMetrics(SM_CYMENU);
  int iXWindowPos = (GetSystemMetrics(SM_CXSCREEN) - iWindowWidth) / 2,
      iYWindowPos = (GetSystemMetrics(SM_CYSCREEN) - iWindowHeight) / 2;

  // Create the window
  m_hWindow = CreateWindow(m_szWindowClass, m_szTitle, WS_POPUPWINDOW |
    WS_CAPTION | WS_MINIMIZEBOX, iXWindowPos, iYWindowPos, iWindowWidth,
    iWindowHeight, NULL, NULL, m_hInstance, NULL);
  if (!m_hWindow)
    return FALSE;

  // Show and update the window
  ShowWindow(m_hWindow, iCmdShow);
  UpdateWindow(m_hWindow);

  return TRUE;
}

LRESULT GameEngine::HandleEvent(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
{
  // Route Windows messages to game engine member functions
  switch (msg)
  {
    case WM_CREATE:
      // Set the game window and start the game
      SetWindow(hWindow);
      GameStart(hWindow);
      return 0;

    case WM_SETFOCUS:
      // Activate the game and update the Sleep status
      GameActivate(hWindow);
      SetSleep(FALSE);
      return 0;

    case WM_KILLFOCUS:
      // Deactivate the game and update the Sleep status
      GameDeactivate(hWindow);
      SetSleep(TRUE);
      return 0;

    case WM_PAINT:
      HDC         hDC;
      PAINTSTRUCT ps;
      hDC = BeginPaint(hWindow, &ps);

      // Paint the game
      GamePaint(hDC);

      EndPaint(hWindow, &ps);
      return 0;

    case WM_LBUTTONDOWN:
      // Handle left mouse button press
      MouseButtonDown(LOWORD(lParam), HIWORD(lParam), TRUE);
      return 0;

    case WM_LBUTTONUP:
      // Handle left mouse button release
      MouseButtonUp(LOWORD(lParam), HIWORD(lParam), TRUE);
      return 0;

    case WM_RBUTTONDOWN:
      // Handle right mouse button press
      MouseButtonDown(LOWORD(lParam), HIWORD(lParam), FALSE);
      return 0;

    case WM_RBUTTONUP:
      // Handle right mouse button release
      MouseButtonUp(LOWORD(lParam), HIWORD(lParam), FALSE);
      return 0;

    case WM_MOUSEMOVE:
      // Handle mouse movement
      MouseMove(LOWORD(lParam), HIWORD(lParam));
      return 0;

    case WM_DESTROY:
      // End the game and exit the application
      GameEnd();
      PostQuitMessage(0);
      return 0;
  }
  return DefWindowProc(hWindow, msg, wParam, lParam);
}

void GameEngine::ErrorQuit(LPTSTR szErrorMsg)
{
  MessageBox(GetWindow(), szErrorMsg, TEXT("Critical Error"), MB_OK | MB_ICONERROR);
  PostQuitMessage(0);
}

BOOL GameEngine::InitJoystick()
{
  // Make sure joystick driver is present
  UINT uiNumJoysticks;
  if ((uiNumJoysticks = joyGetNumDevs()) == 0)
    return FALSE;

  // Make sure the joystick is attached
  JOYINFO jiInfo;
  if (joyGetPos(JOYSTICKID1, &jiInfo) != JOYERR_UNPLUGGED)
    m_uiJoystickID = JOYSTICKID1;
  else
    return FALSE;

  // Calculate the trip values
  JOYCAPS jcCaps;
  joyGetDevCaps(m_uiJoystickID, &jcCaps, sizeof(JOYCAPS));
  DWORD dwXCenter = ((DWORD)jcCaps.wXmin + jcCaps.wXmax) / 2;
  DWORD dwYCenter = ((DWORD)jcCaps.wYmin + jcCaps.wYmax) / 2;
  m_rcJoystickTrip.left = (jcCaps.wXmin + (WORD)dwXCenter) / 2;
  m_rcJoystickTrip.right = (jcCaps.wXmax + (WORD)dwXCenter) / 2;
  m_rcJoystickTrip.top = (jcCaps.wYmin + (WORD)dwYCenter) / 2;
  m_rcJoystickTrip.bottom = (jcCaps.wYmax + (WORD)dwYCenter) / 2;

  return TRUE;
}

void GameEngine::CaptureJoystick()
{
  // Capture the joystick
  if (m_uiJoystickID == JOYSTICKID1)
    joySetCapture(m_hWindow, m_uiJoystickID, NULL, TRUE);
}

void GameEngine::ReleaseJoystick()
{
  // Release the joystick
  if (m_uiJoystickID == JOYSTICKID1)
    joyReleaseCapture(m_uiJoystickID);
}

void GameEngine::CheckJoystick()
{
  if (m_uiJoystickID == JOYSTICKID1)
  {
    JOYINFO jiInfo;
    JOYSTATE jsJoystickState = 0;
    if (joyGetPos(m_uiJoystickID, &jiInfo) == JOYERR_NOERROR)
    {
      // Check horizontal movement
      if (jiInfo.wXpos < (WORD)m_rcJoystickTrip.left)
        jsJoystickState |= JOY_LEFT;
      else if (jiInfo.wXpos > (WORD)m_rcJoystickTrip.right)
        jsJoystickState |= JOY_RIGHT;

      // Check vertical movement
      if (jiInfo.wYpos < (WORD)m_rcJoystickTrip.top)
        jsJoystickState |= JOY_UP;
      else if (jiInfo.wYpos > (WORD)m_rcJoystickTrip.bottom)
        jsJoystickState |= JOY_DOWN;

      // Check buttons
      if(jiInfo.wButtons & JOY_BUTTON1)
        jsJoystickState |= JOY_FIRE1;
      if(jiInfo.wButtons & JOY_BUTTON2)
        jsJoystickState |= JOY_FIRE2;
    }

    // Allow the game to handle the joystick
    HandleJoystick(jsJoystickState);
  }
}

void GameEngine::AddSprite(Sprite* pSprite)
{
  // 向子画面列表增加一个子画面对象
  if (pSprite != NULL)
  {
    // See if there are sprites already in the sprite vector
    if (m_vSprites.size() > 0)
    {
      // Find a spot in the sprite vector to insert the sprite by its z-order
      vector
  
  
   
   ::iterator siSprite;
      for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
        if (pSprite->GetZOrder() < (*siSprite)->GetZOrder())
        {
          // Insert the sprite into the sprite vector
          m_vSprites.insert(siSprite, pSprite);
          return;
        }
    }

    // The sprite's z-order is highest, so add it to the end of the vector
    m_vSprites.push_back(pSprite);
  }
}

void GameEngine::DrawSprites(HDC hDC)
{
  // Draw the sprites in the sprite vector
  vector
   
   
    
    ::iterator siSprite;
  for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
    (*siSprite)->Draw(hDC);
}

void GameEngine::UpdateSprites()
{
  // Check to see if the sprite vector needs to grow
  if (m_vSprites.size() >= (m_vSprites.capacity() / 2))
    m_vSprites.reserve(m_vSprites.capacity() * 2);

  // Update the sprites in the sprite vector
  RECT          rcOldSpritePos;
  SPRITEACTION  saSpriteAction;
  vector
    
    
     
     ::iterator siSprite;
  for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
  {
    // Save the old sprite position in case we need to restore it
    rcOldSpritePos = (*siSprite)->GetPosition();

    // Update the sprite
    saSpriteAction = (*siSprite)->Update();

    // Handle the SA_KILL sprite action
    if (saSpriteAction & SA_KILL)
    {
      delete (*siSprite);
      m_vSprites.erase(siSprite);
      siSprite--;
      continue;
    }

    // See if the sprite collided with any others
    if (CheckSpriteCollision(*siSprite))
      // Restore the old sprite position
      (*siSprite)->SetPosition(rcOldSpritePos);
  }
}

void GameEngine::CleanupSprites()
{
  // Delete and remove the sprites in the sprite vector
  vector
     
     
      
      ::iterator siSprite;
  for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++)
  {
    delete (*siSprite);
    m_vSprites.erase(siSprite);
    siSprite--;
  }
}

Sprite* GameEngine::IsPointInSprite(int x, int y)
{
  // See if the point is in a sprite in the sprite vector
  vector
      
      
        ::reverse_iterator siSprite; for (siSprite = m_vSprites.rbegin(); siSprite != m_vSprites.rend(); siSprite++) if (!(*siSprite)->IsHidden() && (*siSprite)->IsPointInside(x, y)) return (*siSprite); // The point is not in a sprite return NULL; } 
       
 
      
     
     
    
    
   
   
  
  
 
 

 

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

#pragma once

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

//-----------------------------------------------------------------
// Custom Data Types
//-----------------------------------------------------------------
typedef WORD        SPRITEACTION;		  //新增结构类型,定义子画面行为方式
const SPRITEACTION  SA_NONE   = 0x0000L,
                    SA_KILL   = 0x0001L;

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,
                m_rcCollision;		//新增成员变量,碰撞矩形
  POINT         m_ptVelocity;
  int           m_iZOrder;
  RECT          m_rcBounds;
  BOUNDSACTION  m_baBoundsAction;
  BOOL          m_bHidden;

  // Helper Methods
  virtual void  CalcCollisionRect();

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 SPRITEACTION  Update();
  void                  Draw(HDC hDC);
  BOOL                  IsPointInside(int x, int y);
  BOOL                  TestCollision(Sprite* pTestSprite);

  // Accessor Methods
  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);
  RECT&   GetCollision()            { return m_rcCollision; };
  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 Helper Methods
//-----------------------------------------------------------------
inline void Sprite::CalcCollisionRect()
{
  int iXShrink = (m_rcPosition.left - m_rcPosition.right) / 12;
  int iYShrink = (m_rcPosition.top - m_rcPosition.bottom) / 12;
  CopyRect(&m_rcCollision, &m_rcPosition);
  InflateRect(&m_rcCollision, iXShrink, iYShrink);
}

//-----------------------------------------------------------------
// Sprite Inline General Methods
//-----------------------------------------------------------------
inline BOOL Sprite::TestCollision(Sprite* pTestSprite)
{
  RECT& rcTest = pTestSprite->GetCollision();
  return m_rcCollision.left <= rcTest.right &&
         rcTest.left <= m_rcCollision.right &&
         m_rcCollision.top <= rcTest.bottom &&
         rcTest.top <= m_rcCollision.bottom;
}

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);
  CalcCollisionRect();
}

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

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

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)
{
  // Initialize the member variables
  m_pBitmap = pBitmap;
  SetRect(&m_rcPosition, 0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
  CalcCollisionRect();
  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)
{
  // Calculate a random position
  int iXPos = rand() % (rcBounds.right - rcBounds.left);
  int iYPos = rand() % (rcBounds.bottom - rcBounds.top);

  // Initialize the member variables
  m_pBitmap = pBitmap;
  SetRect(&m_rcPosition, iXPos, iYPos, iXPos + pBitmap->GetWidth(),
    iYPos + pBitmap->GetHeight());
  CalcCollisionRect();
  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)
{
  // Initialize the member variables
  m_pBitmap = pBitmap;
  SetRect(&m_rcPosition, ptPosition.x, ptPosition.y,
    ptPosition.x + pBitmap->GetWidth(), ptPosition.y + pBitmap->GetHeight());
  CalcCollisionRect();
  m_ptVelocity = ptVelocity;
  m_iZOrder = iZOrder;
  CopyRect(&m_rcBounds, &rcBounds);
  m_baBoundsAction = baBoundsAction;
  m_bHidden = FALSE;
}

Sprite::~Sprite()
{
}

//-----------------------------------------------------------------
// Sprite General Methods
//-----------------------------------------------------------------
SPRITEACTION Sprite::Update()
{
  // Update the position
  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;

  // Check the bounds
  // Wrap?
  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;
  }
  // Bounce?
  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);
  }
  // Die?
  else if (m_baBoundsAction == BA_DIE)
  {
    if ((ptNewPosition.x + ptSpriteSize.x) < m_rcBounds.left ||
      ptNewPosition.x > m_rcBounds.right ||
      (ptNewPosition.y + ptSpriteSize.y) < m_rcBounds.top ||
      ptNewPosition.y > m_rcBounds.bottom)
      return SA_KILL;
  }
  // Stop (default)
  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);

  return SA_NONE;
}

void Sprite::Draw(HDC hDC)
{
  // Draw the sprite if it isn't hidden
  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;
HDC         g_hOffscreenDC;		//内存设备环境
HBITMAP     g_hOffscreenBitmap;	//屏幕外位图
Bitmap*     g_pGalaxyBitmap;
Bitmap*     g_pPlanetBitmap[3];
Sprite*     g_pDragSprite;

  
  

 
 

 

//-----------------------------------------------------------------
// Planets 2 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 2"),
    TEXT("Planets 2"), 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());

  // 创建屏幕外设备环境和位图
  g_hOffscreenDC = CreateCompatibleDC(GetDC(hWindow));
  g_hOffscreenBitmap = CreateCompatibleBitmap(GetDC(hWindow),
    g_pGame->GetWidth(), g_pGame->GetHeight());
  SelectObject(g_hOffscreenDC, g_hOffscreenBitmap);

  // Create and load the bitmaps
  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 };
  Sprite* pSprite;
  pSprite = new Sprite(g_pPlanetBitmap[0], rcBounds, BA_WRAP);
  pSprite->SetVelocity(3, 2);
  g_pGame->AddSprite(pSprite);
  pSprite = new Sprite(g_pPlanetBitmap[1], rcBounds, BA_WRAP);
  pSprite->SetVelocity(4, 1);
  g_pGame->AddSprite(pSprite);
  rcBounds.right = 200; rcBounds.bottom = 160;
  pSprite = new Sprite(g_pPlanetBitmap[2], rcBounds, BA_BOUNCE);
  pSprite->SetVelocity(-4, 2);
  g_pGame->AddSprite(pSprite);
  rcBounds.left = 400; rcBounds.top = 240;
  rcBounds.right = 600; rcBounds.bottom = 400;
  pSprite = new Sprite(g_pPlanetBitmap[2], rcBounds, BA_BOUNCE);
  pSprite->SetVelocity(7, -3);
  g_pGame->AddSprite(pSprite);

  // 设置初始拖动信息
  g_pDragSprite = NULL;
}

void GameEnd()
{
  // Cleanup the offscreen device context and bitmap
  DeleteObject(g_hOffscreenBitmap);
  DeleteDC(g_hOffscreenDC);  

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

  // Cleanup the sprites
  g_pGame->CleanupSprites();

  // Cleanup the game engine
  delete g_pGame;
}

void GameActivate(HWND hWindow)
{
}

void GameDeactivate(HWND hWindow)
{
}

void GamePaint(HDC hDC)
{
  // Draw the background galaxy
  g_pGalaxyBitmap->Draw(hDC, 0, 0);

  // Draw the sprites
  g_pGame->DrawSprites(hDC);
}

void GameCycle()
{
  // Update the sprites
  g_pGame->UpdateSprites();

  // Obtain a device context for repainting the game
  HWND  hWindow = g_pGame->GetWindow();
  HDC   hDC = GetDC(hWindow);

  // Paint the game to the offscreen device context
  GamePaint(g_hOffscreenDC);

  // Blit the offscreen bitmap to the game screen
  BitBlt(hDC, 0, 0, g_pGame->GetWidth(), g_pGame->GetHeight(),
    g_hOffscreenDC, 0, 0, SRCCOPY);

  // Cleanup
  ReleaseDC(hWindow, hDC);
}

void HandleKeys()
{
}

void MouseButtonDown(int x, int y, BOOL bLeft)
{
  // See if a planet was clicked with the left mouse button
  if (bLeft && (g_pDragSprite == NULL))
  {
    if ((g_pDragSprite = g_pGame->IsPointInSprite(x, y)) != NULL)
    {
      // Capture the mouse
      SetCapture(g_pGame->GetWindow());

      // Simulate a mouse move to get started
      MouseMove(x, y);
    }
  }
}

void MouseButtonUp(int x, int y, BOOL bLeft)
{
  // Release the mouse
  ReleaseCapture();

  // Stop dragging
  g_pDragSprite = NULL;
}

void MouseMove(int x, int y)
{
  if (g_pDragSprite != NULL)
  {
    // Move the sprite to the mouse cursor position
    g_pDragSprite->SetPosition(x - (g_pDragSprite->GetWidth() / 2),
      y - (g_pDragSprite->GetHeight() / 2));

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

void HandleJoystick(JOYSTATE jsJoystickState)
{
}

BOOL SpriteCollision(Sprite* pSpriteHitter, Sprite* pSpriteHittee)
{
  // Swap the sprite velocities so that they appear to bounce
  POINT ptSwapVelocity = pSpriteHitter->GetVelocity();
  pSpriteHitter->SetVelocity(pSpriteHittee->GetVelocity());
  pSpriteHittee->SetVelocity(ptSwapVelocity);
  return TRUE;
}
 

 

//-----------------------------------------------------------------
// Planets Resource Identifiers
// C++ Header - Resource.h
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Icons                    Range : 1000 - 1999
//-----------------------------------------------------------------
#define IDI_PLANETS         1000
#define IDI_PLANETS_SM      1001

//-----------------------------------------------------------------
// Bitmaps                  Range : 2000 - 2999
//-----------------------------------------------------------------
#define IDB_GALAXY          2000
#define IDB_PLANET1         2001
#define IDB_PLANET2         2002
#define IDB_PLANET3         2003

 

//-----------------------------------------------------------------
// Planets Resources
// RC Source - Planets.rc
//-----------------------------------------------------------------

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

//-----------------------------------------------------------------
// Icons
//-----------------------------------------------------------------
IDI_PLANETS        ICON         "Res//Planets.ico"
IDI_PLANETS_SM     ICON         "Res//Planets_sm.ico"

//-----------------------------------------------------------------
// Bitmaps
//-----------------------------------------------------------------
IDB_GALAXY         BITMAP       "Res//Galaxy.bmp"
IDB_PLANET1        BITMAP       "Res//Planet1.bmp"
IDB_PLANET2        BITMAP       "Res//Planet2.bmp"
IDB_PLANET3        BITMAP       "Res//Planet3.bmp"

程序截图:



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值