Documentation
[SDK Documentation] [Creating a complete game: Breakout]

 

Creating a complete game: Breakout

This document has been updated for use with GapiDraw 4.0 or later.
Last updated on October 6, 2008.

 

Step 5 : Ball class

Previous step | Next step

We now want to add a ball and bat to our environment. We will begin by adding the ball class and graphics.

Bat
Our ball. Shiny!

First, download the file ball.png and save it to your Breakout\Common\res folder. Then add it to your Visual Studio project as a PNG image and name it IDB_BALL.

Add the following code to myapplication.h:

//-----------------------------------------------------------------------------
// Name: class CBreakBall
// Desc: Everything related to the ball
//-----------------------------------------------------------------------------
class CBreakBall
{
// Attributes
protected:
    float m_nX;
    float m_nY;
    float m_nXSpeed;
    float m_nYSpeed;
    float m_nSpin;
    CGapiSurface* m_pBallSurface;
 
// Construction
public:
    CBreakBall(CGapiDraw* pGlobal, float nX=0.0f, float nY=0.0f)
    {
        m_nX = nX;
        m_nY = nY;
        m_nXSpeed = 0.0f;
        m_nYSpeed = 0.0f;
        m_nSpin = 0.0f;
        m_pBallSurface = new CGapiSurface(pGlobal);
    }
 
// Operations
public:
    void ResetBall()
    {
        m_nX = 0;
        m_nY = 0;
        m_nXSpeed = 0.0f;
        m_nYSpeed = 0.0f;
        m_nSpin = 0.0f;
    }
    int GetScreenX() { return (int) m_nX; };
    int GetScreenY() { return (int) m_nY; };
    float GetX() { return m_nX; }
    float GetY() { return m_nY; }
    float GetOldX() { return m_nX; }
    float GetOldY() { return m_nY; }
    float GetXSpeed() { return m_nXSpeed; }
    float GetYSpeed() { return m_nYSpeed; }
    float GetSpin() { return m_nSpin; }
    DWORD GetWidth() { return m_pBallSurface->GetWidth(); }
    DWORD GetHeight() { return m_pBallSurface->GetHeight(); }
    CGapiSurface* GetSurface() { return m_pBallSurface; }
    void SetScreenX(int nX) { m_nX = (float) nX; }
    void SetScreenY(int nY) { m_nY = (float) nY; }
    void SetX(float nX) { m_nX = nX; }
    void SetY(float nY) { m_nY = nY; }
    void SetXSpeed(float nSpeed) { m_nXSpeed = nSpeed; }
    void SetYSpeed(float nSpeed) { m_nYSpeed = nSpeed; }
    void InvertXSpeed() { m_nXSpeed = -m_nXSpeed; }
    void InvertYSpeed() { m_nYSpeed = -m_nYSpeed; }
    void SetSpin(float nSpin) { m_nSpin = nSpin; }
    HRESULT DrawBall(CGapiSurface* pSurface)
    {
        int nBallX = GetScreenX();
        int nBallY = GetScreenY();
        return pSurface->BltFast(nBallX, nBallY, GetSurface(), NULL, GDBLTFAST_KEYSRC, NULL);
    }
    HRESULT DrawBallShadow(CGapiSurface* pSurface)
    {
        int nBallX = GetScreenX() + 2;
        int nBallY = GetScreenY() + 2;
        GDBLTFASTFX bltfx;
        bltfx.dwFillColor = RGB(0,0,0);
        bltfx.dwOpacity = 64;
        return pSurface->BltFast(nBallX, nBallY, GetSurface(), NULL, GDBLTFAST_KEYSRC | GDBLTFAST_COLORFILL | GDBLTFAST_OPACITY, &bltfx);
    }
    void MoveBall()
    {
        m_nX += (m_nXSpeed / (float) GAMEPARAM_SUBPIXELSTEPS);
        m_nY += m_nYSpeed / (float) GAMEPARAM_SUBPIXELSTEPS;
    }
    HRESULT CreateSurface(HINSTANCE hInstance)
    {
        HRESULT hr;
        if (SUCCEEDED(hr = m_pBallSurface->CreateSurface(0, hInstance, IDB_BALL, _T("PNG"))))
        {
            m_pBallSurface->SetColorKey(RGB(255,0,255));
        }
        return hr;
    }
 
// Implementation
public:
    virtual ~CBreakBall()
    {
        delete m_pBallSurface;
    };
};
 
class CMyApplication : public CGapiApplication
{
    ...
    CBreakBall* m_pBall;
    ...
}

Add the following code to myapplication.cpp:

CMyApplication::CMyApplication(const GDAPPCONFIG& config) : CGapiApplication(config)
{
    ...
    m_pBall = new CBreakBall(GetGlobal());
    ...
}
 
CMyApplication::~CMyApplication()
{
    ...
    delete m_pBall;
    ...
}
 
HRESULT CMyApplication::CreateVidMemSurfaces(CGapiSurface* pBackBuffer, HINSTANCE hInstance)
{
    ...
    m_pBall->CreateSurface(hInstance);
    ...
}
 
HRESULT CMyApplication::OnDisplayChanged(CGapiSurface* pBackBuffer)
{
    // Display orientation changed, re-center ball
    int nScreenWidth = pBackBuffer->GetWidth();
    int nScreenHeight = pBackBuffer->GetHeight();
    int nScreenXCenter = nScreenWidth >> 1;
    int nScreenYCenter = nScreenHeight >> 1;
    int nBallX = m_pBall->GetScreenX();
    int nBallY = m_pBall->GetScreenY();
    int nBallWidth = m_pBall->GetWidth();
    int nBallHeight = m_pBall->GetHeight();
 
    m_pBall->ResetBall();
    m_pBall->SetScreenX(nScreenXCenter - (nBallWidth>>1) - 8);
    m_pBall->SetScreenY(GAMEPARAM_BRICKOFFSETY  + GAMEPARAM_NUMLINES * (GAMEPARAM_BRICKHEIGHT + GAMEPARAM_BRICKSPACE) + nBallHeight);
    m_nGameBallSpeed = (float)nScreenHeight / 80.0f;
    m_pBall->SetYSpeed(m_nGameBallSpeed);
 
    return S_OK;
}
 
HRESULT CMyApplication::GameInit(CGapiSurface* pBackBuffer, DWORD dwFlags)
{
    int nScreenWidth = pBackBuffer->GetWidth();
    int nScreenHeight = pBackBuffer->GetHeight();
    int nScreenXCenter = nScreenWidth >> 1;
    int nScreenYCenter = nScreenHeight >> 1;
    int nBallX = m_pBall->GetScreenX();
    int nBallY = m_pBall->GetScreenY();
    int nBallWidth = m_pBall->GetWidth();
    int nBallHeight = m_pBall->GetHeight();
 
    m_pBall->ResetBall();
    m_pBall->SetScreenX(nScreenXCenter - (nBallWidth>>1) - 8);
    m_pBall->SetScreenY(GAMEPARAM_BRICKOFFSETY  + GAMEPARAM_NUMLINES * (GAMEPARAM_BRICKHEIGHT + GAMEPARAM_BRICKSPACE) + nBallHeight);
    m_nGameBallSpeed = (float)nScreenHeight / 80.0f;
    m_pBall->SetYSpeed(m_nGameBallSpeed);
 
    m_dwPlayerScore = 0;
    m_dwGameBallsLeft = 3;
 
    return S_OK;
}

Ok, we have now added the ball class and some generic initialization code to our moving background!

Let's make the ball move in the next step!