Enemy AI is now prototyped and can find the player and attack them.
This commit is contained in:
parent
ad71631809
commit
f3e157a0f7
6 changed files with 78 additions and 38 deletions
2
Makefile
2
Makefile
|
@ -34,7 +34,7 @@ debug: build
|
|||
debug_run: build
|
||||
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe
|
||||
|
||||
debug_walk: build
|
||||
debug_walk: build test
|
||||
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster.exe t
|
||||
|
||||
clean:
|
||||
|
|
|
@ -49,8 +49,6 @@ namespace components {
|
|||
std::string ai_script;
|
||||
std::string ai_start_name;
|
||||
std::string ai_goal_name;
|
||||
ai::State ai_start;
|
||||
ai::State ai_goal;
|
||||
};
|
||||
|
||||
struct Debug {
|
||||
|
|
|
@ -198,7 +198,10 @@ namespace DinkyECS
|
|||
return !queue.empty();
|
||||
}
|
||||
|
||||
/* std::optional can't do references. Don't try it! */
|
||||
/* std::optional can't do references. Don't try it!
|
||||
* Actually, this sucks, either delete it or have it
|
||||
* return pointers (assuming optional can handle pointers)
|
||||
*/
|
||||
template <typename Comp>
|
||||
std::optional<Comp> get_if(DinkyECS::Entity entity) {
|
||||
if(has<Comp>(entity)) {
|
||||
|
|
|
@ -340,6 +340,7 @@ namespace gui {
|
|||
}
|
||||
|
||||
void FSM::run_systems() {
|
||||
System::generate_paths($level);
|
||||
System::enemy_ai($level);
|
||||
System::enemy_pathing($level);
|
||||
System::collision($level);
|
||||
|
|
77
systems.cpp
77
systems.cpp
|
@ -18,6 +18,32 @@ using namespace components;
|
|||
using lighting::LightSource;
|
||||
using ftxui::Color;
|
||||
|
||||
struct EntityAI {
|
||||
std::string script;
|
||||
ai::State start;
|
||||
ai::State goal;
|
||||
ai::ActionPlan plan;
|
||||
|
||||
EntityAI(std::string script, ai::State start, ai::State goal) :
|
||||
script(script), start(start), goal(goal)
|
||||
{
|
||||
}
|
||||
|
||||
EntityAI() {};
|
||||
|
||||
bool wants_to(std::string name) {
|
||||
return plan.script[0].name == name;
|
||||
}
|
||||
|
||||
void set_state(std::string name, bool setting) {
|
||||
ai::set(start, name, setting);
|
||||
}
|
||||
|
||||
void update() {
|
||||
plan = ai::plan(script, start, goal);
|
||||
}
|
||||
};
|
||||
|
||||
void System::lighting(GameLevel &level) {
|
||||
auto &light = *level.lights;
|
||||
auto &world = *level.world;
|
||||
|
@ -36,26 +62,34 @@ void System::lighting(GameLevel &level) {
|
|||
});
|
||||
}
|
||||
|
||||
void System::generate_paths(GameLevel &level) {
|
||||
auto player = level.world->get_the<Player>();
|
||||
const auto &player_position = level.world->get<Position>(player.entity);
|
||||
|
||||
level.map->set_target(player_position.location);
|
||||
level.map->make_paths();
|
||||
}
|
||||
|
||||
void System::enemy_ai(GameLevel &level) {
|
||||
auto &world = *level.world;
|
||||
auto &map = *level.map;
|
||||
auto player = world.get_the<Player>();
|
||||
const auto &player_position = world.get<Position>(player.entity);
|
||||
map.set_target(player_position.location);
|
||||
map.make_paths();
|
||||
|
||||
world.query<Position, EnemyConfig>([&](const auto ent, auto& pos, auto& config) {
|
||||
config.ai_start = ai::load_state(config.ai_start_name);
|
||||
config.ai_goal = ai::load_state(config.ai_goal_name);
|
||||
if(world.has<EntityAI>(ent)) {
|
||||
auto&enemy = world.get<EntityAI>(ent);
|
||||
enemy.set_state("detect_enemy", map.distance(pos.location) < config.hearing_distance);
|
||||
enemy.update();
|
||||
} else {
|
||||
auto ai_start = ai::load_state(config.ai_start_name);
|
||||
auto ai_goal = ai::load_state(config.ai_goal_name);
|
||||
|
||||
ai::set(config.ai_start, "detect_enemy",
|
||||
map.distance(pos.location) < config.hearing_distance);
|
||||
EntityAI enemy(config.ai_script, ai_start, ai_goal);
|
||||
enemy.set_state("detect_enemy", map.distance(pos.location) < config.hearing_distance);
|
||||
enemy.update();
|
||||
|
||||
auto a_plan = ai::plan(config.ai_script, config.ai_start, config.ai_goal);
|
||||
|
||||
ai::dump_script("\n\n\n-----ENEMY SCRIPT", config.ai_start, a_plan.script);
|
||||
auto action = a_plan.script.front();
|
||||
world.set<ai::Action>(ent, action);
|
||||
ai::dump_script("\n\n\n-----ENEMY SCRIPT", enemy.start, enemy.plan.script);
|
||||
world.set<EntityAI>(ent, enemy);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -65,13 +99,12 @@ void System::enemy_pathing(GameLevel &level) {
|
|||
auto player = world.get_the<Player>();
|
||||
|
||||
const auto &player_position = world.get<Position>(player.entity);
|
||||
map.set_target(player_position.location);
|
||||
map.make_paths();
|
||||
|
||||
world.query<Position, Motion>([&](auto ent, auto &position, auto &motion) {
|
||||
if(ent != player.entity) {
|
||||
auto action = world.get_if<ai::Action>(ent);
|
||||
if(action && (*action).name == "find_enemy") {
|
||||
auto& action = world.get<EntityAI>(ent);
|
||||
|
||||
if(action.wants_to("find_enemy")) {
|
||||
Point out = position.location; // copy
|
||||
map.neighbors(out, motion.random);
|
||||
motion = { int(out.x - position.location.x), int(out.y - position.location.y)};
|
||||
|
@ -154,6 +187,7 @@ void System::death(GameLevel &level, components::ComponentMap& components) {
|
|||
world.remove<Motion>(ent);
|
||||
world.remove<Combat>(ent);
|
||||
world.remove<EnemyConfig>(ent);
|
||||
world.remove<EntityAI>(ent);
|
||||
world.remove<Animation>(ent);
|
||||
|
||||
if(auto snd = world.get_if<Sound>(ent)) {
|
||||
|
@ -181,12 +215,14 @@ void System::combat(GameLevel &level) {
|
|||
// this is guaranteed to not return the given position
|
||||
auto [found, nearby] = collider.neighbors(player_position.location);
|
||||
|
||||
|
||||
if(found) {
|
||||
for(auto entity : nearby) {
|
||||
// AI: process AI combat actions here
|
||||
if(world.has<EntityAI>(entity)) {
|
||||
auto& enemy_ai = world.get<EntityAI>(entity);
|
||||
enemy_ai.set_state("enemy_found", true);
|
||||
enemy_ai.update();
|
||||
|
||||
if(world.has<Combat>(entity)) {
|
||||
if(enemy_ai.wants_to("kill_enemy")) {
|
||||
auto& enemy_combat = world.get<Combat>(entity);
|
||||
|
||||
Events::Combat result {
|
||||
|
@ -208,6 +244,7 @@ void System::combat(GameLevel &level) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void System::collision(GameLevel &level) {
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace System {
|
|||
void motion(GameLevel &level);
|
||||
void collision(GameLevel &level);
|
||||
void death(GameLevel &level, components::ComponentMap& components);
|
||||
void generate_paths(GameLevel &level);
|
||||
void enemy_pathing(GameLevel &level);
|
||||
void enemy_ai(GameLevel &level);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue