Hey guys,
So I’ve veered away from homebrew development for a bit (fincs has taken over with a Lua port of PALib of his own so tequiLua has been cancelled) to work on some PC development.
This tutorial is for those using wxSmith, a plugin included with the binary for Code::Blocks, a very flexible and configurable IDE. Code::Blocks works with devkitPro as well.
wxSmith is the equivalent to a free, open-source version of Borland C++ builder, a form-based editor used for GUI applications. Installing wxWidgets and its dependencies is relatively straightforward, here’s a list of tutorials on just how to do it:
http://wiki.wxwidgets.org/CodeBlocks_Setup_Guide
http://wiki.codeblocks.org/index.php?title=Installing_Code::Blocks_nightly_build_on_Ubuntu
http://wxpack.sourceforge.net/Tutorials/CodeBlocks
After installing, set up your wxWidgets project through the project creation menu in Code::Blocks. I’m currently using wxWidgets for a more extensive project; however, I will be going through a simple pong example to demonstrate:
Input events (including concurrent keydown)
Drawing on the form’s device context
Flicker-free drawing
Press the Tool tab in the object menu and press the clock icon to include a Timer. A timer icon should now show up above the form. Click on this and under the properties menu, change interval to 17 (about 60 FPS). Double clicking this icon will create an event function named:
void PongFrame::OnTimer1Trigger(wxTimerEvent& event)
This function will then be ran every 17 milliseconds. Go to the header of the current file and include the following:
#include <time.h> //randomizing
#include <wx/dcbuffer.h> //double buffered painting
#include <wx/defs.h> //defining wxKeyCodes
#include <wx/utils.h> //defining timer input events
For Pong, you will need some images. Feel free to use these.
bg.png

ball.png

paddle.png

Access PongMain.h through the Projects menu. We will now modify the PongFrame class to include some variables used in this project.
class PongFrame: public wxFrame
{
wxBitmap bg_img;
wxBitmap ball_img;
wxBitmap paddle_img;
struct projectile
{
double x, y, vx, vy;
} ball, paddle[2];
char turn;
public:
PongFrame(wxWindow* parent,wxWindowID id = -1);
.
.
.
}
This declares three bitmaps stored in the program’s memory as well as a basic projectile structure defining a ball and an array of paddles. Going back to PongMain.cpp, we will declare them in PongFrame’s initialization block:
PongFrame::PongFrame( wxWindow* parent,wxWindowID id )
{
//( *Initialize( PongFrame )
srand( time( NULL ) );
//load the image files into the wxBitmaps declared in PongMain.h
bg_img.LoadFile( wxT( “bg.png” ), wxBITMAP_TYPE_PNG );
ball_img.LoadFile( wxT( “ball.png” ), wxBITMAP_TYPE_PNG );
paddle_img.LoadFile( wxT( “paddle.png” ), wxBITMAP_TYPE_PNG );
//initialize the variables
turn = -1;
ball.x = 232; // Ball’s x component
ball.y = 232; // Ball’s y component
ball.vx = ( rand( ) % 10 + 1 ) * turn; // Generate ball’s velocity y component
ball.vy = rand( ) % 10 + 1; // Generate ball’s velocity x component
paddle[0].x = 0; // Paddle’s x component
paddle[0].y = 208; // Paddle’s x component
paddle[1].x = 456; // Paddle’s y component
paddle[1].y = 208; // Paddle’s y component
.
.
.
}
Now, we’ll look into flicker-free drawing. Refer back to the Timer1Trigger event.
void PongFrame::OnTimer1Trigger( wxTimerEvent& event )
{
ball.x += ball.vx; //change the ball’s position
ball.y += ball.vy;
this->Refresh( );
}
this->Refresh( ); calls two events in wxWidgets : EVT_PAINT and EVT_ERASE_BACKGROUND. Create event instances for these two using the event panel in the Resources menu.
This should create the following events:
void PongFrame::OnEraseBackground( wxEraseEvent& event )
void PongFrame::OnPaint( wxPaintEvent& event )
Keep PongFrame::OnEraseBackground empty, as a prototype. This allows the program to skip over the default function, which erases the screen.
We will then use PongFrame::OnPaint to double-buffer draw.
void PongFrame::OnPaint( wxPaintEvent& event )
{
wxBufferedPaintDC dc( this );
dc.BeginDrawing( );
dc.DrawBitmap( bg_img, 0, 0, true );
dc.DrawBitmap( paddle_img, int( paddle[0].x ), int( paddle[0].y ), true );
dc.DrawBitmap( paddle_img, int( paddle[1].x ), int( paddle[1].y ), true );
dc.DrawBitmap( ball_img, int( ball.x ), int( ball.y ), true );
dc.EndDrawing( );
}
Refer back to the Timer1Trigger function. Here, we will activate the erase and paint events.
void PongFrame::OnTimer1Trigger( wxTimerEvent& event )
{
ball.x += ball.vx; //move the ball using its velocity components
ball.y += ball.vy;
this->Refresh( );
}
this->Refresh( ); calls the OnEraseBackground and OnPaint events. If you compile, you should notice the the paddle and ball images being drawn on the background, without flicker.
Now, we will expand the Timer1Trigger function to include input events and collision detection, making it a fully working pong game.
void PongFrame::OnTimer1Trigger( wxTimerEvent& event )
{
if( wxGetKeyState( WXK_SHIFT ) )
paddle[0].y -= 8;
else if( wxGetKeyState( WXK_CONTROL ) )
paddle[0].y += 8;
if( wxGetKeyState( WXK_UP ) )
paddle[1].y -= 8;
else if( wxGetKeyState( WXK_DOWN ) )
paddle[1].y += 8;
ball.x += ball.vx;
ball.y += ball.vy;
if( ball.x < 0 || ball.x > 464 )
{
ball.x = 232; // Ball’s x component
ball.y = 232; // Ball’s y component
ball.vx = ( rand( ) % 10 + 1 ) * turn; // Generate ball’s velocity y component
ball.vy = rand( ) % 10 + 1; // Generate ball’s velocity x component
paddle[0].x = 0; // Paddle’s x component
paddle[0].y = 208; // Paddle’s x component
paddle[1].x = 456; // Paddle’s y component
paddle[1].y = 208; // Paddle’s y component
turn = ( turn < 0 ) ? 1 : -1;
}
else if( ball.y < 0 || ball.y > 464 )
ball.vy *= -1;
else if( ( ball.x < 24 && ball.y > paddle[0].y && ball.y + 16 < paddle[0].y + 64 )
|| ( ball.x > 456 && ball.y > paddle[1].y && ball.y + 16 < paddle[1].y + 64 ) )
ball.vx *= -1;
this->Refresh( );
}
And that’s all! Any questions or comments are welcome. I’m relatively new to wxWidgets (just started looking into this a month ago) so if any experts would like to adjust anything or add anything to the tutorial, their suggestions are welcome as well.
NOTE: This tutorial is not fully complete.