0
\$\begingroup\$

I'm writing a game where the main character is a ghost, and therefor can possess just about everything. The problem is, I'm not sure how to efficiently & effectively handle the changing actions of the player.

My idea was to have the game controller have a pointer to the current Entity, and a map of keys to actions. Every entity that is possess-able will have a component called OnPossess, which will just be a wrapper around a function pointer to some global function for that type of entity. When that entity gets "possessed", the OnPossess function is called and the controllers key-to-action map is updated.

Something like this:

class Controller
{
    public:
    Entity* controlled_entity_;

    std::map<char, std::function<void(Entity*)> > action_map_;  
    void OnInput(char input);
};

struct Component : public OnPossess
{
    std::function<void(Controller*)> OnPossess;
}

namespace Character_A
{
    void OnPossess(Controller* controller) {
        controller.action_map_ = Character_A_Map;
    }

    std::map<char, std::function<void(Entity*)> > Character_A_Map = { std::make_pair('l',MoveLeft),
                                                                        std::make_pair('r', MoveRight)
                                                                    };

    void MoveLeft(Entity* entity) {
        //Move left stuff
    }       

    void MoveRight(Entity* entity) {
        //Move right stuff
    }
}   //End namespace Character_A

However, I feel as though this is not the way to go. Having every type of entities available actions sitting out in a global namespace with a function pointer map pointing to those functions just doesn't feel right. I had also thought about having a component that held the map of actions, with the actions just being lambdas, but then I have a bunch of copies of the same map lying around in memory.

Would there be any alternative solutions?

\$\endgroup\$
  • \$\begingroup\$ What if every Entity had a controller as a member and Controller class for each type of Entity inherits from a class that has a function that takes in all the (relevant) input? \$\endgroup\$ – zoran404 Jun 8 '15 at 20:43
  • \$\begingroup\$ Entities shouldn't have a controller, IMO. Then, it would go from "Controller has an Entity" to "Entity has a controller", which makes less sense(to me). Additionally, this falls in line with my second problem: having a bunch of maps lying around in memory. However, I do recognize the ability to have different commands per entity based on state. Perhaps I should just expand on that idea, and bite the bullet with having multiple maps in memory. \$\endgroup\$ – Acorn Jun 8 '15 at 20:48
  • \$\begingroup\$ Humm, sounds like the Command pattern might be of help. \$\endgroup\$ – glampert Jun 8 '15 at 21:23
  • \$\begingroup\$ Yeah, that's basically what the Controller is. The problem I'm having is how to set up the controller, and if I should have the Action methods floating around in the global namespace or if there is a better place to put them. \$\endgroup\$ – Acorn Jun 8 '15 at 21:49
0
\$\begingroup\$

Your ghost will possess different Entities and use their actions. But will you ever change the actions of these Entities while the program runs?

If not, you could create a map for each "class" of entities and have the controller point to the current map to use. Say you have an enemy that's a Spider, so all spiders use the same actions' map. You could use a Factory,

class Factory {
public:
    Factory();
    virtual ~Factory();

    virtual Entity* createEntity() = 0;

protected:
    void addAction( char key, std::function< void( Entity* )> action );
    std::map<char, std::function<void(Entity*)> > *getActionMap();

private:
    std::map<char, std::function<void(Entity*)> > _actions;
}

And each factory would have its own map of actions.

SpiderFactory::SpiderFactory() {
    addAction( 'l', []( Entity *e ) { /*...*/ } ); // Move Left
    addAction( 'r', []( Entity *e ) { /*...*/ } ); // Move Right
}

Entity *SpiderFactory::createEntity() {
    return //Entity with pointer to the action map
}

If you don't like to define your functions as lambdas, you could use an anonymous namespace in the SpiderFactory.cpp file, or define them as static methods (I think that would work too)

namespace {
    void MoveLeft( Entity *e ) {
        //...
    }
}

Well that's quite a big suggestion. I'm hoping it will at least give you an idea for what you want to achieve. This will make it so there'so only 1 map per "class" of entities, if you don't need to change the actions at any point.

\$\endgroup\$
  • \$\begingroup\$ I hadn't thought about using a factory pattern, even though it's so glaringly obvious. I may change the design down the line, so that the actions would be able to change (Vase knocks itself off the desk, then it picks itself back up). That would require having a bunch of maps in memory, so that states can be kept. But I guess that's just a sacrifice I have to get used to. \$\endgroup\$ – Acorn Jun 8 '15 at 23:14

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.