Files
ZombieGame-Rawr/project/SurvivalAgentPlugin.cpp
Bram verhulst f9a11385fe Fianlly
2025-06-02 21:29:29 +02:00

270 lines
8.9 KiB
C++

#include "stdafx.h"
#include "SurvivalAgentPlugin.h"
#include "BehaviourTree.h"
#include "IExamInterface.h"
#include "Blackboard.h"
#include "Thinker.h"
#include "BigThink.h"
#include "WorldExplorationGrid.h"
//Called only once, during initialization
void SurvivalAgentPlugin::Initialize(IBaseInterface* pInterface, PluginInfo& info)
{
//Retrieving the interface
//This interface gives you access to certain actions the AI_Framework can perform for you
m_pInterface = static_cast<IExamInterface*>(pInterface);
//Information for the leaderboards!
info.BotName = "Cat";
info.Student_Name = "Bram Verhulst";//No special characters allowed. Highscores won't work with special characters.
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!
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({
BigThink::ItemHandling(),
BigThink::ZombieHandling(),
BigThink::PurgeZoneHandling(),
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);
}
Blackboard* SurvivalAgentPlugin::CreateBlackboard() {
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", 5.f);
blackboardPtr->AddData("FailSafeDoOnce", false);
blackboardPtr->AddData("TargetZombie", EnemyInfo{});
blackboardPtr->AddData("angleDiff", float{});
blackboardPtr->AddData("TimerShotgun", std::chrono::steady_clock::time_point{});
blackboardPtr->AddData("TimerShotgunDoOnce", false);
blackboardPtr->AddData("MaxTimeShotgun", 1.f);
blackboardPtr->AddData("TimerPistol", std::chrono::steady_clock::time_point{});
blackboardPtr->AddData("TimerPistolDoOnce", false);
blackboardPtr->AddData("MaxTimePistol", 1.f);
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", 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;
}
void SurvivalAgentPlugin::UpdateBlackboard(const SteeringPlugin_Output& steering) {
Blackboard* blackboard{ m_BehaviourTree->GetBlackboard() };
blackboard->ChangeData("Steering", steering);
blackboard->GetData("Target", m_Target);
}
SurvivalAgentPlugin::~SurvivalAgentPlugin() {
SAFE_DELETE(m_BehaviourTree);
SAFE_DELETE(m_Thinker);
}
//Called only once
void SurvivalAgentPlugin::DllInit()
{
//Called when the plugin is loaded
}
//Called only once
void SurvivalAgentPlugin::DllShutdown()
{
//Called when the plugin gets unloaded
}
//Called only once, during initialization. Only works in DEBUG Mode
void SurvivalAgentPlugin::InitGameDebugParams(GameDebugParams& params)
{
params.AutoFollowCam = true; //Automatically follow the AI? (Default = true)
params.RenderUI = true; //Render the IMGUI Panel? (Default = true)
params.SpawnEnemies = true; //Do you want to spawn enemies? (Default = true)
params.EnemyCount = 20; //How many enemies? (Default = 20)
params.GodMode = false; //GodMode > You can't die, can be useful to inspect certain behaviors (Default = false)
params.LevelFile = "GameLevel.gppl";
params.AutoGrabClosestItem = true; //A call to Item_Grab(...) returns the closest item that can be grabbed. (EntityInfo argument is ignored)
params.StartingDifficultyStage = 1;
params.InfiniteStamina = false;
params.SpawnDebugPistol = true;
params.SpawnDebugShotgun = true;
params.SpawnPurgeZonesOnMiddleClick = true;
params.PrintDebugMessages = true;
params.ShowDebugItemNames = true;
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)
{
//Demo Event Code
//In the end your Agent should be able to walk around without external input
if (m_pInterface->Input_IsMouseButtonUp(Elite::InputMouseButton::eLeft))
{
//Update_Debug target based on input
Elite::MouseData mouseData = m_pInterface->Input_GetMouseData(Elite::InputType::eMouseButton, Elite::InputMouseButton::eLeft);
const Elite::Vector2 pos = Elite::Vector2(static_cast<float>(mouseData.X), static_cast<float>(mouseData.Y));
m_Target = m_pInterface->Debug_ConvertScreenToWorld(pos);
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_Space))
{
m_CanRun = true;
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_Left))
{
m_AngSpeed -= Elite::ToRadians(10);
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_Right))
{
m_AngSpeed += Elite::ToRadians(10);
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_G))
{
m_GrabItem = true;
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_U))
{
m_UseItem = true;
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_R))
{
m_RemoveItem = true;
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_X))
{
m_DestroyItemsInFOV = true;
}
else if (m_pInterface->Input_IsKeyboardKeyUp(Elite::eScancode_Space))
{
m_CanRun = false;
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_Delete))
{
m_pInterface->RequestShutdown();
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_KP_Minus))
{
if (m_InventorySlot > 0)
--m_InventorySlot;
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_KP_Plus))
{
if (m_InventorySlot < 4)
++m_InventorySlot;
}
else if (m_pInterface->Input_IsKeyboardKeyDown(Elite::eScancode_Q))
{
ItemInfo info = {};
m_pInterface->Inventory_GetItem(m_InventorySlot, info);
std::cout << (int)info.Type << std::endl;
}
}
//This function calculates the new SteeringOutput, called once per frame
SteeringPlugin_Output SurvivalAgentPlugin::UpdateSteering(float dt)
{
auto steering = SteeringPlugin_Output(Elite::Vector2{}, m_pInterface->Agent_GetInfo().MaxAngularSpeed, true, false);
bool spin{ false };
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;
}
if (m_GrabItem) {
ItemInfo item;
m_BehaviourTree->GetBlackboard()->GetData("TargetItem", item);
if (m_pInterface->GrabItem(item)) {
m_pInterface->Inventory_AddItem(m_InventorySlot, item);
}
}
std::cout << m_pInterface->Agent_GetInfo().Position.x << " " << m_pInterface->Agent_GetInfo().Position.y << std::endl;
return steering;
}
//This function should only be used for rendering debug elements
void SurvivalAgentPlugin::Render(float dt) const
{
//This Render function should only contain calls to Interface->Draw_... functions
m_pInterface->Draw_SolidCircle(m_Target, .7f, { 0,0 }, { 1, 0, 0 });
m_pInterface->Draw_Circle(m_pInterface->Agent_GetInfo().Position, 500.f, { 1.f, 0.f, 0 });
m_pInterface->Draw_Circle(m_pInterface->Agent_GetInfo().Position, 400.f, { 1.f, 1.f, 0 });
m_pInterface->Draw_Circle(m_pInterface->Agent_GetInfo().Position, 50.f, { 1.f, 1.f, 1.f });
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();
}