2
\$\begingroup\$

Basically, I have been writing a game in C++ using Allegro. I mostly just use the library to draw bitmaps, draw text, and play audio.

My main concern as the game continues to grow code-wise, is that with all the places I use al_draw_bitmap, al_play_sample, etc it becomes harder and harder to ever switch libraries if I so desire. Aka all the places in code I would have to change the function calls and data types (ALLEGRO_BITMAP, ALLEGRO_SAMPLE, ALLEGRO_COLOR, etc).

I was wondering if it is a good idea to make a class (or classes) with generic mappings so that my code calls my own DrawImage(), PlaySound(), etc and then maybe typecast the data types (ALLEGRO_BITMAP, etc)?

This way its much less to change in the long run. I understand there would still be work involved and obviously I could only switch to another C++ library.

I'm not sure if there is a reason why this would be a bad idea, or if its actually a good idea, whats the best way to go about it.

\$\endgroup\$
  • 1
    \$\begingroup\$ Allegro is already cross-platform, so I'm wondering why you want to abstract away the API if you don't need to. If you intend to encapsulate allegro functionality to simplify your own needs, that's one thing and I encourage that, but it appears that one of your design decisions was "use allegro as the rendering/etc api", so I don't see the harm in leaving your naked al_XXXX calls be as they are, especially if you have a significant code base that will take a long time to modify to be api agnostic. \$\endgroup\$ – PlayDeezGames Sep 18 '13 at 19:41
  • \$\begingroup\$ I guess the main reason currently is that I'm trying to create something that is completely cross platform and while allegro covers most, it seems Android is only available for the unstable branch (5.1). And I'm not really sure how much the Android part of it is being worked on versus other features. I guess my main worry is that it'll never (or not for a long time) get to a stable branch and using an unstable branch for something I hope to be commercial worries me. :/ So I was thinking if the code is generic enough, then it would be easy to switch to another library if need be. \$\endgroup\$ – Zyaga Sep 19 '13 at 6:34
  • \$\begingroup\$ Sadly, I've already done this for version 4.2...then 5.x was released with an entirely new API. :( \$\endgroup\$ – Casey Sep 19 '13 at 19:36
3
\$\begingroup\$

Finding a balance between hardening code against the future and completing your current project is often challenging. You don't want to waste time over-engineering solutions to problems you don't actually have, but you also don't want to create a massive amount of technical debt for yourself.

Some practical considerations:

  • Other APIs almost certainly will have different semantics and interfaces for their corresponding layers of functionality (graphics, sound, et cetera). Unless you have experience with those other APIs, attempting to build yourself wrapper abstractions now will probably just result in abstractions tailored to the single implementation you are currently using (Allegro) and which will need almost as much refactoring themselves as if you just refactored the direct Allegro calls into calls against the new API.

  • Particularly, since you describe the abstraction process as simply one of "typecasting data types," it implies strongly that you don't have the requisite background in other APIs to make forward-thinking decisions about the design of your abstraction.

  • This means writing the abstraction probably will create a net increase in your workload over time, although you will learn some things from the experience.

Switching to another API may involve some changes in code around that which calls into the API as well; you won't have a trivial time of it. Additionally, switching APIs "just because" isn't necessarily a great idea because it doesn't necessarily bring you closer to the goal of finishing a project. Unless there's added value to be had in switching to a new API for something, if you've got one that works and satisfies the requirements of your project, switching to something else isn't really a smart decisions except as a learning exercise.

Hiding implementation dependencies from the rest of your code is a good idea. It helps keep seems isolated and maintainable. To that end, I'd suggest that you build your own interfaces on top of the 3rd party libraries you are using and have the rest of your game call into those interfaces (for example, have your game logic call into your own rendering functions, which themselves call in to the Allegro functions directly). Do not expose Allegro types or enumerations directly outside that layer.

Do this to hide implementation detail, not necessarily to ease future ports. It will teach you things about implementation hiding and its benefits and related techniques, and it will give you a basis to work from in the future should you ever need to change to a different API, but you won't directly solving the "porting" problem since since you don't actually have an immediate need to solve it.

Don't go back and do this as one giant change-all-the-things refactoring operation. That's also taking time away from your goal (finish the game) just to reorganize code that already works and is presumably shippable. Rather, make these changes slowly over time, perhaps only starting with new bits of functionality you need to add.

\$\endgroup\$
  • \$\begingroup\$ This makes a lot of sense. I think at most, I'll do what you mentioned of taking it one chunk at a time possibly and simply building an interface of my own between the two. \$\endgroup\$ – Zyaga Sep 19 '13 at 6:38
0
\$\begingroup\$

As previously answered, Allegro is already cross-platform enough.

If you are writing your own game engine, and you want to work in the exposed API first, so you can see if It is convenient enough to use, and you don't want to work at low level yet, then you can use Allegro behind the scenes for now until you decide to finally replace that with your own code.

Now, do you really need that? As Allegro is already cross-platform, if It already runs in all your target platforms then why the need for code hiding it.

In the past I did something similar to the engine thing but with SDL. The idea was to write my own low level code for some core functionality at some time during development, but in the end time passed, the game continued, and SDL is still there. Replace it would mean to test the platform specific code in each targeted platform. Note that is still the idea, but It is always postponed for latter.

In resume:

Are you writing a game? Only wrap Allegro when you want to group repetitive tasks. Use classes calling Allegro functions where it have sense. Do not wrap simple things like ALLEGRO_COLOR except you want to add something extra that you know you need it to happen always when you use ALLEGRO_COLOR.

Are you writing a reusable engine? As I said in the first paragraph, maybe It may be justified to start wrapping the Allegro API. Maybe you want to add a switch to the build configuration where you let other people decide if they want to depend on Allegro or another libraries that your engine can use.

Are you writing an engine then a game that use it? Rethink things. What are the resources at your disposition (time/manpower)? Maybe you should be writing a game only.

\$\endgroup\$
  • \$\begingroup\$ Just mentioned above, it seems Android is only available for unstable branch (5.1) so that just sort of concerns me as I don't know how much its being worked on. And that's a very good point, I'm not attempting to write an engine but instead just a game. \$\endgroup\$ – Zyaga Sep 19 '13 at 6:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.