ICT290 / src / scene / AIController / EntityBrain / SensoryMemory.cpp
SensoryMemory.cpp
Raw
//
// Created by Micha on 27/09/2021.
//

#include "SensoryMemory.h"
#include "../GameWorld.h"

//------------------------------- ctor ----------------------------------------
//-----------------------------------------------------------------------------
SensoryMemory::SensoryMemory(Vehicle* owner, Uint32 MemorySpan)
    : m_Owner(owner),
      m_MemorySpan(MemorySpan)

{}

//--------------------- MakeNewRecordIfNotAlreadyPresent ----------------------

void SensoryMemory::makeNewRecordIfNotAlreadyPresent(Vehicle* Opponent) {
    // else check to see if this Opponent already exists in the memory. If it
    // doesn't, create a new record
    if (m_MemoryMap.find(Opponent) == m_MemoryMap.end()) {
        m_MemoryMap[Opponent] = MemoryRecord();
    }
}

//------------------------ RemoveBotFromMemory ----------------------- ---------
//
//  this removes a bot's record from memory
//-----------------------------------------------------------------------------
void SensoryMemory::removeBotFromMemory(Vehicle* Bot) {
    auto record = m_MemoryMap.find(Bot);

    if (record != m_MemoryMap.end()) {
        m_MemoryMap.erase(record);
    }
}

//----------------------- UpdateWithSoundSource -------------------------------
//
// this updates the record for an individual opponent. Note, there is no need to
// test if the opponent is within the FOV because that test will be done when
// the UpdateVision method is called
//-----------------------------------------------------------------------------
void SensoryMemory::updateWithSoundSource(Vehicle* NoiseMaker) {
    // make sure the bot being examined is not this bot
    if (m_Owner != NoiseMaker) {
        // if the bot is already part of the memory then update its data, else
        // create a new memory record and add it to the memory
        makeNewRecordIfNotAlreadyPresent(NoiseMaker);

        MemoryRecord& info = m_MemoryMap[NoiseMaker];

        // test if there is LOS between bots
        if (m_Owner->getGameWorld()->isLOSOkay(m_Owner->getPosition(),
                                               NoiseMaker->getPosition())) {
            info.shootable = true;

            // record the position of the bot
            info.lastSensedPosition = NoiseMaker->getPosition();
        } else {
            info.shootable = false;
        }

        // record the time it was sensed
        info.timeLastSensed = SDL_GetTicks();
    }
}

//----------------------------- UpdateVision ----------------------------------
//
//  this method iterates through all the bots in the game world to test if
//  they are in the field of view. Each bot's memory record is updated
//  accordingly
//-----------------------------------------------------------------------------
void SensoryMemory::updateVision() {
    // for each bot in the world test to see if it is visible to the owner of
    // this class
    // const std::list<Vehicle*>& bots = m_Owner->GetWorld()->GetAllBots();
    // std::list<Vehicle*>::const_iterator curBot;
    for (auto curBot : m_Owner->getGameWorld()->getAllBots()) {
        // make sure the bot being examined is not this bot
        if (m_Owner != curBot) {
            // make sure it is part of the memory map
            makeNewRecordIfNotAlreadyPresent(curBot);

            // get a reference to this bot's data
            MemoryRecord& info = m_MemoryMap[curBot];

            // test if there is LOS between bots
            if (m_Owner->getGameWorld()->isLOSOkay(m_Owner->getPosition(),
                                                   curBot->getPosition())) {
                info.shootable = true;

                // test if the bot is within FOV
                if (m_Owner->getGameWorld()
                        ->isSecondInFOVOfFirst(m_Owner->getPosition(),
                                               m_Owner->getFacingVec(),
                                               curBot->getPosition(),
                                               m_Owner->getFieldOfView(),
                                               m_Owner->getViewDistance())) {
                    info.timeLastSensed = SDL_GetTicks();
                    info.lastSensedPosition = curBot->getPosition();
                    info.timeLastVisible = SDL_GetTicks();

                    if (!info.withinFOV) {
                        info.withinFOV = true;
                        info.timeBecameVisible = info.timeLastSensed;
                    }
                }

                else {
                    info.withinFOV = false;
                }
            }

            else {
                info.shootable = false;
                info.withinFOV = false;
            }
        }
    }  // next bot
}

//------------------------ GetListOfRecentlySensedOpponents -------------------
//
//  returns a list of the bots that have been sensed recently
//-----------------------------------------------------------------------------
std::list<Vehicle*> SensoryMemory::getListOfRecentlySensedOpponents() const {
    // this will store all the opponents the bot can remember
    std::list<Vehicle*> opponents;

    Uint32 CurrentTime = SDL_GetTicks();

    // MemoryMap::const_iterator curRecord = m_MemoryMap.begin();
    // for (curRecord; curRecord != m_MemoryMap.end(); ++curRecord) {
    for (auto curRecord : m_MemoryMap) {
        // if this bot has been updated in the memory recently, add to list
        // Uint32 current = CurrentTime;
        // Uint32 lasTTimeSensed = curRecord.second.timeLastSensed;
        // Uint32 difference = CurrentTime - curRecord.second.timeLastSensed;
        // bool temp = (CurrentTime - curRecord.second.timeLastSensed)
        //   <= m_MemorySpan;
        if ((CurrentTime - curRecord.second.timeLastSensed) <= m_MemorySpan) {
            opponents.push_back(curRecord.first);
        }
    }

    return opponents;
}

//----------------------------- isOpponentShootable
//--------------------------------
//
//  returns true if the bot given as a parameter can be shot (ie. its not
//  obscured by walls)
//-----------------------------------------------------------------------------
bool SensoryMemory::isOpponentShootable(Vehicle* Opponent) const {
    MemoryMap::const_iterator it = m_MemoryMap.find(Opponent);

    if (it != m_MemoryMap.end()) {
        return it->second.shootable;
    }

    return false;
}

//----------------------------- isOpponentWithinFOV
//--------------------------------
//
//  returns true if the bot given as a parameter is within FOV
//-----------------------------------------------------------------------------
bool SensoryMemory::isOpponentWithinFOV(Vehicle* Opponent) const {
    MemoryMap::const_iterator it = m_MemoryMap.find(Opponent);

    if (it != m_MemoryMap.end()) {
        return it->second.withinFOV;
    }

    return false;
}

//---------------------------- getLastRecordedPositionOfOpponent
//-------------------
//
//  returns the last recorded position of the bot
//-----------------------------------------------------------------------------
glm::vec2 SensoryMemory::getLastRecordedPositionOfOpponent(
    Vehicle* Opponent) const {
    MemoryMap::const_iterator it = m_MemoryMap.find(Opponent);

    if (it != m_MemoryMap.end()) {
        return it->second.lastSensedPosition;
    }

    throw std::runtime_error(
        "< SensoryMemory::getLastRecordedPositionOfOpponent>: Attempting "
        "to get position of unrecorded bot");
}

//----------------------------- GetTimeOpponentHasBeenVisible
//----------------------
//
//  returns the amount of time the given bot has been visible
//-----------------------------------------------------------------------------
Uint32 SensoryMemory::getTimeOpponentHasBeenVisible(Vehicle* Opponent) const {
    MemoryMap::const_iterator it = m_MemoryMap.find(Opponent);

    if (it != m_MemoryMap.end() && it->second.withinFOV) {
        return SDL_GetTicks() - it->second.timeBecameVisible;
    }

    return 0;
}

//-------------------- GetTimeOpponentHasBeenOutOfView ------------------------
//
//  returns the amount of time the given opponent has remained out of view
//  returns a high value if opponent has never been seen or not present
//-----------------------------------------------------------------------------
Uint32 SensoryMemory::getTimeOpponentHasBeenOutOfView(Vehicle* Opponent) const {
    MemoryMap::const_iterator it = m_MemoryMap.find(Opponent);

    if (it != m_MemoryMap.end()) {
        return SDL_GetTicks() - it->second.timeLastVisible;
    }

    return (std::numeric_limits<Uint32>::max)();
}

//------------------------ GetTimeSinceLastSensed ----------------------
//
//  returns the amount of time the given bot has been visible
//-----------------------------------------------------------------------------
Uint32 SensoryMemory::getTimeSinceLastSensed(Vehicle* Opponent) const {
    MemoryMap::const_iterator it = m_MemoryMap.find(Opponent);

    if (it != m_MemoryMap.end() && it->second.withinFOV) {
        return SDL_GetTicks() - it->second.timeLastSensed;
    }

    return 0;
}
/*
//---------------------- RenderBoxesAroundRecentlySensed ----------------------
//
//  renders boxes around the opponents it has sensed recently.
//-----------------------------------------------------------------------------
void SensoryMemory::renderBoxesAroundRecentlySensed() const {
    std::list<Vehicle*> opponents = getListOfRecentlySensedOpponents();
    std::list<Vehicle*>::const_iterator it;
    for (it = opponents.begin(); it != opponents.end(); ++it) {
        gdi->OrangePen();
        glm::vec2 p = (*it)->getPosition();
        float b = (*it)->BRadius();

        gdi->Line(p.x - b, p.y - b, p.x + b, p.y - b);
        gdi->Line(p.x + b, p.y - b, p.x + b, p.y + b);
        gdi->Line(p.x + b, p.y + b, p.x - b, p.y + b);
        gdi->Line(p.x - b, p.y + b, p.x - b, p.y - b);
    }
}

*/