Compare commits
2 Commits
1d2ca4f9ca
...
f9a11385fe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9a11385fe | ||
|
|
1104b12ba8 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -754,8 +754,8 @@ Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [267 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [194 FPS]]
|
||||
@@ -869,8 +869,8 @@ Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [33 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [315 FPS]]
|
||||
@@ -934,8 +934,8 @@ Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [314 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [280 FPS]]
|
||||
@@ -964,13 +964,13 @@ Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [344 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [329 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [317 FPS]]
|
||||
@@ -1029,8 +1029,8 @@ Size=180,150
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [393 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [348 FPS]]
|
||||
@@ -1144,8 +1144,8 @@ Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [336 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [323 FPS]]
|
||||
@@ -1154,8 +1154,8 @@ Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [310 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [296 FPS]]
|
||||
@@ -1174,8 +1174,8 @@ Size=240,431
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [258 FPS]]
|
||||
Pos=651,10
|
||||
Size=240,431
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [192 FPS]]
|
||||
@@ -2123,3 +2123,583 @@ Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [735 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [30 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [28 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [26 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [24 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [777 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [31 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [776 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [774 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [710 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [769 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [763 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [748 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [775 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [752 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [591 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [571 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [542 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [515 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [485 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [427 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [403 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [381 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [345 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [302 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [233 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [690 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [547 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [461 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [408 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [386 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [366 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [889 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [681 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [652 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [618 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [568 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [492 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [411 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [850 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [659 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [634 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [598 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [526 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [490 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [457 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [407 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [332 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [922 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [677 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [575 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [536 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [500 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [467 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [414 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [371 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [353 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [308 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [295 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [849 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [628 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [602 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [544 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [483 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [313 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [828 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [642 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [617 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [585 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [546 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [520 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [428 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [709 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [539 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [486 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [464 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [722 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [563 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [545 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [516 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [482 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [452 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [702 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [552 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [535 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [509 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [481 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [451 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [424 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [361 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [564 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [532 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [505 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [480 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [967 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [700 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [668 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [622 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [504 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [442 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [417 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [394 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [373 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [354 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [840 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [631 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [607 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [540 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [502 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [470 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [931 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [664 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [639 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [543 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [750 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
[WORLD INFO [517 FPS]]
|
||||
Pos=710,10
|
||||
Size=240,520
|
||||
Collapsed=0
|
||||
|
||||
|
||||
BIN
_DEMO_RELEASE/GPP_Plugin.dll
Normal file
BIN
_DEMO_RELEASE/GPP_Plugin.dll
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
# ./lib CMakeLists.txt
|
||||
|
||||
set(EXAM_LIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/GPP_PluginBase_d.lib" PARENT_SCOPE)
|
||||
#set(EXAM_LIB_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/GPP_PluginBase_d.lib" PARENT_SCOPE)
|
||||
set(EXAM_LIB_DEBUG
|
||||
"$<IF:$<CONFIG:Debug>,${CMAKE_CURRENT_SOURCE_DIR}/GPP_PluginBase_d.lib,${CMAKE_CURRENT_SOURCE_DIR}/GPP_PluginBase.lib>"
|
||||
PARENT_SCOPE)
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#define TO_RAD(i) i * (M_PI / 180)
|
||||
|
||||
#define PRINT_FUNCTION_NAME() std::cout << __func__ << std::endl
|
||||
|
||||
static int randNumRange(int minRange, int maxRange) {
|
||||
std::random_device rd;
|
||||
std::mt19937 seed(rd());
|
||||
@@ -17,6 +19,7 @@ static int randNumRange(int minRange, int maxRange) {
|
||||
namespace BT_Action
|
||||
{
|
||||
BT::State SetTimer(Blackboard* blackboardPtr, const std::string& timerName, bool doOnce) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
bool didOnce{};
|
||||
blackboardPtr->GetData("Timer" + timerName + "DoOnce", didOnce);
|
||||
|
||||
@@ -32,67 +35,73 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State UnlockTimer(Blackboard* blackboardPtr, const std::string& timerName) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
blackboardPtr->ChangeData("TimerLock" + timerName, false);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State LockTimer(Blackboard* blackboardPtr, const std::string& timerName) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
blackboardPtr->ChangeData("TimerLock" + timerName, true);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State GoToTarget(Blackboard* blackboardPtr) {
|
||||
//PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
Elite::Vector2 target{};
|
||||
SteeringPlugin_Output steering{};
|
||||
|
||||
std::chrono::steady_clock::time_point timer{};
|
||||
float maxTime{};
|
||||
float maxTime{ 5.0f }; // Default value if not set
|
||||
bool doOnce{};
|
||||
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
blackboardPtr->GetData("Target", target);
|
||||
blackboardPtr->GetData("Steering", steering);
|
||||
|
||||
blackboardPtr->GetData("FailSafe", timer);
|
||||
blackboardPtr->GetData("MaxFailSafe", maxTime);
|
||||
blackboardPtr->GetData("MaxFailSafe", maxTime); // Make sure this is set before calling
|
||||
blackboardPtr->GetData("FailSafeDoOnce", doOnce);
|
||||
|
||||
// Initialize timer if not done yet
|
||||
if (!doOnce) {
|
||||
blackboardPtr->ChangeData("FailSafe", std::chrono::steady_clock::now());
|
||||
timer = std::chrono::steady_clock::now();
|
||||
blackboardPtr->ChangeData("FailSafe", timer);
|
||||
blackboardPtr->ChangeData("FailSafeDoOnce", true);
|
||||
}
|
||||
|
||||
const auto agentInfo = interfacePtr->Agent_GetInfo();
|
||||
|
||||
const auto nextTargetPos = interfacePtr->NavMesh_GetClosestPathPoint(target);
|
||||
|
||||
steering.LinearVelocity = nextTargetPos - agentInfo.Position;
|
||||
steering.LinearVelocity.Normalize();
|
||||
steering.LinearVelocity *= agentInfo.MaxLinearSpeed * 100;
|
||||
|
||||
// Check success conditions first
|
||||
const std::chrono::steady_clock::time_point currentTime{ std::chrono::steady_clock::now() };
|
||||
const std::chrono::duration<float> elapsedSec{ currentTime - timer };
|
||||
|
||||
// Check if we've reached the target
|
||||
if (Distance(target, agentInfo.Position) < 3.f) {
|
||||
blackboardPtr->ChangeData("FailSafeDoOnce", false);
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
// Check if failsafe timeout has been reached
|
||||
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;
|
||||
}
|
||||
|
||||
// Calculate steering if we're still running
|
||||
steering.LinearVelocity = nextTargetPos - agentInfo.Position;
|
||||
steering.LinearVelocity.Normalize();
|
||||
steering.LinearVelocity *= agentInfo.MaxLinearSpeed;
|
||||
blackboardPtr->ChangeData("Steering", steering);
|
||||
|
||||
return BT::State::Running;
|
||||
}
|
||||
|
||||
BT::State EnableSpin(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
SteeringPlugin_Output steering{};
|
||||
|
||||
@@ -109,6 +118,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State DisableSpin(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
blackboardPtr->ChangeData("Spin", false);
|
||||
|
||||
return BT::State::Success;
|
||||
@@ -116,6 +126,7 @@ namespace BT_Action
|
||||
|
||||
|
||||
BT::State FindClosestEdge(Blackboard* blackboardPtr, int degree) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
@@ -150,6 +161,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State SetZombieTarget(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
@@ -176,6 +188,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State AvoidingZombie(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
SteeringPlugin_Output steering{};
|
||||
|
||||
@@ -201,6 +214,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State RotateToZombie(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
EnemyInfo zombieInfo{};
|
||||
SteeringPlugin_Output steering{};
|
||||
@@ -222,6 +236,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State ReadyToShoot(Blackboard* blackboardPtr, float minAngleDiff) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
float angleDiff{};
|
||||
|
||||
blackboardPtr->GetData("angleDiff", angleDiff);
|
||||
@@ -230,6 +245,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State Shoot(Blackboard* blackboardPtr, eItemType type) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
|
||||
@@ -250,6 +266,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State SetItemAsTarget(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
@@ -277,6 +294,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State DestroyItemOnFloor(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
ItemInfo targetItem{};
|
||||
|
||||
@@ -290,6 +308,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State PickUpItem(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
ItemInfo targetItem{};
|
||||
@@ -312,6 +331,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State SwapItem(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
ItemInfo targetItem{};
|
||||
@@ -332,6 +352,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State CheckItem(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
ItemInfo targetItem{};
|
||||
@@ -372,6 +393,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State UseItem(Blackboard* blackboardPtr, eItemType type) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
|
||||
@@ -392,6 +414,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State TryFindHouse(Blackboard* blackboardPtr, float searchRadius, int degree) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
|
||||
@@ -416,8 +439,9 @@ namespace BT_Action
|
||||
const Elite::Vector2 target = interfacePtr->NavMesh_GetClosestPathPoint(pointOnCircle);
|
||||
|
||||
|
||||
if (target == Elite::Vector2(400, 400)) {
|
||||
std::cout << pointOnCircle << std::endl;
|
||||
const float worldDimensions{ interfacePtr->World_GetInfo().Dimensions.x / 2 };
|
||||
if (std::abs(target.x) >= worldDimensions || std::abs(target.y) >= worldDimensions) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pointOnCircle != target) {
|
||||
@@ -444,12 +468,17 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State FindRandomLocation(Blackboard* blackboardPtr, float randomRadius) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
const Elite::Vector2 playerPos{ interfacePtr->Agent_GetInfo().Position };
|
||||
Elite::Vector2 target = Elite::Vector2(playerPos.x + randNumRange(-randomRadius, randomRadius),
|
||||
playerPos.y + randNumRange(-randomRadius, randomRadius));
|
||||
|
||||
const float randomAngle = Elite::ToRadians(randNumRange(0.0f, 360.0f));
|
||||
|
||||
const Elite::Vector2 offset = Elite::Vector2{ cosf(randomAngle), sinf(randomAngle) } *randomRadius;
|
||||
|
||||
const Elite::Vector2 target = playerPos + offset;
|
||||
|
||||
blackboardPtr->ChangeData("Target", target);
|
||||
|
||||
@@ -457,6 +486,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State GetHouseAsTarget(Blackboard* blackboardPtr, float maxTravelDistance) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
|
||||
@@ -476,6 +506,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State CheckHouses(Blackboard* blackboardPtr) {
|
||||
//PRINT_FUNCTION_NAME();
|
||||
Thinker* thinkerPtr{};
|
||||
IExamInterface* interfacePtr{};
|
||||
|
||||
@@ -490,6 +521,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State SetExpireDate(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
Thinker* thinkerPtr{};
|
||||
HouseInfo targetHouse{};
|
||||
|
||||
@@ -502,6 +534,7 @@ namespace BT_Action
|
||||
}
|
||||
|
||||
BT::State GetInsideTarget(Blackboard* blackboardPtr, float offset) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
HouseInfo targetHouse{};
|
||||
blackboardPtr->GetData("TargetHouse", targetHouse);
|
||||
|
||||
@@ -546,6 +579,28 @@ namespace BT_Condition
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InPurgeZone(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
const Elite::Vector2 playerPos{ interfacePtr->Agent_GetInfo().Position };
|
||||
|
||||
for (const auto purgeZone : interfacePtr->GetPurgeZonesInFOV()) {
|
||||
const Elite::Vector2 purgeCenter{ purgeZone.Center };
|
||||
const float purgeRadius{ purgeZone.Radius };
|
||||
|
||||
const float x{ playerPos.x - purgeCenter.x };
|
||||
const float y{ playerPos.y - purgeCenter.y };
|
||||
|
||||
const float result{ x * x + y * y - purgeRadius * purgeRadius };
|
||||
|
||||
if (result <= 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SeeZombie(Blackboard* blackboardPtr) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
@@ -569,13 +624,6 @@ namespace BT_Condition
|
||||
return dist2 <= maxRange * maxRange;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -626,10 +674,6 @@ namespace BT_Condition
|
||||
Thinker* thinkerPtr{};
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
if (thinkerPtr->EmptyValue()) {
|
||||
std::cout << "empty item\n";
|
||||
}
|
||||
|
||||
return thinkerPtr->EmptyValue();
|
||||
}
|
||||
|
||||
@@ -672,4 +716,91 @@ namespace BT_Condition
|
||||
|
||||
return thinkerPtr->HouseToReExplore();
|
||||
}
|
||||
|
||||
bool CheckMovement(Blackboard* blackboardPtr, float timeout) {
|
||||
IExamInterface* interfacePtr{};
|
||||
blackboardPtr->GetData("Interface", interfacePtr);
|
||||
|
||||
// Get current position
|
||||
const Elite::Vector2 currentPosition = interfacePtr->Agent_GetInfo().Position;
|
||||
|
||||
// Get or initialize last position and timer from blackboard
|
||||
Elite::Vector2 lastPosition;
|
||||
std::chrono::steady_clock::time_point lastMovementTime;
|
||||
|
||||
// Try to get last position from blackboard, or initialize if not present
|
||||
if (!blackboardPtr->GetData("LastPosition", lastPosition)) {
|
||||
lastPosition = currentPosition;
|
||||
blackboardPtr->AddData("LastPosition", lastPosition);
|
||||
}
|
||||
|
||||
// Try to get last movement time from blackboard, or initialize if not present
|
||||
if (!blackboardPtr->GetData("LastMovementTime", lastMovementTime)) {
|
||||
lastMovementTime = std::chrono::steady_clock::now();
|
||||
blackboardPtr->AddData("LastMovementTime", lastMovementTime);
|
||||
}
|
||||
|
||||
// Check if we've moved significantly (more than a small threshold)
|
||||
const float movementThreshold = 0.5f; // Adjust this based on your game scale
|
||||
const float distanceMoved = currentPosition.DistanceSquared(lastPosition);
|
||||
|
||||
if (distanceMoved > movementThreshold * movementThreshold) {
|
||||
// We've moved significantly, update last position and time in blackboard
|
||||
blackboardPtr->ChangeData("LastPosition", currentPosition);
|
||||
blackboardPtr->ChangeData("LastMovementTime", std::chrono::steady_clock::now());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check how long we've been stuck
|
||||
const auto currentTime = std::chrono::steady_clock::now();
|
||||
const auto elapsedTime = std::chrono::duration_cast<std::chrono::seconds>(currentTime - lastMovementTime).count();
|
||||
|
||||
// Return true if we've been stuck for longer than the timeout
|
||||
return elapsedTime >= timeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace BT_Grid {
|
||||
BT::State UpdateExplorationGrid(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
IExamInterface* interfacePtr{};
|
||||
Thinker* thinkerPtr{};
|
||||
|
||||
if (!blackboardPtr->GetData("Interface", interfacePtr) || !blackboardPtr->GetData("Brain", thinkerPtr)) {
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
const AgentInfo agentInfo = interfacePtr->Agent_GetInfo();
|
||||
//Visible houses, enemies, items, and purge zones
|
||||
const std::vector<EnemyInfo>& enemiesInFOV = interfacePtr->GetEnemiesInFOV();
|
||||
const std::vector<ItemInfo>& itemsInFOV = interfacePtr->GetItemsInFOV();
|
||||
const std::vector<PurgeZoneInfo>& purgeZonesInFOV = interfacePtr->GetPurgeZonesInFOV();
|
||||
|
||||
|
||||
const std::vector<HouseInfo>& housesInFOV = interfacePtr->GetHousesInFOV();
|
||||
thinkerPtr->m_ExplorationGrid.Update(agentInfo, housesInFOV);
|
||||
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
BT::State FindUnexploredCell(Blackboard* blackboardPtr) {
|
||||
PRINT_FUNCTION_NAME();
|
||||
Thinker* thinkerPtr{};
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
IExamInterface* interfacePtr{};
|
||||
if (!blackboardPtr->GetData("Interface", interfacePtr)) {
|
||||
return BT::State::Failure;
|
||||
}
|
||||
|
||||
Elite::Vector2 playerPos = interfacePtr->Agent_GetInfo().Position;
|
||||
const Elite::Vector2 target{ thinkerPtr->m_ExplorationGrid.FindNearestUnexplored(playerPos)};
|
||||
if (target == Elite::Vector2{})
|
||||
return BT::State::Failure;
|
||||
blackboardPtr->ChangeData("Target", target);
|
||||
return BT::State::Success;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,12 @@ namespace BT
|
||||
|
||||
class Blackboard;
|
||||
|
||||
namespace BT_Grid {
|
||||
BT::State UpdateExplorationGrid(Blackboard* blackboardPtr);
|
||||
|
||||
BT::State FindUnexploredCell(Blackboard* blackboardPtr);
|
||||
}
|
||||
|
||||
namespace BT_Action
|
||||
{
|
||||
BT::State SetTimer(Blackboard* blackboardPtr, const std::string& timerName, bool doOnce);
|
||||
@@ -49,7 +55,7 @@ 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 InPurgeZone(Blackboard* blackboardPtr);
|
||||
|
||||
bool SeeZombie(Blackboard* blackboardPtr);
|
||||
bool HasWeapon(Blackboard* blackboardPtr);
|
||||
@@ -70,5 +76,7 @@ namespace BT_Condition
|
||||
bool NewHouse(Blackboard* blackboardPtr);
|
||||
bool ReExploreHouse(Blackboard* blackboardPtr);
|
||||
|
||||
bool CheckMovement(Blackboard* blackboardPtr, float timeout);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,24 @@ using namespace std::placeholders;
|
||||
|
||||
namespace BigThink
|
||||
{
|
||||
BT::Selector* ItemHandling() {
|
||||
constexpr float HpThreshold{ 2.f };
|
||||
|
||||
return
|
||||
new BT::Selector({
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::ItemInInv, _1, eItemType::MEDKIT)),
|
||||
new BT::Conditional(std::bind(BT_Condition::HpUnderThreshold, _1, HpThreshold)),
|
||||
new BT::Action(std::bind(BT_Action::UseItem, _1, eItemType::MEDKIT))
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::ItemInInv, _1, eItemType::FOOD)),
|
||||
new BT::Conditional(BT_Condition::CheckMinNeededEnergy),
|
||||
new BT::Action(std::bind(BT_Action::UseItem, _1, eItemType::FOOD))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
BT::Sequence* ZombieHandling() {
|
||||
constexpr float minShotgunAngleDiff{ .2f };
|
||||
constexpr float minPistolAngleDiff{ .1f };
|
||||
@@ -56,30 +74,12 @@ namespace BigThink
|
||||
constexpr int searchDegree{ 5 };
|
||||
return
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(BT_Condition::SeePurgeZone),
|
||||
new BT::Conditional(BT_Condition::InPurgeZone),
|
||||
new BT::Action(std::bind(BT_Action::FindClosestEdge, _1, searchDegree)),
|
||||
new BT::Action(BT_Action::GoToTarget)
|
||||
});
|
||||
}
|
||||
|
||||
BT::Selector* ItemHandling() {
|
||||
constexpr float HpThreshold{ 0.f };
|
||||
|
||||
return
|
||||
new BT::Selector({
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::ItemInInv, _1, eItemType::MEDKIT)),
|
||||
new BT::Conditional(std::bind(BT_Condition::HpUnderThreshold, _1, HpThreshold)),
|
||||
new BT::Action(std::bind(BT_Action::UseItem, _1, eItemType::MEDKIT))
|
||||
}),
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::ItemInInv, _1, eItemType::FOOD)),
|
||||
new BT::Conditional(BT_Condition::CheckMinNeededEnergy),
|
||||
new BT::Action(std::bind(BT_Action::UseItem, _1, eItemType::FOOD))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
BT::PartialSequence* PickUpHandling() {
|
||||
return
|
||||
new BT::PartialSequence({
|
||||
@@ -131,16 +131,29 @@ namespace BigThink
|
||||
constexpr int randomRadius{ 50 };
|
||||
constexpr int searchDegree{ 5 };
|
||||
constexpr float InsideOffset{ 5.f };
|
||||
constexpr float gridCellSize{ 50.f };
|
||||
|
||||
const std::string BeforeLeavingTimer{ "BeforeLeaving" };
|
||||
constexpr bool BeforeLeavingDoOnce{ true };
|
||||
constexpr bool BeforeLeavingDoOnce{ false };
|
||||
|
||||
return
|
||||
new BT::Selector({
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(BT_Condition::SeeHouse),
|
||||
new BT::Action(BT_Action::CheckHouses)
|
||||
}),
|
||||
const std::string NoHouseTimer{ "NoHouse" };
|
||||
constexpr float noHouseTimeout = 5.0f;
|
||||
constexpr bool NoHouseDoOnce{ false };
|
||||
|
||||
const std::string HouseExploreTimer{ "HouseExplore" };
|
||||
constexpr float houseExploreTimeout = 2.0f;
|
||||
constexpr bool HouseExploreDoOnce{ false };
|
||||
|
||||
return new BT::Selector({
|
||||
// [1] House visibility update
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(BT_Condition::SeeHouse),
|
||||
new BT::Action(BT_Action::CheckHouses),
|
||||
//new BT::Action(BT_Grid::UpdateExplorationGrid),
|
||||
new BT::Action(std::bind(BT_Action::SetTimer, _1, NoHouseTimer, NoHouseDoOnce))
|
||||
}),
|
||||
|
||||
// [2] Inside house logic
|
||||
new BT::PartialSequence({
|
||||
new BT::Conditional(BT_Condition::InsideTargetHouse),
|
||||
new BT::Action(BT_Action::SetExpireDate),
|
||||
@@ -180,6 +193,8 @@ namespace BigThink
|
||||
}),
|
||||
})
|
||||
}),
|
||||
|
||||
// [3] Outside house behavior
|
||||
new BT::Selector({
|
||||
new BT::PartialSequence({
|
||||
new BT::Conditional(BT_Condition::NewHouse),
|
||||
@@ -188,22 +203,48 @@ namespace BigThink
|
||||
new BT::Action(BT_Action::GoToTarget),
|
||||
}),
|
||||
new BT::PartialSequence({
|
||||
new BT::Action(std::bind(BT_Action::TryFindHouse, _1, searchRadius, searchDegree)),
|
||||
new BT::Action(BT_Grid::FindUnexploredCell),
|
||||
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, _1, maxTravelDistance)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget),
|
||||
})
|
||||
new BT::Conditional(std::bind(BT_Condition::CheckTimer, _1, NoHouseTimer, NoHouseDoOnce)),
|
||||
new BT::Action(std::bind(BT_Action::SetTimer, _1, NoHouseTimer, NoHouseDoOnce)),
|
||||
new BT::Selector({
|
||||
new BT::PartialSequence({
|
||||
new BT::Action(BT_Grid::FindUnexploredCell),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget)
|
||||
}),
|
||||
new BT::PartialSequence({
|
||||
new BT::Action(std::bind(BT_Action::FindRandomLocation, _1, randomRadius * 2)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget)
|
||||
})
|
||||
})
|
||||
}),
|
||||
}),
|
||||
new BT::PartialSequence({
|
||||
new BT::Action(std::bind(BT_Action::FindRandomLocation, _1, randomRadius)),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
BT::Selector* HandleBug() {
|
||||
const std::string StuckTimer{ "StuckTimer" };
|
||||
constexpr float stuckTimeout = 3.0f; // Time in seconds before considering stuck
|
||||
constexpr bool StuckDoOnce{ false };
|
||||
constexpr float unstuckRange = 10.0f; // Range to pick a random target when stuck
|
||||
|
||||
return
|
||||
new BT::Selector({
|
||||
new BT::Sequence({
|
||||
new BT::Conditional(std::bind(BT_Condition::CheckMovement, _1, stuckTimeout)),
|
||||
new BT::Conditional(std::bind(BT_Condition::CheckTimer, _1, StuckTimer, StuckDoOnce)),
|
||||
new BT::Action(std::bind(BT_Action::SetTimer, _1, StuckTimer, StuckDoOnce)),
|
||||
new BT::Action(std::bind(BT_Action::FindRandomLocation, _1, unstuckRange)),
|
||||
new BT::Action(BT_Action::EnableSpin),
|
||||
new BT::Action(BT_Action::GoToTarget)
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@ namespace BT
|
||||
|
||||
namespace BigThink
|
||||
{
|
||||
BT::Selector* ItemHandling();
|
||||
BT::Sequence* ZombieHandling();
|
||||
BT::Sequence* PurgeZoneHandling();
|
||||
BT::Selector* ItemHandling();
|
||||
BT::PartialSequence* PickUpHandling();
|
||||
BT::Selector* HouseHandling();
|
||||
BT::Selector* HandleBug();
|
||||
}
|
||||
|
||||
@@ -13,11 +13,17 @@ add_library(Exam_Plugin SHARED
|
||||
"Behaviour.cpp"
|
||||
"BigThink.h"
|
||||
"BigThink.cpp"
|
||||
)
|
||||
"WorldExplorationGrid.h" "WorldExplorationGrid.cpp")
|
||||
|
||||
target_link_libraries(Exam_Plugin PUBLIC ${EXAM_LIB_DEBUG})
|
||||
target_include_directories(Exam_Plugin PUBLIC ${EXAM_INCLUDE_DIR})
|
||||
|
||||
# Explicit debug info generation flags for MSVC
|
||||
target_compile_options(Exam_Plugin PRIVATE
|
||||
$<$<CONFIG:Debug>:/Zi>)
|
||||
target_link_options(Exam_Plugin PRIVATE
|
||||
$<$<CONFIG:Debug>:/DEBUG>)
|
||||
|
||||
set_target_properties(Exam_Plugin PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}/_DEMO_DEBUG"
|
||||
LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}/_DEMO_DEBUG"
|
||||
@@ -40,4 +46,4 @@ set_target_properties(GPP_EXAM_EXE PROPERTIES
|
||||
)
|
||||
|
||||
# Ensure the DLL is built before the .exe is "built"
|
||||
add_dependencies(GPP_EXAM_EXE Exam_Plugin)
|
||||
add_dependencies(GPP_EXAM_EXE Exam_Plugin)
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Blackboard.h"
|
||||
#include "Thinker.h"
|
||||
#include "BigThink.h"
|
||||
#include "WorldExplorationGrid.h"
|
||||
|
||||
//Called only once, during initialization
|
||||
void SurvivalAgentPlugin::Initialize(IBaseInterface* pInterface, PluginInfo& info)
|
||||
@@ -29,12 +30,22 @@ void SurvivalAgentPlugin::Initialize(IBaseInterface* pInterface, PluginInfo& inf
|
||||
Blackboard* blackboardPtr{ CreateBlackboard() };
|
||||
m_BehaviourTree = new BT::BehaviorTree(blackboardPtr,
|
||||
new BT::Selector({
|
||||
BigThink::ItemHandling(),
|
||||
BigThink::ZombieHandling(),
|
||||
BigThink::PurgeZoneHandling(),
|
||||
BigThink::ItemHandling(),
|
||||
BigThink::PickUpHandling(),
|
||||
BigThink::HouseHandling()
|
||||
}));
|
||||
|
||||
Thinker* thinkerPtr{};
|
||||
blackboardPtr->GetData("Brain", thinkerPtr);
|
||||
|
||||
const WorldInfo& worldInfo = m_pInterface->World_GetInfo();
|
||||
thinkerPtr->m_ExplorationGrid.SetWorldInfo(worldInfo);
|
||||
|
||||
m_pExplorationGrid = &m_Thinker->m_ExplorationGrid;
|
||||
m_pExplorationGrid->SetInterfacePtr(m_pInterface);
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -48,8 +59,9 @@ Blackboard* SurvivalAgentPlugin::CreateBlackboard() {
|
||||
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("MaxFailSafe", 5.f);
|
||||
blackboardPtr->AddData("FailSafeDoOnce", false);
|
||||
|
||||
blackboardPtr->AddData("TargetZombie", EnemyInfo{});
|
||||
@@ -69,6 +81,17 @@ Blackboard* SurvivalAgentPlugin::CreateBlackboard() {
|
||||
blackboardPtr->AddData("TimerBeforeLeavingDoOnce", false);
|
||||
blackboardPtr->AddData("MaxTimeBeforeLeaving", 3.f);
|
||||
|
||||
blackboardPtr->AddData("MaxTimeNoHouse", 30.f);
|
||||
blackboardPtr->AddData("TimerNoHouse", std::chrono::steady_clock::time_point{});
|
||||
blackboardPtr->AddData("TimerNoHouseDoOnce", false);
|
||||
|
||||
blackboardPtr->AddData("TimerStuckTimer", std::chrono::steady_clock::time_point{});
|
||||
blackboardPtr->AddData("MaxStuckTimer", 5.f);
|
||||
blackboardPtr->AddData("TimerStuckTimerDoOnce", false);
|
||||
|
||||
blackboardPtr->AddData("LastPosition", m_pInterface->Agent_GetInfo().Position);
|
||||
blackboardPtr->AddData("LastMovementTime", std::chrono::steady_clock::now());
|
||||
|
||||
return blackboardPtr;
|
||||
}
|
||||
|
||||
@@ -113,7 +136,7 @@ void SurvivalAgentPlugin::InitGameDebugParams(GameDebugParams& params)
|
||||
params.SpawnPurgeZonesOnMiddleClick = true;
|
||||
params.PrintDebugMessages = true;
|
||||
params.ShowDebugItemNames = true;
|
||||
params.Seed = -1; //-1 = don't set seed. Any other number = fixed seed //TIP: use Seed = int(time(nullptr)) for pure randomness
|
||||
params.Seed = int(time(nullptr)); //-1 = don't set seed. Any other number = fixed seed //TIP: use Seed = int(time(nullptr)) for pure randomness
|
||||
}
|
||||
|
||||
void SurvivalAgentPlugin::Update_Debug(float dt)
|
||||
@@ -189,11 +212,23 @@ SteeringPlugin_Output SurvivalAgentPlugin::UpdateSteering(float dt)
|
||||
|
||||
UpdateBlackboard(steering);
|
||||
|
||||
m_Thinker->m_ExplorationGrid.Update(m_pInterface->Agent_GetInfo(), m_pInterface->GetHousesInFOV());
|
||||
|
||||
m_BehaviourTree->Update();
|
||||
|
||||
m_BehaviourTree->GetBlackboard()->GetData("Steering", steering);
|
||||
m_BehaviourTree->GetBlackboard()->GetData("Spin", spin);
|
||||
|
||||
if (m_pInterface->Agent_GetInfo().Stamina >= 10 || m_Running) {
|
||||
m_Running = true;
|
||||
steering.RunMode = false;
|
||||
}
|
||||
|
||||
if (m_pInterface->Agent_GetInfo().Stamina <= 0.1f) {
|
||||
m_Running = false;
|
||||
steering.RunMode = false;
|
||||
}
|
||||
|
||||
if (spin) {
|
||||
steering.AutoOrient = false;
|
||||
}
|
||||
@@ -208,6 +243,8 @@ SteeringPlugin_Output SurvivalAgentPlugin::UpdateSteering(float dt)
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << m_pInterface->Agent_GetInfo().Position.x << " " << m_pInterface->Agent_GetInfo().Position.y << std::endl;
|
||||
|
||||
return steering;
|
||||
|
||||
|
||||
@@ -225,6 +262,8 @@ void SurvivalAgentPlugin::Render(float dt) const
|
||||
m_pInterface->Draw_Circle(m_pInterface->Agent_GetInfo().Position, 15.f, { 0.f, 1.f, 1.f });
|
||||
m_pInterface->Draw_Circle(m_pInterface->Agent_GetInfo().Position, 8.f, { 0.f, 1.f, 1.f });
|
||||
|
||||
|
||||
m_pExplorationGrid->RenderDebug();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ class IBaseInterface;
|
||||
class IExamInterface;
|
||||
class Blackboard;
|
||||
class Thinker;
|
||||
class WorldExplorationGrid;
|
||||
|
||||
|
||||
class SurvivalAgentPlugin final : public IExamPlugin
|
||||
@@ -47,6 +48,10 @@ private:
|
||||
void UpdateBlackboard(const SteeringPlugin_Output& steering);
|
||||
BT::BehaviorTree* m_BehaviourTree = nullptr;
|
||||
Thinker* m_Thinker = nullptr;
|
||||
|
||||
WorldExplorationGrid* m_pExplorationGrid = nullptr;
|
||||
|
||||
bool m_Running{ false };
|
||||
};
|
||||
|
||||
//ENTRY
|
||||
|
||||
@@ -3,19 +3,18 @@
|
||||
#include <algorithm>
|
||||
|
||||
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; });
|
||||
auto minIt = m_ItemMemory.end();
|
||||
|
||||
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;
|
||||
});
|
||||
for (auto it = m_ItemMemory.begin(); it != m_ItemMemory.end(); ++it) {
|
||||
if (it->ItemInfo.Type != itemType)
|
||||
continue;
|
||||
|
||||
return minItem;
|
||||
if (minIt == m_ItemMemory.end() || it->ItemInfo.Value < minIt->ItemInfo.Value) {
|
||||
minIt = it;
|
||||
}
|
||||
}
|
||||
|
||||
return minIt;
|
||||
}
|
||||
|
||||
bool Thinker::IsInvNotFull() const {
|
||||
@@ -24,7 +23,7 @@ bool Thinker::IsInvNotFull() const {
|
||||
|
||||
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; });
|
||||
[itemType](const ItemMemory& memory)->bool { return memory.ItemInfo.Type == itemType && memory.ItemInfo.Value > 0; });
|
||||
}
|
||||
|
||||
bool Thinker::EmptyValue() {
|
||||
@@ -32,6 +31,7 @@ bool Thinker::EmptyValue() {
|
||||
[](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; });
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <Exam_HelperStructs.h>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include "WorldExplorationGrid.h"
|
||||
|
||||
class Thinker final {
|
||||
public:
|
||||
@@ -49,6 +50,7 @@ public:
|
||||
bool CheckHousesForMemory(const std::vector<HouseInfo>& FOVHouses);
|
||||
|
||||
|
||||
WorldExplorationGrid m_ExplorationGrid;
|
||||
private:
|
||||
std::vector<HouseMemory> m_HousesMemory{};
|
||||
const float m_MaxWaitTimer{ 360.f };
|
||||
@@ -57,4 +59,7 @@ private:
|
||||
const size_t m_MaxStorageSlots{ 5 };
|
||||
|
||||
std::vector<HouseMemory>::iterator FindHouseInMemory(const HouseInfo& targetHouse);
|
||||
|
||||
|
||||
float m_GridCellSize = 50.f; // Adjust based on your needs
|
||||
};
|
||||
|
||||
328
project/WorldExplorationGrid.cpp
Normal file
328
project/WorldExplorationGrid.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
#include "WorldExplorationGrid.h"
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
WorldExplorationGrid::WorldExplorationGrid(float cellSize)
|
||||
: m_CellSize(cellSize) {
|
||||
}
|
||||
|
||||
void WorldExplorationGrid::Reset() {
|
||||
m_ExploredGrid.clear();
|
||||
}
|
||||
|
||||
void WorldExplorationGrid::SetCellSize(float newCellSize) {
|
||||
m_CellSize = newCellSize;
|
||||
Reset(); // Cell size change invalidates previous data
|
||||
}
|
||||
|
||||
WorldExplorationGrid::GridCoords WorldExplorationGrid::WorldToGrid(const Elite::Vector2& pos) const {
|
||||
int gridWidth = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.x / m_CellSize));
|
||||
int gridHeight = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.y / m_CellSize));
|
||||
|
||||
int centerX = gridWidth / 2;
|
||||
int centerY = gridHeight / 2;
|
||||
|
||||
return {
|
||||
static_cast<int>(std::floor(pos.x / m_CellSize)) + centerX,
|
||||
static_cast<int>(std::floor(pos.y / m_CellSize)) + centerY
|
||||
};
|
||||
}
|
||||
|
||||
Elite::Vector2 WorldExplorationGrid::GridToWorld(const GridCoords& coords) const {
|
||||
int gridWidth = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.x / m_CellSize));
|
||||
int gridHeight = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.y / m_CellSize));
|
||||
|
||||
int centerX = gridWidth / 2;
|
||||
int centerY = gridHeight / 2;
|
||||
|
||||
return {
|
||||
(coords.x - centerX + 0.5f) * m_CellSize,
|
||||
(coords.y - centerY + 0.5f) * m_CellSize
|
||||
};
|
||||
}
|
||||
|
||||
void WorldExplorationGrid::MarkExplored(const std::vector<GridCoords>& cells) {
|
||||
for (const auto& cell : cells)
|
||||
m_ExploredGrid[cell] = true;
|
||||
}
|
||||
|
||||
std::vector<WorldExplorationGrid::GridCoords> WorldExplorationGrid::GetCellsInRadius(const Elite::Vector2& center, float radius) const {
|
||||
std::vector<GridCoords> cells;
|
||||
int r = static_cast<int>(std::ceil(radius / m_CellSize));
|
||||
|
||||
GridCoords centerCoords = WorldToGrid(center);
|
||||
for (int dx = -r; dx <= r; ++dx) {
|
||||
for (int dy = -r; dy <= r; ++dy) {
|
||||
GridCoords coords{ centerCoords.x + dx, centerCoords.y + dy };
|
||||
Elite::Vector2 cellCenter = GridToWorld(coords);
|
||||
if (Elite::Distance(center, cellCenter) <= radius + m_CellSize * 0.5f)
|
||||
cells.push_back(coords);
|
||||
}
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
|
||||
std::vector<WorldExplorationGrid::GridCoords> WorldExplorationGrid::GetCellsInRect(const Elite::Vector2& center, const Elite::Vector2& size) const {
|
||||
std::vector<GridCoords> cells;
|
||||
Elite::Vector2 halfSize = size * 0.5f;
|
||||
Elite::Vector2 min = center - halfSize;
|
||||
Elite::Vector2 max = center + halfSize;
|
||||
|
||||
GridCoords minCoords = WorldToGrid(min);
|
||||
GridCoords maxCoords = WorldToGrid(max);
|
||||
|
||||
for (int x = minCoords.x; x <= maxCoords.x; ++x) {
|
||||
for (int y = minCoords.y; y <= maxCoords.y; ++y) {
|
||||
cells.push_back({ x, y });
|
||||
}
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
|
||||
void WorldExplorationGrid::SetWorldInfo(const WorldInfo& info) {
|
||||
m_WorldInfo = info;
|
||||
|
||||
std::cout << "World info: "
|
||||
<< "Dimensions: " << m_WorldInfo.Dimensions.x << " x " << m_WorldInfo.Dimensions.y
|
||||
<< ", Cell Size: " << m_CellSize << std::endl;
|
||||
}
|
||||
|
||||
void WorldExplorationGrid::RenderDebug() {
|
||||
if (!m_pRenderer) return;
|
||||
// Draw explored cells as before
|
||||
const Elite::Vector3 exploredColor{ 0.f, 1.f, 0.f };
|
||||
const float depth = 0.8f;
|
||||
|
||||
for (const auto& pair : m_ExploredGrid) {
|
||||
if (!pair.second) continue;
|
||||
|
||||
Elite::Vector2 center = GridToWorld(pair.first);
|
||||
float half = m_CellSize / 2.f;
|
||||
|
||||
Elite::Vector2 verts[4] = {
|
||||
center + Elite::Vector2{-half, -half},
|
||||
center + Elite::Vector2{ half, -half},
|
||||
center + Elite::Vector2{ half, half},
|
||||
center + Elite::Vector2{-half, half}
|
||||
};
|
||||
|
||||
m_pRenderer->Draw_SolidPolygon(verts, 4, exploredColor, depth);
|
||||
}
|
||||
|
||||
// Draw the world bounds outline in red
|
||||
int gridWidth = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.x / m_CellSize));
|
||||
int gridHeight = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.y / m_CellSize));
|
||||
|
||||
Elite::Vector2 topLeft = GridToWorld({ 0, 0 }) - Elite::Vector2{ m_CellSize / 2.f, m_CellSize / 2.f };
|
||||
Elite::Vector2 topRight = GridToWorld({ gridWidth - 1, 0 }) + Elite::Vector2{ m_CellSize / 2.f, -m_CellSize / 2.f };
|
||||
Elite::Vector2 bottomRight = GridToWorld({ gridWidth - 1, gridHeight - 1 }) + Elite::Vector2{ m_CellSize / 2.f, m_CellSize / 2.f };
|
||||
Elite::Vector2 bottomLeft = GridToWorld({ 0, gridHeight - 1 }) + Elite::Vector2{ -m_CellSize / 2.f, m_CellSize / 2.f };
|
||||
|
||||
Elite::Vector2 borderVerts[4] = { topLeft, topRight, bottomRight, bottomLeft };
|
||||
const Elite::Vector3 borderColor{ 1.f, 0.f, 0.f }; // red
|
||||
|
||||
m_pRenderer->Draw_Polygon(borderVerts, 4, borderColor, 1.f); // Draw outline
|
||||
|
||||
}
|
||||
|
||||
bool WorldExplorationGrid::IsExplored(const Elite::Vector2& position) const {
|
||||
GridCoords coords = WorldToGrid(position);
|
||||
auto it = m_ExploredGrid.find(coords);
|
||||
return it != m_ExploredGrid.end() && it->second;
|
||||
}
|
||||
|
||||
void WorldExplorationGrid::Update(const AgentInfo& agentInfo,
|
||||
const std::vector<HouseInfo>& visibleHouses) {
|
||||
// Mark agent's field of view as explored
|
||||
auto visionCells = GetCellsInRadius(agentInfo.Position, agentInfo.FOV_Range / 2);
|
||||
MarkExplored(visionCells);
|
||||
|
||||
// Optionally mark house interiors if visible
|
||||
for (const auto& house : visibleHouses) {
|
||||
auto houseCells = GetCellsInRect(house.Center, house.Size);
|
||||
MarkExplored(houseCells);
|
||||
}
|
||||
}
|
||||
|
||||
float WorldExplorationGrid::GetExploredPercentage() const {
|
||||
if (m_WorldInfo.Dimensions.x <= 0.0f || m_WorldInfo.Dimensions.y <= 0.0f)
|
||||
return 0.0f;
|
||||
|
||||
int gridWidth = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.x / m_CellSize));
|
||||
int gridHeight = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.y / m_CellSize));
|
||||
int totalCells = gridWidth * gridHeight;
|
||||
|
||||
return totalCells == 0 ? 0.0f : static_cast<float>(m_ExploredGrid.size()) / totalCells;
|
||||
}
|
||||
|
||||
|
||||
float WorldExplorationGrid::GetHouseExploredPercentage(const HouseInfo& house) const {
|
||||
auto houseCells = GetCellsInRect(house.Center, house.Size);
|
||||
int explored = 0;
|
||||
for (const auto& cell : houseCells)
|
||||
if (m_ExploredGrid.count(cell) > 0 && m_ExploredGrid.at(cell)) ++explored;
|
||||
|
||||
return houseCells.empty() ? 0.0f : static_cast<float>(explored) / houseCells.size();
|
||||
}
|
||||
//
|
||||
//Elite::Vector2 WorldExplorationGrid::FindNearestUnexplored(const Elite::Vector2& fromPosition) {
|
||||
// GridCoords start = WorldToGrid(fromPosition);
|
||||
//
|
||||
// const int maxRadius = 10; // Search range
|
||||
// for (int r = 1; r < maxRadius; ++r) {
|
||||
// for (int dx = -r; dx <= r; ++dx) {
|
||||
// for (int dy = -r; dy <= r; ++dy) {
|
||||
// if (std::abs(dx) != r && std::abs(dy) != r) continue; // Only border
|
||||
// GridCoords coords{ start.x + dx, start.y + dy };
|
||||
// if (m_ExploredGrid.count(coords) == 0)
|
||||
// return GridToWorld(coords);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return fromPosition; // No unexplored found
|
||||
//}
|
||||
//
|
||||
//Elite::Vector2 WorldExplorationGrid::FindNearestUnexplored(const Elite::Vector2& fromPosition) {
|
||||
// // Start search from the last unexplored cell to get a local spiral effect
|
||||
// GridCoords start = m_LastUnexploredCell;
|
||||
//
|
||||
// int gridWidth = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.x / m_CellSize));
|
||||
// int gridHeight = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.y / m_CellSize));
|
||||
//
|
||||
// // Clamp start inside the world bounds
|
||||
// start = ClampToWorldBounds(start);
|
||||
//
|
||||
// const int maxRadius = 10; // max search radius in cells
|
||||
//
|
||||
// for (int r = 0; r <= maxRadius; ++r) {
|
||||
// for (int dx = -r; dx <= r; ++dx) {
|
||||
// for (int dy = -r; dy <= r; ++dy) {
|
||||
// if (std::abs(dx) != r && std::abs(dy) != r) continue; // only border cells at radius r
|
||||
//
|
||||
// GridCoords candidate{ start.x + dx, start.y + dy };
|
||||
// candidate = ClampToWorldBounds(candidate);
|
||||
//
|
||||
// if (m_ExploredGrid.count(candidate) == 0) {
|
||||
// m_LastUnexploredCell = candidate; // update last unexplored
|
||||
// return GridToWorld(candidate);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // fallback - no unexplored cell found, return current position
|
||||
// return fromPosition;
|
||||
//}
|
||||
|
||||
Elite::Vector2 WorldExplorationGrid::FindNearestUnexplored(const Elite::Vector2& fromPosition) {
|
||||
GridCoords start = WorldToGrid(fromPosition);
|
||||
|
||||
// We'll use a priority queue that prioritizes cells that are both close to the start
|
||||
// and have more explored neighbors
|
||||
struct Candidate {
|
||||
GridCoords coords;
|
||||
float distance;
|
||||
int exploredNeighbors;
|
||||
|
||||
bool operator<(const Candidate& other) const {
|
||||
// First prioritize cells with more explored neighbors
|
||||
if (exploredNeighbors != other.exploredNeighbors)
|
||||
return exploredNeighbors < other.exploredNeighbors;
|
||||
// Then by distance
|
||||
return distance > other.distance;
|
||||
}
|
||||
};
|
||||
|
||||
std::priority_queue<Candidate> candidates;
|
||||
std::unordered_set<GridCoords, GridCoordsHash> visited;
|
||||
|
||||
// Check 4-connected neighbors first for efficiency
|
||||
const int dx4[] = { 0, 1, 0, -1 };
|
||||
const int dy4[] = { 1, 0, -1, 0 };
|
||||
|
||||
// Start with the immediate neighbors
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
GridCoords neighbor{ start.x + dx4[i], start.y + dy4[i] };
|
||||
if (visited.insert(neighbor).second) {
|
||||
float dist = Elite::Distance(fromPosition, GridToWorld(neighbor));
|
||||
int exploredNeighbors = CountExploredNeighbors(neighbor);
|
||||
candidates.push({ neighbor, dist, exploredNeighbors });
|
||||
}
|
||||
}
|
||||
|
||||
const int maxSearchRadius = 20; // Limit search area
|
||||
int currentRadius = 1;
|
||||
|
||||
while (!candidates.empty()) {
|
||||
auto current = candidates.top();
|
||||
candidates.pop();
|
||||
|
||||
// If this cell is unexplored, return it
|
||||
if (m_ExploredGrid.count(current.coords) == 0) {
|
||||
return GridToWorld(current.coords);
|
||||
}
|
||||
|
||||
// Expand search to this cell's neighbors
|
||||
if (current.distance < maxSearchRadius) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
GridCoords neighbor{ current.coords.x + dx4[i], current.coords.y + dy4[i] };
|
||||
if (visited.insert(neighbor).second) {
|
||||
float dist = Elite::Distance(fromPosition, GridToWorld(neighbor));
|
||||
int exploredNeighbors = CountExploredNeighbors(neighbor);
|
||||
candidates.push({ neighbor, dist, exploredNeighbors });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: spiral search if priority queue didn't find anything
|
||||
for (int r = 1; r < maxSearchRadius; ++r) {
|
||||
for (int dx = -r; dx <= r; ++dx) {
|
||||
for (int dy = -r; dy <= r; ++dy) {
|
||||
if (std::abs(dx) != r && std::abs(dy) != r) continue; // Only border
|
||||
GridCoords coords{ start.x + dx, start.y + dy };
|
||||
if (m_ExploredGrid.count(coords) == 0)
|
||||
return GridToWorld(coords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fromPosition; // No unexplored found
|
||||
}
|
||||
|
||||
int WorldExplorationGrid::CountExploredNeighbors(const GridCoords& coords) const {
|
||||
const int dx[] = { 0, 1, 0, -1, 1, 1, -1, -1 }; // 8-connected neighbors
|
||||
const int dy[] = { 1, 0, -1, 0, 1, -1, 1, -1 };
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
GridCoords neighbor{ coords.x + dx[i], coords.y + dy[i] };
|
||||
if (m_ExploredGrid.count(neighbor) > 0 && m_ExploredGrid.at(neighbor)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
Elite::Vector2 WorldExplorationGrid::FindUnexploredInHouse(const Elite::Vector2& fromPosition, const HouseInfo& house) const {
|
||||
auto houseCells = GetCellsInRect(house.Center, house.Size);
|
||||
Elite::Vector2 closestPos = fromPosition;
|
||||
//hardcode max
|
||||
float minDistSq = 10000000.f;
|
||||
|
||||
for (const auto& cell : houseCells) {
|
||||
if (m_ExploredGrid.count(cell) == 0) {
|
||||
Elite::Vector2 worldPos = GridToWorld(cell);
|
||||
float distSq = Elite::DistanceSquared(fromPosition, worldPos);
|
||||
if (distSq < minDistSq) {
|
||||
closestPos = worldPos;
|
||||
minDistSq = distSq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closestPos;
|
||||
}
|
||||
81
project/WorldExplorationGrid.h
Normal file
81
project/WorldExplorationGrid.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
#define NOMINMAX
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <Exam_HelperStructs.h>
|
||||
#include <IExamInterface.h>
|
||||
|
||||
class WorldExplorationGrid {
|
||||
public:
|
||||
WorldExplorationGrid(float cellSize = 35);
|
||||
|
||||
void Update(const AgentInfo& agentInfo, const std::vector<HouseInfo>& visibleHouses);
|
||||
|
||||
Elite::Vector2 FindNearestUnexplored(const Elite::Vector2& fromPosition);
|
||||
Elite::Vector2 FindUnexploredInHouse(const Elite::Vector2& fromPosition, const HouseInfo& house) const;
|
||||
|
||||
bool IsExplored(const Elite::Vector2& position) const;
|
||||
float GetExploredPercentage() const;
|
||||
float GetHouseExploredPercentage(const HouseInfo& house) const;
|
||||
|
||||
void Reset();
|
||||
void SetCellSize(float newCellSize);
|
||||
float GetCellSize() const { return m_CellSize; }
|
||||
|
||||
void SetWorldInfo(const WorldInfo& info);
|
||||
void SetInterfacePtr(IExamInterface* pInterface) { m_pRenderer = pInterface; }
|
||||
|
||||
void RenderDebug();
|
||||
|
||||
|
||||
|
||||
private:
|
||||
IExamInterface* m_pRenderer{ nullptr };
|
||||
float m_CellSize;
|
||||
WorldInfo m_WorldInfo{};
|
||||
int m_MaxSearchRadius = 100;
|
||||
|
||||
|
||||
struct GridCoords {
|
||||
int x, y;
|
||||
bool operator==(const GridCoords& other) const {
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
};
|
||||
|
||||
struct GridHash {
|
||||
size_t operator()(const GridCoords& coords) const {
|
||||
return static_cast<size_t>(coords.x) << 32 | coords.y;
|
||||
}
|
||||
};
|
||||
|
||||
struct GridCoordsHash {
|
||||
size_t operator()(const GridCoords& coords) const {
|
||||
return std::hash<int>()(coords.x) ^ (std::hash<int>()(coords.y) << 1);
|
||||
}
|
||||
};
|
||||
|
||||
WorldExplorationGrid::GridCoords ClampToWorldBounds(const GridCoords& coords) const {
|
||||
int gridWidth = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.x / m_CellSize));
|
||||
int gridHeight = static_cast<int>(std::ceil(m_WorldInfo.Dimensions.y / m_CellSize));
|
||||
|
||||
return {
|
||||
std::clamp(coords.x, 0, gridWidth - 1),
|
||||
std::clamp(coords.y, 0, gridHeight - 1)
|
||||
};
|
||||
}
|
||||
std::unordered_map<GridCoords, bool, GridHash> m_ExploredGrid;
|
||||
|
||||
GridCoords WorldToGrid(const Elite::Vector2& pos) const;
|
||||
Elite::Vector2 GridToWorld(const GridCoords& gridCoords) const;
|
||||
void MarkExplored(const std::vector<GridCoords>& cells);
|
||||
std::vector<GridCoords> GetCellsInRadius(const Elite::Vector2& center, float radius) const;
|
||||
std::vector<GridCoords> GetCellsInRect(const Elite::Vector2& center, const Elite::Vector2& size) const;
|
||||
int CountExploredNeighbors(const GridCoords& coords) const;
|
||||
|
||||
GridCoords m_LastUnexploredCell = { 0,0 };
|
||||
};
|
||||
Reference in New Issue
Block a user