August 22, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Cross-Platform Game Development for C++ Developers, Part IV: ClanLib SDK

  • September 7, 2005
  • By Victor Volkman
  • Send Email »
  • More Articles »

66 void Boxes::init()
67 {
68    CL_SetupCore::init();
69    CL_SetupDisplay::init();
70    CL_SetupGL::init();
71    CL_SetupSound::init();
72    CL_SetupVorbis::init();
73
74    CL_DisplayWindow window("Boxes", winsize, winsize);
75    CL_SoundOutput output(44100);    //44Khz sampling selected
76
77    CL_Surface *cursimg = new CL_Surface("cursor.tga");
78    cursimg->set_alignment(origin_center);
79    CL_Surface *redpict = new CL_Surface("handtransp.tga");
80    redpict->set_alignment(origin_center);
81    redpict->set_scale(float(spacing)/float(redpict->get_width()),
82       float(spacing)/float(redpict->get_height()));
83    CL_Surface *bluepict = new CL_Surface("circlehandtransp.tga");
84    bluepict->set_alignment(origin_center);
85    bluepict->set_scale(float(spacing) /
                float(bluepict->get_width()),
86              float(spacing) / float(bluepict->get_height()));
87

The init() method does mostly what you would expect from game setup: initializes needed subsystems of ClanLib for graphics and sound (lines 68-72) and then constructs a window to be used for all display graphics (line 75).

CL_Surface (lines 77-87) is a 2D bitmap class used for cursors, the blue-filled square, and the red-filled square (in other words, indicating that red won this square).

TGA files are bitmap file formats from the now obscure AT&T Targa Graphics Adapter (TGA). ClanLib has an integrated copy of PNG library, so it can read and write most popular bitmap file formats.

Next, you must initialize the board to an empty state (lines 87-103) and perform similar housekeeping for other game counters.

 89
 90    redturn = true;
 91    curs.vert = false;
 92    fullup = false;
 93    curs.x = curs.y = 1;
 94
 95    srand(CL_System::get_time());    // Seed random number
                                        // generator
 96
 97    for (int x = 0; x < boardsize - 1; x++) {
 98    for (int y = 0; y < boardsize; y++)
 99    hor[x][y] = ver[y][x] = false;
100
101    for (int y = 0; y < boardsize - 1; y++)
102    squares[x][y] = off;
103
104

An interesting aspect of ClanLib is that it eschews the traditional callback model used in many frameworks for the "signals and slots" model. This has been popularized by the Boost C++ library and implemented in QT (among other frameworks). Signals represent callbacks with multiple targets, and are also called publishers or events in similar systems. Signals are connected to some set of slots, which are callback receivers (also called event targets or subscribers), which are called when the signal is "emitted." Signals have the great advantage of being typesafe and they avoid the inevitable cast-a-thon seen in traditional frameworks.

Signals and slots are managed, in that signals and slots (or, more properly, objects that occur as part of the slots) track all connections and are capable of automatically disconnecting signal/slot connections when either is destroyed. This enables the user to make signal/slot connections without expending great effort to manage the lifetimes of those connections with regard to the lifetimes of all objects involved. In line 105, you just want to trap all the keypress ("down") events and insure your own inputHandler() is used (see lines 168-216).

105    CL_Slot keypress =
          CL_Keyboard::sig_key_down().connect(this,
          &Boxes::inputHandler);

Now, you are ready to initialize the musical portion of the program. First, you load up a CL_SoundBuffer with a waveform ("binary") music file and then prepare a session handle so it's ready to play. Next, you apply a fade filter to asynchronously bring the music from zero to 60 percent volume over the course of five seconds (lines 108-112).

106    CL_SoundBuffer *music = new CL_SoundBuffer("linemusic.ogg");
107    CL_SoundBuffer_Session session = music->prepare();
108    CL_FadeFilter *fade = new CL_FadeFilter(0.0f);
109    session.add_filter(fade);
110    session.set_looping(true);
111    session.play();
112    fade->fade_to_volume(0.6f, 5000);
113 }

The drawBoard() method draws the dotted grid pattern where line segments lie, the tomato red and cornflower blue squares that each player has won, and last but not least the simulated cursor. The most important line of code here is line 165. CL_Display::flip() swaps the front buffer and back buffers. The back buffer is where you draw all your graphics during the frame, and the front buffer is what displays on the screen.

115 void Boxes::drawBoard()
116 {
117    CL_Display::clear(redturn ? CL_Color::red : CL_Color::blue);
118    CL_Display::fill_rect(CL_Rect(border/2, border/2,
119                          winsize - border/2, winsize - border/2),
                             CL_Color::black);
120
121    // Draw squares
122    for (int x = 0; x < boardsize - 1; x++)
123       for (int y = 0; y < boardsize - 1; y++) {
124          if (squares[x][y] == red) {
125             CL_Display::fill_rect(CL_Rect(x * spacing + border,
                   y * spacing + border, x * spacing + border +
                   spacing,
127                y * spacing + border + spacing),
                      CL_Gradient(CL_Color::red,
128                CL_Color::red, CL_Color::tomato, CL_Color::tomato));
129          redpict->draw(x * spacing + border + spacing / 2,
130                        y * spacing + border + spacing / 2);
131       }
132       else if (squares[x][y] == blue) {
133          CL_Display::fill_rect(CL_Rect(x * spacing + border,
134                                        y * spacing + border,
                                           x * spacing + border +
                                           spacing,
135                                        y * spacing + border +
                                           spacing),
                                           CL_Gradient(CL_Color::blue,
136          CL_Color::blue, CL_Color::cornflowerblue,
             CL_Color::cornflowerblue));
137       bluepict->draw(x * spacing + border + spacing / 2,
                         y * spacing + border + spacing / 2);
139       }
140    }
141
142    // Draw lines
143    for (int x = 0; x < boardsize; x++) {
144    for (int y = 0; y < boardsize - 1; y++) {
145       if (ver[x][y]) CL_Display::draw_line(x * spacing + border,
146                                            y * spacing + border,
                                               x * spacing + border,
147                                            y * spacing + border
                                               + spacing,
                                               CL_Color::yellow);
148       if (hor[y][x]) CL_Display::draw_line(y * spacing + border,
149                                            x * spacing + border,
                                               y * spacing + border
                                               + spacing,
                                               x * spacing + border,
                                               CL_Color::yellow);
151       }
152    }
153
154    // Draw grid
155    for (int x = 0; x < boardsize; x++)
156       for (int y = 0; y < boardsize; y++)
157          CL_Display::draw_rect(CL_Rect(x * spacing + border,
158                                        y * spacing + border,
                                           x * spacing + border + 2,
159                                        y * spacing + border + 2),
                                           CL_Color::white);
160
161    //Draw cursor
162    if (curs.vert) cursimg->draw((curs.x - 1) * spacing + border,
          int((curs.y - 0.5) * spacing + border));
163    else cursimg->draw(int((curs.x - 0.5) * spacing + border),
          (curs.y - 1) * spacing + border);
164
165   CL_Display::flip();
166 }

You installed the inputHandler() to watch the key down signal back on line 105. This function handles the cumbersome details of turning keystrokes into game moves, the most significant being SPACE or ENTER to signify a selection by the current player (lines 200-210). Then, you check to see whether you completed a "square" and return control to the same player if you've done so.





Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel