#ifndef GAME_OBJECT_H #define GAME_OBJECT_H /**** Introduction: class Game_object is a pure virtual base class for all gpl objects such as: class Circle : public Game_object class Triangle : public Game_object class Rectangle : public Game_object It provides support for two main parts of a gpl object 1) member variables (named variables of type int, double, string) 2) graphics (animation, drawing, calculations (e.g. touches)) Users of Game_object (and the classes that inherit it) should focus on its public member functions. In other words, you can use Game_object without fully understanding how it works. Member variables Motivation: Need to be able to set/get member variables knowing only the variable's textual name This arises from the fact that in a gpl script we have the textual names of variables but since gpl is not C++ code, we can't simply use "obj.x" Need a mechanism that is extensible. Specifically, when a new class is created, need to be able to set/get its member variables knowing only the variable's textual name Solution: Keep a registry of variables that can be set/get from gpl. Implement this registry in class Game_object. Require all objects w/variables that need to be set/get from gpl to inherit Game_object. Registry Need to map the name of the variable to its memory location Also keep an enumerated label of the type so we can do type checking The class Typed_void_ptr will store the memory location (as void *) and an enumerated variable (of type Gpl_type) to store the real type. A map will implement the registry: std::map m_variable_registry; Each object that inherits from Game_object will have to put all variables it wants accessible from gpl into the registry by calling void register_member_variable(string name, int *value) void register_member_variable(string name, double *value) void register_member_variable(string name, string *value) ... Each of these will set the enum flag to the correct value Access: The gpl code can now set/get member variables by using the member functions: Status set_member_variable(string name, int value); Status set_member_variable(string name, double value); Status set_member_variable(string name, string *value); ... The get functions return a status: enum Status {OK, VARIABLE_NOT_OF_GIVEN_TYPE, VARIABLE_NOT_DECLARED }; Status get_member_variable(string name, int &value); Status get_member_variable(string name, double &value); Status get_member_variable(string name, string &value); ... Comments: This has gotten a bit more complex than I thought it would. I wonder if there is an easier way to do this. However, I don't think there are lots of situations when one needs to access a member variable only having the textual names. In C++, the textual names are usually long gone by run time. Graphics All graphics are done using OpenGL display lists. In order to define the graphics for an object, it must override the pure virtual function: virtual void build_display_list() = 0; in this function the graphics should be drawn to the display list m_display_list. Updating display list When a member variable is changed, build_display_list() is called before the object is redrawn. A class can redefine this behavior by providing the following function: virtual void updated(string name) {m_display_list_dirty = true;} If a member variable is not linked to the graphics, then don't mark the display list as dirty when that variable changes Drawing order An integer is associated with each Game_object to specify its drawing order. Game_objects with smaller numbers are drawn before Game_objects with larger numbers. Thus the Game_object with the largest drawing_order number is drawn last and will thus appear on top of all other game objects. ****/ #include "gpl_type.h" #ifdef __APPLE__ #include #include #else #include #include #endif #include #include #include using namespace std; class Animation_block; class Game_object { public: Game_object(double red = 0.5, double green = 0.5, double blue = 0.5); virtual ~Game_object(); const string type() const {return m_object_type_name;} void draw(); Status set_member_variable(string name, int value); Status set_member_variable(string name, double value); Status set_member_variable(string name, string value); Status set_member_variable(string name, Animation_block *block); Status get_member_variable_type(string name, Gpl_type &type); Status get_member_variable(string name, int &value); Status get_member_variable(string name, double &value); Status get_member_variable(string name, string &value); Status get_member_variable(string name, Animation_block *&value); bool visible() {return m_visible;} // a game object used as a parameter should never be drawn or animated // it is just used as a placeholder for the actual parameter // thus when creating an object to be used as a parameter, set them // to by calling never_draw() and never_animate() void never_draw() {m_should_draw = false;} void never_animate() {m_should_animate = false;} int touches(Game_object *obj); int near(Game_object *obj); // if no objects have changed, do not draw static bool graphics_out_of_date_with_last_rendering(); // draw all game objects in the vector all_game_objects static void draw_all_game_objects(); static void animate_all_game_objects(); void animate(); bool valid() const; ostream &print(ostream &os) const; protected: void insert_into_all_game_objects_vector(); void update_order_in_game_objects_vector(); void register_member_variable(string name, int *value) { register_member_variable(INT, name, (void *) value);} void register_member_variable(string name, double *value) { register_member_variable(DOUBLE, name, (void *) value);} void register_member_variable(string name, string *value) { register_member_variable(STRING, name, (void *) value);} void register_member_variable(string name, Animation_block **value) { register_member_variable(ANIMATION_BLOCK, name, (void *) value);} Status mark_member_variable_as_derived(string name); int m_x; int m_y; int m_w; int m_h; double m_red; double m_green; double m_blue; Animation_block *m_animation_block; int m_visible; int m_proximity; bool m_should_draw; bool m_should_animate; bool m_display_list_dirty; int m_drawing_order; int m_user_int; double m_user_double; string m_user_string; int m_user_int2; double m_user_double2; string m_user_string2; int m_user_int3; double m_user_double3; string m_user_string3; int m_user_int4; double m_user_double4; string m_user_string4; int m_user_int5; double m_user_double5; string m_user_string5; string m_object_type_name; GLuint m_display_list; // each object that inherits us must implement build_display_list() virtual void build_display_list() = 0; // the default is to mark the display list as dirty when any member // variable changes. Subclasses can redefine this behavior if the // display list changes only when some members fields are changed virtual void updated(string name) {m_display_list_dirty = true;} private: class Typed_void_ptr { public: Typed_void_ptr(Gpl_type type, void *value) {m_type = type; m_value = value; m_derived = false;} Gpl_type m_type; void *m_value; bool m_derived; }; std::map m_variable_registry; Typed_void_ptr* lookup_registered_member_variable(std::string name); void register_member_variable(Gpl_type type, string name, void *value ); static vector all_game_objects; static vector deleted_game_objects; static bool graphics_dirty; // disable default copy constructor and default assignment // done as a precaution, they should never be called Game_object(const Game_object &); const Game_object &operator=(const Game_object &); }; ostream &operator<<(ostream &os, const Game_object &game_object); ostream &operator<<(ostream &os, const Game_object *game_object); #endif // #ifndef GAME_OBJECT_H