March 24, 2019
Hot Topics:

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

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

ClanLib is a cross-platform C++ framework focused primarily on the needs of game developers. Although the API is streamlined for gaming, you could easily use ClanLib to develop a scientific 3D visualization tool or multimedia application (such as the Gecko Multimedia System).

ClanLib has APIs for 2D and 3D graphics, sound, network, I/O, input, and GUI and resource administration. It provides transparent support for OpenGL, so you can use native OpenGL commands while letting ClanLib handle the OS-dependent window management and everything else. ClanLib renders 2D graphics through DirectX or Simple Direct Media Layer (a platform-independent multimedia library). The ClanLib games page lists about 50 well-developed games, including puzzles, strategy, and shooter games in 2D and 3D. For example, Asteroid Arena (see Figure 1) uses ClanLib and OpenGL to one-up the arcade classic.

Click here for a larger image.

Figure 1. Screenshot of Asteroid Arena

ClanLib works on Windows, Linux, and MacOS and is supplied in source-only zip or tar files. Windows developers can use Microsoft Visual Studio, Borland C++, or MinGW (Minimalist GNU for Windows) compilers and environments. Third-party support for Ruby and Perl language bindings is also available. Optional extras include a Lua plug-in (the popular lightweight scripting language) and FreeType (a free TrueType font library).

Inside the ClanLib Feature Set

Before digging into the API, take a quick glance at its major features:

  • Basic cross-platform runtime (GUI, threading, file I/O, and so forth)
  • Template-based C++ signal/slots library (type-safe callbacks/delegates)
  • Integrated resource management
  • Sound mixer supporting .WAV files, Ogg Vorbis, and anything supported by the MikMod library (MOD, S3M, XM, and so on)
  • Document Object Model (DOM) XML parser support
  • High-level 2D graphics API supporting OpenGL, DirectX, and SDL as render targets
  • Batch rendering engine for best performance when rendering 2D with OpenGL
  • 2D collision detection
  • 2D sprite animation support
  • Highly customizable GUI framework
  • Network library with low- to high-level interfaces

The Basic Gaming Model of ClanLib

Now, examine the ClanLib API model from the inside out. I've always found that the best tutorial is a fully explained example program. Specifically, you'll look inside Luke Worth's boxes, an electronic version of the two-player, paper-and-pencil game (see Figure 2). The boxes game consists of a grid of points between which players alternately draw lines. Whoever encloses a square with the final line, scores one point and gets to play another turn. (If you're eager to see the API reference first, by all means do so.)

Figure 2. A Boxes Game in Progress with a Score of Blue 8 and Red 3

I purposely kept the main program as short as possible to better highlight the "game loop:"

 1 #include <iostream>
 2 #include <ClanLib/application.h>
 3 #include <ClanLib/core.h>
 4 #include <ClanLib/display.h>
 5 #include <ClanLib/gl.h>
 6 #include <ClanLib/sound.h>
 7 #include <ClanLib/vorbis.h>
 9 const int boardsize = 6, spacing = 50, border = 20;
10 const int numsquares = int(pow(float(boardsize - 1), 2));
12 enum coloursquare { off, blue, red };
13 struct cursor {
14    int x, y;
15    bool vert;
16 };
18 class Boxes: public CL_ClanApplication {
19    bool ver[boardsize][boardsize - 1];
20    bool hor[boardsize - 1][boardsize];
21    coloursquare squares[boardsize - 1][boardsize - 1];
22    bool redturn;
23    bool fullup;
24    cursor curs;
26    void inputHandler(const CL_InputEvent &i);
27    bool findsquares(void);
28    inline int numaroundsquare(int x, int y);
29    void init();
30    void drawBoard();
31    void endOfGame();
33 public:
34    virtual int Boxes::main(int, char **);
35 } app;
37 using namespace std;
41 int Boxes::main(int, char **)
42 {
43    int winsize = spacing * (boardsize - 1) + border * 2;
44    try {
45       Boxes::init();
46       while (!CL_Keyboard::get_keycode(CL_KEY_ESCAPE)) {
47          Boxes::drawBoard();
48          if (fullup) break;
49          CL_System::keep_alive(20);
50    }
51    Boxes::endOfGame();
53    CL_SetupVorbis::deinit();
54    CL_SetupSound::deinit();
55    CL_SetupGL::deinit();
56    CL_SetupDisplay::deinit();
57    CL_SetupCore::deinit();
58    }
59    catch (CL_Error err) {
60       std::cout << "Exception caught: "
                   << err.message.c_str()
                   << std::endl;
61    }
63 return 0;
64 }

The first thing to notice about this application is that the main() function (see line #41) is not a top-level function but rather is embedded in an object derived from CL_ClanApplication. This serves to encapsulate a lot of the inevitable platform dependencies that might surround a traditional ::main() implementation (such as having to use WinMain() in Win32 apps).

Also, note that virtually all the executable code (lines 43-58) are enclosed in a try{}/catch{} exception handler. ClanLib will throw exceptions if needed and you can restart a game, and the like. Basically, all program logic resides in init(), drawBoard(), endOfGame(), and inputHandler(). If the board has no more moves (fullup==true), you exit the game loop (in line 48). CL_System::keep_alive() updates all input and system events (like closing the window or moving it), and if given an argument, it will wait that many milliseconds before proceeding. This frees up CPU cycles in the vein of the old::Yield() from Win16 API or sleep() in Linux.

Page 1 of 3

Comment and Contribute


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



Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date