From 4b4125e234cb727c70822e0a1fce0688c357741e Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Thu, 19 Mar 2015 16:15:47 -0400 Subject: Implemented a simple AI --- src/components/ai.cpp | 142 ++++++++++++++++++++++++++++++++++++++ src/components/ai.h | 73 ++++++++++++++++++++ src/components/map_collision.cpp | 15 +++- src/components/physics_body.cpp | 8 +-- src/components/player_physics.cpp | 8 +-- 5 files changed, 235 insertions(+), 11 deletions(-) create mode 100644 src/components/ai.cpp create mode 100644 src/components/ai.h (limited to 'src/components') diff --git a/src/components/ai.cpp b/src/components/ai.cpp new file mode 100644 index 0000000..9f8c764 --- /dev/null +++ b/src/components/ai.cpp @@ -0,0 +1,142 @@ +#include "ai.h" +#include +#include "entity.h" + +void AIActionContainer::addAction(std::shared_ptr action) +{ + actions.push_back(action); +} + +void AIActionContainer::start(Game& game, Entity& entity) +{ + currentAction = begin(actions); + + if (currentAction != end(actions)) + { + (*currentAction)->start(game, entity); + } +} + +void AIActionContainer::perform(Game& game, Entity& entity, double dt) +{ + if (!isDone()) + { + (*currentAction)->perform(game, entity, dt); + + if ((*currentAction)->isDone()) + { + currentAction++; + + if (!isDone()) + { + (*currentAction)->start(game, entity); + } + } + } +} + +bool AIActionContainer::isDone() const +{ + return currentAction == end(actions); +} + +AI::AI(int chance) +{ + this->chance = chance; +} + +int AI::getChance() const +{ + return chance; +} + +AI& AIComponent::emplaceAI(int chance) +{ + maxChance += chance; + ais.emplace_back(chance); + + return ais.back(); +} + +void AIComponent::tick(Game& game, Entity& entity, double dt) +{ + if (currentAI == nullptr) + { + int toChoose = rand() % maxChance; + for (auto& ai : ais) + { + if (toChoose < ai.getChance()) + { + currentAI = &ai; + break; + } else { + toChoose -= ai.getChance(); + } + } + + if (currentAI != nullptr) + { + currentAI->start(game, entity); + } + } + + if (currentAI != nullptr) + { + currentAI->perform(game, entity, dt); + + if (currentAI->isDone()) + { + currentAI = nullptr; + } + } +} + +MoveAIAction::MoveAIAction(Direction dir, int len, int speed) +{ + this->dir = dir; + this->len = len; + this->speed = speed; +} + +void MoveAIAction::start(Game& game, Entity& entity) +{ + remaining = len; +} + +void MoveAIAction::perform(Game&, Entity& entity, double dt) +{ + double dist = dt * speed; + remaining -= dist; + + switch (dir) + { + case Direction::Left: + { + entity.position.first -= dist; + break; + } + + case Direction::Right: + { + entity.position.first += dist; + break; + } + + case Direction::Up: + { + entity.position.second -= dist; + break; + } + + case Direction::Down: + { + entity.position.second += dist; + break; + } + } +} + +bool MoveAIAction::isDone() const +{ + return remaining <= 0.0; +} diff --git a/src/components/ai.h b/src/components/ai.h new file mode 100644 index 0000000..840283b --- /dev/null +++ b/src/components/ai.h @@ -0,0 +1,73 @@ +#ifndef AI_H +#define AI_H + +#include +#include +#include +#include + +#include "entity.h" + +class AIAction { + public: + virtual void start(Game& game, Entity& entity) = 0; + virtual void perform(Game& game, Entity& entity, double dt) = 0; + virtual bool isDone() const = 0; +}; + +class AIActionContainer { + public: + void addAction(std::shared_ptr action); + virtual void start(Game& game, Entity& entity); + virtual void perform(Game& game, Entity& entity, double dt); + virtual bool isDone() const; + + private: + std::list> actions; + std::list>::iterator currentAction {end(actions)}; +}; + +class AI : public AIActionContainer { + public: + AI(int chance); + + int getChance() const; + + private: + int chance; +}; + +class AIComponent : public Component { + public: + AI& emplaceAI(int chance); + void tick(Game& game, Entity& entity, double dt); + + private: + int maxChance = 0; + std::list ais; + AI* currentAI = nullptr; +}; + +class MoveAIAction : public AIAction { + public: + enum class Direction { + Left, + Right, + Up, + Down + }; + + MoveAIAction(Direction dir, int len, int speed); + + void start(Game& game, Entity& entity); + void perform(Game& game, Entity& entity, double dt); + bool isDone() const; + + private: + Direction dir; + int len; + int speed; + double remaining; +}; + +#endif /* end of include guard: AI_H */ diff --git a/src/components/map_collision.cpp b/src/components/map_collision.cpp index 83ad33d..432fea6 100644 --- a/src/components/map_collision.cpp +++ b/src/components/map_collision.cpp @@ -156,15 +156,24 @@ void MapCollisionComponent::processCollision(Game& game, Entity& collider, Colli if (dir == Direction::left) { collider.position.first = collision.axis; - collider.send(game, Message::Type::stopMovingHorizontally); + + Message msg(Message::Type::setHorizontalVelocity); + msg.velocity = 0.0; + collider.send(game, msg); } else if (dir == Direction::right) { collider.position.first = collision.axis - collider.size.first; - collider.send(game, Message::Type::stopMovingHorizontally); + + Message msg(Message::Type::setHorizontalVelocity); + msg.velocity = 0.0; + collider.send(game, msg); } else if (dir == Direction::up) { collider.position.second = collision.axis; - collider.send(game, Message::Type::stopMovingVertically); + + Message msg(Message::Type::setVerticalVelocity); + msg.velocity = 0.0; + collider.send(game, msg); } else if (dir == Direction::down) { collider.position.second = collision.axis - collider.size.second; diff --git a/src/components/physics_body.cpp b/src/components/physics_body.cpp index acbdc5d..97394d1 100644 --- a/src/components/physics_body.cpp +++ b/src/components/physics_body.cpp @@ -13,12 +13,12 @@ void PhysicsBodyComponent::receive(Game&, Entity&, const Message& msg) } else if (msg.type == Message::Type::stopWalking) { velocity.first = 0.0; - } else if (msg.type == Message::Type::stopMovingHorizontally) + } else if (msg.type == Message::Type::setHorizontalVelocity) { - velocity.first = 0.0; - } else if (msg.type == Message::Type::stopMovingVertically) + velocity.first = msg.velocity; + } else if (msg.type == Message::Type::setVerticalVelocity) { - velocity.second = 0.0; + velocity.second = msg.velocity; } } diff --git a/src/components/player_physics.cpp b/src/components/player_physics.cpp index 1d14f35..40e9948 100644 --- a/src/components/player_physics.cpp +++ b/src/components/player_physics.cpp @@ -29,12 +29,12 @@ void PlayerPhysicsComponent::receive(Game&, Entity& entity, const Message& msg) { velocity.first = 0.0; direction = 0; - } else if (msg.type == Message::Type::stopMovingHorizontally) + } else if (msg.type == Message::Type::setHorizontalVelocity) { - velocity.first = 0.0; - } else if (msg.type == Message::Type::stopMovingVertically) + velocity.first = msg.velocity; + } else if (msg.type == Message::Type::setVerticalVelocity) { - velocity.second = 0.0; + velocity.second = msg.velocity; } else if (msg.type == Message::Type::hitTheGround) { if (isFalling) -- cgit 1.4.1