Bud can run and explore buildings
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
project(GGP_Exam VERSION 1.0.0)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -579,8 +579,8 @@ Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [305 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [291 FPS]]
|
||||
@@ -984,8 +984,8 @@ Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [284 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [275 FPS]]
|
||||
@@ -1024,7 +1024,7 @@ Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[*GAME OVER*]
|
||||
Pos=360,150
|
||||
Pos=390,195
|
||||
Size=180,150
|
||||
Collapsed=0
|
||||
|
||||
@@ -1139,8 +1139,8 @@ Size=240,431
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [352 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [336 FPS]]
|
||||
@@ -1763,3 +1763,213 @@ Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [739 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [615 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [592 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [573 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [531 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [491 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [463 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [435 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [410 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [388 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [368 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [292 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [779 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [633 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [609 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [583 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [538 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [468 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [441 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [395 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [374 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [339 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [808 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [673 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [646 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [620 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [570 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [465 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [436 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [412 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [389 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [370 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [781 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [632 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [572 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [494 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [433 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [387 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [765 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [472 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [458 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [422 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
|
||||
@@ -2,31 +2,45 @@
|
||||
#include "Behaviour.h"
|
||||
#include "BehaviourTree.h"
|
||||
#include <IExamInterface.h>
|
||||
#include "Thinker.h"
|
||||
|
||||
#define TO_RAD(i) i * (M_PI / 180)
|
||||
|
||||
static int randNumRange(int minRange, int maxRange) {
|
||||
std::random_device rd;
|
||||
std::mt19937 seed(rd());
|
||||
std::uniform_int_distribution<> range(minRange, maxRange);
|
||||
|
||||
return range(seed);
|
||||
}
|
||||
|
||||
namespace BT_Action
|
||||
{
|
||||
BT::State FindAHouse(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
const Elite::Vector2 worldDimensions{ interfacePtr->World_GetInfo().Dimensions };
|
||||
|
||||
std::random_device rd; // obtain a random number from hardware
|
||||
std::mt19937 seed(rd()); // seed the generator
|
||||
std::uniform_int_distribution<> range(-worldDimensions.x, worldDimensions.x); // define the range
|
||||
|
||||
const Elite::Vector2 randomLocation(range(seed), range(seed));
|
||||
const Elite::Vector2 target = interfacePtr->NavMesh_GetClosestPathPoint(randomLocation);
|
||||
|
||||
if (randomLocation != target) {
|
||||
blackboardPtr->ChangeData("Target", randomLocation);
|
||||
|
||||
std::cout << "Data send " << randomLocation << "\n";
|
||||
BT::State SetTimer(Blackboard* blackboardPtr, const std::string& timerName, bool doOnce) {
|
||||
bool didOnce{};
|
||||
blackboardPtr->GetData("Timer" + timerName + "DoOnce", didOnce);
|
||||
|
||||
if (doOnce && didOnce)
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
return BT::State::Failure;
|
||||
if (doOnce)
|
||||
blackboardPtr->ChangeData("Timer" + timerName + "DoOnce", true);
|
||||
|
||||
blackboardPtr->ChangeData("Timer" + timerName, std::chrono::steady_clock::now());
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State UnlockTimer(Blackboard* blackboardPtr, const std::string& timerName) {
|
||||
blackboardPtr->ChangeData("TimerLock" + timerName, false);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State LockTimer(Blackboard* blackboardPtr, const std::string& timerName) {
|
||||
blackboardPtr->ChangeData("TimerLock" + timerName, true);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State GoToTarget(Blackboard* blackboardPtr) {
|
||||
@@ -34,11 +48,22 @@ namespace BT_Action
|
||||
Elite::Vector2 target{};
|
||||
SteeringPlugin_Output steering{};
|
||||
|
||||
std::chrono::steady_clock::time_point timer{};
|
||||
float maxTime{};
|
||||
bool doOnce{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Target", target);
|
||||
blackboardPtr->GetData("Steering", steering);
|
||||
|
||||
std::cout << "target received " << target << "\n";
|
||||
blackboardPtr->GetData("FailSafe", timer);
|
||||
blackboardPtr->GetData("MaxFailSafe", maxTime);
|
||||
blackboardPtr->GetData("FailSafeDoOnce", doOnce);
|
||||
|
||||
if (!doOnce) {
|
||||
blackboardPtr->ChangeData("FailSafe", std::chrono::steady_clock::now());
|
||||
blackboardPtr->ChangeData("FailSafeDoOnce", true);
|
||||
}
|
||||
|
||||
const auto agentInfo = interfacePtr->Agent_GetInfo();
|
||||
|
||||
@@ -46,12 +71,18 @@ namespace BT_Action
|
||||
|
||||
steering.LinearVelocity = nextTargetPos - agentInfo.Position;
|
||||
steering.LinearVelocity.Normalize();
|
||||
steering.LinearVelocity *= agentInfo.MaxLinearSpeed;
|
||||
steering.LinearVelocity *= agentInfo.MaxLinearSpeed * 100;
|
||||
|
||||
if (Distance(nextTargetPos, agentInfo.Position) < 2.f) {
|
||||
steering.LinearVelocity = Elite::ZeroVector2;
|
||||
const std::chrono::steady_clock::time_point currentTime{ std::chrono::steady_clock::now() };
|
||||
const std::chrono::duration<float> elapsedSec{ currentTime - timer };
|
||||
|
||||
std::cout << "target reached at " << target << "\n";
|
||||
if (elapsedSec.count() > maxTime) {
|
||||
blackboardPtr->ChangeData("FailSafeDoOnce", false);
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
if (Distance(target, agentInfo.Position) < 2.f) {
|
||||
blackboardPtr->ChangeData("FailSafeDoOnce", false);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
@@ -60,4 +91,434 @@ namespace BT_Action
|
||||
|
||||
return BT::State::Running;
|
||||
}
|
||||
}
|
||||
|
||||
BT::State EnableSpin(Blackboard* blackboardPtr) {
|
||||
blackboardPtr->ChangeData("Spin", true);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State DisableSpin(Blackboard* blackboardPtr) {
|
||||
blackboardPtr->ChangeData("Spin", false);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State FindClosestEdge(Blackboard* blackboardPtr, int degree) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
const Elite::Vector2 playerPos{ interfacePtr->Agent_GetInfo().Position };
|
||||
|
||||
constexpr float offset{ 3.f };
|
||||
const Elite::Vector2 center{ interfacePtr->GetPurgeZonesInFOV()[0].Center };
|
||||
const float radius{ interfacePtr->GetPurgeZonesInFOV()[0].Radius + offset };
|
||||
|
||||
float closestTarget{ FLT_MAX };
|
||||
Elite::Vector2 finalTarget{};
|
||||
|
||||
constexpr int circleDegrees{ 360 };
|
||||
|
||||
if (degree > circleDegrees) {
|
||||
degree = circleDegrees;
|
||||
}
|
||||
for (int i = 0; i <= circleDegrees; i += degree) {
|
||||
const Elite::Vector2 pointOnCircle{ center.x + radius * std::cosf(TO_RAD(i)), center.y + radius * std::sinf(TO_RAD(i)) };
|
||||
|
||||
const float targetDistance{ playerPos.DistanceSquared(pointOnCircle) };
|
||||
|
||||
if (closestTarget > targetDistance) {
|
||||
closestTarget = targetDistance;
|
||||
finalTarget = pointOnCircle;
|
||||
}
|
||||
}
|
||||
|
||||
blackboardPtr->ChangeData("Target", finalTarget);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State SetItemAsTarget(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
if (interfacePtr->GetItemsInFOV().capacity() == 0) {
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
ItemInfo targetItem{};
|
||||
float closestItem{ FLT_MAX };
|
||||
|
||||
for (const auto item : interfacePtr->GetItemsInFOV()) {
|
||||
const float itemDistance{ interfacePtr->Agent_GetInfo().Position.DistanceSquared(item.Location) };
|
||||
|
||||
if (closestItem < itemDistance)
|
||||
continue;
|
||||
|
||||
closestItem = itemDistance;
|
||||
targetItem = item;
|
||||
}
|
||||
|
||||
blackboardPtr->ChangeData("TargetItem", targetItem);
|
||||
blackboardPtr->ChangeData("Target", targetItem.Location);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State DestroyItemOnFloor(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
ItemInfo targetItem{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("TargetItem", targetItem);
|
||||
|
||||
if (interfacePtr->DestroyItem(targetItem))
|
||||
return BT::State::Success;
|
||||
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
BT::State PickUpItem(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
ItemInfo targetItem{};
|
||||
int freeSlot{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
blackboardPtr->GetData("TargetItem", targetItem);
|
||||
blackboardPtr->GetData("NextFreeSlot", freeSlot);
|
||||
|
||||
if (interfacePtr->GrabItem(targetItem)) {
|
||||
interfacePtr->Inventory_AddItem(freeSlot, targetItem);
|
||||
|
||||
blackboardPtr->ChangeData("NextFreeSlot", thinkerPtr->AddItemToMemory(targetItem));
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
BT::State SwapItem(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
ItemInfo targetItem{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
blackboardPtr->GetData("TargetItem", targetItem);
|
||||
|
||||
if (interfacePtr->GrabItem(targetItem)) {
|
||||
const int slot = thinkerPtr->FindEmptyValue(targetItem);
|
||||
interfacePtr->Inventory_RemoveItem(slot);
|
||||
interfacePtr->Inventory_AddItem(slot, targetItem);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
BT::State CheckItem(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
ItemInfo targetItem{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
blackboardPtr->GetData("TargetItem", targetItem);
|
||||
|
||||
const int slotIndex{ thinkerPtr->CheckItem(targetItem) };
|
||||
|
||||
if (slotIndex == interfacePtr->Inventory_GetCapacity() - 1) {
|
||||
if (targetItem.Type == eItemType::SHOTGUN || targetItem.Type == eItemType::PISTOL) {
|
||||
interfacePtr->DestroyItem(targetItem);
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
if (interfacePtr->GrabItem(targetItem)) {
|
||||
interfacePtr->Inventory_AddItem(slotIndex, targetItem);
|
||||
interfacePtr->Inventory_UseItem(slotIndex);
|
||||
interfacePtr->Inventory_RemoveItem(slotIndex);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(targetItem.Type == eItemType::SHOTGUN || targetItem.Type == eItemType::PISTOL)) {
|
||||
interfacePtr->Inventory_UseItem(slotIndex);
|
||||
}
|
||||
|
||||
if (interfacePtr->GrabItem(targetItem)) {
|
||||
interfacePtr->Inventory_RemoveItem(slotIndex);
|
||||
interfacePtr->Inventory_AddItem(slotIndex, targetItem);
|
||||
return BT::State::Success;
|
||||
}
|
||||
}
|
||||
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
BT::State UseItem(Blackboard* blackboardPtr, eItemType type) {
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
const auto item = thinkerPtr->FindLeastValueItem(type);
|
||||
|
||||
if (item->ItemInfo.Value <= 0)
|
||||
return BT::State::Failure;
|
||||
|
||||
if (interfacePtr->Inventory_UseItem(item->invIndex)) {
|
||||
item->ItemInfo.Value = 0;
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
BT::State TryFindHouse(Blackboard* blackboardPtr, float searchRadius, int degree) {
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
blackboardPtr->ChangeData("TargetHouse", HouseInfo{});
|
||||
|
||||
const Elite::Vector2 playerPos{ interfacePtr->Agent_GetInfo().Position };
|
||||
|
||||
float closestTarget{ FLT_MAX };
|
||||
Elite::Vector2 finalTarget{};
|
||||
|
||||
constexpr int circleDegrees{ 360 };
|
||||
|
||||
if (degree > circleDegrees) {
|
||||
degree = circleDegrees;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= circleDegrees; i += degree) {
|
||||
const Elite::Vector2 pointOnCircle{ playerPos.x + searchRadius * std::cosf(TO_RAD(i)), playerPos.y + searchRadius * std::sinf(TO_RAD(i)) };
|
||||
const Elite::Vector2 target = interfacePtr->NavMesh_GetClosestPathPoint(pointOnCircle);
|
||||
|
||||
if (pointOnCircle != target) {
|
||||
constexpr float houseOffset{ 5.f };
|
||||
if (thinkerPtr->CheckIfTargetIsExplored(target, houseOffset))
|
||||
continue;
|
||||
|
||||
const float targetDistance{ playerPos.DistanceSquared(target) };
|
||||
|
||||
if (closestTarget > targetDistance) {
|
||||
closestTarget = targetDistance;
|
||||
finalTarget = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (finalTarget == Elite::Vector2{}) {
|
||||
finalTarget = Elite::Vector2(randNumRange(-searchRadius, searchRadius),
|
||||
randNumRange(-searchRadius, searchRadius));
|
||||
}
|
||||
|
||||
blackboardPtr->ChangeData("Target", finalTarget);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State GetHouseAsTarget(Blackboard* blackboardPtr, float maxTravelDistance) {
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
const HouseInfo targetHouse{ thinkerPtr->CheckHouseValidTarget(interfacePtr->Agent_GetInfo().Position, maxTravelDistance) };
|
||||
|
||||
if (targetHouse.Size.x <= 0) {
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
blackboardPtr->ChangeData("Target", targetHouse.Center);
|
||||
blackboardPtr->ChangeData("TargetHouse", targetHouse);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State CheckHouses(Blackboard* blackboardPtr) {
|
||||
Thinker* thinkerPtr{};
|
||||
IExamInterface* interfacePtr{};
|
||||
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
if (thinkerPtr->CheckHousesForMemory(interfacePtr->GetHousesInFOV())) {
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
BT::State SetExpireDate(Blackboard* blackboardPtr) {
|
||||
Thinker* thinkerPtr{};
|
||||
HouseInfo targetHouse{};
|
||||
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
blackboardPtr->GetData("TargetHouse", targetHouse);
|
||||
|
||||
thinkerPtr->SetTargetHouseExpireDate(targetHouse);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State GetInsideTarget(Blackboard* blackboardPtr, float offset) {
|
||||
HouseInfo targetHouse{};
|
||||
blackboardPtr->GetData("TargetHouse", targetHouse);
|
||||
|
||||
const Elite::Vector2 houseCenter{ targetHouse.Center };
|
||||
const Elite::Vector2 houseSize{ targetHouse.Size };
|
||||
|
||||
const Elite::Vector2 targetLocation(randNumRange(int(houseCenter.x - houseSize.x / 2 + offset), int(houseCenter.x + houseSize.x / 2 - offset)),
|
||||
randNumRange(int(houseCenter.y - houseSize.y / 2 + offset), int(houseCenter.y + houseSize.y / 2 - offset)));
|
||||
|
||||
blackboardPtr->ChangeData("Target", targetLocation);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
}
|
||||
|
||||
namespace BT_Condition
|
||||
{
|
||||
bool CheckTimerLock(Blackboard* blackboardPtr, const std::string& timerName) {
|
||||
bool lock{};
|
||||
blackboardPtr->GetData(timerName + "TimerLock", lock);
|
||||
|
||||
return !lock;
|
||||
}
|
||||
|
||||
bool CheckTimer(Blackboard* blackboardPtr, const std::string& timerName, bool doOnce) {
|
||||
std::chrono::steady_clock::time_point timer{};
|
||||
float maxTime{};
|
||||
|
||||
blackboardPtr->GetData("Timer" + timerName, timer);
|
||||
blackboardPtr->GetData("MaxTime" + timerName, maxTime);
|
||||
|
||||
const std::chrono::steady_clock::time_point currentTime{ std::chrono::steady_clock::now() };
|
||||
const std::chrono::duration<float> elapsedSec{ currentTime - timer };
|
||||
|
||||
if (elapsedSec.count() > maxTime) {
|
||||
if (doOnce)
|
||||
blackboardPtr->ChangeData("Timer" + timerName + "DoOnce", false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SeePurgeZone(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
return interfacePtr->GetPurgeZonesInFOV().capacity() > 0;
|
||||
}
|
||||
|
||||
bool ItemInInv(Blackboard* blackboardPtr, eItemType type) {
|
||||
Thinker* thinkerPtr{};
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
return thinkerPtr->IsItemInInv(type);
|
||||
}
|
||||
|
||||
bool HpUnderThreshold(Blackboard* blackboardPtr, float threshold) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
return interfacePtr->Agent_GetInfo().Health <= threshold;
|
||||
}
|
||||
|
||||
bool CheckMinNeededEnergy(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
const auto item = thinkerPtr->FindLeastValueItem(eItemType::FOOD);
|
||||
|
||||
return interfacePtr->Agent_GetInfo().Energy <= 10.f - item->ItemInfo.Value;
|
||||
}
|
||||
|
||||
bool SeeItem(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
return interfacePtr->GetItemsInFOV().capacity() > 0;
|
||||
}
|
||||
|
||||
bool IsTypeOfItem(Blackboard* blackboardPtr, eItemType type) {
|
||||
ItemInfo targetItem{};
|
||||
blackboardPtr->GetData("TargetItem", targetItem);
|
||||
|
||||
return targetItem.Type == type;
|
||||
}
|
||||
|
||||
bool InvIsNotFull(Blackboard* blackboardPtr) {
|
||||
Thinker* thinkerPtr{};
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
return thinkerPtr->IsInvNotFull();
|
||||
}
|
||||
|
||||
bool EmptyValue(Blackboard* blackboardPtr) {
|
||||
Thinker* thinkerPtr{};
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
if (thinkerPtr->EmptyValue()) {
|
||||
std::cout << "empty item\n";
|
||||
}
|
||||
|
||||
return thinkerPtr->EmptyValue();
|
||||
}
|
||||
|
||||
bool InvIsFull(Blackboard* blackboardPtr) {
|
||||
return !InvIsNotFull(blackboardPtr);
|
||||
}
|
||||
|
||||
bool InsideTargetHouse(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
HouseInfo targetHouse{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
blackboardPtr->GetData("TargetHouse", targetHouse);
|
||||
|
||||
if (interfacePtr->Agent_GetInfo().IsInHouse) {
|
||||
return thinkerPtr->CheckIfTargetIsInside(targetHouse, interfacePtr->Agent_GetInfo().Position);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SeeHouse(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
return interfacePtr->GetHousesInFOV().capacity() > 0;
|
||||
}
|
||||
|
||||
bool NewHouse(Blackboard* blackboardPtr) {
|
||||
Thinker* thinkerPtr{};
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
return thinkerPtr->NewHouseToExplore();
|
||||
}
|
||||
|
||||
bool ReExploreHouse(Blackboard* blackboardPtr) {
|
||||
Thinker* thinkerPtr{};
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
return thinkerPtr->HouseToReExplore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <Exam_HelperStructs.h>
|
||||
|
||||
namespace BT
|
||||
{
|
||||
@@ -9,10 +10,52 @@ class Blackboard;
|
||||
|
||||
namespace BT_Action
|
||||
{
|
||||
BT::State FindAHouse(Blackboard* blackboardPtr);
|
||||
BT::State SetTimer(Blackboard* blackboardPtr, const std::string& timerName, bool doOnce);
|
||||
BT::State UnlockTimer(Blackboard* blackboardPtr, const std::string& timerName);
|
||||
BT::State LockTimer(Blackboard* blackboardPtr, const std::string& timerName);
|
||||
|
||||
BT::State GoToTarget(Blackboard* blackboardPtr);
|
||||
BT::State EnableSpin(Blackboard* blackboardPtr);
|
||||
BT::State DisableSpin(Blackboard* blackboardPtr);
|
||||
|
||||
BT::State FindClosestEdge(Blackboard* blackboardPtr, int degree);
|
||||
|
||||
BT::State UseItem(Blackboard* blackboardPtr, eItemType type);
|
||||
|
||||
BT::State SetItemAsTarget(Blackboard* blackboardPtr);
|
||||
BT::State DestroyItemOnFloor(Blackboard* blackboardPtr);
|
||||
BT::State PickUpItem(Blackboard* blackboardPtr);
|
||||
BT::State SwapItem(Blackboard* blackboardPtr);
|
||||
BT::State CheckItem(Blackboard* blackboardPtr);
|
||||
|
||||
BT::State TryFindHouse(Blackboard* blackboardPtr, float searchRadius, int degree);
|
||||
BT::State GetHouseAsTarget(Blackboard* blackboardPtr, float maxTravelDistance);
|
||||
BT::State CheckHouses(Blackboard* blackboardPtr);
|
||||
BT::State SetExpireDate(Blackboard* blackboardPtr);
|
||||
BT::State GetInsideTarget(Blackboard* blackboardPtr, float offset);
|
||||
|
||||
}
|
||||
|
||||
namespace BT_Conditions
|
||||
namespace BT_Condition
|
||||
{
|
||||
bool CheckTimerLock(Blackboard* blackboardPtr, const std::string& timerName);
|
||||
bool CheckTimer(Blackboard* blackboardPtr, const std::string& timerName, bool doOnce);
|
||||
|
||||
bool SeePurgeZone(Blackboard* blackboardPtr);
|
||||
|
||||
bool ItemInInv(Blackboard* blackboardPtr, eItemType type);
|
||||
bool HpUnderThreshold(Blackboard* blackboardPtr, float threshold);
|
||||
bool CheckMinNeededEnergy(Blackboard* blackboardPtr);
|
||||
|
||||
bool SeeItem(Blackboard* blackboardPtr);
|
||||
bool IsTypeOfItem(Blackboard* blackboardPtr, eItemType type);
|
||||
bool InvIsNotFull(Blackboard* blackboardPtr);
|
||||
bool EmptyValue(Blackboard* blackboardPtr);
|
||||
bool InvIsFull(Blackboard* blackboardPtr);
|
||||
|
||||
bool InsideTargetHouse(Blackboard* blackboardPtr);
|
||||
bool SeeHouse(Blackboard* blackboardPtr);
|
||||
bool NewHouse(Blackboard* blackboardPtr);
|
||||
bool ReExploreHouse(Blackboard* blackboardPtr);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ State Action::Execute(Blackboard* blackboardPtr) {
|
||||
|
||||
BehaviorTree::~BehaviorTree() {
|
||||
SAFE_DELETE(m_RootBehaviorPtr)
|
||||
SAFE_DELETE(m_BlackboardPtr) //Takes ownership of passed blackboard!
|
||||
SAFE_DELETE(m_BlackboardPtr) //Takes ownership of passed blackboard!
|
||||
}
|
||||
|
||||
void BehaviorTree::Update() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <Exam_HelperStructs.h>
|
||||
|
||||
#include "Blackboard.h"
|
||||
|
||||
namespace BT
|
||||
{
|
||||
enum class State
|
||||
@@ -87,7 +88,9 @@ namespace BT
|
||||
class Action final : public IBehavior
|
||||
{
|
||||
public:
|
||||
explicit Action(std::function<State(Blackboard*)> fp) : m_ActionPtr(std::move(fp)) {}
|
||||
explicit Action(std::function<State(Blackboard*)> fp)
|
||||
: m_ActionPtr(std::move(fp)) {
|
||||
}
|
||||
State Execute(Blackboard* blackboardPtr) override;
|
||||
|
||||
private:
|
||||
|
||||
152
project/BigThink.cpp
Normal file
152
project/BigThink.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "stdafx.h"
|
||||
#include "BigThink.h"
|
||||
|
||||
#include "Behaviour.h"
|
||||
#include "BehaviourTree.h"
|
||||
|
||||
namespace BigThink
|
||||
{
|
||||
constexpr float HpThreshold{ 8.f }; // TODO: Make this a parameter
|
||||
|
||||
BT::Sequence* PurgeZoneHandling() {
|
||||
constexpr int searchDegree{ 45 };
|
||||
return
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(BT_Condition::SeePurgeZone),
|
||||
new BT::Action(std::bind(BT_Action::FindClosestEdge, std::placeholders::_1, searchDegree)),
|
||||
new BT::Action(BT_Action::GoToTarget)
|
||||
});
|
||||
}
|
||||
|
||||
BT::Selector* ItemHandling() {
|
||||
return
|
||||
new BT::Selector({
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::ItemInInv, std::placeholders::_1, eItemType::MEDKIT)),
|
||||
new BT::Conditional(std::bind(BT_Condition::HpUnderThreshold, std::placeholders::_1, HpThreshold)),
|
||||
new BT::Action(std::bind(BT_Action::UseItem, std::placeholders::_1, eItemType::MEDKIT))
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::ItemInInv, std::placeholders::_1, eItemType::FOOD)),
|
||||
new BT::Conditional(BT_Condition::CheckMinNeededEnergy),
|
||||
new BT::Action(std::bind(BT_Action::UseItem, std::placeholders::_1, eItemType::FOOD))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
BT::PartialSequence* PickUpHandling() {
|
||||
return
|
||||
new BT::PartialSequence({
|
||||
new BT::Conditional(BT_Condition::SeeItem),
|
||||
new BT::Action(BT_Action::DisableSpin),
|
||||
new BT::Action(BT_Action::SetItemAsTarget),
|
||||
new BT::Action(BT_Action::GoToTarget),
|
||||
new BT::Selector({
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::IsTypeOfItem, std::placeholders::_1, eItemType::GARBAGE)),
|
||||
new BT::Action(BT_Action::DestroyItemOnFloor)
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(BT_Condition::EmptyValue),
|
||||
new BT::Action(BT_Action::SwapItem)
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(BT_Condition::InvIsNotFull),
|
||||
new BT::Action(BT_Action::PickUpItem)
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(BT_Condition::InvIsFull),
|
||||
new BT::Selector({
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::IsTypeOfItem, std::placeholders::_1, eItemType::FOOD)),
|
||||
new BT::Action(BT_Action::CheckItem)
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::IsTypeOfItem, std::placeholders::_1, eItemType::MEDKIT)),
|
||||
new BT::Action(BT_Action::CheckItem)
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::IsTypeOfItem, std::placeholders::_1, eItemType::SHOTGUN)),
|
||||
new BT::Action(BT_Action::CheckItem)
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::IsTypeOfItem, std::placeholders::_1, eItemType::PISTOL)),
|
||||
new BT::Action(BT_Action::CheckItem)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
BT::Selector* HouseHandling() {
|
||||
constexpr float maxTravelDistance{ 100.f };
|
||||
constexpr int searchRadius{ 300 };
|
||||
constexpr int searchDegree{ 45 }; //TODO
|
||||
constexpr float InsideOffset{ 5.f };
|
||||
|
||||
const std::string BeforeLeavingTimer{ "BeforeLeaving" };
|
||||
constexpr bool BeforeLeavingDoOnce{ true };
|
||||
|
||||
return
|
||||
new BT::Selector({
|
||||
new BT::PartialSequence({
|
||||
new BT::Conditional(BT_Condition::InsideTargetHouse),
|
||||
new BT::Action(BT_Action::SetExpireDate),
|
||||
new BT::Action(std::bind(BT_Action::SetTimer, std::placeholders::_1, BeforeLeavingTimer, BeforeLeavingDoOnce)),
|
||||
new BT::Selector({
|
||||
new BT::PartialSequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::CheckTimer, std::placeholders::_1, BeforeLeavingTimer, BeforeLeavingDoOnce)),
|
||||
new BT::Selector({
|
||||
new BT::PartialSequence({
|
||||
new BT::Conditional(BT_Condition::NewHouse),
|
||||
new BT::Action(std::bind(BT_Action::GetHouseAsTarget, std::placeholders::_1, maxTravelDistance)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget),
|
||||
}),
|
||||
new BT::PartialSequence({
|
||||
new BT::Conditional(BT_Condition::ReExploreHouse),
|
||||
new BT::Action(std::bind(BT_Action::GetHouseAsTarget, std::placeholders::_1, maxTravelDistance)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget),
|
||||
}),
|
||||
new BT::PartialSequence({
|
||||
new BT::Action(std::bind(BT_Action::TryFindHouse, std::placeholders::_1, searchRadius, searchDegree)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget)
|
||||
})
|
||||
}),
|
||||
}),
|
||||
new BT::PartialSequence({
|
||||
new BT::Action(std::bind(BT_Action::GetInsideTarget, std::placeholders::_1, InsideOffset)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget)
|
||||
}),
|
||||
})
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(BT_Condition::SeeHouse),
|
||||
new BT::Action(BT_Action::CheckHouses)
|
||||
}),
|
||||
new BT::Selector({
|
||||
new BT::PartialSequence({
|
||||
new BT::Conditional(BT_Condition::NewHouse),
|
||||
new BT::Action(std::bind(BT_Action::GetHouseAsTarget, std::placeholders::_1, maxTravelDistance)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget),
|
||||
}),
|
||||
new BT::PartialSequence({
|
||||
new BT::Conditional(BT_Condition::ReExploreHouse),
|
||||
new BT::Action(std::bind(BT_Action::GetHouseAsTarget, std::placeholders::_1, maxTravelDistance)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget),
|
||||
})
|
||||
}),
|
||||
new BT::PartialSequence({
|
||||
new BT::Action(std::bind(BT_Action::TryFindHouse, std::placeholders::_1, searchRadius, searchDegree)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget)
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
17
project/BigThink.h
Normal file
17
project/BigThink.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
namespace BT
|
||||
{
|
||||
class PartialSequence;
|
||||
class Sequence;
|
||||
class Selector;
|
||||
}
|
||||
|
||||
namespace BigThink
|
||||
{
|
||||
BT::Sequence* PurgeZoneHandling();
|
||||
BT::Selector* ItemHandling();
|
||||
BT::PartialSequence* PickUpHandling();
|
||||
BT::Selector* HouseHandling();
|
||||
}
|
||||
@@ -3,7 +3,17 @@
|
||||
# ADD NEW .cpp FILES HERE
|
||||
add_library(Exam_Plugin SHARED
|
||||
"stdafx.cpp"
|
||||
"SurvivalAgentPlugin.cpp" "BehaviourTree.cpp" "BehaviourTree.h" "BlackBoard.h" "Thinker.h" "Thinker.cpp" "Behaviour.h" "Behaviour.cpp")
|
||||
"SurvivalAgentPlugin.cpp"
|
||||
"BehaviourTree.cpp"
|
||||
"BehaviourTree.h"
|
||||
"BlackBoard.h"
|
||||
"Thinker.h"
|
||||
"Thinker.cpp"
|
||||
"Behaviour.h"
|
||||
"Behaviour.cpp"
|
||||
"BigThink.h"
|
||||
"BigThink.cpp"
|
||||
)
|
||||
|
||||
target_link_libraries(Exam_Plugin PUBLIC ${EXAM_LIB_DEBUG})
|
||||
target_include_directories(Exam_Plugin PUBLIC ${EXAM_INCLUDE_DIR})
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "stdafx.h"
|
||||
#include "SurvivalAgentPlugin.h"
|
||||
#include "BehaviourTree.h"
|
||||
#include "IExamInterface.h"
|
||||
#include "Blackboard.h"
|
||||
#include "BehaviourTree.h"
|
||||
#include "Behaviour.h"
|
||||
#include "Thinker.h"
|
||||
#include "BigThink.h"
|
||||
|
||||
//Called only once, during initialization
|
||||
void SurvivalAgentPlugin::Initialize(IBaseInterface* pInterface, PluginInfo& info)
|
||||
@@ -18,34 +19,61 @@ void SurvivalAgentPlugin::Initialize(IBaseInterface* pInterface, PluginInfo& inf
|
||||
info.Student_Class = "2DAE11";
|
||||
info.LB_Password = "ILikeCuteCats!";//Don't use a real password! This is only to prevent other students from overwriting your highscore!
|
||||
|
||||
Blackboard* blackboard = CreateBlackboard();
|
||||
m_BehaviourTree = new BT::BehaviorTree(blackboard,
|
||||
m_Thinker = new Thinker();
|
||||
|
||||
constexpr float closeRadius{ 50.f };
|
||||
const float farRadius{ m_pInterface->World_GetInfo().Dimensions.x };
|
||||
|
||||
const std::string searchTimer{ "Search" };
|
||||
|
||||
Blackboard* blackboardPtr{ CreateBlackboard() };
|
||||
m_BehaviourTree = new BT::BehaviorTree(blackboardPtr,
|
||||
new BT::Selector({
|
||||
new BT::PartialSequence({
|
||||
new BT::Action(BT_Action::FindAHouse),
|
||||
new BT::Action(BT_Action::GoToTarget)
|
||||
})
|
||||
})
|
||||
);
|
||||
BigThink::PurgeZoneHandling(),
|
||||
BigThink::ItemHandling(),
|
||||
BigThink::PickUpHandling(),
|
||||
BigThink::HouseHandling()
|
||||
}));
|
||||
|
||||
|
||||
}
|
||||
|
||||
Blackboard* SurvivalAgentPlugin::CreateBlackboard() {
|
||||
Blackboard* blackboard = new Blackboard();
|
||||
blackboard->AddData("Interface", m_pInterface);
|
||||
blackboard->AddData("Steering", SteeringPlugin_Output{});
|
||||
blackboard->AddData("Target", m_Target);
|
||||
return blackboard;
|
||||
|
||||
Blackboard* blackboardPtr = new Blackboard();
|
||||
|
||||
blackboardPtr->AddData("Brain", m_Thinker);
|
||||
blackboardPtr->AddData("Interface", m_pInterface);
|
||||
blackboardPtr->AddData("Steering", SteeringPlugin_Output{});
|
||||
blackboardPtr->AddData("Target", m_Target);
|
||||
blackboardPtr->AddData("Spin", false);
|
||||
blackboardPtr->AddData("FailSafe", std::chrono::steady_clock::time_point{});
|
||||
blackboardPtr->AddData("MaxFailSafe", 2.f);
|
||||
blackboardPtr->AddData("FailSafeDoOnce", false);
|
||||
|
||||
blackboardPtr->AddData("TargetItem", ItemInfo{});
|
||||
blackboardPtr->AddData("NextFreeSlot", 0);
|
||||
|
||||
blackboardPtr->AddData("TargetHouse", HouseInfo{});
|
||||
blackboardPtr->AddData("TimerBeforeLeaving", std::chrono::steady_clock::time_point{});
|
||||
blackboardPtr->AddData("TimerBeforeLeavingDoOnce", false);
|
||||
blackboardPtr->AddData("MaxTimeBeforeLeaving", 5.f);
|
||||
|
||||
return blackboardPtr;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SurvivalAgentPlugin::UpdateBlackboard(const SteeringPlugin_Output& steering) {
|
||||
Blackboard* blackboard{ m_BehaviourTree->GetBlackboard() };
|
||||
|
||||
//blackboard->ChangeData("playerPos", m_pInterface->Agent_GetInfo().Position);
|
||||
blackboard->ChangeData("Steering", steering);
|
||||
blackboard->GetData("Target", m_Target);
|
||||
}
|
||||
|
||||
SurvivalAgentPlugin::~SurvivalAgentPlugin() {
|
||||
SAFE_DELETE(m_BehaviourTree);
|
||||
SAFE_DELETE(m_Thinker);
|
||||
}
|
||||
|
||||
//Called only once
|
||||
@@ -80,8 +108,6 @@ void SurvivalAgentPlugin::InitGameDebugParams(GameDebugParams& params)
|
||||
params.Seed = 0; //-1 = don't set seed. Any other number = fixed seed //TIP: use Seed = int(time(nullptr)) for pure randomness
|
||||
}
|
||||
|
||||
//Only Active in DEBUG Mode
|
||||
//(=Use only for Debug Purposes)
|
||||
void SurvivalAgentPlugin::Update_Debug(float dt)
|
||||
{
|
||||
//Demo Event Code
|
||||
@@ -151,21 +177,32 @@ void SurvivalAgentPlugin::Update_Debug(float dt)
|
||||
SteeringPlugin_Output SurvivalAgentPlugin::UpdateSteering(float dt)
|
||||
{
|
||||
auto steering = SteeringPlugin_Output();
|
||||
|
||||
//Use the Interface (IAssignmentInterface) to 'interface' with the AI_Framework
|
||||
auto agentInfo = m_pInterface->Agent_GetInfo();
|
||||
bool spin{};
|
||||
|
||||
UpdateBlackboard(steering);
|
||||
|
||||
m_BehaviourTree->Update();
|
||||
|
||||
m_BehaviourTree->GetBlackboard()->GetData("Steering", steering);
|
||||
m_BehaviourTree->GetBlackboard()->GetData("Spin", spin);
|
||||
|
||||
steering.AngularVelocity = m_AngSpeed;
|
||||
steering.AutoOrient = false;
|
||||
if (spin) {
|
||||
steering.AutoOrient = false;
|
||||
steering.AngularVelocity = 3.14f;
|
||||
}
|
||||
|
||||
if (m_GrabItem) {
|
||||
ItemInfo item;
|
||||
|
||||
m_BehaviourTree->GetBlackboard()->GetData("TargetItem", item);
|
||||
|
||||
if (m_pInterface->GrabItem(item)) {
|
||||
m_pInterface->Inventory_AddItem(m_InventorySlot, item);
|
||||
}
|
||||
}
|
||||
|
||||
return steering;
|
||||
|
||||
}
|
||||
|
||||
//This function should only be used for rendering debug elements
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
#include "IExamPlugin.h"
|
||||
#include "Exam_HelperStructs.h"
|
||||
|
||||
namespace BT{
|
||||
namespace BT
|
||||
{
|
||||
class BehaviorTree;
|
||||
}
|
||||
|
||||
class IBaseInterface;
|
||||
class IExamInterface;
|
||||
class Blackboard;
|
||||
class Thinker;
|
||||
|
||||
class SurvivalAgentPlugin final :public IExamPlugin
|
||||
|
||||
class SurvivalAgentPlugin final : public IExamPlugin
|
||||
{
|
||||
public:
|
||||
SurvivalAgentPlugin() = default;
|
||||
@@ -43,6 +46,7 @@ private:
|
||||
Blackboard* CreateBlackboard();
|
||||
void UpdateBlackboard(const SteeringPlugin_Output& steering);
|
||||
BT::BehaviorTree* m_BehaviourTree = nullptr;
|
||||
Thinker* m_Thinker = nullptr;
|
||||
};
|
||||
|
||||
//ENTRY
|
||||
|
||||
@@ -2,20 +2,191 @@
|
||||
#include "Thinker.h"
|
||||
#include <algorithm>
|
||||
|
||||
void Thinker::CheckIfNewHouse(const HouseInfo& newHouse) {
|
||||
auto it = std::find_if(m_HousesMemory.begin(), m_HousesMemory.end(),
|
||||
[&newHouse](const HouseMemory& house) {
|
||||
return house.info.Center == newHouse.Center;
|
||||
std::vector<Thinker::ItemMemory>::iterator Thinker::FindLeastValueItem(const eItemType& itemType) {
|
||||
std::ranges::partition(m_ItemMemory,
|
||||
[itemType](const ItemMemory& memory)->bool { return memory.ItemInfo.Type == itemType; });
|
||||
|
||||
const auto minItem =
|
||||
std::ranges::min_element(m_ItemMemory,
|
||||
[itemType](const ItemMemory& lhs, const ItemMemory& rhs)->bool {
|
||||
if (lhs.ItemInfo.Type == itemType && rhs.ItemInfo.Type == itemType) {
|
||||
return lhs.ItemInfo.Value < rhs.ItemInfo.Value;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (it != m_HousesMemory.end()) {
|
||||
//it->lastSaw = std::chrono::steady_clock::now();
|
||||
//it->newHouse = false;
|
||||
return;
|
||||
return minItem;
|
||||
}
|
||||
|
||||
bool Thinker::IsInvNotFull() const {
|
||||
return m_ItemMemory.capacity() < m_MaxStorageSlots;
|
||||
}
|
||||
|
||||
bool Thinker::IsItemInInv(const eItemType& itemType) {
|
||||
return std::any_of(std::begin(m_ItemMemory), std::end(m_ItemMemory),
|
||||
[itemType](const ItemMemory& memory)->bool { return memory.ItemInfo.Type == itemType; });
|
||||
}
|
||||
|
||||
bool Thinker::EmptyValue() {
|
||||
return std::any_of(std::begin(m_ItemMemory), std::end(m_ItemMemory),
|
||||
[](const ItemMemory& memory)->bool { return memory.ItemInfo.Value <= 0; });
|
||||
}
|
||||
|
||||
int Thinker::FindEmptyValue(const ItemInfo& item) {
|
||||
const auto foundItem = std::find_if(std::begin(m_ItemMemory), std::end(m_ItemMemory),
|
||||
[item](const ItemMemory& memory)->bool { return memory.ItemInfo.Type == item.Type; });
|
||||
if (foundItem != std::end(m_ItemMemory)) {
|
||||
return foundItem->invIndex;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Thinker::AddItemToMemory(const ItemInfo& item) {
|
||||
if (m_ItemMemory.capacity() >= m_MaxStorageSlots)
|
||||
return -1;
|
||||
ItemMemory newItem{};
|
||||
newItem.ItemInfo = item;
|
||||
newItem.invIndex = static_cast<int>(m_ItemMemory.size());
|
||||
m_ItemMemory.push_back(newItem);
|
||||
return newItem.invIndex;
|
||||
}
|
||||
|
||||
int Thinker::CheckItem(const ItemInfo& item) {
|
||||
if (std::ranges::any_of(m_ItemMemory,
|
||||
[item](const ItemMemory& memory)->bool { return memory.ItemInfo.Type == item.Type; })) {
|
||||
const auto minItem{ FindLeastValueItem(item.Type) };
|
||||
|
||||
if (minItem->ItemInfo.Value <= item.Value) {
|
||||
minItem->ItemInfo = item;
|
||||
return minItem->invIndex;
|
||||
}
|
||||
else {
|
||||
return m_MaxStorageSlots - 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::ranges::sort(m_ItemMemory,
|
||||
[](const ItemMemory& lhs, const ItemMemory& rhs)->bool { return lhs.ItemInfo.Type < rhs.ItemInfo.Type; });
|
||||
|
||||
const auto duplicate =
|
||||
std::ranges::adjacent_find(m_ItemMemory,
|
||||
[](const ItemMemory& lhs, const ItemMemory& rhs)->bool { return lhs.ItemInfo.Type == rhs.ItemInfo.Type; });
|
||||
|
||||
const auto minItem =
|
||||
std::min_element(duplicate, duplicate + 1,
|
||||
[](const ItemMemory& lhs, const ItemMemory& rhs)->bool { return lhs.ItemInfo.Value < rhs.ItemInfo.Value; });
|
||||
|
||||
minItem->ItemInfo = item;
|
||||
return minItem->invIndex;
|
||||
}
|
||||
}
|
||||
|
||||
bool Thinker::CheckIfTargetIsInside(const HouseInfo& targetHouse, Elite::Vector2 playerPos) {
|
||||
const float houseOffset{ 5.f };
|
||||
const Elite::Vector2 houseCenter{ targetHouse.Center };
|
||||
return (playerPos.x >= houseCenter.x - houseOffset && playerPos.x <= houseCenter.x + houseOffset &&
|
||||
playerPos.y >= houseCenter.y - houseOffset && playerPos.y <= houseCenter.y + houseOffset);
|
||||
}
|
||||
|
||||
bool Thinker::CheckIfTargetIsExplored(Elite::Vector2 target, float offset) const {
|
||||
return std::any_of(std::begin(m_HousesMemory), std::end(m_HousesMemory),
|
||||
[target, offset](const HouseMemory& memory)->bool {
|
||||
return memory.info.Center.x >= target.x - offset && memory.info.Center.x <= target.x + offset &&
|
||||
memory.info.Center.y >= target.y - offset && memory.info.Center.y <= target.y + offset;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool Thinker::NewHouseToExplore() {
|
||||
if (m_HousesMemory.capacity() != 0) {
|
||||
if (std::ranges::any_of(m_HousesMemory,
|
||||
[](const HouseMemory& houseMemory)->bool { return houseMemory.newHouse == true; })) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Thinker::HouseToReExplore() {
|
||||
if (m_HousesMemory.capacity() != 0) {
|
||||
const std::chrono::steady_clock::time_point currentTime{ std::chrono::steady_clock::now() };
|
||||
|
||||
if (std::ranges::any_of(m_HousesMemory,
|
||||
[=](const HouseMemory& houseMemory)->bool {
|
||||
const std::chrono::duration<float> elapsedSec{ currentTime - houseMemory.lastSaw };
|
||||
return elapsedSec.count() >= m_MaxWaitTimer;
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Thinker::SetTargetHouseExpireDate(const HouseInfo& targetHouse) {
|
||||
assert(m_HousesMemory.capacity() != 0);
|
||||
|
||||
const auto foundHouse = FindHouseInMemory(targetHouse);
|
||||
|
||||
foundHouse->lastSaw = std::chrono::steady_clock::now();
|
||||
foundHouse->newHouse = false;
|
||||
}
|
||||
|
||||
HouseInfo Thinker::CheckHouseValidTarget(Elite::Vector2 playerPos, float maxRadius) const {
|
||||
HouseInfo targetHouse{};
|
||||
float closestHouse{ FLT_MAX };
|
||||
|
||||
for (auto house : m_HousesMemory) {
|
||||
const float houseDistance{ house.info.Center.DistanceSquared(playerPos) };
|
||||
|
||||
if (houseDistance > maxRadius * maxRadius)
|
||||
continue;
|
||||
|
||||
if (closestHouse < houseDistance)
|
||||
continue;
|
||||
|
||||
if (house.newHouse == true) {
|
||||
targetHouse = house.info;
|
||||
closestHouse = houseDistance;
|
||||
}
|
||||
else {
|
||||
const std::chrono::steady_clock::time_point currentTime{ std::chrono::steady_clock::now() };
|
||||
const std::chrono::duration<float> elapsedSec{ currentTime - house.lastSaw };
|
||||
|
||||
if (elapsedSec.count() < m_MaxWaitTimer)
|
||||
continue;
|
||||
|
||||
targetHouse = house.info;
|
||||
closestHouse = houseDistance;
|
||||
}
|
||||
}
|
||||
|
||||
HouseMemory houseToMemory{};
|
||||
houseToMemory.info = newHouse;
|
||||
|
||||
m_HousesMemory.push_back(houseToMemory);
|
||||
return targetHouse;
|
||||
}
|
||||
|
||||
bool Thinker::CheckHousesForMemory(const std::vector<HouseInfo>& FOVHouses) {
|
||||
bool result{};
|
||||
|
||||
for (auto& newHouse : FOVHouses) {
|
||||
if (m_HousesMemory.capacity() != 0) {
|
||||
if (std::ranges::any_of(m_HousesMemory,
|
||||
[newHouse](const HouseMemory& houseMemory)->bool { return houseMemory.info.Center == newHouse.Center; })) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
HouseMemory houseToMemory{};
|
||||
houseToMemory.info = newHouse;
|
||||
|
||||
m_HousesMemory.push_back(houseToMemory);
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Thinker::HouseMemory>::iterator Thinker::FindHouseInMemory(const HouseInfo& targetHouse) {
|
||||
return
|
||||
std::ranges::find_if(m_HousesMemory,
|
||||
[targetHouse](const HouseMemory& houseMemory)->bool { return houseMemory.info.Center == targetHouse.Center; });
|
||||
}
|
||||
|
||||
@@ -11,6 +11,13 @@ public:
|
||||
HouseInfo info;
|
||||
std::chrono::steady_clock::time_point lastSaw;
|
||||
};
|
||||
|
||||
struct ItemMemory
|
||||
{
|
||||
ItemInfo ItemInfo;
|
||||
int invIndex;
|
||||
};
|
||||
|
||||
Thinker() = default;
|
||||
|
||||
~Thinker() = default;
|
||||
@@ -19,7 +26,35 @@ public:
|
||||
Thinker(Thinker&&) = default;
|
||||
Thinker& operator=(Thinker&&) = default;
|
||||
|
||||
void CheckIfNewHouse(const HouseInfo& newHouse);
|
||||
/*bool NewHouseToExplore();
|
||||
bool HouseToReExplore();
|
||||
void SetTargetHouseExpireDate(const HouseInfo& targetHouse);
|
||||
HouseInfo CheckHouseValidTarget(Elite::Vector2 playerPos, float maxRadius) const;
|
||||
bool CheckHousesForMemory(const std::vector<HouseInfo>& FOVHouses);*/
|
||||
|
||||
std::vector<ItemMemory>::iterator FindLeastValueItem(const eItemType& itemType);
|
||||
bool IsInvNotFull() const;
|
||||
bool IsItemInInv(const eItemType& itemType);
|
||||
bool EmptyValue();
|
||||
int FindEmptyValue(const ItemInfo& item);
|
||||
int AddItemToMemory(const ItemInfo& item);
|
||||
int CheckItem(const ItemInfo& item);
|
||||
|
||||
bool CheckIfTargetIsInside(const HouseInfo& targetHouse, Elite::Vector2 playerPos);
|
||||
bool CheckIfTargetIsExplored(Elite::Vector2 target, float offset) const;
|
||||
bool NewHouseToExplore();
|
||||
bool HouseToReExplore();
|
||||
void SetTargetHouseExpireDate(const HouseInfo& targetHouse);
|
||||
HouseInfo CheckHouseValidTarget(Elite::Vector2 playerPos, float maxRadius) const;
|
||||
bool CheckHousesForMemory(const std::vector<HouseInfo>& FOVHouses);
|
||||
|
||||
|
||||
private:
|
||||
std::vector<HouseMemory> m_HousesMemory{};
|
||||
const float m_MaxWaitTimer{ 360.f };
|
||||
|
||||
std::vector<ItemMemory> m_ItemMemory{};
|
||||
const size_t m_MaxStorageSlots{ 5 };
|
||||
|
||||
std::vector<HouseMemory>::iterator FindHouseInMemory(const HouseInfo& targetHouse);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user