Browse Source

Work for HTN Vertical Slice

- Added TestWorldResourceLocator which is for locating game resources
- Added TestMovementTasks (Find Resource, Go to target, Get Resource compound)
- TestMovementComponent now more closely resembles how the actual component might behave. It's pretty awful, but the idea is there
- My initial slice isn't quite working yet; I am checking in now to make sure everything is safely in
unreal4.14
Macoy Madson 6 years ago
parent
commit
efad0448b1
  1. 147
      GalavantUnreal/Source/GalavantUnreal/GalaEntityComponents/TestMovementComponent.cpp
  2. 48
      GalavantUnreal/Source/GalavantUnreal/GalaEntityComponents/TestMovementComponent.hpp
  3. 3
      GalavantUnreal/Source/GalavantUnreal/GalavantUnreal.Build.cs
  4. 87
      GalavantUnreal/Source/GalavantUnreal/GalavantUnrealMain.cpp
  5. 19
      GalavantUnreal/Source/GalavantUnreal/GalavantUnrealMain.h
  6. 126
      GalavantUnreal/Source/GalavantUnreal/TestHtn/TestMovementTasks.cpp
  7. 71
      GalavantUnreal/Source/GalavantUnreal/TestHtn/TestMovementTasks.hpp
  8. 105
      GalavantUnreal/Source/GalavantUnreal/TestHtn/TestWorldResourceLocator.cpp
  9. 41
      GalavantUnreal/Source/GalavantUnreal/TestHtn/TestWorldResourceLocator.hpp
  10. 2
      GalavantUnreal/Source/GalavantUnreal/TestPolyVoxChunk.cpp

147
GalavantUnreal/Source/GalavantUnreal/GalaEntityComponents/TestMovementComponent.cpp

@ -3,19 +3,23 @@
#include "TestMovementComponent.hpp"
#include "RandomStream.h"
#include "entityComponentSystem/PooledComponentManager.hpp"
#include "entityComponentSystem/EntitySharedData.hpp"
TestMovementComponent::TestMovementComponent(void)
: PooledComponentManager<TestMovementComponentData>(100)
TestMovementComponent::TestMovementComponent()
: gv::PooledComponentManager<TestMovementComponentData>(100)
{
}
TestMovementComponent::~TestMovementComponent(void)
TestMovementComponent::~TestMovementComponent()
{
}
void TestMovementComponent::Initialize(ATestAgent* defaultTestActor)
void TestMovementComponent::Initialize(ATestAgent* defaultTestActor,
TestWorldResourceLocator* newResourceLocator)
{
DefaultActor = defaultTestActor;
ResourceLocator = newResourceLocator;
}
AActor* TestMovementComponent::CreateDefaultActor(FVector& location)
@ -33,26 +37,49 @@ AActor* TestMovementComponent::CreateDefaultActor(FVector& location)
void TestMovementComponent::Update(float deltaSeconds)
{
static FRandomStream randomStream;
const float SPEED = 500.f;
static FRandomStream randomStream;
PooledComponentManager::FragmentedPoolIterator it = PooledComponentManager::NULL_POOL_ITERATOR;
for (PooledComponent<TestMovementComponentData>* currentComponent = ActivePoolBegin(it);
currentComponent != nullptr && it != PooledComponentManager::NULL_POOL_ITERATOR;
std::vector<Htn::TaskEvent> eventQueue;
// TODO: Adding true iterator support to pool will drastically help damning this to hell
gv::PooledComponentManager<TestMovementComponentData>::FragmentedPoolIterator it =
gv::PooledComponentManager<TestMovementComponentData>::NULL_POOL_ITERATOR;
for (gv::PooledComponent<TestMovementComponentData>* currentComponent = ActivePoolBegin(it);
currentComponent != nullptr &&
it != gv::PooledComponentManager<TestMovementComponentData>::NULL_POOL_ITERATOR;
currentComponent = GetNextActivePooledComponent(it))
{
AActor* currentActor = currentComponent->data.Actor;
FVector& currentPosition = currentComponent->data.Position;
gv::Position& goalWorldPosition = currentComponent->data.GoalWorldPosition;
USceneComponent* sceneComponent = currentActor->GetRootComponent();
FVector worldPosition = sceneComponent->GetComponentLocation();
FVector trueWorldPosition = sceneComponent->GetComponentLocation();
FVector deltaLocation(0.f, 0.f, 0.f);
if (goalWorldPosition)
{
gv::Position currentWorldPosition(currentPosition.X, currentPosition.Y,
currentPosition.Z);
if (!currentWorldPosition.Equals(goalWorldPosition, GoalPositionTolerance))
// TODO: This fucking sucks
currentPosition =
FVector(goalWorldPosition.X, goalWorldPosition.Y, goalWorldPosition.Z);
else
{
goalWorldPosition.Reset();
Htn::TaskEvent goalPositionReachedEvent{Htn::TaskEvent::TaskResult::TaskSucceeded,
currentComponent->entity};
eventQueue.push_back(goalPositionReachedEvent);
}
}
// If the component Position doesn't match the actor's actual position, have the actor
// move towards the component Position. Otherwise, pick a random new target (show you're
// alive)
if (worldPosition.Equals(currentPosition, 100.f))
// alive). Only random walk if no goal position
else if (trueWorldPosition.Equals(currentPosition, 100.f))
{
float randomRange = 250.f;
currentPosition += FVector(randomStream.FRandRange(-randomRange, randomRange),
@ -60,33 +87,115 @@ void TestMovementComponent::Update(float deltaSeconds)
randomStream.FRandRange(-randomRange, randomRange));
}
deltaLocation = currentPosition - worldPosition;
// Give ResourceLocator our new position
if (ResourceLocator)
{
gv::Position trueGvWorldPosition(trueWorldPosition.X, trueWorldPosition.Y,
trueWorldPosition.Z);
ResourceLocator->MoveResource(WorldResourceType::Agent,
currentComponent->data.ResourcePosition,
trueGvWorldPosition);
currentComponent->data.ResourcePosition = trueGvWorldPosition;
}
deltaLocation = currentPosition - trueWorldPosition;
FVector deltaVelocity = deltaLocation.GetSafeNormal(0.1f);
deltaVelocity *= SPEED * deltaSeconds;
sceneComponent->AddLocalOffset(deltaVelocity, false, NULL, ETeleportType::None);
}
for (const Htn::TaskEvent& event : eventQueue)
{
Notify(event);
}
}
void TestMovementComponent::SubscribeEntitiesInternal(TestMovementComponentRefList& components)
void TestMovementComponent::SubscribeEntitiesInternal(const gv::EntityList& subscribers,
TestMovementComponentRefList& components)
{
gv::PositionRefList newPositionRefs;
for (TestMovementComponentRefList::iterator it = components.begin(); it != components.end();
++it)
{
PooledComponent<TestMovementComponentData>* currentComponent = (*it);
if (currentComponent && !currentComponent->data.Actor)
currentComponent->data.Actor = CreateDefaultActor(currentComponent->data.Position);
gv::PooledComponent<TestMovementComponentData>* currentComponent = (*it);
if (!currentComponent)
continue;
if (!currentComponent->data.Actor)
{
FVector newActorLocation(currentComponent->data.WorldPosition.X,
currentComponent->data.WorldPosition.Y,
currentComponent->data.WorldPosition.Z);
currentComponent->data.Actor = CreateDefaultActor(newActorLocation);
currentComponent->data.Position = newActorLocation;
}
if (ResourceLocator)
{
ResourceLocator->AddResource(WorldResourceType::Agent,
currentComponent->data.WorldPosition);
currentComponent->data.ResourcePosition = currentComponent->data.WorldPosition;
newPositionRefs.push_back(&currentComponent->data.WorldPosition);
}
}
gv::EntityCreatePositions(subscribers, newPositionRefs);
}
void TestMovementComponent::UnsubscribeEntitiesInternal(TestMovementComponentRefList& components)
void TestMovementComponent::UnsubscribeEntitiesInternal(const gv::EntityList& unsubscribers,
TestMovementComponentRefList& components)
{
for (TestMovementComponentRefList::iterator it = components.begin(); it != components.end();
++it)
{
PooledComponent<TestMovementComponentData>* currentComponent = (*it);
if (currentComponent && currentComponent->data.Actor)
gv::PooledComponent<TestMovementComponentData>* currentComponent = (*it);
if (!currentComponent)
continue;
if (currentComponent->data.Actor)
currentComponent->data.Actor->Destroy();
if (ResourceLocator)
ResourceLocator->RemoveResource(WorldResourceType::Agent,
currentComponent->data.ResourcePosition);
}
// TODO: We assume we own the positions of these entities. This could be dangerous later on
gv::EntityDestroyPositions(unsubscribers);
}
void TestMovementComponent::PathEntitiesTo(gv::EntityList& entities,
std::vector<gv::Position>& positions)
{
const gv::EntityList& subscribers = GetSubscriberList();
if (entities.empty() || entities.size() != positions.size())
return;
for (int i = 0; i < entities.size(); i++)
{
gv::Entity& entityToMove = entities[i];
gv::Position& targetPosition = positions[i];
// For now, entities which are not subscribed will be tossed out
if (std::find(subscribers.begin(), subscribers.end(), entityToMove) == subscribers.end())
continue;
gv::PooledComponentManager<TestMovementComponentData>::FragmentedPoolIterator it =
gv::PooledComponentManager<TestMovementComponentData>::NULL_POOL_ITERATOR;
for (gv::PooledComponent<TestMovementComponentData>* currentComponent = ActivePoolBegin(it);
currentComponent != nullptr &&
it != gv::PooledComponentManager<TestMovementComponentData>::NULL_POOL_ITERATOR;
currentComponent = GetNextActivePooledComponent(it))
{
if (currentComponent->entity == entityToMove)
{
currentComponent->data.GoalWorldPosition = targetPosition;
}
}
}
}

48
GalavantUnreal/Source/GalavantUnreal/GalaEntityComponents/TestMovementComponent.hpp

@ -1,14 +1,19 @@
#ifndef TESTMOVEMENTCOMPONENT_H__
#define TESTMOVEMENTCOMPONENT_H__
#pragma once
// Unreal includes
#include "GameFramework/Actor.h"
#include "TestAgent.h"
#include "../TestHtn/TestWorldResourceLocator.hpp"
// Galavant includes
#include "entityComponentSystem/ComponentManager.hpp"
#include "entityComponentSystem/PooledComponentManager.hpp"
#include "world/Position.hpp"
#include "util/SubjectObserver.hpp"
#include "ai/htn/HTNTypes.hpp"
// using namespace gv;
struct TestMovementComponentData
{
@ -16,29 +21,44 @@ struct TestMovementComponentData
AActor* Actor;
FVector Position;
gv::Position WorldPosition;
gv::Position GoalWorldPosition;
// The last position we told the ResourceLocator we were at (used so that when we move we can
// find the agent to move in ResourceLocator)
gv::Position ResourcePosition;
};
class TestMovementComponent : public PooledComponentManager<TestMovementComponentData>
class TestMovementComponent : public gv::PooledComponentManager<TestMovementComponentData>,
public gv::Subject<Htn::TaskEvent>
{
private:
EntityList Subscribers;
ATestAgent* DefaultActor;
AActor* CreateDefaultActor(FVector& location);
float GoalPositionTolerance = 100.f;
TestWorldResourceLocator* ResourceLocator;
protected:
typedef std::vector<PooledComponent<TestMovementComponentData>*> TestMovementComponentRefList;
typedef std::vector<gv::PooledComponent<TestMovementComponentData>*>
TestMovementComponentRefList;
virtual void SubscribeEntitiesInternal(TestMovementComponentRefList& components);
virtual void UnsubscribeEntitiesInternal(TestMovementComponentRefList& components);
virtual void SubscribeEntitiesInternal(const gv::EntityList& subscribers,
TestMovementComponentRefList& components);
virtual void UnsubscribeEntitiesInternal(const gv::EntityList& unsubscribers,
TestMovementComponentRefList& components);
public:
typedef std::vector<PooledComponent<TestMovementComponentData> > TestMovementComponentList;
typedef std::vector<gv::PooledComponent<TestMovementComponentData>> TestMovementComponentList;
TestMovementComponent(void);
virtual ~TestMovementComponent(void);
void Initialize(ATestAgent* defaultTestActor);
TestMovementComponent();
virtual ~TestMovementComponent();
void Initialize(ATestAgent* defaultTestActor, TestWorldResourceLocator* newResourceLocator);
virtual void Update(float deltaSeconds);
};
#endif /* end of include guard: TESTMOVEMENTCOMPONENT_H__ */
// TODO: This should return whether it was actually successful (i.e. the entity exists)
void PathEntitiesTo(gv::EntityList& entities, std::vector<gv::Position>& positions);
};

3
GalavantUnreal/Source/GalavantUnreal/GalavantUnreal.Build.cs

@ -33,6 +33,9 @@ public class GalavantUnreal : ModuleRules
var libs = new string[] {"../../ThirdParty/galavant/lib/libGalavant.a",
"../../ThirdParty/galavant/lib/thirdPartyWrapper/libGalaThirdPartyWrapper.a",
"../../ThirdParty/galavant/lib/libGalaEntityComponent.a",
"../../ThirdParty/galavant/lib/libGalaAi.a",
"../../ThirdParty/galavant/lib/libGalaWorld.a",
"../../ThirdParty/galavant/lib/libGalaGame.a",
"../../ThirdParty/polyvox/build/library/PolyVoxCore/libPolyVoxCore",
"../../ThirdParty/polyvox/build/library/PolyVoxUtil/libPolyVoxUtil"};

87
GalavantUnreal/Source/GalavantUnreal/GalavantUnrealMain.cpp

@ -6,6 +6,7 @@
#include "entityComponentSystem/EntityTypes.hpp"
// Sets default values
// TODO: This task shit is ugly :(
AGalavantUnrealMain::AGalavantUnrealMain()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if
@ -13,39 +14,86 @@ AGalavantUnrealMain::AGalavantUnrealMain()
PrimaryActorTick.bCanEverTick = true;
}
void AGalavantUnrealMain::InitializeGalavant(void)
void AGalavantUnrealMain::InitializeGalavant()
{
FVector location(0.f, 0.f, 0.f);
FRotator rotation(0.f, 0.f, 0.f);
FActorSpawnParameters spawnParams;
// Initialize TestMovementComponent
{
FVector location(0.f, 0.f, 0.f);
FRotator rotation(0.f, 0.f, 0.f);
FActorSpawnParameters spawnParams;
// ATestAgent* testAgentTemplate = (ATestAgent*)ATestAgent::StaticClass();
// ATestAgent* testAgentTemplate = (ATestAgent*)ATestAgent::StaticClass();
ATestAgent* testAgent =
(ATestAgent*)GetWorld()->SpawnActor<ATestAgent>(location, rotation, spawnParams);
ATestAgent* testAgent =
(ATestAgent*)GetWorld()->SpawnActor<ATestAgent>(location, rotation, spawnParams);
TestMovementComponentManager.Initialize(testAgent, &ResourceLocator);
}
TestMovementComponentManager.Initialize(testAgent);
// Initialize PlanComponentManager
{
PlanComponentManager.Initialize(&WorldStateManager);
}
EntityComponentSystem.AddComponentManager(&TestMovementComponentManager);
EntityComponentSystem.AddComponentManager(&PlanComponentManager);
// Initialize Tasks
{
testFindResourceTask.Initialize(&ResourceLocator);
testMoveToTask.Initialize(&TestMovementComponentManager);
testGetResourceTask.Initialize(&testFindResourceTask, &testMoveToTask);
}
// Create a couple test entities
int numTestEntities = 20;
EntityList testEntities;
gv::EntityList testEntities;
EntityComponentSystem.GetNewEntities(testEntities, numTestEntities);
TestMovementComponent::TestMovementComponentList newEntityMovementComponents;
newEntityMovementComponents.resize(numTestEntities);
int i = 0;
for (EntityListIterator it = testEntities.begin(); it != testEntities.end(); ++it)
// Add Movement components to all of them
{
newEntityMovementComponents[i].entity = (*it);
newEntityMovementComponents[i].data.Actor = nullptr;
newEntityMovementComponents[i].data.Position = FVector(0.f, i * 500.f, 0.f);
i++;
TestMovementComponent::TestMovementComponentList newEntityMovementComponents;
newEntityMovementComponents.resize(numTestEntities);
int i = 0;
for (gv::EntityListIterator it = testEntities.begin(); it != testEntities.end(); ++it)
{
newEntityMovementComponents[i].entity = (*it);
newEntityMovementComponents[i].data.Actor = nullptr;
newEntityMovementComponents[i].data.WorldPosition.Set(0.f, i * 500.f, 0.f);
i++;
}
TestMovementComponentManager.SubscribeEntities(newEntityMovementComponents);
}
TestMovementComponentManager.SubscribeEntities(newEntityMovementComponents);
// Test Plan component by adding to half of them, making their goal finding other agents
{
// Task for each agent: find another agent
Htn::Parameter resourceToFind;
resourceToFind.IntValue = WorldResourceType::Agent;
Htn::ParameterList parameters = {resourceToFind};
// TODO: Fuck this static
static Htn::Task getResourceTask(&testGetResourceTask);
Htn::TaskCall findAgentCall{&getResourceTask, parameters};
Htn::TaskCallList findAgentTasks = {findAgentCall};
gv::PlanComponentManager::PlanComponentList newPlanComponents;
newPlanComponents.resize(numTestEntities / 2);
int currentEntityIndex = 0;
for (gv::PooledComponent<gv::PlanComponentData>& currentPlanComponent : newPlanComponents)
{
currentPlanComponent.entity = testEntities[currentEntityIndex];
currentPlanComponent.data.Tasks.insert(currentPlanComponent.data.Tasks.end(),
findAgentTasks.begin(), findAgentTasks.end());
currentEntityIndex += 2;
if (currentEntityIndex > newPlanComponents.size())
break;
}
PlanComponentManager.SubscribeEntities(newPlanComponents);
}
}
// Called when the game starts or when spawned
@ -64,6 +112,7 @@ void AGalavantUnrealMain::Tick(float DeltaTime)
GalavantMain.Update(DeltaTime);
PlanComponentManager.Update(DeltaTime);
TestMovementComponentManager.Update(DeltaTime);
EntityComponentSystem.DestroyEntitiesPendingDestruction();

19
GalavantUnreal/Source/GalavantUnreal/GalavantUnrealMain.h

@ -7,9 +7,12 @@
#include "GalavantMain.hpp"
#include "entityComponentSystem/EntityComponentManager.hpp"
#include "game/agent/PlanComponentManager.hpp"
// Testing
#include "GalaEntityComponents/TestMovementComponent.hpp"
#include "TestHtn/TestMovementTasks.hpp"
#include "TestHtn/TestWorldResourceLocator.hpp"
#include "GalavantUnrealMain.generated.h"
@ -20,10 +23,22 @@ class GALAVANTUNREAL_API AGalavantUnrealMain : public AActor
gv::GalavantMain GalavantMain;
EntityComponentManager EntityComponentSystem;
// Entity Components
gv::EntityComponentManager EntityComponentSystem;
TestMovementComponent TestMovementComponentManager;
gv::PlanComponentManager PlanComponentManager;
void InitializeGalavant(void);
// World
gv::WorldStateManager WorldStateManager;
TestWorldResourceLocator ResourceLocator;
// Hierarchical Task Networks
// TODO: How should this work?
TestFindResourceTask testFindResourceTask;
TestMoveToTask testMoveToTask;
TestGetResourceTask testGetResourceTask;
void InitializeGalavant();
public:
// Sets default values for this actor's properties

126
GalavantUnreal/Source/GalavantUnreal/TestHtn/TestMovementTasks.cpp

@ -0,0 +1,126 @@
#include "GalavantUnreal.h"
#include "TestMovementTasks.hpp"
#include "world/Position.hpp"
void TestFindResourceTask::Initialize(TestWorldResourceLocator* newResourceLocator)
{
ResourceLocator = newResourceLocator;
}
bool TestFindResourceTask::StateMeetsPreconditions(const gv::WorldState& state,
const Htn::ParameterList& parameters) const
{
return parameters.size() == 1 && parameters[0].Type == Htn::Parameter::ParamType::Int &&
ResourceLocator &&
ResourceLocator->ResourceExistsInWorld((WorldResourceType)parameters[0].IntValue);
}
void TestFindResourceTask::ApplyStateChange(gv::WorldState& state,
const Htn::ParameterList& parameters)
{
// TODO: Should this be the case? Should StateMeetsPreconditions find the position? This isn't
// that much of a problem if ResourceLocator caches searches
float manhattanTo = 0.f;
gv::Position targetPosition = ResourceLocator->FindNearestResource(
(WorldResourceType)parameters[0].IntValue, state.SourceAgent.position, manhattanTo);
if (manhattanTo != -1.f)
state.SourceAgent.TargetPosition = targetPosition;
}
bool TestFindResourceTask::Execute(gv::WorldState& state, const Htn::ParameterList& parameters)
{
if (ResourceLocator)
{
float manhattanTo = 0.f;
gv::Position targetPosition = ResourceLocator->FindNearestResource(
(WorldResourceType)parameters[0].IntValue, state.SourceAgent.position, manhattanTo);
if (manhattanTo != -1.f)
{
state.SourceAgent.TargetPosition = targetPosition;
// TODO: This task finishes instantly; do we need to return Success, Fail, Running and
// add a Running() function? That'd make this observer stuff go away
return true;
}
}
return false;
}
void TestMoveToTask::Initialize(TestMovementComponent* newMovementManager)
{
MovementManager = newMovementManager;
}
bool TestMoveToTask::StateMeetsPreconditions(const gv::WorldState& state,
const Htn::ParameterList& parameters) const
{
// We're good to move to a position as long as we have a target
if (state.SourceAgent.TargetPosition)
return true;
return false;
}
void TestMoveToTask::ApplyStateChange(gv::WorldState& state, const Htn::ParameterList& parameters)
{
state.SourceAgent.position = state.SourceAgent.TargetPosition;
}
bool TestMoveToTask::Execute(gv::WorldState& state, const Htn::ParameterList& parameters)
{
if (MovementManager)
{
gv::EntityList entitiesToMove{state.SourceAgent.SourceEntity};
std::vector<gv::Position> positions{state.SourceAgent.TargetPosition};
MovementManager->PathEntitiesTo(entitiesToMove, positions);
return true;
}
return false;
}
// TODO: This isn't generic, so PlanComponentManager has no way of executing it :(
bool TestMoveToTask::ExecuteAndObserve(gv::WorldState& state, const Htn::ParameterList& parameters,
gv::Observer<Htn::TaskEvent>* observer)
{
if (Execute(state, parameters))
{
MovementManager->AddObserver(observer);
return true;
}
else
return false;
}
void TestGetResourceTask::Initialize(TestFindResourceTask* newFindResourceTask,
TestMoveToTask* newMoveToTask)
{
FindResourceTask.Initialize(newFindResourceTask);
MoveToTask.Initialize(newMoveToTask);
}
bool TestGetResourceTask::StateMeetsPreconditions(const gv::WorldState& state,
const Htn::ParameterList& parameters) const
{
// TODO: What is the purpose of the compound task checking preconditions if they'll be near
// identical to the combined primitive task preconditions?
return parameters.size() == 1 && parameters[1].Type == Htn::Parameter::ParamType::Int;
}
bool TestGetResourceTask::Decompose(Htn::TaskCallList& taskCallList, const gv::WorldState& state,
const Htn::ParameterList& parameters)
{
Htn::ParameterList findResourceParams = parameters;
Htn::ParameterList moveToParams;
Htn::TaskCall FindResourceTaskCall{&FindResourceTask, findResourceParams};
Htn::TaskCall MoveToTaskCall{&MoveToTask, moveToParams};
// TODO: Make it clear that users should only ever push to this list
taskCallList.push_back(FindResourceTaskCall);
taskCallList.push_back(MoveToTaskCall);
return true;
}

71
GalavantUnreal/Source/GalavantUnreal/TestHtn/TestMovementTasks.hpp

@ -0,0 +1,71 @@
#pragma once
#include "TestWorldResourceLocator.hpp"
#include "../GalaEntityComponents/TestMovementComponent.hpp"
#include "ai/htn/HTNTypes.hpp"
#include "ai/htn/HTNTasks.hpp"
#include "ai/WorldState.hpp"
#include "util/SubjectObserver.hpp"
// Parameters:
// [0]: Resource type (int)
class TestFindResourceTask : public Htn::PrimitiveTask
{
private:
TestWorldResourceLocator* ResourceLocator;
public:
TestFindResourceTask() = default;
virtual ~TestFindResourceTask() = default;
void Initialize(TestWorldResourceLocator* newResourceLocator);
virtual bool StateMeetsPreconditions(const gv::WorldState& state,
const Htn::ParameterList& parameters) const;
virtual void ApplyStateChange(gv::WorldState& state, const Htn::ParameterList& parameters);
virtual bool Execute(gv::WorldState& state, const Htn::ParameterList& parameters);
bool ExecuteAndObserve(gv::WorldState& state, const Htn::ParameterList& parameters,
gv::Observer<Htn::TaskEvent>* observer);
};
// Parameters:
// None - Entity to move and target come from world state
class TestMoveToTask : public Htn::PrimitiveTask
{
private:
TestMovementComponent* MovementManager;
public:
TestMoveToTask() = default;
virtual ~TestMoveToTask() = default;
void Initialize(TestMovementComponent* newMovementManager);
virtual bool StateMeetsPreconditions(const gv::WorldState& state,
const Htn::ParameterList& parameters) const;
virtual void ApplyStateChange(gv::WorldState& state, const Htn::ParameterList& parameters);
virtual bool Execute(gv::WorldState& state, const Htn::ParameterList& parameters);
bool ExecuteAndObserve(gv::WorldState& state, const Htn::ParameterList& parameters,
gv::Observer<Htn::TaskEvent>* observer);
};
// Parameters:
// [0]: Resource type (int)
class TestGetResourceTask : public Htn::CompoundTask
{
private:
// Should this be how it is? Should tasks be singletons?
Htn::Task FindResourceTask;
Htn::Task MoveToTask;
public:
TestGetResourceTask() = default;
virtual ~TestGetResourceTask() = default;
void Initialize(TestFindResourceTask* newFindResourceTask, TestMoveToTask* newMoveToTask);
virtual bool StateMeetsPreconditions(const gv::WorldState& state,
const Htn::ParameterList& parameters) const;
virtual bool Decompose(Htn::TaskCallList& taskCallList, const gv::WorldState& state,
const Htn::ParameterList& parameters);
};

105
GalavantUnreal/Source/GalavantUnreal/TestHtn/TestWorldResourceLocator.cpp

@ -0,0 +1,105 @@
#include "GalavantUnreal.h"
#include "TestWorldResourceLocator.hpp"
#include <limits>
TestWorldResourceLocator::~TestWorldResourceLocator()
{
for (std::pair<const WorldResourceType, ResourceList*>& resourceTypeList : Resources)
{
delete resourceTypeList.second;
}
Resources.clear();
}
bool TestWorldResourceLocator::ResourceListExists(const WorldResourceType type) const
{
return Resources.find(type) != Resources.end();
}
bool TestWorldResourceLocator::ResourceExistsInWorld(const WorldResourceType type)
{
return ResourceListExists(type) && !Resources[type]->empty();
}
void TestWorldResourceLocator::AddResource(const WorldResourceType type,
const gv::Position& location)
{
gv::Position newResource(location);
// Ensure we're not exactly 0,0,0 because I designed this poorly
newResource.Z = !newResource ? 0.1f : newResource.Z;
if (ResourceListExists(type))
{
Resources[type]->push_back(newResource);
}
else
{
ResourceList* newResourceList = new ResourceList;
newResourceList->push_back(newResource);
Resources[type] = newResourceList;
}
}
void TestWorldResourceLocator::RemoveResource(const WorldResourceType type,
const gv::Position& location)
{
if (ResourceListExists(type))
{
ResourceList* resourceList = Resources[type];
ResourceList::iterator resourceIt =
std::find(resourceList->begin(), resourceList->end(), location);
if (resourceIt != resourceList->end())
resourceList->erase(resourceIt);
}
}
void TestWorldResourceLocator::MoveResource(const WorldResourceType type,
const gv::Position& oldLocation,
const gv::Position& newLocation)
{
if (ResourceListExists(type))
{
for (gv::Position& currentResource : *Resources[type])
{
// They should be exactly equal. It's the caller's responsibility to keep track of this
if (currentResource.Equals(oldLocation, 0.f))
{
currentResource = newLocation;
// Ensure we're not exactly 0,0,0 because I designed this poorly
currentResource.Z = !currentResource ? 0.1f : currentResource.Z;
break;
}
}
}
}
// Find the nearest resource. Uses Manhattan distance
// Manhattan distance of -1 indicates no resource was found
gv::Position TestWorldResourceLocator::FindNearestResource(const WorldResourceType type,
const gv::Position& location,
float& manhattanToOut)
{
gv::Position zeroPosition;
if (ResourceListExists(type))
{
gv::Position closestResource;
float closestResourceDistance = std::numeric_limits<float>::max();
for (gv::Position& currentResource : *Resources[type])
{
float currentResourceDistance = location.ManhattanTo(currentResource);
if (currentResourceDistance < closestResourceDistance)
{
closestResourceDistance = currentResourceDistance;
closestResource = currentResource;
}
}
manhattanToOut = closestResourceDistance;
return closestResource;
}
manhattanToOut = -1.f;
return zeroPosition;
}

41
GalavantUnreal/Source/GalavantUnreal/TestHtn/TestWorldResourceLocator.hpp

@ -0,0 +1,41 @@
#pragma once
#include <map>
#include <vector>
#include "world/Position.hpp"
enum WorldResourceType
{
None = 0,
Agent = 1,
BusStop = 2
};
// This is for testing only and will not be used in the final game
class TestWorldResourceLocator
{
private:
typedef std::vector<gv::Position> ResourceList;
typedef std::map<WorldResourceType, ResourceList*> ResourceMap;
ResourceMap Resources;
bool ResourceListExists(const WorldResourceType type) const;
public:
TestWorldResourceLocator() = default;
~TestWorldResourceLocator();
bool ResourceExistsInWorld(const WorldResourceType type);
void AddResource(const WorldResourceType type, const gv::Position& location);
void RemoveResource(const WorldResourceType type, const gv::Position& location);
void MoveResource(const WorldResourceType type, const gv::Position& oldLocation,
const gv::Position& newLocation);
// Find the nearest resource. Uses Manhattan distance
// Manhattan distance of -1 indicates no resource was found
gv::Position FindNearestResource(const WorldResourceType type, const gv::Position& location,
float& manhattanToOut);
};

2
GalavantUnreal/Source/GalavantUnreal/TestPolyVoxChunk.cpp

@ -494,7 +494,7 @@ ATestPolyVoxChunk::ATestPolyVoxChunk() : LastUpdatedPosition(0.f, 0.f, 0.f) //,
SetActorEnableCollision(true);
}
void ATestPolyVoxChunk::Destroyed(void)
void ATestPolyVoxChunk::Destroyed()
{
FlushPersistentDebugLines(GetWorld());
}

Loading…
Cancel
Save