mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-07 11:22:45 +01:00
clang-format files in rwengine/src/ai
This commit is contained in:
parent
9aa3af6703
commit
d5e853d23f
@ -1,116 +1,116 @@
|
|||||||
#include "ai/AIGraph.hpp"
|
#include "ai/AIGraph.hpp"
|
||||||
#include <objects/GameObject.hpp>
|
|
||||||
#include <ai/AIGraphNode.hpp>
|
#include <ai/AIGraphNode.hpp>
|
||||||
#include <glm/gtx/norm.hpp>
|
#include <glm/gtx/norm.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <objects/GameObject.hpp>
|
||||||
|
|
||||||
AIGraph::~AIGraph()
|
AIGraph::~AIGraph() {
|
||||||
{
|
for (auto n : nodes) {
|
||||||
for( auto n : nodes ) {
|
delete n;
|
||||||
delete n;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIGraph::createPathNodes(const glm::vec3& position, const glm::quat& rotation, PathData& path)
|
void AIGraph::createPathNodes(const glm::vec3& position,
|
||||||
{
|
const glm::quat& rotation, PathData& path) {
|
||||||
size_t startIndex = nodes.size();
|
size_t startIndex = nodes.size();
|
||||||
std::vector<AIGraphNode*> pathNodes;
|
std::vector<AIGraphNode*> pathNodes;
|
||||||
pathNodes.reserve(path.nodes.size());
|
pathNodes.reserve(path.nodes.size());
|
||||||
|
|
||||||
for( size_t n = 0; n < path.nodes.size(); ++n ) {
|
for (size_t n = 0; n < path.nodes.size(); ++n) {
|
||||||
auto& node = path.nodes[n];
|
auto& node = path.nodes[n];
|
||||||
AIGraphNode* ainode = nullptr;
|
AIGraphNode* ainode = nullptr;
|
||||||
glm::vec3 nodePosition = position + (rotation * node.position);
|
glm::vec3 nodePosition = position + (rotation * node.position);
|
||||||
|
|
||||||
if( node.type == PathNode::EXTERNAL ) {
|
if (node.type == PathNode::EXTERNAL) {
|
||||||
for( size_t rn = 0; rn < externalNodes.size(); ++rn ) {
|
for (size_t rn = 0; rn < externalNodes.size(); ++rn) {
|
||||||
auto& realNode = externalNodes[rn];
|
auto& realNode = externalNodes[rn];
|
||||||
auto d = glm::distance2(realNode->position, nodePosition);
|
auto d = glm::distance2(realNode->position, nodePosition);
|
||||||
if( d < 1.f ) {
|
if (d < 1.f) {
|
||||||
pathNodes.push_back(realNode);
|
pathNodes.push_back(realNode);
|
||||||
ainode = realNode;
|
ainode = realNode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ainode == nullptr ) {
|
|
||||||
ainode = new AIGraphNode;
|
|
||||||
ainode->type = (path.type == PathData::PATH_PED ? AIGraphNode::Pedestrian : AIGraphNode::Vehicle);
|
|
||||||
ainode->nextIndex = node.next >= 0 ? startIndex + node.next : -1;
|
|
||||||
ainode->flags = AIGraphNode::None;
|
|
||||||
ainode->size = node.size;
|
|
||||||
ainode->other_thing = node.other_thing;
|
|
||||||
ainode->other_thing2 = node.other_thing2;
|
|
||||||
ainode->position = nodePosition;
|
|
||||||
ainode->external = node.type == PathNode::EXTERNAL;
|
|
||||||
ainode->disabled = false;
|
|
||||||
|
|
||||||
pathNodes.push_back(ainode);
|
if (ainode == nullptr) {
|
||||||
nodes.push_back(ainode);
|
ainode = new AIGraphNode;
|
||||||
|
ainode->type =
|
||||||
|
(path.type == PathData::PATH_PED ? AIGraphNode::Pedestrian
|
||||||
|
: AIGraphNode::Vehicle);
|
||||||
|
ainode->nextIndex = node.next >= 0 ? startIndex + node.next : -1;
|
||||||
|
ainode->flags = AIGraphNode::None;
|
||||||
|
ainode->size = node.size;
|
||||||
|
ainode->other_thing = node.other_thing;
|
||||||
|
ainode->other_thing2 = node.other_thing2;
|
||||||
|
ainode->position = nodePosition;
|
||||||
|
ainode->external = node.type == PathNode::EXTERNAL;
|
||||||
|
ainode->disabled = false;
|
||||||
|
|
||||||
if( ainode->external )
|
pathNodes.push_back(ainode);
|
||||||
{
|
nodes.push_back(ainode);
|
||||||
externalNodes.push_back(ainode);
|
|
||||||
|
|
||||||
// Determine which grid cell this node falls into
|
|
||||||
float lowerCoord = -(WORLD_GRID_SIZE)/2.f;
|
|
||||||
auto gridrel = glm::vec2(ainode->position) - glm::vec2(lowerCoord, lowerCoord);
|
|
||||||
auto gridcoord = glm::floor(gridrel / glm::vec2(WORLD_CELL_SIZE));
|
|
||||||
if( gridcoord.x < 0 || gridcoord.y < 0 || gridcoord.x >= WORLD_GRID_WIDTH || gridcoord.y >= WORLD_GRID_WIDTH )
|
|
||||||
{
|
|
||||||
std::cout << "Warning: Node outside of grid at coord " << gridcoord.x << " " << gridcoord.y << std::endl;
|
|
||||||
}
|
|
||||||
auto index = (gridcoord.x * WORLD_GRID_WIDTH) + gridcoord.y;
|
|
||||||
gridNodes[index].push_back(ainode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t pn = 0; pn < path.nodes.size(); ++pn) {
|
if (ainode->external) {
|
||||||
if(path.nodes[pn].next >= 0 && (unsigned) path.nodes[pn].next < pathNodes.size()) {
|
externalNodes.push_back(ainode);
|
||||||
auto node = pathNodes[pn];
|
|
||||||
auto next = pathNodes[path.nodes[pn].next];
|
// Determine which grid cell this node falls into
|
||||||
|
float lowerCoord = -(WORLD_GRID_SIZE) / 2.f;
|
||||||
node->connections.push_back(next);
|
auto gridrel = glm::vec2(ainode->position) -
|
||||||
next->connections.push_back(node);
|
glm::vec2(lowerCoord, lowerCoord);
|
||||||
}
|
auto gridcoord =
|
||||||
}
|
glm::floor(gridrel / glm::vec2(WORLD_CELL_SIZE));
|
||||||
|
if (gridcoord.x < 0 || gridcoord.y < 0 ||
|
||||||
|
gridcoord.x >= WORLD_GRID_WIDTH ||
|
||||||
|
gridcoord.y >= WORLD_GRID_WIDTH) {
|
||||||
|
std::cout << "Warning: Node outside of grid at coord "
|
||||||
|
<< gridcoord.x << " " << gridcoord.y << std::endl;
|
||||||
|
}
|
||||||
|
auto index = (gridcoord.x * WORLD_GRID_WIDTH) + gridcoord.y;
|
||||||
|
gridNodes[index].push_back(ainode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t pn = 0; pn < path.nodes.size(); ++pn) {
|
||||||
|
if (path.nodes[pn].next >= 0 &&
|
||||||
|
(unsigned)path.nodes[pn].next < pathNodes.size()) {
|
||||||
|
auto node = pathNodes[pn];
|
||||||
|
auto next = pathNodes[path.nodes[pn].next];
|
||||||
|
|
||||||
|
node->connections.push_back(next);
|
||||||
|
next->connections.push_back(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::ivec2 worldToGrid(const glm::vec2& world)
|
glm::ivec2 worldToGrid(const glm::vec2& world) {
|
||||||
{
|
static const float lowerCoord = -(WORLD_GRID_SIZE) / 2.f;
|
||||||
static const float lowerCoord = -(WORLD_GRID_SIZE)/2.f;
|
return glm::ivec2((world - glm::vec2(lowerCoord)) /
|
||||||
return glm::ivec2((world - glm::vec2(lowerCoord)) / glm::vec2(WORLD_CELL_SIZE));
|
glm::vec2(WORLD_CELL_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIGraph::gatherExternalNodesNear(const glm::vec3& center, const float radius, std::vector< AIGraphNode* >& nodes)
|
void AIGraph::gatherExternalNodesNear(const glm::vec3& center,
|
||||||
{
|
const float radius,
|
||||||
// the bounds end up covering more than might fit
|
std::vector<AIGraphNode*>& nodes) {
|
||||||
auto planecoords = glm::vec2(center);
|
// the bounds end up covering more than might fit
|
||||||
auto minWorld = planecoords - glm::vec2(radius);
|
auto planecoords = glm::vec2(center);
|
||||||
auto maxWorld = planecoords + glm::vec2(radius);
|
auto minWorld = planecoords - glm::vec2(radius);
|
||||||
auto minGrid = worldToGrid(minWorld);
|
auto maxWorld = planecoords + glm::vec2(radius);
|
||||||
auto maxGrid = worldToGrid(maxWorld);
|
auto minGrid = worldToGrid(minWorld);
|
||||||
|
auto maxGrid = worldToGrid(maxWorld);
|
||||||
|
|
||||||
for( int x = minGrid.x; x <= maxGrid.x; ++x )
|
for (int x = minGrid.x; x <= maxGrid.x; ++x) {
|
||||||
{
|
for (int y = minGrid.y; y <= maxGrid.y; ++y) {
|
||||||
for( int y = minGrid.y; y <= maxGrid.y; ++y )
|
int i = (x * WORLD_GRID_WIDTH) + y;
|
||||||
{
|
if (i < 0 || i >= (int)gridNodes.size()) {
|
||||||
int i = (x * WORLD_GRID_WIDTH) + y;
|
continue;
|
||||||
if( i < 0 || i >= (int)gridNodes.size() )
|
}
|
||||||
{
|
auto& external = gridNodes[i];
|
||||||
continue;
|
for (AIGraphNode* node : external) {
|
||||||
}
|
if (glm::distance2(center, node->position) < radius * radius) {
|
||||||
auto& external = gridNodes[i];
|
nodes.push_back(node);
|
||||||
for ( AIGraphNode* node : external )
|
}
|
||||||
{
|
}
|
||||||
if ( glm::distance2( center, node->position ) < radius*radius )
|
}
|
||||||
{
|
}
|
||||||
nodes.push_back( node );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,37 +1,37 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifndef _AIGRAPH_HPP_
|
#ifndef _AIGRAPH_HPP_
|
||||||
#define _AIGRAPH_HPP_
|
#define _AIGRAPH_HPP_
|
||||||
#include <vector>
|
|
||||||
#include <glm/gtc/quaternion.hpp>
|
|
||||||
#include <data/PathData.hpp>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <data/PathData.hpp>
|
||||||
|
#include <glm/gtc/quaternion.hpp>
|
||||||
#include <rw/types.hpp>
|
#include <rw/types.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
struct AIGraphNode;
|
struct AIGraphNode;
|
||||||
|
|
||||||
class AIGraph
|
class AIGraph {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
~AIGraph();
|
||||||
|
|
||||||
~AIGraph();
|
std::vector<AIGraphNode*> nodes;
|
||||||
|
|
||||||
std::vector<AIGraphNode*> nodes;
|
/**
|
||||||
|
* List of external nodes, which are links between each
|
||||||
|
* Instance's paths and where new pedestrians and vehicles
|
||||||
|
* are spawned
|
||||||
|
*/
|
||||||
|
std::vector<AIGraphNode*> externalNodes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of external nodes, which are links between each
|
* Stores the external AI Grid Nodes organised by world grid cell
|
||||||
* Instance's paths and where new pedestrians and vehicles
|
*/
|
||||||
* are spawned
|
std::array<std::vector<AIGraphNode*>, WORLD_GRID_CELLS> gridNodes;
|
||||||
*/
|
|
||||||
std::vector<AIGraphNode*> externalNodes;
|
|
||||||
|
|
||||||
/**
|
void createPathNodes(const glm::vec3& position, const glm::quat& rotation,
|
||||||
* Stores the external AI Grid Nodes organised by world grid cell
|
PathData& path);
|
||||||
*/
|
|
||||||
std::array<std::vector<AIGraphNode*>,WORLD_GRID_CELLS> gridNodes;
|
|
||||||
|
|
||||||
void createPathNodes(const glm::vec3& position, const glm::quat& rotation, PathData& path);
|
void gatherExternalNodesNear(const glm::vec3& center, const float radius,
|
||||||
|
std::vector<AIGraphNode*>& nodes);
|
||||||
void gatherExternalNodesNear(const glm::vec3& center, const float radius, std::vector<AIGraphNode*>& nodes);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,35 +1,32 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifndef _AIGRAPHNODE_HPP_
|
#ifndef _AIGRAPHNODE_HPP_
|
||||||
#define _AIGRAPHNODE_HPP_
|
#define _AIGRAPHNODE_HPP_
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct AIGraphNode
|
struct AIGraphNode {
|
||||||
{
|
enum NodeType { Vehicle, Pedestrian };
|
||||||
enum NodeType {
|
|
||||||
Vehicle,
|
|
||||||
Pedestrian
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
None = 0,
|
None = 0,
|
||||||
CrossesRoad = 1 /// No documentation for other flags yet, but this is mentioned.
|
CrossesRoad =
|
||||||
|
1 /// No documentation for other flags yet, but this is mentioned.
|
||||||
};
|
};
|
||||||
|
|
||||||
NodeType type;
|
NodeType type;
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
float size;
|
float size;
|
||||||
int other_thing;
|
int other_thing;
|
||||||
int other_thing2;
|
int other_thing2;
|
||||||
bool external;
|
bool external;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
|
|
||||||
int32_t nextIndex;
|
int32_t nextIndex;
|
||||||
|
|
||||||
bool disabled;
|
bool disabled;
|
||||||
|
|
||||||
std::vector<AIGraphNode*> connections;
|
std::vector<AIGraphNode*> connections;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
#include <btBulletDynamicsCommon.h>
|
||||||
#include <ai/CharacterController.hpp>
|
#include <ai/CharacterController.hpp>
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/VehicleObject.hpp>
|
#include <objects/VehicleObject.hpp>
|
||||||
#include <btBulletDynamicsCommon.h>
|
|
||||||
|
|
||||||
#include <data/Model.hpp>
|
#include <data/Model.hpp>
|
||||||
#include <engine/Animator.hpp>
|
#include <engine/Animator.hpp>
|
||||||
@ -10,504 +10,477 @@
|
|||||||
|
|
||||||
constexpr float kCloseDoorIdleTime = 2.f;
|
constexpr float kCloseDoorIdleTime = 2.f;
|
||||||
|
|
||||||
CharacterController::CharacterController(CharacterObject* character)
|
CharacterController::CharacterController(CharacterObject *character)
|
||||||
: character(character)
|
: character(character)
|
||||||
, _currentActivity(nullptr)
|
, _currentActivity(nullptr)
|
||||||
, _nextActivity(nullptr)
|
, _nextActivity(nullptr)
|
||||||
, m_closeDoorTimer(0.f)
|
, m_closeDoorTimer(0.f)
|
||||||
, currentGoal(None)
|
, currentGoal(None)
|
||||||
, leader(nullptr)
|
, leader(nullptr)
|
||||||
, targetNode(nullptr)
|
, targetNode(nullptr) {
|
||||||
{
|
character->controller = this;
|
||||||
character->controller = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterController::updateActivity()
|
bool CharacterController::updateActivity() {
|
||||||
{
|
if (_currentActivity && character->isAlive()) {
|
||||||
if( _currentActivity && character->isAlive() ) {
|
return _currentActivity->update(character, this);
|
||||||
return _currentActivity->update(character, this);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setActivity(CharacterController::Activity* activity)
|
void CharacterController::setActivity(CharacterController::Activity *activity) {
|
||||||
{
|
if (_currentActivity) delete _currentActivity;
|
||||||
if( _currentActivity ) delete _currentActivity;
|
_currentActivity = activity;
|
||||||
_currentActivity = activity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::skipActivity()
|
void CharacterController::skipActivity() {
|
||||||
{
|
// Some activities can't be cancelled, such as the final phase of entering a
|
||||||
// Some activities can't be cancelled, such as the final phase of entering a vehicle
|
// vehicle
|
||||||
// or jumping.
|
// or jumping.
|
||||||
if (getCurrentActivity() != nullptr &&
|
if (getCurrentActivity() != nullptr &&
|
||||||
getCurrentActivity()->canSkip(character, this))
|
getCurrentActivity()->canSkip(character, this))
|
||||||
setActivity(nullptr);
|
setActivity(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setNextActivity(CharacterController::Activity* activity)
|
void CharacterController::setNextActivity(
|
||||||
{
|
CharacterController::Activity *activity) {
|
||||||
if( _currentActivity == nullptr ) {
|
if (_currentActivity == nullptr) {
|
||||||
setActivity(activity);
|
setActivity(activity);
|
||||||
_nextActivity = nullptr;
|
_nextActivity = nullptr;
|
||||||
}
|
} else {
|
||||||
else {
|
if (_nextActivity) delete _nextActivity;
|
||||||
if(_nextActivity) delete _nextActivity;
|
_nextActivity = activity;
|
||||||
_nextActivity = activity;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterController::isCurrentActivity(const std::string& activity) const
|
bool CharacterController::isCurrentActivity(const std::string &activity) const {
|
||||||
{
|
if (getCurrentActivity() == nullptr) return false;
|
||||||
if (getCurrentActivity() == nullptr) return false;
|
return getCurrentActivity()->name() == activity;
|
||||||
return getCurrentActivity()->name() == activity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::update(float dt)
|
void CharacterController::update(float dt) {
|
||||||
{
|
if (character->getCurrentVehicle()) {
|
||||||
if( character->getCurrentVehicle() ) {
|
// Nevermind, the player is in a vehicle.
|
||||||
// Nevermind, the player is in a vehicle.
|
|
||||||
|
|
||||||
auto& d = character->getMovement();
|
auto &d = character->getMovement();
|
||||||
|
|
||||||
if( character->getCurrentSeat() == 0 )
|
if (character->getCurrentSeat() == 0) {
|
||||||
{
|
character->getCurrentVehicle()->setSteeringAngle(d.y);
|
||||||
character->getCurrentVehicle()->setSteeringAngle(d.y);
|
|
||||||
|
|
||||||
if( std::abs(d.x) > 0.01f )
|
|
||||||
{
|
|
||||||
character->getCurrentVehicle()->setHandbraking(false);
|
|
||||||
}
|
|
||||||
character->getCurrentVehicle()->setThrottle(d.x);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _currentActivity == nullptr ) {
|
if (std::abs(d.x) > 0.01f) {
|
||||||
// If character is idle in vehicle, try to close the door.
|
character->getCurrentVehicle()->setHandbraking(false);
|
||||||
auto v = character->getCurrentVehicle();
|
}
|
||||||
auto entryDoor = v->getSeatEntryDoor(character->getCurrentSeat());
|
character->getCurrentVehicle()->setThrottle(d.x);
|
||||||
|
}
|
||||||
|
|
||||||
if (entryDoor && entryDoor->constraint) {
|
if (_currentActivity == nullptr) {
|
||||||
if (glm::length( d ) <= 0.1f) {
|
// If character is idle in vehicle, try to close the door.
|
||||||
if (m_closeDoorTimer >= kCloseDoorIdleTime) {
|
auto v = character->getCurrentVehicle();
|
||||||
character->getCurrentVehicle()->setPartTarget(entryDoor, true, entryDoor->closedAngle);
|
auto entryDoor = v->getSeatEntryDoor(character->getCurrentSeat());
|
||||||
}
|
|
||||||
m_closeDoorTimer += dt;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_closeDoorTimer = 0.f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_closeDoorTimer = 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( updateActivity() ) {
|
if (entryDoor && entryDoor->constraint) {
|
||||||
character->activityFinished();
|
if (glm::length(d) <= 0.1f) {
|
||||||
if( _currentActivity ) {
|
if (m_closeDoorTimer >= kCloseDoorIdleTime) {
|
||||||
delete _currentActivity;
|
character->getCurrentVehicle()->setPartTarget(
|
||||||
_currentActivity = nullptr;
|
entryDoor, true, entryDoor->closedAngle);
|
||||||
}
|
}
|
||||||
if( _nextActivity ) {
|
m_closeDoorTimer += dt;
|
||||||
setActivity( _nextActivity );
|
} else {
|
||||||
_nextActivity = nullptr;
|
m_closeDoorTimer = 0.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_closeDoorTimer = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateActivity()) {
|
||||||
|
character->activityFinished();
|
||||||
|
if (_currentActivity) {
|
||||||
|
delete _currentActivity;
|
||||||
|
_currentActivity = nullptr;
|
||||||
|
}
|
||||||
|
if (_nextActivity) {
|
||||||
|
setActivity(_nextActivity);
|
||||||
|
_nextActivity = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterObject *CharacterController::getCharacter() const
|
CharacterObject *CharacterController::getCharacter() const {
|
||||||
{
|
return character;
|
||||||
return character;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setMoveDirection(const glm::vec3 &movement)
|
void CharacterController::setMoveDirection(const glm::vec3 &movement) {
|
||||||
{
|
character->setMovement(movement);
|
||||||
character->setMovement(movement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setLookDirection(const glm::vec2 &look)
|
void CharacterController::setLookDirection(const glm::vec2 &look) {
|
||||||
{
|
character->setLook(look);
|
||||||
character->setLook(look);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setRunning(bool run)
|
void CharacterController::setRunning(bool run) {
|
||||||
{
|
character->setRunning(run);
|
||||||
character->setRunning(run);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Activities::GoTo::update(CharacterObject *character,
|
||||||
|
CharacterController *controller) {
|
||||||
|
/* TODO: Use the ai nodes to navigate to the position */
|
||||||
|
auto cpos = character->getPosition();
|
||||||
|
glm::vec3 targetDirection = target - cpos;
|
||||||
|
|
||||||
bool Activities::GoTo::update(CharacterObject *character, CharacterController *controller)
|
// Ignore vertical axis for the sake of simplicity.
|
||||||
{
|
if (glm::length(glm::vec2(targetDirection)) < 0.1f) {
|
||||||
/* TODO: Use the ai nodes to navigate to the position */
|
character->setPosition(glm::vec3(glm::vec2(target), cpos.z));
|
||||||
auto cpos = character->getPosition();
|
controller->setMoveDirection({0.f, 0.f, 0.f});
|
||||||
glm::vec3 targetDirection = target - cpos;
|
character->controller->setRunning(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore vertical axis for the sake of simplicity.
|
float hdg =
|
||||||
if( glm::length(glm::vec2(targetDirection)) < 0.1f ) {
|
atan2(targetDirection.y, targetDirection.x) - glm::half_pi<float>();
|
||||||
character->setPosition(glm::vec3(glm::vec2(target), cpos.z));
|
character->setHeading(glm::degrees(hdg));
|
||||||
controller->setMoveDirection({0.f, 0.f, 0.f});
|
|
||||||
character->controller->setRunning(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float hdg = atan2(targetDirection.y, targetDirection.x) - glm::half_pi<float>();
|
controller->setMoveDirection({1.f, 0.f, 0.f});
|
||||||
character->setHeading(glm::degrees(hdg));
|
controller->setRunning(sprint);
|
||||||
|
|
||||||
controller->setMoveDirection({1.f, 0.f, 0.f});
|
return false;
|
||||||
controller->setRunning(sprint);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Activities::Jump::update(CharacterObject* character, CharacterController* controller)
|
bool Activities::Jump::update(CharacterObject *character,
|
||||||
{
|
CharacterController *controller) {
|
||||||
RW_UNUSED(controller);
|
RW_UNUSED(controller);
|
||||||
if (character->physCharacter == nullptr) return true;
|
if (character->physCharacter == nullptr) return true;
|
||||||
|
|
||||||
if( !jumped )
|
if (!jumped) {
|
||||||
{
|
character->jump();
|
||||||
character->jump();
|
jumped = true;
|
||||||
jumped = true;
|
} else {
|
||||||
}
|
if (character->physCharacter->canJump()) {
|
||||||
else
|
return true;
|
||||||
{
|
}
|
||||||
if (character->physCharacter->canJump()) {
|
}
|
||||||
return true;
|
|
||||||
}
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Activities::EnterVehicle::canSkip(CharacterObject *character, CharacterController *) const
|
bool Activities::EnterVehicle::canSkip(CharacterObject *character,
|
||||||
{
|
CharacterController *) const {
|
||||||
// If we're already inside the vehicle, it can't helped.
|
// If we're already inside the vehicle, it can't helped.
|
||||||
return character->getCurrentVehicle() == nullptr;
|
return character->getCurrentVehicle() == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Activities::EnterVehicle::update(CharacterObject *character, CharacterController *controller)
|
bool Activities::EnterVehicle::update(CharacterObject *character,
|
||||||
{
|
CharacterController *controller) {
|
||||||
constexpr float kSprintToEnterDistance = 5.f;
|
constexpr float kSprintToEnterDistance = 5.f;
|
||||||
constexpr float kGiveUpDistance = 100.f;
|
constexpr float kGiveUpDistance = 100.f;
|
||||||
|
|
||||||
RW_UNUSED(controller);
|
RW_UNUSED(controller);
|
||||||
|
|
||||||
// Boats don't have any kind of entry animation unless you're onboard.
|
// Boats don't have any kind of entry animation unless you're onboard.
|
||||||
if( vehicle->vehicle->type == VehicleData::BOAT ) {
|
if (vehicle->vehicle->type == VehicleData::BOAT) {
|
||||||
character->enterVehicle(vehicle, seat);
|
character->enterVehicle(vehicle, seat);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( seat == ANY_SEAT )
|
|
||||||
{
|
|
||||||
// Determine which seat to take.
|
|
||||||
float nearest = std::numeric_limits<float>::max();
|
|
||||||
for(unsigned int s = 1; s < vehicle->info->seats.size(); ++s)
|
|
||||||
{
|
|
||||||
auto entry = vehicle->getSeatEntryPositionWorld(s);
|
|
||||||
float dist = glm::distance(entry, character->getPosition());
|
|
||||||
if( dist < nearest )
|
|
||||||
{
|
|
||||||
seat = s;
|
|
||||||
nearest = dist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto entryDoor = vehicle->getSeatEntryDoor(seat);
|
|
||||||
auto entryPos = vehicle->getSeatEntryPositionWorld(seat);
|
|
||||||
auto entryPosLocal = vehicle->getSeatEntryPosition(seat);
|
|
||||||
|
|
||||||
auto anm_open = character->animations.car_open_lhs;
|
if (seat == ANY_SEAT) {
|
||||||
auto anm_enter = character->animations.car_getin_lhs;
|
// Determine which seat to take.
|
||||||
auto anm_pullout = character->animations.car_pullout_lhs;
|
float nearest = std::numeric_limits<float>::max();
|
||||||
|
for (unsigned int s = 1; s < vehicle->info->seats.size(); ++s) {
|
||||||
|
auto entry = vehicle->getSeatEntryPositionWorld(s);
|
||||||
|
float dist = glm::distance(entry, character->getPosition());
|
||||||
|
if (dist < nearest) {
|
||||||
|
seat = s;
|
||||||
|
nearest = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( entryPosLocal.x > 0.f )
|
auto entryDoor = vehicle->getSeatEntryDoor(seat);
|
||||||
{
|
auto entryPos = vehicle->getSeatEntryPositionWorld(seat);
|
||||||
anm_open = character->animations.car_open_rhs;
|
auto entryPosLocal = vehicle->getSeatEntryPosition(seat);
|
||||||
anm_enter = character->animations.car_getin_rhs;
|
|
||||||
anm_pullout = character->animations.car_pullout_rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's someone in this seat already, we may have to ask them to leave.
|
auto anm_open = character->animations.car_open_lhs;
|
||||||
auto currentOccupant= static_cast<CharacterObject*>(vehicle->getOccupant(seat));
|
auto anm_enter = character->animations.car_getin_lhs;
|
||||||
|
auto anm_pullout = character->animations.car_pullout_lhs;
|
||||||
|
|
||||||
bool tryToEnter = false;
|
if (entryPosLocal.x > 0.f) {
|
||||||
|
anm_open = character->animations.car_open_rhs;
|
||||||
if( entering ) {
|
anm_enter = character->animations.car_getin_rhs;
|
||||||
if( character->animator->getAnimation(AnimIndexAction) == anm_open ) {
|
anm_pullout = character->animations.car_pullout_rhs;
|
||||||
if( character->animator->isCompleted(AnimIndexAction) ) {
|
}
|
||||||
tryToEnter = true;
|
|
||||||
}
|
|
||||||
else if( entryDoor && character->animator->getAnimationTime(AnimIndexAction) >= 0.5f )
|
|
||||||
{
|
|
||||||
vehicle->setPartTarget(entryDoor, true, entryDoor->openAngle);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//character->setPosition(vehicle->getSeatEntryPosition(seat));
|
|
||||||
character->rotation = vehicle->getRotation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (character->animator->getAnimation(AnimIndexAction) == anm_pullout) {
|
|
||||||
if (character->animator->isCompleted(AnimIndexAction)) {
|
|
||||||
tryToEnter = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( character->animator->getAnimation(AnimIndexAction) == anm_enter ) {
|
|
||||||
if( character->animator->isCompleted(AnimIndexAction) ) {
|
|
||||||
// VehicleGetIn is over, finish activity
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
glm::vec3 targetDirection = entryPos - character->getPosition();
|
|
||||||
targetDirection.z = 0.f;
|
|
||||||
|
|
||||||
float targetDistance = glm::length(targetDirection);
|
// If there's someone in this seat already, we may have to ask them to
|
||||||
|
// leave.
|
||||||
|
auto currentOccupant =
|
||||||
|
static_cast<CharacterObject *>(vehicle->getOccupant(seat));
|
||||||
|
|
||||||
if( targetDistance <= 0.4f ) {
|
bool tryToEnter = false;
|
||||||
entering = true;
|
|
||||||
// Warp character to vehicle orientation
|
|
||||||
character->controller->setMoveDirection({0.f, 0.f, 0.f});
|
|
||||||
character->controller->setRunning(false);
|
|
||||||
character->setHeading(
|
|
||||||
glm::degrees(glm::roll(vehicle->getRotation())));
|
|
||||||
|
|
||||||
// Determine if the door open animation should be skipped.
|
|
||||||
if( entryDoor == nullptr || (entryDoor->constraint != nullptr && glm::abs(entryDoor->constraint->getHingeAngle()) >= 0.6f ) )
|
|
||||||
{
|
|
||||||
tryToEnter = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
character->playActivityAnimation(anm_open, false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (targetDistance > kGiveUpDistance) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if( targetDistance > kSprintToEnterDistance ) {
|
|
||||||
character->controller->setRunning(true);
|
|
||||||
}
|
|
||||||
character->setHeading(
|
|
||||||
glm::degrees(atan2(targetDirection.y, targetDirection.x) - glm::half_pi<float>()));
|
|
||||||
character->controller->setMoveDirection({1.f, 0.f, 0.f});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tryToEnter) {
|
if (entering) {
|
||||||
if (currentOccupant != nullptr && currentOccupant != character) {
|
if (character->animator->getAnimation(AnimIndexAction) == anm_open) {
|
||||||
// Play the pullout animation and tell the other character to get out.
|
if (character->animator->isCompleted(AnimIndexAction)) {
|
||||||
character->playActivityAnimation(anm_pullout, false, true);
|
tryToEnter = true;
|
||||||
currentOccupant->controller->setNextActivity(new Activities::ExitVehicle(true));
|
} else if (entryDoor &&
|
||||||
}
|
character->animator->getAnimationTime(AnimIndexAction) >=
|
||||||
else {
|
0.5f) {
|
||||||
character->playActivityAnimation(anm_enter, false, true);
|
vehicle->setPartTarget(entryDoor, true, entryDoor->openAngle);
|
||||||
character->enterVehicle(vehicle, seat);
|
} else {
|
||||||
}
|
// character->setPosition(vehicle->getSeatEntryPosition(seat));
|
||||||
}
|
character->rotation = vehicle->getRotation();
|
||||||
return false;
|
}
|
||||||
|
} else if (character->animator->getAnimation(AnimIndexAction) ==
|
||||||
|
anm_pullout) {
|
||||||
|
if (character->animator->isCompleted(AnimIndexAction)) {
|
||||||
|
tryToEnter = true;
|
||||||
|
}
|
||||||
|
} else if (character->animator->getAnimation(AnimIndexAction) ==
|
||||||
|
anm_enter) {
|
||||||
|
if (character->animator->isCompleted(AnimIndexAction)) {
|
||||||
|
// VehicleGetIn is over, finish activity
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
glm::vec3 targetDirection = entryPos - character->getPosition();
|
||||||
|
targetDirection.z = 0.f;
|
||||||
|
|
||||||
|
float targetDistance = glm::length(targetDirection);
|
||||||
|
|
||||||
|
if (targetDistance <= 0.4f) {
|
||||||
|
entering = true;
|
||||||
|
// Warp character to vehicle orientation
|
||||||
|
character->controller->setMoveDirection({0.f, 0.f, 0.f});
|
||||||
|
character->controller->setRunning(false);
|
||||||
|
character->setHeading(
|
||||||
|
glm::degrees(glm::roll(vehicle->getRotation())));
|
||||||
|
|
||||||
|
// Determine if the door open animation should be skipped.
|
||||||
|
if (entryDoor == nullptr ||
|
||||||
|
(entryDoor->constraint != nullptr &&
|
||||||
|
glm::abs(entryDoor->constraint->getHingeAngle()) >= 0.6f)) {
|
||||||
|
tryToEnter = true;
|
||||||
|
} else {
|
||||||
|
character->playActivityAnimation(anm_open, false, true);
|
||||||
|
}
|
||||||
|
} else if (targetDistance > kGiveUpDistance) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (targetDistance > kSprintToEnterDistance) {
|
||||||
|
character->controller->setRunning(true);
|
||||||
|
}
|
||||||
|
character->setHeading(
|
||||||
|
glm::degrees(atan2(targetDirection.y, targetDirection.x) -
|
||||||
|
glm::half_pi<float>()));
|
||||||
|
character->controller->setMoveDirection({1.f, 0.f, 0.f});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tryToEnter) {
|
||||||
|
if (currentOccupant != nullptr && currentOccupant != character) {
|
||||||
|
// Play the pullout animation and tell the other character to get
|
||||||
|
// out.
|
||||||
|
character->playActivityAnimation(anm_pullout, false, true);
|
||||||
|
currentOccupant->controller->setNextActivity(
|
||||||
|
new Activities::ExitVehicle(true));
|
||||||
|
} else {
|
||||||
|
character->playActivityAnimation(anm_enter, false, true);
|
||||||
|
character->enterVehicle(vehicle, seat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Activities::ExitVehicle::update(CharacterObject *character,
|
||||||
|
CharacterController *controller) {
|
||||||
|
RW_UNUSED(controller);
|
||||||
|
|
||||||
bool Activities::ExitVehicle::update(CharacterObject *character, CharacterController *controller)
|
if (jacked) {
|
||||||
{
|
auto anm_jacked_lhs = character->animations.car_jacked_lhs;
|
||||||
RW_UNUSED(controller);
|
auto anm_jacked_rhs = character->animations.car_jacked_lhs;
|
||||||
|
auto anm_current = character->animator->getAnimation(AnimIndexAction);
|
||||||
|
|
||||||
if (jacked) {
|
if (anm_current == anm_jacked_lhs || anm_current == anm_jacked_rhs) {
|
||||||
auto anm_jacked_lhs = character->animations.car_jacked_lhs;
|
if (character->animator->isCompleted(AnimIndexAction)) {
|
||||||
auto anm_jacked_rhs = character->animations.car_jacked_lhs;
|
return true;
|
||||||
auto anm_current = character->animator->getAnimation(AnimIndexAction);
|
}
|
||||||
|
} else {
|
||||||
|
if (character->getCurrentVehicle() == nullptr) return true;
|
||||||
|
|
||||||
if (anm_current == anm_jacked_lhs || anm_current == anm_jacked_rhs) {
|
auto vehicle = character->getCurrentVehicle();
|
||||||
if (character->animator->isCompleted(AnimIndexAction)) {
|
auto seat = character->getCurrentSeat();
|
||||||
return true;
|
auto door = vehicle->getSeatEntryDoor(seat);
|
||||||
}
|
auto exitPos = vehicle->getSeatEntryPositionWorld(seat);
|
||||||
}
|
auto exitPosLocal = vehicle->getSeatEntryPosition(seat);
|
||||||
else {
|
|
||||||
if (character->getCurrentVehicle() == nullptr) return true;
|
|
||||||
|
|
||||||
auto vehicle = character->getCurrentVehicle();
|
character->rotation = vehicle->getRotation();
|
||||||
auto seat = character->getCurrentSeat();
|
|
||||||
auto door = vehicle->getSeatEntryDoor(seat);
|
|
||||||
auto exitPos = vehicle->getSeatEntryPositionWorld(seat);
|
|
||||||
auto exitPosLocal = vehicle->getSeatEntryPosition(seat);
|
|
||||||
|
|
||||||
character->rotation = vehicle->getRotation();
|
// Exit the vehicle immediatley
|
||||||
|
character->enterVehicle(nullptr, seat);
|
||||||
|
character->setPosition(exitPos);
|
||||||
|
|
||||||
// Exit the vehicle immediatley
|
if (exitPosLocal.x > 0.f) {
|
||||||
character->enterVehicle(nullptr, seat);
|
character->playActivityAnimation(anm_jacked_rhs, false, true);
|
||||||
character->setPosition(exitPos);
|
} else {
|
||||||
|
character->playActivityAnimation(anm_jacked_lhs, false, true);
|
||||||
|
}
|
||||||
|
// No need to open the door, it should already be open.
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (exitPosLocal.x > 0.f) {
|
if (character->getCurrentVehicle() == nullptr) return true;
|
||||||
character->playActivityAnimation(anm_jacked_rhs, false, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
character->playActivityAnimation(anm_jacked_lhs, false, true);
|
|
||||||
}
|
|
||||||
// No need to open the door, it should already be open.
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( character->getCurrentVehicle() == nullptr ) return true;
|
auto vehicle = character->getCurrentVehicle();
|
||||||
|
auto seat = character->getCurrentSeat();
|
||||||
|
auto door = vehicle->getSeatEntryDoor(seat);
|
||||||
|
auto exitPos = vehicle->getSeatEntryPositionWorld(seat);
|
||||||
|
auto exitPosLocal = vehicle->getSeatEntryPosition(seat);
|
||||||
|
|
||||||
auto vehicle = character->getCurrentVehicle();
|
auto anm_exit = character->animations.car_getout_lhs;
|
||||||
auto seat = character->getCurrentSeat();
|
|
||||||
auto door = vehicle->getSeatEntryDoor(seat);
|
|
||||||
auto exitPos = vehicle->getSeatEntryPositionWorld(seat);
|
|
||||||
auto exitPosLocal = vehicle->getSeatEntryPosition(seat);
|
|
||||||
|
|
||||||
auto anm_exit = character->animations.car_getout_lhs;
|
if (exitPosLocal.x > 0.f) {
|
||||||
|
anm_exit = character->animations.car_getout_rhs;
|
||||||
|
}
|
||||||
|
|
||||||
if( exitPosLocal.x > 0.f )
|
if (vehicle->vehicle->type == VehicleData::BOAT) {
|
||||||
{
|
auto ppos = character->getPosition();
|
||||||
anm_exit = character->animations.car_getout_rhs;
|
character->enterVehicle(nullptr, seat);
|
||||||
}
|
character->setPosition(ppos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if( vehicle->vehicle->type == VehicleData::BOAT ) {
|
bool isDriver = vehicle->isOccupantDriver(character->getCurrentSeat());
|
||||||
auto ppos = character->getPosition();
|
|
||||||
character->enterVehicle(nullptr, seat);
|
|
||||||
character->setPosition(ppos);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDriver = vehicle->isOccupantDriver(character->getCurrentSeat());
|
// If the vehicle is going too fast, slow down
|
||||||
|
if (isDriver) {
|
||||||
|
if (!vehicle->canOccupantExit()) {
|
||||||
|
vehicle->setBraking(1.f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the vehicle is going too fast, slow down
|
if (character->animator->getAnimation(AnimIndexAction) == anm_exit) {
|
||||||
if (isDriver)
|
if (character->animator->isCompleted(AnimIndexAction)) {
|
||||||
{
|
character->enterVehicle(nullptr, seat);
|
||||||
if (!vehicle->canOccupantExit())
|
character->setPosition(exitPos);
|
||||||
{
|
|
||||||
vehicle->setBraking(1.f);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( character->animator->getAnimation(AnimIndexAction) == anm_exit ) {
|
if (isDriver) {
|
||||||
if( character->animator->isCompleted(AnimIndexAction) ) {
|
// Apply the handbrake
|
||||||
|
vehicle->setHandbraking(true);
|
||||||
|
vehicle->setThrottle(0.f);
|
||||||
|
}
|
||||||
|
|
||||||
character->enterVehicle(nullptr, seat);
|
return true;
|
||||||
character->setPosition(exitPos);
|
}
|
||||||
|
} else {
|
||||||
|
character->playActivityAnimation(anm_exit, false, true);
|
||||||
|
if (door) {
|
||||||
|
vehicle->setPartTarget(door, true, door->openAngle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isDriver)
|
return false;
|
||||||
{
|
|
||||||
// Apply the handbrake
|
|
||||||
vehicle->setHandbraking(true);
|
|
||||||
vehicle->setThrottle(0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
character->playActivityAnimation(anm_exit, false, true);
|
|
||||||
if( door )
|
|
||||||
{
|
|
||||||
vehicle->setPartTarget(door, true, door->openAngle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <engine/GameWorld.hpp>
|
|
||||||
#include <engine/GameData.hpp>
|
|
||||||
#include <data/Model.hpp>
|
#include <data/Model.hpp>
|
||||||
bool Activities::ShootWeapon::update(CharacterObject *character, CharacterController *controller)
|
#include <engine/GameData.hpp>
|
||||||
{
|
#include <engine/GameWorld.hpp>
|
||||||
RW_UNUSED(controller);
|
bool Activities::ShootWeapon::update(CharacterObject *character,
|
||||||
|
CharacterController *controller) {
|
||||||
|
RW_UNUSED(controller);
|
||||||
|
|
||||||
auto& wepdata = _item->getWeaponData();
|
auto &wepdata = _item->getWeaponData();
|
||||||
|
|
||||||
// Instant hit weapons loop their anim
|
// Instant hit weapons loop their anim
|
||||||
// Thrown projectiles have lob / throw.
|
// Thrown projectiles have lob / throw.
|
||||||
|
|
||||||
// Update player direction
|
// Update player direction
|
||||||
character->setRotation(glm::angleAxis(character->getLook().x, glm::vec3{0.f, 0.f, 1.f}));
|
character->setRotation(
|
||||||
|
glm::angleAxis(character->getLook().x, glm::vec3{0.f, 0.f, 1.f}));
|
||||||
|
|
||||||
RW_CHECK(wepdata->inventorySlot < maxInventorySlots, "Inventory slot out of bounds");
|
RW_CHECK(wepdata->inventorySlot < maxInventorySlots,
|
||||||
auto& itemState = character->getCurrentState().weapons[wepdata->inventorySlot];
|
"Inventory slot out of bounds");
|
||||||
if (itemState.bulletsClip == 0 && itemState.bulletsTotal > 0) {
|
auto &itemState =
|
||||||
itemState.bulletsClip += std::min(int(itemState.bulletsTotal), wepdata->clipSize);
|
character->getCurrentState().weapons[wepdata->inventorySlot];
|
||||||
itemState.bulletsTotal -= itemState.bulletsClip;
|
if (itemState.bulletsClip == 0 && itemState.bulletsTotal > 0) {
|
||||||
}
|
itemState.bulletsClip +=
|
||||||
bool hasammo = itemState.bulletsClip > 0;
|
std::min(int(itemState.bulletsTotal), wepdata->clipSize);
|
||||||
|
itemState.bulletsTotal -= itemState.bulletsClip;
|
||||||
|
}
|
||||||
|
bool hasammo = itemState.bulletsClip > 0;
|
||||||
|
|
||||||
if( wepdata->fireType == WeaponData::INSTANT_HIT ) {
|
if (wepdata->fireType == WeaponData::INSTANT_HIT) {
|
||||||
if( _item->isFiring(character) && hasammo ) {
|
if (_item->isFiring(character) && hasammo) {
|
||||||
|
auto shootanim =
|
||||||
|
character->engine->data->animations[wepdata->animation1];
|
||||||
|
if (shootanim) {
|
||||||
|
if (character->animator->getAnimation(AnimIndexAction) !=
|
||||||
|
shootanim) {
|
||||||
|
character->playActivityAnimation(shootanim, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
auto shootanim = character->engine->data->animations[wepdata->animation1];
|
auto loopstart = wepdata->animLoopStart / 100.f;
|
||||||
if( shootanim ) {
|
auto loopend = wepdata->animLoopEnd / 100.f;
|
||||||
if( character->animator->getAnimation(AnimIndexAction) != shootanim ) {
|
auto firetime = wepdata->animFirePoint / 100.f;
|
||||||
character->playActivityAnimation(shootanim, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto loopstart = wepdata->animLoopStart / 100.f;
|
auto currID =
|
||||||
auto loopend = wepdata->animLoopEnd / 100.f;
|
character->animator->getAnimationTime(AnimIndexAction);
|
||||||
auto firetime = wepdata->animFirePoint / 100.f;
|
|
||||||
|
|
||||||
auto currID = character->animator->getAnimationTime(AnimIndexAction);
|
if (currID >= firetime && !_fired) {
|
||||||
|
itemState.bulletsClip--;
|
||||||
|
_item->fire(character);
|
||||||
|
_fired = true;
|
||||||
|
}
|
||||||
|
if (currID > loopend) {
|
||||||
|
character->animator->setAnimationTime(AnimIndexAction,
|
||||||
|
loopstart);
|
||||||
|
_fired = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (character->animator->isCompleted(AnimIndexAction)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// @todo Use Thrown flag instead of project (RPG isn't thrown eg.)
|
||||||
|
else if (wepdata->fireType == WeaponData::PROJECTILE && hasammo) {
|
||||||
|
auto shootanim =
|
||||||
|
character->engine->data->animations[wepdata->animation1];
|
||||||
|
auto throwanim =
|
||||||
|
character->engine->data->animations[wepdata->animation2];
|
||||||
|
|
||||||
if( currID >= firetime && ! _fired ) {
|
if (character->animator->getAnimation(AnimIndexAction) == shootanim) {
|
||||||
itemState.bulletsClip --;
|
if (character->animator->isCompleted(AnimIndexAction)) {
|
||||||
_item->fire(character);
|
character->playActivityAnimation(throwanim, false, false);
|
||||||
_fired = true;
|
}
|
||||||
}
|
} else if (character->animator->getAnimation(AnimIndexAction) ==
|
||||||
if( currID > loopend ) {
|
throwanim) {
|
||||||
character->animator->setAnimationTime( AnimIndexAction, loopstart );
|
auto firetime = wepdata->animCrouchFirePoint / 100.f;
|
||||||
_fired = false;
|
auto currID =
|
||||||
}
|
character->animator->getAnimationTime(AnimIndexAction);
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if( character->animator->isCompleted(AnimIndexAction) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// @todo Use Thrown flag instead of project (RPG isn't thrown eg.)
|
|
||||||
else if( wepdata->fireType == WeaponData::PROJECTILE && hasammo ) {
|
|
||||||
auto shootanim = character->engine->data->animations[wepdata->animation1];
|
|
||||||
auto throwanim = character->engine->data->animations[wepdata->animation2];
|
|
||||||
|
|
||||||
if( character->animator->getAnimation(AnimIndexAction) == shootanim ) {
|
if (currID >= firetime && !_fired) {
|
||||||
if( character->animator->isCompleted(AnimIndexAction) ) {
|
itemState.bulletsClip--;
|
||||||
character->playActivityAnimation(throwanim, false, false);
|
_item->fire(character);
|
||||||
}
|
_fired = true;
|
||||||
}
|
}
|
||||||
else if( character->animator->getAnimation(AnimIndexAction) == throwanim ) {
|
if (character->animator->isCompleted(AnimIndexAction)) {
|
||||||
auto firetime = wepdata->animCrouchFirePoint / 100.f;
|
return true;
|
||||||
auto currID = character->animator->getAnimationTime(AnimIndexAction);
|
}
|
||||||
|
} else {
|
||||||
|
character->playActivityAnimation(throwanim, false, true);
|
||||||
|
}
|
||||||
|
} else if (wepdata->fireType == WeaponData::MELEE) {
|
||||||
|
RW_CHECK(wepdata->fireType != WeaponData::MELEE,
|
||||||
|
"Melee attacks not implemented");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
RW_ERROR("Unrecognized fireType: " << wepdata->fireType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if( currID >= firetime && !_fired ) {
|
return false;
|
||||||
itemState.bulletsClip --;
|
|
||||||
_item->fire(character);
|
|
||||||
_fired = true;
|
|
||||||
}
|
|
||||||
if( character->animator->isCompleted(AnimIndexAction) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
character->playActivityAnimation(throwanim, false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( wepdata->fireType == WeaponData::MELEE ) {
|
|
||||||
RW_CHECK(wepdata->fireType != WeaponData::MELEE, "Melee attacks not implemented");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RW_ERROR("Unrecognized fireType: " << wepdata->fireType);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
@ -11,127 +11,141 @@ class VehicleObject;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @class CharacterController
|
* @class CharacterController
|
||||||
* Character Controller Interface, translates high-level behaviours into low level actions.
|
* Character Controller Interface, translates high-level behaviours into low
|
||||||
|
* level actions.
|
||||||
*/
|
*/
|
||||||
class CharacterController
|
class CharacterController {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief The Activity struct interface
|
||||||
|
*/
|
||||||
|
struct Activity {
|
||||||
|
virtual ~Activity() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
virtual std::string name() const = 0;
|
||||||
* @brief The Activity struct interface
|
|
||||||
*/
|
|
||||||
struct Activity {
|
|
||||||
|
|
||||||
virtual ~Activity() {}
|
/**
|
||||||
|
* @brief canSkip
|
||||||
|
* @return true if the activity can be skipped.
|
||||||
|
*/
|
||||||
|
virtual bool canSkip(CharacterObject*, CharacterController*) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::string name() const = 0;
|
virtual bool update(CharacterObject* character,
|
||||||
|
CharacterController* controller) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief canSkip
|
* Available AI goals.
|
||||||
* @return true if the activity can be skipped.
|
*/
|
||||||
*/
|
enum Goal {
|
||||||
virtual bool canSkip(CharacterObject*, CharacterController*) const { return false; }
|
/**
|
||||||
|
* No goal, will idle or execute external Activities.
|
||||||
virtual bool update(CharacterObject* character, CharacterController* controller) = 0;
|
*/
|
||||||
};
|
None,
|
||||||
|
/**
|
||||||
/**
|
* Keep close to leader character
|
||||||
* Available AI goals.
|
*/
|
||||||
*/
|
FollowLeader,
|
||||||
enum Goal
|
/**
|
||||||
{
|
* Wander randomly around the map
|
||||||
/**
|
*/
|
||||||
* No goal, will idle or execute external Activities.
|
TrafficWander
|
||||||
*/
|
};
|
||||||
None,
|
|
||||||
/**
|
|
||||||
* Keep close to leader character
|
|
||||||
*/
|
|
||||||
FollowLeader,
|
|
||||||
/**
|
|
||||||
* Wander randomly around the map
|
|
||||||
*/
|
|
||||||
TrafficWander
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/**
|
||||||
/**
|
* The character being controlled.
|
||||||
* The character being controlled.
|
*/
|
||||||
*/
|
CharacterObject* character;
|
||||||
CharacterObject* character;
|
|
||||||
|
|
||||||
Activity* _currentActivity;
|
Activity* _currentActivity;
|
||||||
Activity* _nextActivity;
|
Activity* _nextActivity;
|
||||||
|
|
||||||
bool updateActivity();
|
bool updateActivity();
|
||||||
void setActivity(Activity* activity);
|
void setActivity(Activity* activity);
|
||||||
|
|
||||||
float m_closeDoorTimer;
|
float m_closeDoorTimer;
|
||||||
|
|
||||||
// Goal related variables
|
// Goal related variables
|
||||||
Goal currentGoal;
|
Goal currentGoal;
|
||||||
CharacterObject* leader;
|
CharacterObject* leader;
|
||||||
AIGraphNode* targetNode;
|
AIGraphNode* targetNode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
CharacterController(CharacterObject* character);
|
||||||
CharacterController(CharacterObject* character);
|
|
||||||
|
|
||||||
virtual ~CharacterController() { }
|
virtual ~CharacterController() {
|
||||||
|
}
|
||||||
|
|
||||||
Activity* getCurrentActivity() const { return _currentActivity; }
|
Activity* getCurrentActivity() const {
|
||||||
|
return _currentActivity;
|
||||||
|
}
|
||||||
|
|
||||||
Activity* getNextActivity() const { return _nextActivity; }
|
Activity* getNextActivity() const {
|
||||||
|
return _nextActivity;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief skipActivity Cancel the current activity immediatley, if possible.
|
* @brief skipActivity Cancel the current activity immediatley, if possible.
|
||||||
*/
|
*/
|
||||||
void skipActivity();
|
void skipActivity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief setNextActivity Sets the next Activity with a parameter.
|
* @brief setNextActivity Sets the next Activity with a parameter.
|
||||||
* @param activity
|
* @param activity
|
||||||
* @param position
|
* @param position
|
||||||
*/
|
*/
|
||||||
void setNextActivity( Activity* activity );
|
void setNextActivity(Activity* activity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief IsCurrentActivity
|
* @brief IsCurrentActivity
|
||||||
* @param activity Name of activity to check for
|
* @param activity Name of activity to check for
|
||||||
* @return if the given activity is the current activity
|
* @return if the given activity is the current activity
|
||||||
*/
|
*/
|
||||||
bool isCurrentActivity(const std::string& activity) const;
|
bool isCurrentActivity(const std::string& activity) const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief update Updates the controller.
|
|
||||||
* @param dt
|
|
||||||
*/
|
|
||||||
virtual void update(float dt);
|
|
||||||
|
|
||||||
virtual glm::vec3 getTargetPosition() = 0;
|
/**
|
||||||
|
* @brief update Updates the controller.
|
||||||
|
* @param dt
|
||||||
|
*/
|
||||||
|
virtual void update(float dt);
|
||||||
|
|
||||||
/**
|
virtual glm::vec3 getTargetPosition() = 0;
|
||||||
* @brief
|
|
||||||
* @return Returns the Character Object
|
|
||||||
*/
|
|
||||||
CharacterObject* getCharacter() const;
|
|
||||||
|
|
||||||
void setMoveDirection(const glm::vec3& movement);
|
/**
|
||||||
void setLookDirection(const glm::vec2& look);
|
* @brief
|
||||||
|
* @return Returns the Character Object
|
||||||
|
*/
|
||||||
|
CharacterObject* getCharacter() const;
|
||||||
|
|
||||||
void setRunning(bool run);
|
void setMoveDirection(const glm::vec3& movement);
|
||||||
|
void setLookDirection(const glm::vec2& look);
|
||||||
void setGoal(Goal goal) { currentGoal = goal; }
|
|
||||||
Goal getGoal() const { return currentGoal; }
|
void setRunning(bool run);
|
||||||
|
|
||||||
void setTargetCharacter(CharacterObject* c) { leader = c; }
|
void setGoal(Goal goal) {
|
||||||
CharacterObject* getTargetCharacter() const { return leader; }
|
currentGoal = goal;
|
||||||
|
}
|
||||||
|
Goal getGoal() const {
|
||||||
|
return currentGoal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTargetCharacter(CharacterObject* c) {
|
||||||
|
leader = c;
|
||||||
|
}
|
||||||
|
CharacterObject* getTargetCharacter() const {
|
||||||
|
return leader;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DECL_ACTIVITY( activity_name ) \
|
#define DECL_ACTIVITY(activity_name) \
|
||||||
static constexpr auto ActivityName = #activity_name; \
|
static constexpr auto ActivityName = #activity_name; \
|
||||||
std::string name() const { return ActivityName; }
|
std::string name() const { \
|
||||||
|
return ActivityName; \
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Refactor this with an ugly macro to reduce code dup.
|
// TODO: Refactor this with an ugly macro to reduce code dup.
|
||||||
class WeaponItem;
|
class WeaponItem;
|
||||||
@ -142,74 +156,78 @@ class WeaponItem;
|
|||||||
* @todo Move into ControllerActivities.hpp or equivelant
|
* @todo Move into ControllerActivities.hpp or equivelant
|
||||||
*/
|
*/
|
||||||
namespace Activities {
|
namespace Activities {
|
||||||
struct GoTo : public CharacterController::Activity {
|
struct GoTo : public CharacterController::Activity {
|
||||||
DECL_ACTIVITY( GoTo )
|
DECL_ACTIVITY(GoTo)
|
||||||
|
|
||||||
glm::vec3 target;
|
glm::vec3 target;
|
||||||
bool sprint;
|
bool sprint;
|
||||||
|
|
||||||
GoTo( const glm::vec3& target, bool _sprint = false )
|
GoTo(const glm::vec3& target, bool _sprint = false)
|
||||||
: target( target ), sprint(_sprint) {}
|
: target(target), sprint(_sprint) {
|
||||||
|
}
|
||||||
|
|
||||||
bool update(CharacterObject* character, CharacterController* controller);
|
bool update(CharacterObject* character, CharacterController* controller);
|
||||||
|
|
||||||
bool canSkip(CharacterObject *, CharacterController *) const { return true; }
|
bool canSkip(CharacterObject*, CharacterController*) const {
|
||||||
};
|
return true;
|
||||||
|
}
|
||||||
struct Jump : public CharacterController::Activity
|
};
|
||||||
{
|
|
||||||
DECL_ACTIVITY( Jump )
|
|
||||||
|
|
||||||
bool jumped;
|
|
||||||
|
|
||||||
Jump() : jumped(false) {}
|
|
||||||
|
|
||||||
bool update(CharacterObject* character, CharacterController* controller);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EnterVehicle : public CharacterController::Activity {
|
struct Jump : public CharacterController::Activity {
|
||||||
DECL_ACTIVITY( EnterVehicle )
|
DECL_ACTIVITY(Jump)
|
||||||
|
|
||||||
VehicleObject* vehicle;
|
bool jumped;
|
||||||
int seat;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
ANY_SEAT = -1 // Magic number for any seat but the driver's.
|
|
||||||
};
|
|
||||||
|
|
||||||
bool entering;
|
Jump() : jumped(false) {
|
||||||
|
}
|
||||||
|
|
||||||
EnterVehicle( VehicleObject* vehicle, int seat = 0 )
|
bool update(CharacterObject* character, CharacterController* controller);
|
||||||
: vehicle( vehicle ), seat( seat ), entering(false) {}
|
};
|
||||||
|
|
||||||
bool canSkip(CharacterObject* character, CharacterController*) const override;
|
struct EnterVehicle : public CharacterController::Activity {
|
||||||
|
DECL_ACTIVITY(EnterVehicle)
|
||||||
|
|
||||||
bool update(CharacterObject *character, CharacterController *controller);
|
VehicleObject* vehicle;
|
||||||
};
|
int seat;
|
||||||
|
|
||||||
struct ExitVehicle : public CharacterController::Activity {
|
enum {
|
||||||
DECL_ACTIVITY( ExitVehicle )
|
ANY_SEAT = -1 // Magic number for any seat but the driver's.
|
||||||
|
};
|
||||||
|
|
||||||
const bool jacked;
|
bool entering;
|
||||||
|
|
||||||
ExitVehicle(bool jacked_ = false)
|
EnterVehicle(VehicleObject* vehicle, int seat = 0)
|
||||||
: jacked(jacked_)
|
: vehicle(vehicle), seat(seat), entering(false) {
|
||||||
{}
|
}
|
||||||
|
|
||||||
bool update(CharacterObject *character, CharacterController *controller);
|
bool canSkip(CharacterObject* character,
|
||||||
};
|
CharacterController*) const override;
|
||||||
|
|
||||||
struct ShootWeapon : public CharacterController::Activity {
|
bool update(CharacterObject* character, CharacterController* controller);
|
||||||
DECL_ACTIVITY( ShootWeapon )
|
};
|
||||||
|
|
||||||
WeaponItem* _item;
|
struct ExitVehicle : public CharacterController::Activity {
|
||||||
bool _fired;
|
DECL_ACTIVITY(ExitVehicle)
|
||||||
|
|
||||||
ShootWeapon( WeaponItem* item )
|
const bool jacked;
|
||||||
: _item(item), _fired(false) {}
|
|
||||||
|
|
||||||
bool update(CharacterObject *character, CharacterController *controller);
|
ExitVehicle(bool jacked_ = false) : jacked(jacked_) {
|
||||||
};
|
}
|
||||||
|
|
||||||
|
bool update(CharacterObject* character, CharacterController* controller);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShootWeapon : public CharacterController::Activity {
|
||||||
|
DECL_ACTIVITY(ShootWeapon)
|
||||||
|
|
||||||
|
WeaponItem* _item;
|
||||||
|
bool _fired;
|
||||||
|
|
||||||
|
ShootWeapon(WeaponItem* item) : _item(item), _fired(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update(CharacterObject* character, CharacterController* controller);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,101 +1,88 @@
|
|||||||
#include <ai/DefaultAIController.hpp>
|
#include <ai/DefaultAIController.hpp>
|
||||||
#include <objects/CharacterObject.hpp>
|
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
|
#include <objects/CharacterObject.hpp>
|
||||||
|
|
||||||
glm::vec3 DefaultAIController::getTargetPosition()
|
glm::vec3 DefaultAIController::getTargetPosition() {
|
||||||
{
|
/*if(targetNode) {
|
||||||
/*if(targetNode) {
|
if(lastNode && character->getCurrentVehicle()) {
|
||||||
if(lastNode && character->getCurrentVehicle()) {
|
auto nDir = glm::normalize(targetNode->position -
|
||||||
auto nDir = glm::normalize(targetNode->position - lastNode->position);
|
lastNode->position);
|
||||||
auto right = glm::cross(nDir, glm::vec3(0.f, 0.f, 1.f));
|
auto right = glm::cross(nDir, glm::vec3(0.f, 0.f, 1.f));
|
||||||
return targetNode->position + right * 2.2f;
|
return targetNode->position + right * 2.2f;
|
||||||
}
|
}
|
||||||
return targetNode->position;
|
return targetNode->position;
|
||||||
}*/
|
}*/
|
||||||
return glm::vec3();
|
return glm::vec3();
|
||||||
}
|
}
|
||||||
|
|
||||||
const float followRadius = 5.f;
|
const float followRadius = 5.f;
|
||||||
|
|
||||||
void DefaultAIController::update(float dt)
|
void DefaultAIController::update(float dt) {
|
||||||
{
|
switch (currentGoal) {
|
||||||
switch(currentGoal)
|
case FollowLeader: {
|
||||||
{
|
if (!leader) break;
|
||||||
case FollowLeader:
|
if (getCharacter()->getCurrentVehicle()) {
|
||||||
{
|
if (leader->getCurrentVehicle() !=
|
||||||
if( ! leader ) break;
|
getCharacter()->getCurrentVehicle()) {
|
||||||
if( getCharacter()->getCurrentVehicle() )
|
skipActivity();
|
||||||
{
|
setNextActivity(new Activities::ExitVehicle);
|
||||||
if( leader->getCurrentVehicle() != getCharacter()->getCurrentVehicle() )
|
}
|
||||||
{
|
// else we're already in the right spot.
|
||||||
skipActivity();
|
} else {
|
||||||
setNextActivity(new Activities::ExitVehicle);
|
if (leader->getCurrentVehicle()) {
|
||||||
}
|
setNextActivity(new Activities::EnterVehicle(
|
||||||
// else we're already in the right spot.
|
leader->getCurrentVehicle(), 1));
|
||||||
}
|
} else {
|
||||||
else
|
glm::vec3 dir =
|
||||||
{
|
leader->getPosition() - getCharacter()->getPosition();
|
||||||
if( leader->getCurrentVehicle() )
|
if (glm::length(dir) > followRadius) {
|
||||||
{
|
if (glm::distance(gotoPos, leader->getPosition()) >
|
||||||
setNextActivity(new Activities::EnterVehicle(leader->getCurrentVehicle(), 1));
|
followRadius) {
|
||||||
}
|
gotoPos =
|
||||||
else
|
leader->getPosition() +
|
||||||
{
|
(glm::normalize(-dir) * followRadius * 0.7f);
|
||||||
glm::vec3 dir = leader->getPosition() - getCharacter()->getPosition();
|
skipActivity();
|
||||||
if( glm::length(dir) > followRadius )
|
setNextActivity(new Activities::GoTo(gotoPos));
|
||||||
{
|
}
|
||||||
if( glm::distance(gotoPos, leader->getPosition()) > followRadius )
|
}
|
||||||
{
|
}
|
||||||
gotoPos = leader->getPosition() + ( glm::normalize(-dir) * followRadius * 0.7f );
|
}
|
||||||
skipActivity();
|
} break;
|
||||||
setNextActivity(new Activities::GoTo(gotoPos));
|
case TrafficWander: {
|
||||||
}
|
if (targetNode) {
|
||||||
}
|
auto targetDistance =
|
||||||
}
|
glm::vec2(character->getPosition() - targetNode->position);
|
||||||
}
|
if (glm::length(targetDistance) <= 0.1f) {
|
||||||
}
|
// Assign the next target node
|
||||||
break;
|
auto lastTarget = targetNode;
|
||||||
case TrafficWander:
|
std::random_device rd;
|
||||||
{
|
std::default_random_engine re(rd());
|
||||||
if( targetNode )
|
std::uniform_int_distribution<> d(
|
||||||
{
|
0, lastTarget->connections.size() - 1);
|
||||||
auto targetDistance = glm::vec2(character->getPosition() - targetNode->position);
|
targetNode = lastTarget->connections.at(d(re));
|
||||||
if( glm::length(targetDistance) <= 0.1f )
|
setNextActivity(new Activities::GoTo(targetNode->position));
|
||||||
{
|
} else if (getCurrentActivity() == nullptr) {
|
||||||
// Assign the next target node
|
setNextActivity(new Activities::GoTo(targetNode->position));
|
||||||
auto lastTarget = targetNode;
|
}
|
||||||
std::random_device rd;
|
} else {
|
||||||
std::default_random_engine re(rd());
|
// We need to pick an initial node
|
||||||
std::uniform_int_distribution<> d(0, lastTarget->connections.size()-1);
|
auto& graph = getCharacter()->engine->aigraph;
|
||||||
targetNode = lastTarget->connections.at(d(re));
|
AIGraphNode* node = nullptr;
|
||||||
setNextActivity(new Activities::GoTo(targetNode->position));
|
float mindist = std::numeric_limits<float>::max();
|
||||||
}
|
for (auto n : graph.nodes) {
|
||||||
else if ( getCurrentActivity() == nullptr )
|
float d = glm::distance(n->position,
|
||||||
{
|
getCharacter()->getPosition());
|
||||||
setNextActivity(new Activities::GoTo(targetNode->position));
|
if (d < mindist) {
|
||||||
}
|
node = n;
|
||||||
}
|
mindist = d;
|
||||||
else
|
}
|
||||||
{
|
}
|
||||||
// We need to pick an initial node
|
targetNode = node;
|
||||||
auto& graph = getCharacter()->engine->aigraph;
|
}
|
||||||
AIGraphNode* node = nullptr;
|
} break;
|
||||||
float mindist = std::numeric_limits<float>::max();
|
default:
|
||||||
for( auto n : graph.nodes )
|
break;
|
||||||
{
|
}
|
||||||
float d = glm::distance( n->position, getCharacter()->getPosition() );
|
|
||||||
if( d < mindist )
|
CharacterController::update(dt);
|
||||||
{
|
|
||||||
node = n;
|
|
||||||
mindist = d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
targetNode = node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CharacterController::update(dt);
|
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,16 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
struct AIGraphNode;
|
struct AIGraphNode;
|
||||||
class DefaultAIController : public CharacterController
|
class DefaultAIController : public CharacterController {
|
||||||
{
|
glm::vec3 gotoPos;
|
||||||
glm::vec3 gotoPos;
|
|
||||||
public:
|
public:
|
||||||
|
DefaultAIController(CharacterObject* character)
|
||||||
DefaultAIController(CharacterObject* character)
|
: CharacterController(character) {
|
||||||
: CharacterController(character) {}
|
}
|
||||||
|
|
||||||
|
glm::vec3 getTargetPosition();
|
||||||
|
|
||||||
glm::vec3 getTargetPosition();
|
|
||||||
|
|
||||||
virtual void update(float dt);
|
virtual void update(float dt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,81 +1,74 @@
|
|||||||
#include <ai/PlayerController.hpp>
|
#include <ai/PlayerController.hpp>
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <engine/Animator.hpp>
|
||||||
#include <objects/VehicleObject.hpp>
|
|
||||||
#include <engine/GameWorld.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <engine/Animator.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
|
#include <objects/VehicleObject.hpp>
|
||||||
|
|
||||||
PlayerController::PlayerController(CharacterObject* character)
|
PlayerController::PlayerController(CharacterObject* character)
|
||||||
: CharacterController(character), lastRotation(glm::vec3(0.f, 0.f, 0.f)), _enabled(true)
|
: CharacterController(character)
|
||||||
{
|
, lastRotation(glm::vec3(0.f, 0.f, 0.f))
|
||||||
|
, _enabled(true) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::setInputEnabled(bool enabled)
|
void PlayerController::setInputEnabled(bool enabled) {
|
||||||
{
|
_enabled = enabled;
|
||||||
_enabled = enabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerController::isInputEnabled() const
|
bool PlayerController::isInputEnabled() const {
|
||||||
{
|
return _enabled;
|
||||||
return _enabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::updateCameraDirection(const glm::quat& rot)
|
void PlayerController::updateCameraDirection(const glm::quat& rot) {
|
||||||
{
|
cameraRotation = rot;
|
||||||
cameraRotation = rot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::updateMovementDirection(const glm::vec3& dir, const glm::vec3 &rawdirection)
|
void PlayerController::updateMovementDirection(const glm::vec3& dir,
|
||||||
{
|
const glm::vec3& rawdirection) {
|
||||||
if( _currentActivity == nullptr ) {
|
if (_currentActivity == nullptr) {
|
||||||
direction = dir;
|
direction = dir;
|
||||||
setMoveDirection(rawdirection);
|
setMoveDirection(rawdirection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::exitVehicle()
|
void PlayerController::exitVehicle() {
|
||||||
{
|
if (character->getCurrentVehicle()) {
|
||||||
if(character->getCurrentVehicle()) {
|
setNextActivity(new Activities::ExitVehicle());
|
||||||
setNextActivity(new Activities::ExitVehicle());
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::enterNearestVehicle()
|
void PlayerController::enterNearestVehicle() {
|
||||||
{
|
if (!character->getCurrentVehicle()) {
|
||||||
if(! character->getCurrentVehicle()) {
|
auto world = character->engine;
|
||||||
auto world = character->engine;
|
VehicleObject* nearest = nullptr;
|
||||||
VehicleObject* nearest = nullptr; float d = 10.f;
|
float d = 10.f;
|
||||||
|
|
||||||
for( auto& p : world->vehiclePool.objects ) {
|
for (auto& p : world->vehiclePool.objects) {
|
||||||
auto object = p.second;
|
auto object = p.second;
|
||||||
float vd = glm::length( character->getPosition() - object->getPosition());
|
float vd =
|
||||||
if( vd < d ) {
|
glm::length(character->getPosition() - object->getPosition());
|
||||||
d = vd;
|
if (vd < d) {
|
||||||
nearest = static_cast<VehicleObject*>(object);
|
d = vd;
|
||||||
}
|
nearest = static_cast<VehicleObject*>(object);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( nearest ) {
|
if (nearest) {
|
||||||
setNextActivity(new Activities::EnterVehicle(nearest, 0));
|
setNextActivity(new Activities::EnterVehicle(nearest, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::update(float dt)
|
void PlayerController::update(float dt) {
|
||||||
{
|
CharacterController::update(dt);
|
||||||
CharacterController::update(dt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 PlayerController::getTargetPosition()
|
glm::vec3 PlayerController::getTargetPosition() {
|
||||||
{
|
return direction;
|
||||||
return direction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerController::jump()
|
void PlayerController::jump() {
|
||||||
{
|
if (!character->isInWater()) {
|
||||||
if(! character->isInWater() ) {
|
setNextActivity(new Activities::Jump());
|
||||||
setNextActivity(new Activities::Jump());
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,45 +3,46 @@
|
|||||||
#define _PLAYERCONTROLLER_HPP_
|
#define _PLAYERCONTROLLER_HPP_
|
||||||
#include <ai/CharacterController.hpp>
|
#include <ai/CharacterController.hpp>
|
||||||
|
|
||||||
class PlayerController : public CharacterController
|
class PlayerController : public CharacterController {
|
||||||
{
|
glm::quat cameraRotation;
|
||||||
glm::quat cameraRotation;
|
|
||||||
|
|
||||||
glm::vec3 direction;
|
|
||||||
|
|
||||||
glm::quat lastRotation;
|
glm::vec3 direction;
|
||||||
|
|
||||||
|
glm::quat lastRotation;
|
||||||
|
|
||||||
|
bool _enabled;
|
||||||
|
|
||||||
bool _enabled;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
PlayerController(CharacterObject* character);
|
||||||
PlayerController(CharacterObject* character);
|
|
||||||
|
/**
|
||||||
|
* @brief Enables and disables player input.
|
||||||
|
* @todo actually implement input being disabled.
|
||||||
|
*/
|
||||||
|
void setInputEnabled(bool enabled);
|
||||||
|
bool isInputEnabled() const;
|
||||||
|
|
||||||
|
void updateCameraDirection(const glm::quat& rot);
|
||||||
|
|
||||||
|
void updateMovementDirection(const glm::vec3& pos,
|
||||||
|
const glm::vec3& rawdirection);
|
||||||
|
|
||||||
|
void exitVehicle();
|
||||||
|
|
||||||
|
void enterNearestVehicle();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enables and disables player input.
|
|
||||||
* @todo actually implement input being disabled.
|
|
||||||
*/
|
|
||||||
void setInputEnabled(bool enabled);
|
|
||||||
bool isInputEnabled() const;
|
|
||||||
|
|
||||||
void updateCameraDirection(const glm::quat& rot);
|
|
||||||
|
|
||||||
void updateMovementDirection(const glm::vec3& pos, const glm::vec3& rawdirection);
|
|
||||||
|
|
||||||
void exitVehicle();
|
|
||||||
|
|
||||||
void enterNearestVehicle();
|
|
||||||
|
|
||||||
virtual void update(float dt);
|
virtual void update(float dt);
|
||||||
|
|
||||||
virtual glm::vec3 getTargetPosition();
|
|
||||||
|
|
||||||
void jump();
|
|
||||||
|
|
||||||
/**
|
virtual glm::vec3 getTargetPosition();
|
||||||
* returns 0 (only one player supported)
|
|
||||||
*/
|
void jump();
|
||||||
int getScriptObjectID() const { return 0; }
|
|
||||||
|
/**
|
||||||
|
* returns 0 (only one player supported)
|
||||||
|
*/
|
||||||
|
int getScriptObjectID() const {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,172 +1,169 @@
|
|||||||
#include "ai/TrafficDirector.hpp"
|
#include "ai/TrafficDirector.hpp"
|
||||||
#include <ai/AIGraphNode.hpp>
|
#include <ai/AIGraphNode.hpp>
|
||||||
#include <ai/CharacterController.hpp>
|
#include <ai/CharacterController.hpp>
|
||||||
#include <engine/GameWorld.hpp>
|
#include <core/Logger.hpp>
|
||||||
#include <engine/GameState.hpp>
|
#include <engine/GameState.hpp>
|
||||||
#include <objects/GameObject.hpp>
|
#include <engine/GameWorld.hpp>
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
|
#include <objects/GameObject.hpp>
|
||||||
#include <objects/VehicleObject.hpp>
|
#include <objects/VehicleObject.hpp>
|
||||||
#include <render/ViewCamera.hpp>
|
#include <render/ViewCamera.hpp>
|
||||||
#include <core/Logger.hpp>
|
|
||||||
|
|
||||||
#include <glm/gtx/string_cast.hpp>
|
|
||||||
#include <glm/gtx/norm.hpp>
|
#include <glm/gtx/norm.hpp>
|
||||||
|
#include <glm/gtx/string_cast.hpp>
|
||||||
#ifdef RW_WINDOWS
|
#ifdef RW_WINDOWS
|
||||||
#include <rw_mingw.hpp>
|
#include <rw_mingw.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TrafficDirector::TrafficDirector(AIGraph* g, GameWorld* w)
|
TrafficDirector::TrafficDirector(AIGraph* g, GameWorld* w)
|
||||||
: graph( g ), world( w ), pedDensity(1.f), carDensity(1.f),
|
: graph(g)
|
||||||
maximumPedestrians(20), maximumCars(10)
|
, world(w)
|
||||||
{
|
, pedDensity(1.f)
|
||||||
|
, carDensity(1.f)
|
||||||
|
, maximumPedestrians(20)
|
||||||
|
, maximumCars(10) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector< AIGraphNode* > TrafficDirector::findAvailableNodes(AIGraphNode::NodeType type, const ViewCamera& camera, float radius)
|
std::vector<AIGraphNode*> TrafficDirector::findAvailableNodes(
|
||||||
{
|
AIGraphNode::NodeType type, const ViewCamera& camera, float radius) {
|
||||||
std::vector<AIGraphNode*> available;
|
std::vector<AIGraphNode*> available;
|
||||||
available.reserve(20);
|
available.reserve(20);
|
||||||
|
|
||||||
graph->gatherExternalNodesNear(camera.position, radius, available);
|
graph->gatherExternalNodesNear(camera.position, radius, available);
|
||||||
|
|
||||||
float density = type == AIGraphNode::Vehicle ? carDensity : pedDensity;
|
float density = type == AIGraphNode::Vehicle ? carDensity : pedDensity;
|
||||||
float minDist = (10.f / density) * (10.f / density);
|
float minDist = (10.f / density) * (10.f / density);
|
||||||
float halfRadius2 = std::pow(radius / 2.f, 2.f);
|
float halfRadius2 = std::pow(radius / 2.f, 2.f);
|
||||||
|
|
||||||
// Check if any of the nearby nodes are blocked by a pedestrian standing on it
|
// Check if any of the nearby nodes are blocked by a pedestrian standing on
|
||||||
// or because it's inside the view frustum
|
// it
|
||||||
for (auto it = available.begin(); it != available.end();) {
|
// or because it's inside the view frustum
|
||||||
bool blocked = false;
|
for (auto it = available.begin(); it != available.end();) {
|
||||||
float dist2 = glm::distance2(camera.position, (*it)->position);
|
bool blocked = false;
|
||||||
|
float dist2 = glm::distance2(camera.position, (*it)->position);
|
||||||
|
|
||||||
for (auto& obj : world->pedestrianPool.objects) {
|
for (auto& obj : world->pedestrianPool.objects) {
|
||||||
if (glm::distance2( (*it)->position, obj.second->getPosition() ) <= minDist) {
|
if (glm::distance2((*it)->position, obj.second->getPosition()) <=
|
||||||
blocked = true;
|
minDist) {
|
||||||
break;
|
blocked = true;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check that we're not going to spawn something right where the player is looking
|
// Check that we're not going to spawn something right where the player
|
||||||
if (dist2 <= halfRadius2 && camera.frustum.intersects((*it)->position, 1.f)) {
|
// is looking
|
||||||
blocked = true;
|
if (dist2 <= halfRadius2 &&
|
||||||
}
|
camera.frustum.intersects((*it)->position, 1.f)) {
|
||||||
|
blocked = true;
|
||||||
if (blocked) {
|
}
|
||||||
it = available.erase( it );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return available;
|
if (blocked) {
|
||||||
|
it = available.erase(it);
|
||||||
|
} else {
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return available;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrafficDirector::setDensity(AIGraphNode::NodeType type, float density)
|
void TrafficDirector::setDensity(AIGraphNode::NodeType type, float density) {
|
||||||
{
|
switch (type) {
|
||||||
switch ( type )
|
case AIGraphNode::Vehicle:
|
||||||
{
|
carDensity = density;
|
||||||
case AIGraphNode::Vehicle:
|
break;
|
||||||
carDensity = density;
|
case AIGraphNode::Pedestrian:
|
||||||
break;
|
pedDensity = density;
|
||||||
case AIGraphNode::Pedestrian:
|
break;
|
||||||
pedDensity = density;
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<GameObject*> TrafficDirector::populateNearby(const ViewCamera& camera, float radius, int maxSpawn)
|
std::vector<GameObject*> TrafficDirector::populateNearby(
|
||||||
{
|
const ViewCamera& camera, float radius, int maxSpawn) {
|
||||||
int availablePeds = maximumPedestrians - world->pedestrianPool.objects.size();
|
int availablePeds =
|
||||||
|
maximumPedestrians - world->pedestrianPool.objects.size();
|
||||||
|
|
||||||
std::vector<GameObject*> created;
|
std::vector<GameObject*> created;
|
||||||
|
|
||||||
/// @todo Check how "in player view" should be determined.
|
/// @todo Check how "in player view" should be determined.
|
||||||
|
|
||||||
// Don't check the frustum for things more than 1/2 of the radius away
|
// Don't check the frustum for things more than 1/2 of the radius away
|
||||||
// so that things will spawn as you drive towards them
|
// so that things will spawn as you drive towards them
|
||||||
float halfRadius2 = std::pow(radius/ 2.f, 2.f);
|
float halfRadius2 = std::pow(radius / 2.f, 2.f);
|
||||||
|
|
||||||
// Spawn vehicles at vehicle generators
|
// Spawn vehicles at vehicle generators
|
||||||
auto camera2D = glm::vec2(camera.position);
|
auto camera2D = glm::vec2(camera.position);
|
||||||
for (auto& gen : world->state->vehicleGenerators) {
|
for (auto& gen : world->state->vehicleGenerators) {
|
||||||
/// @todo verify how vehicle generator proximity is determined
|
/// @todo verify how vehicle generator proximity is determined
|
||||||
auto gen2D = glm::vec2(gen.position);
|
auto gen2D = glm::vec2(gen.position);
|
||||||
float dist2 = glm::distance2(camera2D, gen2D);
|
float dist2 = glm::distance2(camera2D, gen2D);
|
||||||
if (dist2 < radius * radius) {
|
if (dist2 < radius * radius) {
|
||||||
auto position = gen.position;
|
auto position = gen.position;
|
||||||
// Check that the on-ground position is not in view
|
// Check that the on-ground position is not in view
|
||||||
if (gen.position.z < -90.f) {
|
if (gen.position.z < -90.f) {
|
||||||
position = world->getGroundAtPosition(position);
|
position = world->getGroundAtPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dist2 <= halfRadius2 &&
|
if (dist2 <= halfRadius2 &&
|
||||||
camera.frustum.intersects(position, 1.f)) {
|
camera.frustum.intersects(position, 1.f)) {
|
||||||
if (!gen.alwaysSpawn) {
|
if (!gen.alwaysSpawn) {
|
||||||
// Don't spawn in the view frustum unless we're forced to
|
// Don't spawn in the view frustum unless we're forced to
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto spawned = world->tryToSpawnVehicle(gen);
|
auto spawned = world->tryToSpawnVehicle(gen);
|
||||||
if (spawned) {
|
if (spawned) {
|
||||||
created.push_back(spawned);
|
created.push_back(spawned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto type = AIGraphNode::Pedestrian;
|
auto type = AIGraphNode::Pedestrian;
|
||||||
auto available = findAvailableNodes(type, camera, radius);
|
auto available = findAvailableNodes(type, camera, radius);
|
||||||
|
|
||||||
if( availablePeds <= 0 )
|
|
||||||
{
|
|
||||||
// We have already reached the limit of spawned traffic
|
|
||||||
return { };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Hardcoded cop Pedestrian
|
|
||||||
std::vector<uint16_t> validPeds = { 1 };
|
|
||||||
validPeds.insert(validPeds.end(), {20, 11, 19, 5});
|
|
||||||
std::random_device rd;
|
|
||||||
std::default_random_engine re(rd());
|
|
||||||
std::uniform_int_distribution<> d(0, validPeds.size()-1);
|
|
||||||
|
|
||||||
int counter = availablePeds;
|
if (availablePeds <= 0) {
|
||||||
// maxSpawn can be -1 for "as many as possible"
|
// We have already reached the limit of spawned traffic
|
||||||
if( maxSpawn > -1 )
|
return {};
|
||||||
{
|
}
|
||||||
counter = std::min( availablePeds, maxSpawn );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( AIGraphNode* spawn : available )
|
/// Hardcoded cop Pedestrian
|
||||||
{
|
std::vector<uint16_t> validPeds = {1};
|
||||||
if( spawn->type != AIGraphNode::Pedestrian )
|
validPeds.insert(validPeds.end(), {20, 11, 19, 5});
|
||||||
{
|
std::random_device rd;
|
||||||
continue;
|
std::default_random_engine re(rd());
|
||||||
}
|
std::uniform_int_distribution<> d(0, validPeds.size() - 1);
|
||||||
if ( counter > -1 )
|
|
||||||
{
|
|
||||||
if ( counter == 0 )
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
counter --;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn a pedestrian from the available pool
|
int counter = availablePeds;
|
||||||
auto ped = world->createPedestrian(validPeds[d(re)], spawn->position + glm::vec3( 0.f, 0.f, 1.f ) );
|
// maxSpawn can be -1 for "as many as possible"
|
||||||
ped->setLifetime(GameObject::TrafficLifetime);
|
if (maxSpawn > -1) {
|
||||||
ped->controller->setGoal(CharacterController::TrafficWander);
|
counter = std::min(availablePeds, maxSpawn);
|
||||||
created.push_back( ped );
|
}
|
||||||
}
|
|
||||||
|
for (AIGraphNode* spawn : available) {
|
||||||
// Find places it's legal to spawn things
|
if (spawn->type != AIGraphNode::Pedestrian) {
|
||||||
|
continue;
|
||||||
return created;
|
}
|
||||||
|
if (counter > -1) {
|
||||||
|
if (counter == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn a pedestrian from the available pool
|
||||||
|
auto ped = world->createPedestrian(
|
||||||
|
validPeds[d(re)], spawn->position + glm::vec3(0.f, 0.f, 1.f));
|
||||||
|
ped->setLifetime(GameObject::TrafficLifetime);
|
||||||
|
ped->controller->setGoal(CharacterController::TrafficWander);
|
||||||
|
created.push_back(ped);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find places it's legal to spawn things
|
||||||
|
|
||||||
|
return created;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrafficDirector::setPopulationLimits(int maxPeds, int maxCars)
|
void TrafficDirector::setPopulationLimits(int maxPeds, int maxCars) {
|
||||||
{
|
maximumPedestrians = maxPeds;
|
||||||
maximumPedestrians = maxPeds;
|
maximumCars = maxCars;
|
||||||
maximumCars = maxCars;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,34 +11,35 @@ class GameObject;
|
|||||||
class GameWorld;
|
class GameWorld;
|
||||||
class ViewCamera;
|
class ViewCamera;
|
||||||
|
|
||||||
class TrafficDirector
|
class TrafficDirector {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
TrafficDirector(AIGraph* graph, GameWorld* world);
|
||||||
TrafficDirector(AIGraph* graph, GameWorld* world);
|
|
||||||
|
|
||||||
std::vector< AIGraphNode* > findAvailableNodes(AIGraphNode::NodeType type, const ViewCamera& camera, float radius);
|
|
||||||
|
|
||||||
void setDensity(AIGraphNode::NodeType type, float density);
|
|
||||||
|
|
||||||
/**
|
std::vector<AIGraphNode*> findAvailableNodes(AIGraphNode::NodeType type,
|
||||||
* Creates new traffic at available locations.
|
const ViewCamera& camera,
|
||||||
* @param camera The camera to spawn around
|
float radius);
|
||||||
* @param radius the maximum distance to spawn in
|
|
||||||
* @param max The maximum number of traffic to create.
|
void setDensity(AIGraphNode::NodeType type, float density);
|
||||||
*/
|
|
||||||
std::vector<GameObject*> populateNearby( const ViewCamera& camera, float radius, int maxSpawn = -1 );
|
/**
|
||||||
|
* Creates new traffic at available locations.
|
||||||
|
* @param camera The camera to spawn around
|
||||||
|
* @param radius the maximum distance to spawn in
|
||||||
|
* @param max The maximum number of traffic to create.
|
||||||
|
*/
|
||||||
|
std::vector<GameObject*> populateNearby(const ViewCamera& camera,
|
||||||
|
float radius, int maxSpawn = -1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum number of pedestrians and cars in the traffic system
|
||||||
|
*/
|
||||||
|
void setPopulationLimits(int maxPeds, int maxCars);
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the maximum number of pedestrians and cars in the traffic system
|
|
||||||
*/
|
|
||||||
void setPopulationLimits(int maxPeds, int maxCars);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AIGraph* graph;
|
AIGraph* graph;
|
||||||
GameWorld* world;
|
GameWorld* world;
|
||||||
float pedDensity;
|
float pedDensity;
|
||||||
float carDensity;
|
float carDensity;
|
||||||
int maximumPedestrians;
|
int maximumPedestrians;
|
||||||
int maximumCars;
|
int maximumCars;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user