From 4bbfeae42a1245b1b84e8847787d7643e6a6f2cf Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 10 May 2018 19:27:59 -0400 Subject: Started integrating Lua as a scripting engine Currently moving platforms are able to have their movement controlled by a script rather than by XML, which is probably a better implementation and scales better to other things. The scripts, instead of using the components as state, use the stack as state. In this way, they pretend to be multithreaded. For instance, the moving platform calls moveRight and then moveLeft. Both of those functions internally make calls that say to wait until the next tick. When the AutomatingSystem ticks, it continues execution of all scripts (sequentially, of course) until they ask for the next tick again. This is implemented using coroutines. --- src/systems/automating.cpp | 99 ++++++++++++++++------------- src/systems/automating.h | 3 + src/systems/realizing.cpp | 153 +++------------------------------------------ 3 files changed, 68 insertions(+), 187 deletions(-) (limited to 'src/systems') diff --git a/src/systems/automating.cpp b/src/systems/automating.cpp index 61b97d9..6cec3bf 100644 --- a/src/systems/automating.cpp +++ b/src/systems/automating.cpp @@ -2,13 +2,24 @@ #include "game.h" #include "components/automatable.h" #include "components/ponderable.h" -#include "systems/pondering.h" +#include "components/realizable.h" +#include "systems/realizing.h" +#include "vector.h" + +struct script_entity { + using id_type = EntityManager::id_type; + + id_type id; + + script_entity(id_type id) : id(id) + { + } +}; void AutomatingSystem::tick(double dt) { auto entities = game_.getEntityManager().getEntitiesWithComponents< - AutomatableComponent, - PonderableComponent>(); + AutomatableComponent>(); for (id_type entity : entities) { @@ -20,43 +31,7 @@ void AutomatingSystem::tick(double dt) continue; } - if (automatable.behaviorRunning && - (automatable.remaining <= 0.0)) - { - automatable.currentAction++; - automatable.actionRunning = false; - - if (automatable.currentAction == - automatable.behaviors[automatable.currentBehavior].size()) - { - automatable.behaviorRunning = false; - } - } - - if (!automatable.behaviorRunning) - { - automatable.currentBehavior = automatable.behaviorDist(game_.getRng()); - automatable.currentAction = 0; - automatable.behaviorRunning = true; - } - - AutomatableComponent::Action& curAction = - automatable.behaviors - [automatable.currentBehavior] - [automatable.currentAction]; - - if (!automatable.actionRunning) - { - automatable.remaining = curAction.dur; - automatable.actionRunning = true; - } - - auto& ponderable = game_.getEntityManager(). - getComponent(entity); - - ponderable.vel = curAction.speed; - - automatable.remaining -= dt; + (*automatable.behavior)(dt); } } @@ -65,6 +40,46 @@ void AutomatingSystem::initPrototype(id_type prototype) auto& automatable = game_.getEntityManager(). getComponent(prototype); - automatable.behaviorRunning = false; - automatable.actionRunning = false; + auto& realizable = game_.getEntityManager(). + getComponent( + game_.getSystemManager().getSystem().getSingleton()); + automatable.behavior.reset(); + automatable.runner = std::unique_ptr(new sol::thread(sol::thread::create(realizable.scriptEngine.lua_state()))); + automatable.behavior = std::unique_ptr(new sol::coroutine(automatable.runner->state()["run"])); + (*automatable.behavior)(script_entity(prototype)); +} + +void AutomatingSystem::initScriptEngine(sol::state& scriptEngine) +{ + scriptEngine.open_libraries(sol::lib::base, sol::lib::coroutine); + scriptEngine.new_usertype( + "vec2d", + sol::constructors(), + "x", sol::property( + [] (vec2d& v) -> double { return v.x(); }, + [] (vec2d& v, double x) { v.x() = x; }), + "y", sol::property( + [] (vec2d& v) -> double { return v.y(); }, + [] (vec2d& v, double y) { v.y() = y; })); + + scriptEngine.new_usertype( + "vec2i", + sol::constructors(), + "x", [] (vec2i& v) -> int& { return v.x(); }, + "y", [] (vec2i& v) -> int& { return v.y(); }); + + scriptEngine.new_usertype( + "entity", + sol::constructors(), + "id", &script_entity::id, + "ponderable", + [&] (script_entity& entity) -> PonderableComponent& { + return game_.getEntityManager(). + getComponent(entity.id); + }); + + scriptEngine.new_usertype( + "ponderable", + "vel", &PonderableComponent::vel, + "accel", &PonderableComponent::accel); } diff --git a/src/systems/automating.h b/src/systems/automating.h index c78b7cf..117b622 100644 --- a/src/systems/automating.h +++ b/src/systems/automating.h @@ -2,6 +2,7 @@ #define AUTOMATING_H_E6E5D76E #include "system.h" +#include class AutomatingSystem : public System { public: @@ -14,6 +15,8 @@ public: void initPrototype(id_type prototype); + void initScriptEngine(sol::state& scriptEngine); + }; #endif /* end of include guard: AUTOMATING_H_E6E5D76E */ diff --git a/src/systems/realizing.cpp b/src/systems/realizing.cpp index f9285ad..28e2279 100644 --- a/src/systems/realizing.cpp +++ b/src/systems/realizing.cpp @@ -29,92 +29,6 @@ inline xmlChar* getProp(xmlNodePtr node, const char* attr) return key; } -void parseAI( - xmlNodePtr node, - std::vector& behavior, - const std::map& items) -{ - xmlChar* key = nullptr; - - if (!xmlStrcmp( - node->name, - reinterpret_cast("switch"))) - { - key = getProp(node, "item"); - std::string switchItem = reinterpret_cast(key); - xmlFree(key); - - for (xmlNodePtr switchNode = node->xmlChildrenNode; - switchNode != nullptr; - switchNode = switchNode->next) - { - if (!xmlStrcmp( - switchNode->name, - reinterpret_cast("case"))) - { - key = getProp(switchNode, "value"); - int caseValue = atoi(reinterpret_cast(key)); - xmlFree(key); - - if (items.at(switchItem) == caseValue) - { - for (xmlNodePtr caseNode = switchNode->xmlChildrenNode; - caseNode != nullptr; - caseNode = caseNode->next) - { - parseAI( - caseNode, - behavior, - items); - } - } - } - } - } else if (!xmlStrcmp( - node->name, - reinterpret_cast("move"))) - { - key = getProp(node, "direction"); - std::string direction = reinterpret_cast(key); - xmlFree(key); - - key = getProp(node, "length-var"); - std::string lengthVar = reinterpret_cast(key); - xmlFree(key); - - key = getProp(node, "speed-var"); - std::string speedVar = reinterpret_cast(key); - xmlFree(key); - - double length = items.at(lengthVar); - double speed = items.at(speedVar); - - AutomatableComponent::Action action; - - if (direction == "left") - { - action.speed.x() = -speed; - action.speed.y() = 0; - } else if (direction == "right") - { - action.speed.x() = speed; - action.speed.y() = 0; - } else if (direction == "up") - { - action.speed.x() = 0; - action.speed.y() = -speed; - } else if (direction == "down") - { - action.speed.x() = 0; - action.speed.y() = speed; - } - - action.dur = length / speed; - - behavior.push_back(std::move(action)); - } -} - // TODO: neither the XML doc nor any of the emplaced entities are properly // destroyed if this method throws an exception. EntityManager::id_type RealizingSystem::initSingleton( @@ -126,6 +40,9 @@ EntityManager::id_type RealizingSystem::initSingleton( auto& realizable = game_.getEntityManager(). emplaceComponent(world); + game_.getSystemManager().getSystem(). + initScriptEngine(realizable.scriptEngine); + realizable.worldFile = worldFile; realizable.prototypeFile = prototypeFile; @@ -299,68 +216,14 @@ EntityManager::id_type RealizingSystem::initSingleton( game_.getSystemManager().getSystem(). initializeBody(mapObject, PonderableComponent::Type::vacuumed); - // Look for any object configuration. - std::map items; - - for (xmlNodePtr objectNode = mapNode->xmlChildrenNode; - objectNode != nullptr; - objectNode = objectNode->next) + if (prototypeId == "movplat") { - if (!xmlStrcmp( - objectNode->name, - reinterpret_cast("item"))) - { - key = getProp(objectNode, "id"); - std::string itemName = reinterpret_cast(key); - xmlFree(key); - - key = xmlNodeGetContent(objectNode); - int itemVal = atoi(reinterpret_cast(key)); - xmlFree(key); - - items[itemName] = itemVal; - } - } + auto& automatable = game_.getEntityManager(). + emplaceComponent(mapObject); - // Add any AI behaviors. - std::vector behaviorWeights; - for (xmlNodePtr protoSubNode = prototypeNode->xmlChildrenNode; - protoSubNode != nullptr; - protoSubNode = protoSubNode->next) - { - if (!xmlStrcmp( - protoSubNode->name, - reinterpret_cast("ai"))) - { - if (!game_.getEntityManager(). - hasComponent(mapObject)) - { - game_.getEntityManager(). - emplaceComponent(mapObject); - } - - auto& automatable = game_.getEntityManager(). - getComponent(mapObject); - - key = getProp(protoSubNode, "chance"); - behaviorWeights.push_back(atof(reinterpret_cast(key))); - xmlFree(key); - - std::vector behavior; - - for (xmlNodePtr aiNode = protoSubNode->xmlChildrenNode; - aiNode != nullptr; - aiNode = aiNode->next) - { - parseAI( - aiNode, - behavior, - items); - } - - automatable.behaviors.push_back(std::move(behavior)); - } + realizable.scriptEngine.script_file( + "res/platform.lua");//, } mappable.objects.push_back(mapObject); -- cgit 1.4.1