Pausing and Scoping

I've cleaned up my game code significantly in the last day or two, breaking things out into sensible modules. I've added asset_pipeline.c which stores an array of SDL_Texture references (a reference to a sprite sheet, basically). I can add an asset to the pipeline via a call to the function of this prototype:

int load_asset(char link_name[], char file[])

Then I can retrive a texture by name via a call to the function of this prototype:

SDL_Texture *get_texture(char link_name[])

Once I implement audio assets I'll figure out how to load them via that same first function call. I'll probably need to parse the file extension of an asset and add it to its own array based on that.

Pausing

A more simple addition to the game has been a pause overlay. It stops all rendering while showing and will pause the game time once I implement a timer. I set up a secondary font for this which I'll use for debug output as well. The pause key will not work when there's dialog displaying in the menu area since that already prevents anything else from happening in game while showing; pausing at such a time would be redundant.

Scoping

Since I don't fancy myself a C programmer and don't have 30 years of experience with the language I don't know all the tricks of the trade for code organization. I'm very used to object orientation and the scoping which it provides. Even PHP got some rudimentary class support in version 4 which has improved over time, and that's more or less a wrapper around C. That being said, since C doesn't support classes or even closures (at least not natively - there is supposedly some closure support in Apple's version of the GCC compiler), I felt the need to organize my code in such a way that it seems like I'm calling variables and functions within classes with scoping to protect the implementation even though at the end of the day I'm still accessing things within the global scope.

Here's an example of global variable and function prototypes and their corresponding access struct defined in my message_box.h file:

char message[MESSAGE_MAX_LEN];
void init_message_area();
void render_message();
void set_dialog(char msg[]);
int has_dialog();
void handle_message_box_keys(SDL_KeyboardEvent *key);

// This should NOT be accessible outside of message_box.h
// (It is in reality, but due to convention we'll avoid calling it without prefacing the MESSAGE_BOX struct)
void paginate(int len, int i, char *word);

typedef struct struct_messagebox {
	char *message[MESSAGE_MAX_LEN];
	void (*init)();
	void (*render_message)();
	void (*set_dialog)(char msg[]);
	int (*has_dialog)();
	void (*handle_message_box_keys)(SDL_KeyboardEvent *key);
} struct_messagebox;
static struct_messagebox MESSAGE_BOX = {
	.message = &*message,
	.init = init_message_area,
	.render_message = render_message,
	.set_dialog = set_dialog,
	.has_dialog = has_dialog,
	.handle_message_box_keys = handle_message_box_keys
};

The idea here is that MESSAGE_BOX will be accessible in the global scope to all other modules, and I can reference anything within that struct as if it were an object in an OO language (sort of - just bear with me here). Obviously this is a convention only and there is no strict scoping actually happening; you could just as well call init_message_area() in a standalone manner wherever you want to in the entirety of the codebase, but so that I know exactly where a function or variable is defined, I'll preface it as such:

MESSAGE_BOX.init();

This also allows me to alias function names so they're not so verbose, as in the case of various init functions. Many of my modules have them, but of course due to the compiler we can't name them all init. I would prefer to (and do) call them such as:

ASSET_PIPELINE.init();
MESSAGE_BOX.init();
PLAYER.init();

rather than:

ASSET_PIPELINE.init_pipeline();
MESSAGE_BOX.init_message_box();
PLAYER.init_player();

The struct is named after the header file that it appears in. I.E. message_box.h will have a struct MESSAGE_BOX. The only functions and variables accessible outside of message_box.h and message_box.c must be referenced in MESSAGE_BOX. However, message_box.c is allowed to reference any function or variable defined in message_Box.h without going routing it through the MESSAGE_BOX struct since they're assumed to be native to the module.

I'm hoping that this added verbosity will help alleviate too much spaghetti tangling and allow me to easily see what module is referenced where. So far this has been a very helpful change to my code layout. Yes, you have to make sure that when you change your function prototypes in the header that you change them in two places (the actual prototype itself and its reference within the struct), but to me this seems like a small price for the overall increase in comprehensible code structure. I'll keep an eye on how this works out as my codebase grows larger and reassess my feelings on it as I go.

Code Stats

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C                               10             99             38            639
C/C++ Header                    13             69             42            482
make                             1              0              0              3
-------------------------------------------------------------------------------
SUM:                            24            168             80           1124
-------------------------------------------------------------------------------