1 #include <chaiscript/chaiscript.hpp>
2 
3 class Entity
4 {
5   public:
6     int width;
7     int height;
8     int x;
9     int y;
10     std::string name;
11 
12     std::function<void (Entity &)> updater;
13 
Entity(const int t_width,const int t_height,const int t_x,const int t_y,std::string t_name)14     Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name)
15       : width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name))
16     {
17     }
18 };
19 
20 class Factory
21 {
22   public:
23     // we may as well pass the parameters for the entity to the factory method, this does the initialization
24     // in one step.
make_entity(const int width,const int height,const int x,const int y,const std::string & name)25     Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name)
26     {
27       auto entity = entities.insert({name, Entity{width, height, x, y, name}});
28       return &(entity.first->second);
29     }
30 
get_entity(const std::string & name)31     Entity *get_entity(const std::string &name)
32     {
33       return &entities.at(name);
34     }
35 
36 
37     // loop over all entities and all their updater function (if it exists)
update_entities()38     void update_entities()
39     {
40       for (auto &entity : entities)
41       {
42         if (entity.second.updater) {
43           entity.second.updater(entity.second);
44         }
45       }
46     }
47 
48 
49   private:
50     // we cannot store the entities in a std::vector if we want to return a pointer to them,
51     // because a vector automatically resizing itself can invalidate the pointer that was returned.
52     // using a map guarantees that the memory assigned to the entity will never change, plus
53     // lets us easily look up an entity by name
54     std::map<std::string, Entity> entities;
55 };
56 
main()57 int main()
58 {
59   chaiscript::ChaiScript chai;
60 
61   chai.add(chaiscript::fun(&Entity::width), "width");
62   chai.add(chaiscript::fun(&Entity::height), "height");
63   chai.add(chaiscript::fun(&Entity::x), "x");
64   chai.add(chaiscript::fun(&Entity::y), "y");
65   chai.add(chaiscript::fun(&Entity::name), "name");
66   chai.add(chaiscript::fun(&Entity::updater), "updater");
67   chai.add(chaiscript::user_type<Entity>(), "Entity"); // this isn't strictly necessary but makes error messages nicer
68 
69   chai.add(chaiscript::fun(&Factory::make_entity), "make_entity");
70   chai.add(chaiscript::fun(&Factory::get_entity), "get_entity");
71   chai.add(chaiscript::fun(&Factory::update_entities), "update_entities");
72   chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer
73 
74 
75   Factory f;
76   chai.add(chaiscript::var(&f), "f");
77 
78   std::string script = R""(
79     f.make_entity(10,10,1,1,"entity1").updater = fun(e){ e.x += 1; e.y += 1 };
80     f.make_entity(10,10,10,10,"entity2").updater = fun(e){ e.x += 2; e.y += 2 };
81     f.make_entity(10,10,20,20,"entity3");
82 
83     print(f.get_entity("entity1").x == 1)
84     print(f.get_entity("entity2").x == 10)
85     print(f.get_entity("entity3").x == 20)
86 
87     f.update_entities(); // this runs the function objects we set in the previous lines
88     // we should now see the updated values
89 
90     print(f.get_entity("entity1").x == 2)
91     print(f.get_entity("entity2").x == 12)
92     print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
93     )"";
94 
95 
96   chai.eval(script);
97 
98 
99 
100 }
101 
102 
103