Shape Sling
Language: C++
Library: OGRE 3D , OGRE Newt (Newton Dynamics Physics)

Programming/Design/Menu Art: Daniel Zeligman
Texturing: Xin Guo


Shape sling is a single-player projectile tower based game. The player controls a single tower which contains an elastic sling shot weapon. The weapon fires various shapes as its projectiles to defeat oncoming waves of shapes that are attempting to destroy the tower.

The shapes themselves differ in size, color, geometry and a variety of other parameters. There are different levels of power for each shape as well, including boss shapes that will fly around throwing smaller shapes at each tower.

Each shape projectile the player may fire differs in their ability. A cube may produce large area-of-effect damage, while a pyramid may do significant damage to a single target.

This project is still in development with the initial architecture being ironed out. Concept art is also being created to define the world upon which the shapes will be created.


ShapeSling Concept Art
Architecture Decisions

ShapeSling has given me the opportunity to venture into a new area of software architecture. The game uses a Component-based system rather than the traditional deep inheritance-hiearchy approach. I had read about this approach in various places on the web and in the Game Programming Gems series and finally decided to give it a try.

I chose to apply this approach in order to achieve greater flexibility when making design changes as well as give me an easier time when I need to refactor. In a Component-based system game objects are usually just a collection of the components that they need in order to function. Each component exists to provide a single piece of functionality to their parent game object. For instance, a simple system would have a Render component, Physics component, AI component and maybe a Position component.

A Component-based architecture also allows easier data-driven approaches to the gameplay. Logic or specific values can be easily written in scripts or XML files top tie directly to individual components which can be added to objects at run-time.

My initial Component and GameObject headers can be seen below in the Code Snippet section of this page. They are currently quite simple in their implementation. Each GameObject contains a map of its components. The map ensures that the object only has one instance of a particular type or family of component. The object also provides public accessors to its components. Each individual component contains a shared pointer to their parent allowing them to query their parent to look for other components. This is a simple method of inter-component communication where other objects are accessed in constant time using the hash map. It may not be the most optimal solution in the long run, but for now it is efficient enough for my means. I plan later to implement an event handler that will communicate between various subsystems of components.

Individual objects are going to be created by different factory templates depending on their type. ie: a geometric wave of enemies vs the sling shot tower. The factories will know what default components to attach to these certain units. Those components will have their pointers added to the overall family or system they represent. For example, a single pyramid entity would be created and initialized with its preset components from say a pyramid factory. The pyramids physics component ptr would be added to the physics subsystem so one can update all the physics components in the game at once in a certain order for an efficient method of doing collision detection and handling.

Code Snippets:

Below our my interfaces for a simple GameObject container for various components. It is simple and can represent a variety of objects, ranging from Enemy Shapes, the player's tower, a light or camera in the game or anything else than can be made up of individual components. The Component class and a PhysicsComponent implementation are also provided.

class GameObject
{
public:
     GameObject(
const std::string& id);
     ~GameObject(
void);

     const std::string& getID();
     void setID(const std::string& newGoID);

     Component* getComponentByFamilyID( const std::string& familyID);
     void addComponent (Component* newComponent);
     void clearGOCs();

private:
     std::string goID;
     std::map<const std::string, Component*> components;

};

class Component
{
public:
    Component ();
    
virtual  ~Component(void);

     virtual const std::string& familyID() const = 0;

     void setOwner(GameObject* go);
     GameObject* getOwner();

     void setSubSystem(SubSystem* subSystem);
     SubSystem* getSubSystem();

private:
     GameObject* owner;

};

class PhysicsComponent : Component
{
public:
    PhysicsComponent (PhysicsData* data);
    
virtual  ~PhysicsComponentComponent(void);

     virtual const std::string& familyID() const = 0;

     void addToNode();
     OgreNewt::Body* getBody();

protected:
     OgreNewt::Body* mBod;
     OgreNewt::Collision* mCol;

private:
     static std::string mFamilyID:

};