Compare commits
3 Commits
d4bac06d94
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| d139e77969 | |||
| 685b15933a | |||
| a54b042e49 |
13
Game.cpp
13
Game.cpp
@@ -18,6 +18,8 @@
|
||||
#include "GUIModuleCommon.h"
|
||||
#include "AppModule.h"
|
||||
#include "GUIModule.h"
|
||||
#include "PhysicsModule.h"
|
||||
#include "physics.h"
|
||||
#include "sound.h"
|
||||
class App;
|
||||
class SkyRenderer : public Ogre::SceneManager::Listener {
|
||||
@@ -626,10 +628,13 @@ end:
|
||||
void setupInput()
|
||||
{
|
||||
}
|
||||
JoltPhysicsWrapper *mJolt;
|
||||
void createContent()
|
||||
{
|
||||
int i;
|
||||
sky = new SkyBoxRenderer(getSceneManager());
|
||||
mJolt = new JoltPhysicsWrapper(mScnMgr, mCameraNode);
|
||||
|
||||
sky = new SkyBoxRenderer(getSceneManager());
|
||||
bool drawFirst = true;
|
||||
uint8_t renderQueue = drawFirst ?
|
||||
Ogre::RENDER_QUEUE_SKIES_EARLY :
|
||||
@@ -651,6 +656,12 @@ end:
|
||||
ECS::setupExteriorScene(mScnMgr,
|
||||
/*mDynWorld.get(), */ mCameraNode,
|
||||
mCamera, getRenderWindow());
|
||||
|
||||
ECS::get().import <ECS::PhysicsModule>();
|
||||
ECS::Physics &ph = ECS::get().ensure<ECS::Physics>();
|
||||
ph.physics = mJolt;
|
||||
ECS::modified<ECS::Physics>();
|
||||
|
||||
ECS::get()
|
||||
.observer<ECS::App>("UpdateInputListener")
|
||||
.event(flecs::OnSet)
|
||||
|
||||
@@ -9,7 +9,89 @@
|
||||
#include "CharacterAIModule.h"
|
||||
namespace ECS
|
||||
{
|
||||
class ActionNodeActions {
|
||||
struct ActionExec {
|
||||
struct PlanExecData {
|
||||
TownNPCs::NPCData &npc;
|
||||
Blackboard &bb;
|
||||
nlohmann::json &memory;
|
||||
};
|
||||
enum { OK = 0, BUSY, ERROR };
|
||||
TownNPCs::NPCData &npc;
|
||||
Blackboard &bb;
|
||||
nlohmann::json &memory;
|
||||
bool complete;
|
||||
bool active;
|
||||
const goap::BaseAction<Blackboard> *action;
|
||||
ActionExec(PlanExecData &data,
|
||||
const goap::BaseAction<Blackboard> *action)
|
||||
: npc(data.npc)
|
||||
, bb(data.bb)
|
||||
, memory(data.memory)
|
||||
, complete(false)
|
||||
, active(false)
|
||||
, action(action)
|
||||
{
|
||||
}
|
||||
ActionExec(const ActionExec &other)
|
||||
: npc(other.npc)
|
||||
, bb(other.bb)
|
||||
, memory(other.memory)
|
||||
, complete(other.complete)
|
||||
, active(other.active)
|
||||
, action(other.action)
|
||||
{
|
||||
}
|
||||
ActionExec &operator=(const ActionExec &other)
|
||||
{
|
||||
npc = other.npc;
|
||||
bb = other.bb;
|
||||
memory = other.memory;
|
||||
complete = other.complete;
|
||||
active = other.active;
|
||||
action = other.action;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual int update(float delta) = 0;
|
||||
virtual void finish(int result) = 0;
|
||||
virtual void activate() = 0;
|
||||
|
||||
public:
|
||||
int operator()(float delta)
|
||||
{
|
||||
if (!active)
|
||||
activate();
|
||||
int ret = update(delta);
|
||||
if (ret != BUSY)
|
||||
finish(ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
struct PlanExec {
|
||||
enum { OK = 0, BUSY, ERROR };
|
||||
std::vector<struct ActionExec *> action_exec;
|
||||
int index;
|
||||
PlanExec()
|
||||
: index(-1)
|
||||
{
|
||||
}
|
||||
int operator()(float delta)
|
||||
{
|
||||
if (index == -1)
|
||||
index = 0;
|
||||
int rc = (*action_exec[index])(delta);
|
||||
if (rc == ActionExec::ERROR)
|
||||
return ERROR;
|
||||
if (action_exec[index]->complete)
|
||||
index++;
|
||||
if (index >= action_exec.size())
|
||||
return OK;
|
||||
return BUSY;
|
||||
}
|
||||
};
|
||||
|
||||
struct ActionNodeActions {
|
||||
struct WalkToAction : public goap::BaseAction<Blackboard> {
|
||||
int node;
|
||||
WalkToAction(int node, int cost)
|
||||
@@ -98,12 +180,103 @@ out:
|
||||
std::vector<goap::BaseAction<Blackboard> *> m_actions;
|
||||
|
||||
public:
|
||||
struct ActionExecWalk : ActionExec {
|
||||
private:
|
||||
Ogre::Vector3 targetPosition;
|
||||
float radius;
|
||||
int update(float delta) override
|
||||
{
|
||||
if (npc.e.is_valid()) {
|
||||
Ogre::Vector3 position =
|
||||
npc.e.get<CharacterBase>()
|
||||
.mBodyNode
|
||||
->_getDerivedPosition();
|
||||
if (position.squaredDistance(targetPosition) >=
|
||||
radius * radius) {
|
||||
if (npc.e.is_valid())
|
||||
npc.e.get<CharacterBase>()
|
||||
.mBodyNode
|
||||
->_setDerivedPosition(
|
||||
targetPosition);
|
||||
npc.position = targetPosition;
|
||||
return BUSY;
|
||||
}
|
||||
} else {
|
||||
if (npc.position.squaredDistance(
|
||||
targetPosition) >=
|
||||
radius * radius) {
|
||||
npc.position = targetPosition;
|
||||
return BUSY;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
const ActionNodeActions::WalkToAction *wtaction =
|
||||
static_cast<
|
||||
const ActionNodeActions::WalkToAction *>(
|
||||
action);
|
||||
radius = ECS::get<ActionNodeList>()
|
||||
.dynamicNodes[wtaction->node]
|
||||
.radius;
|
||||
targetPosition = ECS::get<ActionNodeList>()
|
||||
.dynamicNodes[wtaction->node]
|
||||
.position;
|
||||
Ogre::Vector3 direction =
|
||||
(targetPosition - npc.position).normalisedCopy();
|
||||
targetPosition -= direction * radius;
|
||||
std::cout << action->get_name();
|
||||
}
|
||||
|
||||
public:
|
||||
ActionExecWalk(ActionExec::PlanExecData &data,
|
||||
goap::BaseAction<Blackboard> *action)
|
||||
: ActionExec(data, action)
|
||||
{
|
||||
}
|
||||
};
|
||||
struct ActionExecUse : ActionExec {
|
||||
private:
|
||||
int update(float delta) override
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
std::cout << action->get_name();
|
||||
const ActionNodeActions::RunActionNode *runaction =
|
||||
static_cast<const ActionNodeActions::RunActionNode
|
||||
*>(action);
|
||||
if (runaction)
|
||||
std::cout << "Is Run" << std::endl;
|
||||
OgreAssert(false, "activate");
|
||||
}
|
||||
|
||||
public:
|
||||
ActionExecUse(ActionExec::PlanExecData &data,
|
||||
goap::BaseAction<Blackboard> *action)
|
||||
: ActionExec(data, action)
|
||||
{
|
||||
}
|
||||
};
|
||||
ActionNodeActions(int node, const Blackboard &prereq, int cost)
|
||||
{
|
||||
OgreAssert(
|
||||
node < ECS::get<ActionNodeList>().dynamicNodes.size(),
|
||||
"bad node " + Ogre::StringConverter::toString(node));
|
||||
m_actions.push_back(OGRE_NEW WalkToAction(node, 10000));
|
||||
auto paction = OGRE_NEW WalkToAction(node, 10000);
|
||||
m_actions.push_back(paction);
|
||||
nlohmann::json jactionPrereq = nlohmann::json::object();
|
||||
nlohmann::json jactionEffect = nlohmann::json::object();
|
||||
jactionPrereq["at_object"] = 1;
|
||||
@@ -176,6 +349,32 @@ public:
|
||||
return m_actions;
|
||||
}
|
||||
};
|
||||
struct ActionExecCommon : ActionExec {
|
||||
private:
|
||||
int update(float delta) override
|
||||
{
|
||||
std::cout << "running: " << action->get_name() << std::endl;
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
std::cout << "finish: " << action->get_name() << std::endl;
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
std::cout << action->get_name();
|
||||
std::cout << "!";
|
||||
}
|
||||
|
||||
public:
|
||||
ActionExecCommon(ActionExec::PlanExecData &data,
|
||||
goap::BaseAction<Blackboard> *action)
|
||||
: ActionExec(data, action)
|
||||
{
|
||||
}
|
||||
};
|
||||
CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
{
|
||||
static std::mutex ecs_mutex;
|
||||
@@ -376,6 +575,81 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
});
|
||||
});
|
||||
});
|
||||
static std::unordered_map<int, struct PlanExec> plan_exec;
|
||||
ecs.system<const EngineData, TownNPCs, TownAI>("RunPLAN")
|
||||
.kind(flecs::OnUpdate)
|
||||
.each([&](flecs::entity town, const EngineData &eng,
|
||||
TownNPCs &npcs, TownAI &ai) {
|
||||
for (const auto &plans : ai.plans) {
|
||||
if (plan_exec.find(plans.first) !=
|
||||
plan_exec.end()) {
|
||||
int rc = plan_exec[plans.first](
|
||||
eng.delta);
|
||||
if (rc != PlanExec::BUSY) {
|
||||
plan_exec.erase(plans.first);
|
||||
ai.plans[plans.first].erase(
|
||||
ai.plans[plans.first]
|
||||
.begin());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
std::cout << "NPC: " << plans.first;
|
||||
std::cout << " Plans: " << plans.second.size();
|
||||
for (const auto &plan : plans.second) {
|
||||
struct PlanExec pexec;
|
||||
if (plan.plan.size() == 0)
|
||||
continue;
|
||||
std::cout << " Goal: ";
|
||||
plan.goal->goal.dump_bits();
|
||||
for (const auto &action : plan.plan) {
|
||||
ActionExec::PlanExecData data({
|
||||
npcs.npcs.at(
|
||||
plans.first),
|
||||
ai.blackboards.at(
|
||||
plans.first),
|
||||
ai.memory.at(
|
||||
plans.first),
|
||||
|
||||
});
|
||||
// TODO: executor factory is needed
|
||||
if (action->get_name().substr(
|
||||
0, 4) == "Walk") {
|
||||
ActionExec *e = OGRE_NEW
|
||||
ActionNodeActions::ActionExecWalk(
|
||||
data,
|
||||
action);
|
||||
pexec.action_exec
|
||||
.push_back(e);
|
||||
} else if (action->get_name()
|
||||
.substr(0,
|
||||
4) ==
|
||||
"Use(") {
|
||||
ActionExec *e = OGRE_NEW
|
||||
ActionNodeActions::ActionExecUse(
|
||||
data,
|
||||
action);
|
||||
pexec.action_exec
|
||||
.push_back(e);
|
||||
} else {
|
||||
std::cout
|
||||
<< action->get_name()
|
||||
<< " ";
|
||||
ActionExec *e = OGRE_NEW
|
||||
ActionExecCommon(
|
||||
data,
|
||||
action);
|
||||
pexec.action_exec
|
||||
.push_back(e);
|
||||
}
|
||||
std::cout << action->get_name()
|
||||
<< " ";
|
||||
}
|
||||
plan_exec[plans.first] = pexec;
|
||||
break;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CharacterAIModule::createAI(flecs::entity town)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "CharacterAIModule.h"
|
||||
#include "QuestModule.h"
|
||||
#include "world-build.h"
|
||||
#include "physics.h"
|
||||
|
||||
namespace ECS
|
||||
{
|
||||
@@ -50,9 +51,11 @@ void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window)
|
||||
{
|
||||
std::cout << "Setup GameData\n";
|
||||
setup_minimal();
|
||||
setup_minimal();
|
||||
|
||||
std::cout << "Setup Editor\n";
|
||||
ecs.component<GameState>().add(flecs::Singleton);
|
||||
ecs.import <CharacterModule>();
|
||||
ecs.import <CharacterModule>();
|
||||
ecs.import <BoatModule>();
|
||||
ecs.import <PhysicsModule>();
|
||||
ecs.import <WaterModule>();
|
||||
@@ -104,6 +107,7 @@ void setupExteriorScene(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
ecs.set<EngineData>({ scnMgr, 0.0f, 5.0f, (int)window->getWidth(),
|
||||
(int)window->getHeight(), false });
|
||||
ecs.set<Camera>({ cameraNode, camera, false });
|
||||
PhysicsModule::configurePhysics();
|
||||
ecs.add<GameData>();
|
||||
ecs.add<Input>();
|
||||
ecs.observer<GameState>("Game_Start_Scen_Startup")
|
||||
@@ -207,9 +211,11 @@ void setupInventoryScene(Ogre::SceneManager *scnMgr,
|
||||
void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
Ogre::Camera *camera, Ogre::RenderWindow *window)
|
||||
{
|
||||
std::cout << "Setup Editor\n";
|
||||
setup_minimal();
|
||||
ecs.component<RenderWindow>().add(flecs::Singleton);
|
||||
setup_minimal();
|
||||
Physics &ph = ECS::get().ensure<Physics>();
|
||||
ph.physics = new JoltPhysicsWrapper(scnMgr, cameraNode);
|
||||
ECS::modified<Physics>();
|
||||
ecs.component<RenderWindow>().add(flecs::Singleton);
|
||||
ecs.component<EditorSceneSwitch>().add(flecs::Singleton);
|
||||
ecs.import <CharacterModule>();
|
||||
ecs.import <BoatModule>();
|
||||
@@ -261,7 +267,8 @@ void setupEditor(Ogre::SceneManager *scnMgr, Ogre::SceneNode *cameraNode,
|
||||
#if 0
|
||||
ecs.set<EditorSceneSwitch>({ 0 });
|
||||
#endif
|
||||
ecs.add<GameData>();
|
||||
PhysicsModule::configurePhysics();
|
||||
ecs.add<GameData>();
|
||||
ecs.add<Input>();
|
||||
ecs.add<WaterSurface>();
|
||||
ecs.set<Sun>({ nullptr, nullptr, nullptr, nullptr });
|
||||
|
||||
@@ -61,15 +61,6 @@ PhysicsModule::PhysicsModule(flecs::world &ecs)
|
||||
ecs.component<CachedMass>();
|
||||
ecs.import <TerrainModule>();
|
||||
ecs.import <WaterModule>();
|
||||
ecs.system<const EngineData, const Camera>("physics_init")
|
||||
.kind(PhysicsPreUpdate)
|
||||
.without<Physics>()
|
||||
.each([&](const EngineData &e, const Camera &c) {
|
||||
Physics &ph = ECS::get().ensure<Physics>();
|
||||
ph.physics = new JoltPhysicsWrapper(e.mScnMgr,
|
||||
c.mCameraNode);
|
||||
ECS::modified<Physics>();
|
||||
});
|
||||
ecs.system<EngineData, Physics>("physics_update")
|
||||
.kind(PhysicsUpdate)
|
||||
.each([&](EngineData &e, Physics &ph) {
|
||||
@@ -633,6 +624,10 @@ void PhysicsModule::setDebugDraw(bool enable)
|
||||
{
|
||||
JoltPhysicsWrapper::getSingleton().setDebugDraw(enable);
|
||||
}
|
||||
|
||||
void PhysicsModule::configurePhysics()
|
||||
{
|
||||
}
|
||||
bool WaterBody::isInWater(const JPH::BodyID &id) const
|
||||
{
|
||||
flecs::entity e =
|
||||
|
||||
@@ -61,6 +61,7 @@ struct PhysicsModule {
|
||||
const Ogre::Vector3 &endPos,
|
||||
Ogre::Vector3 &position, JPH::BodyID &id);
|
||||
static void setDebugDraw(bool enable);
|
||||
static void configurePhysics();
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -576,9 +576,9 @@ public:
|
||||
, object_vs_object_layer_filter{}
|
||||
, debugDraw(false)
|
||||
{
|
||||
// Create a factory, this class is responsible for creating instances of classes based on their name or hash and is mainly used for deserialization of saved data.
|
||||
// It is not directly used in this example but still required.
|
||||
JPH::Factory::sInstance = new JPH::Factory();
|
||||
static int instanceCount = 0;
|
||||
OgreAssert(instanceCount == 0, "Bad initialisation");
|
||||
instanceCount++;
|
||||
|
||||
// Register all physics types with the factory and install their collision handlers with the CollisionDispatch class.
|
||||
// If you have your own custom shape types you probably need to register their handlers with the CollisionDispatch before calling this function.
|
||||
@@ -1527,7 +1527,11 @@ JoltPhysicsWrapper::JoltPhysicsWrapper(Ogre::SceneManager *scnMgr,
|
||||
// This needs to be done before any other Jolt function is called.
|
||||
JPH::RegisterDefaultAllocator();
|
||||
|
||||
// Install trace and assert callbacks
|
||||
// Create a factory, this class is responsible for creating instances of classes based on their name or hash and is mainly used for deserialization of saved data.
|
||||
// It is not directly used in this example but still required.
|
||||
JPH::Factory::sInstance = new JPH::Factory();
|
||||
|
||||
// Install trace and assert callbacks
|
||||
JPH::Trace = TraceImpl;
|
||||
JPH_IF_ENABLE_ASSERTS(JPH::AssertFailed = AssertFailedImpl;)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user