This is a question about the quality of the approach. I am attempting to get better at writing nicer code, however I can't tell if certain things are good to do / bad to do sometimes.
Here is the project I am currently working on. I can't post the whole thing as it is kinda big, however I'll post snippets and explain my thoughts.
The goal for this project was to be as modular as possible. This means that once I write the main part of it, my idea is that if I ever wanted to add functionality, I would write a new file/files (I call them modules) and put it in a directory, and it would be implemented in the program upon compilation.
The main program functions like this. It stores a list of Base * objects. the Base class consists of only virtual functions, the idea is that any module I want to add MUST inherit from the Base class. All the modules will have render() give_input() etc...
Then the base class simply renders everything in this big list. Here is the header file of the main class (STUSURF)
#ifndef STUSURF_H
#define STUSURF_H
#include "common.h"
#include "headers.h"
// this is the main class. It will contain all the objects we need. This is the class we will interface with in main.
// It will deal with the other data types for us.
class STUSURF{
public:
char * path_start_screen;
FILE * file_start_screen;
int * width;
int * height;
//store a list of pointers that point to the base class.
// This class is guaranteed to have the functions we have such as render() and the input function. This is defined in the file common.h
Base * * main_list;
int main_list_len;
// constructor. Takes in the path of the file that the program will start to display from. If file does not exist it will create it.
STUSURF( char * _start );
// setting the program up
void give_window_size( int * _w, int * _h );
void mouse_press( int _button, int _state, int _x, int _y );
void mouse_move_passive( int _x, int _y );
void mouse_move_active( int _x, int _y );
void key_press( unsigned char _key, int _x, int _y );
void key_press_special( unsigned char _key, int _x, int _y );
void add( Base * a );
void render( void );
void toString( void );
};
#endif
Here is where my first few design questions come. I'll start with the headers.h file include in the top.
In order to guarantee that all the modules are included, I had to write a bash script that will automatically write the header.h file with the needed modules included. I run this bash script using makefile before compilation. The reason this makes me uneasy is because it is a hurdle for cross platform support. I use OpenGL and this feels like it is undermining the cross-platform power of it. How should I be doing this ? How would it be done in industry ?
I'll arrive at my other problem. If you notice, the add() function takes in a Base *. This means that objects I pass will loose any non Base functionality right ? Is this OK ? I can work around it, but it feels like patchy fixes and I dislike the direction it is heading. Here is an example of an issue:
When the mouse is pressed, the main program wants to check if the mouse if hovering over any of the objects in the main list So I can do a loop and traverse the list:
void STUSURF::mouse_press( int _button, int _state, int _x, int _y ){
for( int i = 0; i < main_list_len; i++ ){
if( check_inside( _x, _y, main_list[i] ) )
main_list[i]->mouse_press( _button, _state, _x, _y );
}
}
Here is the problem, it is the check_inside() function
bool check_inside( int _x, int _y, Base * b ){
int pos_x = _x - WINDOW_WIDTH;
int pos_y = _y - WINDOW_HEIGHT;
// this is just a test..... I know its not checking collision....
std::cout << b->x << "\n";
return false;
}
The x value that is returned is the one assigned to the Base class which is always 0. Even if the value is different. I know the value is different because it is being rendered at the correct x position.
It would work if I do this.
bool check_inside( int _x, int _y, Base * b ){
int pos_x = _x - WINDOW_WIDTH;
int pos_y = _y - WINDOW_HEIGHT;
std::cout << (( test_module * )b)->x << "\n";
return false;
}
However this means I can't just add modules and completely forget about the main code. I also attempted to use a template, however that didn't work because the only parameters passed to the check_inside() function is of type Base* .
The workaround here would be just giving all the objects mouse info at every click, and the objects will decide whether they should do something or not. But again, this feels janky for some reason.
How can I make this program modular in a good way ? is there a way for an object to store a type for me to use that to cast ? for example the test_module class will know it is a test_module, and when I need to I can make it cast itself ?
sorry for the long question.