summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2018-05-13 00:50:11 -0400
committerKelly Rauchenberger <fefferburbia@gmail.com>2018-05-17 15:39:39 -0400
commit5269e7c09a0b17c8c972c8ad996b04d42dbcd9cb (patch)
tree94a3f4ce0a0e54375cd2f27fb90d7c35295bda2e
parent59808c86bf0e4d5cf0b6ab3d6ed1d8bdcd303a37 (diff)
downloadtherapy-5269e7c09a0b17c8c972c8ad996b04d42dbcd9cb.tar.gz
therapy-5269e7c09a0b17c8c972c8ad996b04d42dbcd9cb.tar.bz2
therapy-5269e7c09a0b17c8c972c8ad996b04d42dbcd9cb.zip
Started event handlers
The AutomatingSystem has been renamed to the ScriptingSystem, since the automatic behavior script is just a special case of the scripts that an entity can exhibit. The AutomatableComponent has largely been moved to the new RunnableComponent (might not be the final name for it).

The Lua state object, previously living on the singleton RealizableComponent, is now a member of the ScriptingSystem itself, because it A) doesn't really belong on the realizable entity, and B) a singleton entity seems weird and like a cumbersome attempt to apply the ECS rules to places they don't apply. In a similar vein, the RealizableComponent itself will probably soon be integrated into the RealizingSystem too.

The attempt at using Lua environments in order to encapsulate the different behaviors that objects exhibit was scrapped in preference of just creating differently named Lua tables for each prototype.

The new PrototypableComponent contains some information about entities which were prototyped. It is partially used by the ScriptingSystem to figure out what event handlers are appropriate, which may not be the best approach. It also has some data about automatic behavior, which also maybe does not belong in this component.

The OnTouch event is raised by a player colliding with a physics body with the collider type "event", which may not be the best way to implement this.

The result of all of this is that checkpoints now work, although no sound is played, and the result is not persistent across exiting the game.
-rw-r--r--CMakeLists.txt2
-rw-r--r--res/platform.lua24
-rw-r--r--scripts/checkpoint.lua17
-rw-r--r--scripts/common.lua21
-rw-r--r--scripts/movplat.lua8
-rw-r--r--src/components/automatable.h25
-rw-r--r--src/components/playable.h3
-rw-r--r--src/components/ponderable.h3
-rw-r--r--src/components/prototypable.h22
-rw-r--r--src/components/realizable.h3
-rw-r--r--src/components/runnable.h15
-rw-r--r--src/game.cpp4
-rw-r--r--src/systems/automating.cpp106
-rw-r--r--src/systems/automating.h22
-rw-r--r--src/systems/pondering.cpp13
-rw-r--r--src/systems/realizing.cpp66
-rw-r--r--src/systems/scripting.cpp219
-rw-r--r--src/systems/scripting.h28
18 files changed, 393 insertions, 208 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index fbc843c..837df0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -70,7 +70,7 @@ add_executable(Aromatherapy
70 src/systems/playing.cpp 70 src/systems/playing.cpp
71 src/systems/scheduling.cpp 71 src/systems/scheduling.cpp
72 src/systems/realizing.cpp 72 src/systems/realizing.cpp
73 src/systems/automating.cpp 73 src/systems/scripting.cpp
74 vendor/stb_image.cpp 74 vendor/stb_image.cpp
75) 75)
76 76
diff --git a/res/platform.lua b/res/platform.lua deleted file mode 100644 index 5200e22..0000000 --- a/res/platform.lua +++ /dev/null
@@ -1,24 +0,0 @@
1function moveLeft(entity, len, speed)
2 local remaining = len / speed
3
4 while (remaining > 0) do
5 entity:ponderable().vel.x = -speed
6 remaining = remaining - coroutine.yield()
7 end
8end
9
10function moveRight(entity, len, speed)
11 local remaining = len / speed
12
13 while (remaining > 0) do
14 entity:ponderable().vel.x = speed
15 remaining = remaining - coroutine.yield()
16 end
17end
18
19function run(entity)
20 while true do
21 moveRight(entity, 90, 30)
22 moveLeft(entity, 90, 30)
23 end
24end \ No newline at end of file
diff --git a/scripts/checkpoint.lua b/scripts/checkpoint.lua new file mode 100644 index 0000000..452f81d --- /dev/null +++ b/scripts/checkpoint.lua
@@ -0,0 +1,17 @@
1checkpoint = {}
2
3function checkpoint.OnTouch(id, player)
4 curMap = entity.new(realizing():singleton():realizable().activeMap)
5
6 if not player:playable().checkpointMapObject or
7 not curMap:mappable().mapId == player:playable().checkpointMapId or
8 not id:prototypable().mapObjectIndex ==
9 player:playable().checkpointMapObjectIndex then
10
11 player:playable().checkpointMapObject = true
12 player:playable().checkpointMapId = curMap:mappable().mapId
13 player:playable().checkpointMapObjectIndex =
14 id:prototypable().mapObjectIndex
15 player:playable().checkpointPos = player:transformable().pos
16 end
17end
diff --git a/scripts/common.lua b/scripts/common.lua new file mode 100644 index 0000000..d84d97d --- /dev/null +++ b/scripts/common.lua
@@ -0,0 +1,21 @@
1function waitForTick()
2 return coroutine.yield()
3end
4
5function moveLeft(id, len, speed)
6 local remaining = len / speed
7
8 while (remaining > 0) do
9 id:ponderable().vel.x = -speed
10 remaining = remaining - waitForTick()
11 end
12end
13
14function moveRight(id, len, speed)
15 local remaining = len / speed
16
17 while (remaining > 0) do
18 id:ponderable().vel.x = speed
19 remaining = remaining - waitForTick()
20 end
21end
diff --git a/scripts/movplat.lua b/scripts/movplat.lua new file mode 100644 index 0000000..21cc61a --- /dev/null +++ b/scripts/movplat.lua
@@ -0,0 +1,8 @@
1movplat = {}
2
3function movplat.Behavior(id)
4 while true do
5 moveRight(id, 90, 30)
6 moveLeft(id, 90, 30)
7 end
8end
diff --git a/src/components/automatable.h b/src/components/automatable.h deleted file mode 100644 index d30340a..0000000 --- a/src/components/automatable.h +++ /dev/null
@@ -1,25 +0,0 @@
1#ifndef AUTOMATABLE_H_3D519131
2#define AUTOMATABLE_H_3D519131
3
4#include "component.h"
5#include <sol.hpp>
6#include <memory>
7
8class AutomatableComponent : public Component {
9public:
10
11 std::unique_ptr<sol::thread> runner;
12 std::unique_ptr<sol::coroutine> behavior;
13
14 sol::environment origBehavior;
15
16 /**
17 * If this flag is disabled, the entity will be ignored by the automating
18 * system.
19 *
20 * @managed_by RealizingSystem
21 */
22 bool active = false;
23};
24
25#endif /* end of include guard: AUTOMATABLE_H_3D519131 */
diff --git a/src/components/playable.h b/src/components/playable.h index b8af0f2..7404f1f 100644 --- a/src/components/playable.h +++ b/src/components/playable.h
@@ -27,6 +27,9 @@ public:
27 size_t checkpointMapId; 27 size_t checkpointMapId;
28 vec2d checkpointPos; 28 vec2d checkpointPos;
29 29
30 bool checkpointMapObject = false;
31 size_t checkpointMapObjectIndex;
32
30}; 33};
31 34
32#endif /* end of include guard: PLAYABLE_H_DDC566C3 */ 35#endif /* end of include guard: PLAYABLE_H_DDC566C3 */
diff --git a/src/components/ponderable.h b/src/components/ponderable.h index e6aa976..221d267 100644 --- a/src/components/ponderable.h +++ b/src/components/ponderable.h
@@ -34,7 +34,8 @@ public:
34 platform, 34 platform,
35 adjacency, 35 adjacency,
36 warp, 36 warp,
37 danger 37 danger,
38 event
38 }; 39 };
39 40
40 /** 41 /**
diff --git a/src/components/prototypable.h b/src/components/prototypable.h new file mode 100644 index 0000000..4659e7c --- /dev/null +++ b/src/components/prototypable.h
@@ -0,0 +1,22 @@
1#ifndef PROTOTYPABLE_H_817F2205
2#define PROTOTYPABLE_H_817F2205
3
4#include "component.h"
5#include "entity_manager.h"
6
7class PrototypableComponent : public Component {
8public:
9
10 using id_type = EntityManager::id_type;
11
12 size_t mapObjectIndex;
13
14 std::string prototypeId;
15
16 bool hasBehavior = false;
17 bool runningBehavior = false;
18
19 id_type behaviorScript;
20};
21
22#endif /* end of include guard: PROTOTYPABLE_H_817F2205 */
diff --git a/src/components/realizable.h b/src/components/realizable.h index bc834a2..b749aeb 100644 --- a/src/components/realizable.h +++ b/src/components/realizable.h
@@ -4,7 +4,6 @@
4#include "component.h" 4#include "component.h"
5#include <set> 5#include <set>
6#include <map> 6#include <map>
7#include <sol.hpp>
8#include "entity_manager.h" 7#include "entity_manager.h"
9#include "vector.h" 8#include "vector.h"
10 9
@@ -70,8 +69,6 @@ public:
70 * The entity ID of the currently active player. 69 * The entity ID of the currently active player.
71 */ 70 */
72 id_type activePlayer; 71 id_type activePlayer;
73
74 sol::state scriptEngine;
75}; 72};
76 73
77#endif /* end of include guard: REALIZABLE_H_36D8D71E */ 74#endif /* end of include guard: REALIZABLE_H_36D8D71E */
diff --git a/src/components/runnable.h b/src/components/runnable.h new file mode 100644 index 0000000..1b994fb --- /dev/null +++ b/src/components/runnable.h
@@ -0,0 +1,15 @@
1#ifndef AUTOMATABLE_H_3D519131
2#define AUTOMATABLE_H_3D519131
3
4#include "component.h"
5#include <sol.hpp>
6#include <memory>
7
8class RunnableComponent : public Component {
9public:
10
11 std::unique_ptr<sol::thread> runner;
12 std::unique_ptr<sol::coroutine> callable;
13};
14
15#endif /* end of include guard: AUTOMATABLE_H_3D519131 */
diff --git a/src/game.cpp b/src/game.cpp index bf2b10b..f2992e1 100644 --- a/src/game.cpp +++ b/src/game.cpp
@@ -12,7 +12,7 @@
12#include "systems/playing.h" 12#include "systems/playing.h"
13#include "systems/scheduling.h" 13#include "systems/scheduling.h"
14#include "systems/realizing.h" 14#include "systems/realizing.h"
15#include "systems/automating.h" 15#include "systems/scripting.h"
16#include "animation.h" 16#include "animation.h"
17#include "consts.h" 17#include "consts.h"
18 18
@@ -36,7 +36,7 @@ Game::Game(std::mt19937& rng) : rng_(rng)
36 systemManager_.emplaceSystem<PlayingSystem>(*this); 36 systemManager_.emplaceSystem<PlayingSystem>(*this);
37 systemManager_.emplaceSystem<SchedulingSystem>(*this); 37 systemManager_.emplaceSystem<SchedulingSystem>(*this);
38 systemManager_.emplaceSystem<ControllingSystem>(*this); 38 systemManager_.emplaceSystem<ControllingSystem>(*this);
39 systemManager_.emplaceSystem<AutomatingSystem>(*this); 39 systemManager_.emplaceSystem<ScriptingSystem>(*this);
40 systemManager_.emplaceSystem<OrientingSystem>(*this); 40 systemManager_.emplaceSystem<OrientingSystem>(*this);
41 systemManager_.emplaceSystem<PonderingSystem>(*this); 41 systemManager_.emplaceSystem<PonderingSystem>(*this);
42 systemManager_.emplaceSystem<MappingSystem>(*this); 42 systemManager_.emplaceSystem<MappingSystem>(*this);
diff --git a/src/systems/automating.cpp b/src/systems/automating.cpp deleted file mode 100644 index 4a5357d..0000000 --- a/src/systems/automating.cpp +++ /dev/null
@@ -1,106 +0,0 @@
1#include "automating.h"
2#include "game.h"
3#include "components/automatable.h"
4#include "components/ponderable.h"
5#include "components/realizable.h"
6#include "components/transformable.h"
7#include "systems/realizing.h"
8#include "vector.h"
9
10struct script_entity {
11 using id_type = EntityManager::id_type;
12
13 id_type id;
14
15 script_entity(id_type id) : id(id)
16 {
17 }
18};
19
20void AutomatingSystem::tick(double dt)
21{
22 auto entities = game_.getEntityManager().getEntitiesWithComponents<
23 AutomatableComponent>();
24
25 for (id_type entity : entities)
26 {
27 auto& automatable = game_.getEntityManager().
28 getComponent<AutomatableComponent>(entity);
29
30 if (!automatable.active)
31 {
32 continue;
33 }
34
35 auto result = (*automatable.behavior)(dt);
36 if (!result.valid())
37 {
38 sol::error e = result;
39 throw std::runtime_error(e.what());
40 }
41 }
42}
43
44void AutomatingSystem::initPrototype(id_type prototype)
45{
46 auto& automatable = game_.getEntityManager().
47 getComponent<AutomatableComponent>(prototype);
48
49 auto& realizable = game_.getEntityManager().
50 getComponent<RealizableComponent>(
51 game_.getSystemManager().getSystem<RealizingSystem>().getSingleton());
52 automatable.behavior.reset();
53 automatable.runner = std::unique_ptr<sol::thread>(new sol::thread(sol::thread::create(realizable.scriptEngine.lua_state())));
54 automatable.behavior = std::unique_ptr<sol::coroutine>(new sol::coroutine(automatable.runner->state()["run"]));
55
56 auto result = (*automatable.behavior)(script_entity(prototype));
57 if (!result.valid())
58 {
59 sol::error e = result;
60 throw std::runtime_error(e.what());
61 }
62}
63
64void AutomatingSystem::initScriptEngine(sol::state& scriptEngine)
65{
66 scriptEngine.open_libraries(sol::lib::base, sol::lib::coroutine);
67 scriptEngine.new_usertype<vec2d>(
68 "vec2d",
69 sol::constructors<vec2d(), vec2d(double, double)>(),
70 "x", sol::property(
71 [] (vec2d& v) -> double { return v.x(); },
72 [] (vec2d& v, double x) { v.x() = x; }),
73 "y", sol::property(
74 [] (vec2d& v) -> double { return v.y(); },
75 [] (vec2d& v, double y) { v.y() = y; }));
76
77 scriptEngine.new_usertype<vec2i>(
78 "vec2i",
79 sol::constructors<vec2i(), vec2i(int, int)>(),
80 "x", [] (vec2i& v) -> int& { return v.x(); },
81 "y", [] (vec2i& v) -> int& { return v.y(); });
82
83 scriptEngine.new_usertype<script_entity>(
84 "entity",
85 sol::constructors<script_entity(id_type)>(),
86 "id", &script_entity::id,
87 "transformable",
88 [&] (script_entity& entity) -> TransformableComponent& {
89 return game_.getEntityManager().
90 getComponent<TransformableComponent>(entity.id);
91 },
92 "ponderable",
93 [&] (script_entity& entity) -> PonderableComponent& {
94 return game_.getEntityManager().
95 getComponent<PonderableComponent>(entity.id);
96 });
97
98 scriptEngine.new_usertype<TransformableComponent>(
99 "transformable",
100 "pos", &TransformableComponent::pos);
101
102 scriptEngine.new_usertype<PonderableComponent>(
103 "ponderable",
104 "vel", &PonderableComponent::vel,
105 "accel", &PonderableComponent::accel);
106}
diff --git a/src/systems/automating.h b/src/systems/automating.h deleted file mode 100644 index 117b622..0000000 --- a/src/systems/automating.h +++ /dev/null
@@ -1,22 +0,0 @@
1#ifndef AUTOMATING_H_E6E5D76E
2#define AUTOMATING_H_E6E5D76E
3
4#include "system.h"
5#include <sol.hpp>
6
7class AutomatingSystem : public System {
8public:
9
10 AutomatingSystem(Game& game) : System(game)
11 {
12 }
13
14 void tick(double dt);
15
16 void initPrototype(id_type prototype);
17
18 void initScriptEngine(sol::state& scriptEngine);
19
20};
21
22#endif /* end of include guard: AUTOMATING_H_E6E5D76E */
diff --git a/src/systems/pondering.cpp b/src/systems/pondering.cpp index c806cc8..a3eb36d 100644 --- a/src/systems/pondering.cpp +++ b/src/systems/pondering.cpp
@@ -11,6 +11,7 @@
11#include "systems/orienting.h" 11#include "systems/orienting.h"
12#include "systems/playing.h" 12#include "systems/playing.h"
13#include "systems/realizing.h" 13#include "systems/realizing.h"
14#include "systems/scripting.h"
14#include "consts.h" 15#include "consts.h"
15 16
16void PonderingSystem::tick(double dt) 17void PonderingSystem::tick(double dt)
@@ -857,6 +858,18 @@ void PonderingSystem::processCollision(
857 break; 858 break;
858 } 859 }
859 860
861 case PonderableComponent::Collision::event:
862 {
863 if (game_.getEntityManager().
864 hasComponent<PlayableComponent>(entity))
865 {
866 game_.getSystemManager().getSystem<ScriptingSystem>().
867 onTouch(collider, entity);
868 }
869
870 break;
871 }
872
860 default: 873 default:
861 { 874 {
862 // Not yet implemented. 875 // Not yet implemented.
diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index 28e2279..2ee5897 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp
@@ -12,11 +12,11 @@
12#include "components/playable.h" 12#include "components/playable.h"
13#include "components/ponderable.h" 13#include "components/ponderable.h"
14#include "components/transformable.h" 14#include "components/transformable.h"
15#include "components/automatable.h" 15#include "components/prototypable.h"
16#include "systems/mapping.h" 16#include "systems/mapping.h"
17#include "systems/animating.h" 17#include "systems/animating.h"
18#include "systems/pondering.h" 18#include "systems/pondering.h"
19#include "systems/automating.h" 19#include "systems/scripting.h"
20 20
21inline xmlChar* getProp(xmlNodePtr node, const char* attr) 21inline xmlChar* getProp(xmlNodePtr node, const char* attr)
22{ 22{
@@ -40,9 +40,6 @@ EntityManager::id_type RealizingSystem::initSingleton(
40 auto& realizable = game_.getEntityManager(). 40 auto& realizable = game_.getEntityManager().
41 emplaceComponent<RealizableComponent>(world); 41 emplaceComponent<RealizableComponent>(world);
42 42
43 game_.getSystemManager().getSystem<AutomatingSystem>().
44 initScriptEngine(realizable.scriptEngine);
45
46 realizable.worldFile = worldFile; 43 realizable.worldFile = worldFile;
47 realizable.prototypeFile = prototypeFile; 44 realizable.prototypeFile = prototypeFile;
48 45
@@ -216,14 +213,28 @@ EntityManager::id_type RealizingSystem::initSingleton(
216 game_.getSystemManager().getSystem<PonderingSystem>(). 213 game_.getSystemManager().getSystem<PonderingSystem>().
217 initializeBody(mapObject, PonderableComponent::Type::vacuumed); 214 initializeBody(mapObject, PonderableComponent::Type::vacuumed);
218 215
216
217
218
219
220 auto& prototypable = game_.getEntityManager().
221 emplaceComponent<PrototypableComponent>(mapObject);
222
223 prototypable.prototypeId = prototypeId;
224
225 key = getProp(mapNode, "index");
226 prototypable.mapObjectIndex = atoi(reinterpret_cast<char*>(key));
227 xmlFree(key);
228
219 if (prototypeId == "movplat") 229 if (prototypeId == "movplat")
220 { 230 {
221 auto& automatable = game_.getEntityManager(). 231 prototypable.hasBehavior = true;
222 emplaceComponent<AutomatableComponent>(mapObject); 232 } else if (prototypeId == "checkpoint")
223 233 {
234 auto& ponderable = game_.getEntityManager().
235 getComponent<PonderableComponent>(mapObject);
224 236
225 realizable.scriptEngine.script_file( 237 ponderable.colliderType = PonderableComponent::Collision::event;
226 "res/platform.lua");//,
227 } 238 }
228 239
229 mappable.objects.push_back(mapObject); 240 mappable.objects.push_back(mapObject);
@@ -319,7 +330,6 @@ void RealizingSystem::loadMap(id_type mapEntity)
319 330
320 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>(); 331 auto& animating = game_.getSystemManager().getSystem<AnimatingSystem>();
321 auto& pondering = game_.getSystemManager().getSystem<PonderingSystem>(); 332 auto& pondering = game_.getSystemManager().getSystem<PonderingSystem>();
322 auto& automating = game_.getSystemManager().getSystem<AutomatingSystem>();
323 333
324 std::set<id_type> players = 334 std::set<id_type> players =
325 game_.getEntityManager().getEntitiesWithComponents< 335 game_.getEntityManager().getEntitiesWithComponents<
@@ -380,11 +390,6 @@ void RealizingSystem::loadMap(id_type mapEntity)
380 pondering.initPrototype(prototype); 390 pondering.initPrototype(prototype);
381 } 391 }
382 392
383 if (game_.getEntityManager().hasComponent<AutomatableComponent>(prototype))
384 {
385 automating.initPrototype(prototype);
386 }
387
388 enterActiveMap(prototype); 393 enterActiveMap(prototype);
389 } 394 }
390 395
@@ -419,12 +424,19 @@ void RealizingSystem::enterActiveMap(id_type entity)
419 ponderable.active = true; 424 ponderable.active = true;
420 } 425 }
421 426
422 if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity)) 427 if (game_.getEntityManager().hasComponent<PrototypableComponent>(entity))
423 { 428 {
424 auto& automatable = game_.getEntityManager(). 429 auto& prototypable = game_.getEntityManager().
425 getComponent<AutomatableComponent>(entity); 430 getComponent<PrototypableComponent>(entity);
431
432 if (prototypable.hasBehavior)
433 {
434 auto& scripting = game_.getSystemManager().getSystem<ScriptingSystem>();
426 435
427 automatable.active = true; 436 prototypable.hasBehavior = true;
437 prototypable.runningBehavior = true;
438 prototypable.behaviorScript = scripting.runBehaviorScript(entity);
439 }
428 } 440 }
429} 441}
430 442
@@ -446,11 +458,17 @@ void RealizingSystem::leaveActiveMap(id_type entity)
446 ponderable.active = false; 458 ponderable.active = false;
447 } 459 }
448 460
449 if (game_.getEntityManager().hasComponent<AutomatableComponent>(entity)) 461 if (game_.getEntityManager().hasComponent<PrototypableComponent>(entity))
450 { 462 {
451 auto& automatable = game_.getEntityManager(). 463 auto& prototypable = game_.getEntityManager().
452 getComponent<AutomatableComponent>(entity); 464 getComponent<PrototypableComponent>(entity);
453 465
454 automatable.active = false; 466 if (prototypable.runningBehavior)
467 {
468 auto& scripting = game_.getSystemManager().getSystem<ScriptingSystem>();
469 scripting.killScript(prototypable.behaviorScript);
470
471 prototypable.runningBehavior = false;
472 }
455 } 473 }
456} 474}
diff --git a/src/systems/scripting.cpp b/src/systems/scripting.cpp new file mode 100644 index 0000000..dc1fff5 --- /dev/null +++ b/src/systems/scripting.cpp
@@ -0,0 +1,219 @@
1#include "scripting.h"
2#include "game.h"
3#include "components/runnable.h"
4#include "components/ponderable.h"
5#include "components/realizable.h"
6#include "components/transformable.h"
7#include "components/playable.h"
8#include "components/mappable.h"
9#include "components/prototypable.h"
10#include "systems/realizing.h"
11#include "vector.h"
12
13struct script_entity {
14 using id_type = EntityManager::id_type;
15
16 id_type id;
17
18 script_entity(id_type id) : id(id)
19 {
20 }
21};
22
23ScriptingSystem::ScriptingSystem(Game& game) : System(game)
24{
25 id_type entity = game_.getEntityManager().emplaceEntity();
26
27 engine.open_libraries(sol::lib::base, sol::lib::coroutine);
28
29 engine.new_usertype<vec2d>(
30 "vec2d",
31 sol::constructors<vec2d(), vec2d(double, double)>(),
32 "x", sol::property(
33 [] (vec2d& v) -> double { return v.x(); },
34 [] (vec2d& v, double x) { v.x() = x; }),
35 "y", sol::property(
36 [] (vec2d& v) -> double { return v.y(); },
37 [] (vec2d& v, double y) { v.y() = y; }));
38
39 engine.new_usertype<vec2i>(
40 "vec2i",
41 sol::constructors<vec2i(), vec2i(int, int)>(),
42 "x", [] (vec2i& v) -> int& { return v.x(); },
43 "y", [] (vec2i& v) -> int& { return v.y(); });
44
45 engine.new_usertype<script_entity>(
46 "entity",
47 sol::constructors<script_entity(id_type)>(),
48 "id", &script_entity::id,
49 "transformable",
50 [&] (script_entity& entity) -> TransformableComponent& {
51 return game_.getEntityManager().
52 getComponent<TransformableComponent>(entity.id);
53 },
54 "ponderable",
55 [&] (script_entity& entity) -> PonderableComponent& {
56 return game_.getEntityManager().
57 getComponent<PonderableComponent>(entity.id);
58 },
59 "mappable",
60 [&] (script_entity& entity) -> MappableComponent& {
61 return game_.getEntityManager().
62 getComponent<MappableComponent>(entity.id);
63 },
64 "playable",
65 [&] (script_entity& entity) -> PlayableComponent& {
66 return game_.getEntityManager().
67 getComponent<PlayableComponent>(entity.id);
68 },
69 "realizable",
70 [&] (script_entity& entity) -> RealizableComponent& {
71 return game_.getEntityManager().
72 getComponent<RealizableComponent>(entity.id);
73 },
74 "prototypable",
75 [&] (script_entity& entity) -> PrototypableComponent& {
76 return game_.getEntityManager().
77 getComponent<PrototypableComponent>(entity.id);
78 });
79
80 engine.new_usertype<TransformableComponent>(
81 "transformable",
82 "pos", &TransformableComponent::pos);
83
84 engine.new_usertype<PonderableComponent>(
85 "ponderable",
86 "vel", &PonderableComponent::vel,
87 "accel", &PonderableComponent::accel);
88
89 engine.new_usertype<MappableComponent>(
90 "mappable",
91 "mapId", &MappableComponent::mapId);
92
93 engine.new_usertype<PlayableComponent>(
94 "playable",
95 "checkpointPos", &PlayableComponent::checkpointPos,
96 "checkpointMapId", &PlayableComponent::checkpointMapId,
97 "checkpointMapObject", &PlayableComponent::checkpointMapObject,
98 "checkpointMapObjectIndex", &PlayableComponent::checkpointMapObjectIndex);
99
100 engine.new_usertype<RealizableComponent>(
101 "realizable",
102 "activeMap", &RealizableComponent::activeMap);
103
104 engine.new_usertype<PrototypableComponent>(
105 "prototypable",
106 "mapObjectIndex", &PrototypableComponent::mapObjectIndex,
107 "prototypeId", &PrototypableComponent::prototypeId);
108
109 engine.new_usertype<RealizingSystem>(
110 "realizing",
111 "singleton",
112 [&] (RealizingSystem& realizing) -> script_entity {
113 return realizing.getSingleton();
114 });
115
116 engine.set_function(
117 "realizing",
118 [&] () {
119 return game_.getSystemManager().getSystem<RealizingSystem>();
120 });
121
122 engine.script_file("scripts/common.lua");
123 engine.script_file("scripts/movplat.lua");
124 engine.script_file("scripts/checkpoint.lua");
125}
126
127void ScriptingSystem::tick(double dt)
128{
129 auto entities = game_.getEntityManager().getEntitiesWithComponents<
130 RunnableComponent>();
131
132 for (id_type entity : entities)
133 {
134 auto& runnable = game_.getEntityManager().
135 getComponent<RunnableComponent>(entity);
136
137 if (*runnable.callable)
138 {
139 auto result = (*runnable.callable)(dt);
140 if (!result.valid())
141 {
142 sol::error e = result;
143 throw std::runtime_error(e.what());
144 }
145 }
146
147 if (!*runnable.callable)
148 {
149 game_.getEntityManager().deleteEntity(entity);
150 }
151 }
152}
153
154void ScriptingSystem::killScript(id_type entity)
155{
156 if (game_.getEntityManager().hasComponent<RunnableComponent>(entity))
157 {
158 game_.getEntityManager().deleteEntity(entity);
159 }
160}
161
162template <typename... Args>
163EntityManager::id_type ScriptingSystem::runScript(
164 std::string event,
165 id_type entity,
166 Args&&... args)
167{
168 auto& prototypable = game_.getEntityManager().
169 getComponent<PrototypableComponent>(entity);
170
171 id_type script = game_.getEntityManager().emplaceEntity();
172
173 auto& runnable = game_.getEntityManager().
174 emplaceComponent<RunnableComponent>(script);
175
176 runnable.runner =
177 std::unique_ptr<sol::thread>(
178 new sol::thread(
179 sol::thread::create(
180 engine.lua_state())));
181
182 runnable.callable =
183 std::unique_ptr<sol::coroutine>(
184 new sol::coroutine(
185 runnable.runner->state().
186 traverse_get<sol::function>(
187 prototypable.prototypeId,
188 event)));
189
190 if (!*runnable.callable)
191 {
192 throw std::runtime_error("Error running script");
193 }
194
195 auto result = (*runnable.callable)(
196 script_entity(entity),
197 std::forward<Args>(args)...);
198
199 if (!result.valid())
200 {
201 sol::error e = result;
202 throw std::runtime_error(e.what());
203 }
204
205 return script;
206}
207
208EntityManager::id_type ScriptingSystem::runBehaviorScript(id_type entity)
209{
210 return runScript("Behavior", entity);
211}
212
213void ScriptingSystem::onTouch(id_type entity, id_type player)
214{
215 runScript(
216 "OnTouch",
217 entity,
218 script_entity(player));
219}
diff --git a/src/systems/scripting.h b/src/systems/scripting.h new file mode 100644 index 0000000..d5380f1 --- /dev/null +++ b/src/systems/scripting.h
@@ -0,0 +1,28 @@
1#ifndef AUTOMATING_H_E6E5D76E
2#define AUTOMATING_H_E6E5D76E
3
4#include "system.h"
5#include <sol.hpp>
6
7class ScriptingSystem : public System {
8public:
9
10 ScriptingSystem(Game& game);
11
12 void tick(double dt);
13
14 void killScript(id_type entity);
15
16 id_type runBehaviorScript(id_type entity);
17
18 void onTouch(id_type entity, id_type player);
19
20private:
21
22 template <typename... Args>
23 id_type runScript(std::string event, id_type entity, Args&&... args);
24
25 sol::state engine;
26};
27
28#endif /* end of include guard: AUTOMATING_H_E6E5D76E */