mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 18:32:44 +01:00
Improved pedestrian KD behaviour
This commit is contained in:
parent
f7ae75876e
commit
657ae86ea4
@ -181,3 +181,8 @@ glm::mat4 Animator::getFrameMatrix(size_t frame) const
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Animator::isCompleted() const
|
||||
{
|
||||
return serverTime >= animation->duration;
|
||||
}
|
@ -68,22 +68,25 @@ void GTACharacter::changeAction(Activity newAction)
|
||||
switch( currentActivity ) {
|
||||
default:
|
||||
case Idle:
|
||||
createActor();
|
||||
animator->setAnimation(engine->gameData.animations.at("idle_stance"));
|
||||
break;
|
||||
case Walk:
|
||||
createActor();
|
||||
animator->setAnimation(engine->gameData.animations.at("walk_civi"));
|
||||
break;
|
||||
case Run:
|
||||
createActor();
|
||||
animator->setAnimation(engine->gameData.animations.at("run_civi"));
|
||||
break;
|
||||
case KnockedDown:
|
||||
// Change body shape.
|
||||
position += glm::vec3(0.f, 0.f, 0.5f);
|
||||
createActor(glm::vec3(0.5f, 0.5f, 0.1f));
|
||||
animator->setAnimation(engine->gameData.animations.at("kd_front"), false);
|
||||
break;
|
||||
case GettingUp:
|
||||
// Change body shape back to normal.
|
||||
createActor();
|
||||
animator->setAnimation(engine->gameData.animations.at("getup"), false);
|
||||
break;
|
||||
case VehicleDrive:
|
||||
animator->setAnimation(engine->gameData.animations.at("car_sit"));
|
||||
break;
|
||||
|
@ -1,102 +1,129 @@
|
||||
#include "renderwure/ai/GTADefaultAIController.hpp"
|
||||
#include <renderwure/objects/GTACharacter.hpp>
|
||||
#include <renderwure/engine/GTAEngine.hpp>
|
||||
#include <renderwure/engine/Animator.hpp>
|
||||
#include <renderwure/objects/GTAVehicle.hpp>
|
||||
|
||||
void GTADefaultAIController::update(float dt)
|
||||
{
|
||||
if( action == Wander ) {
|
||||
if( targetNode == nullptr ) {
|
||||
GTAAINode::NodeType currentType = character->getCurrentVehicle()
|
||||
? GTAAINode::Vehicle : GTAAINode::Pedestrian;
|
||||
|
||||
float d = std::numeric_limits< float >::max();
|
||||
for( auto n = character->engine->aigraph.nodes.begin();
|
||||
n != character->engine->aigraph.nodes.end();
|
||||
++n ) {
|
||||
if( (*n)->type != currentType ) continue;
|
||||
if( (*n) == lastNode ) continue;
|
||||
float ld = glm::length( (*n)->position - character->getPosition() );
|
||||
if( ld > nodeMargin && ld < d ) {
|
||||
d = ld;
|
||||
targetNode = (*n);
|
||||
}
|
||||
}
|
||||
|
||||
if( targetNode == nullptr ) {
|
||||
character->changeAction(GTACharacter::Idle);
|
||||
}
|
||||
else {
|
||||
character->changeAction(GTACharacter::Walk);
|
||||
// Choose a new random margin
|
||||
if(character->getCurrentVehicle()) {
|
||||
std::uniform_real_distribution<float> dist(2.f, 2.5f);
|
||||
nodeMargin = dist(character->engine->randomEngine);
|
||||
}
|
||||
else {
|
||||
std::uniform_real_distribution<float> dist(1.f, 1.5f);
|
||||
nodeMargin = dist(character->engine->randomEngine);
|
||||
}
|
||||
}
|
||||
if( character->currentActivity == GTACharacter::KnockedDown ) {
|
||||
if( getUpTime < 0.f ) {
|
||||
getUpTime = 1.5f;
|
||||
}
|
||||
else if( glm::length(getTargetPosition() - character->getPosition()) < nodeMargin ) {
|
||||
if(targetNode->connections.size() > 0) {
|
||||
std::uniform_int_distribution<int> uniform(0, targetNode->connections.size()-1);
|
||||
GTAAINode* nextNode = nullptr; size_t i = 0;
|
||||
do
|
||||
{
|
||||
nextNode = targetNode->connections[uniform(character->engine->randomEngine)];
|
||||
} while(i++ < targetNode->connections.size() && nextNode == lastNode);
|
||||
lastNode = targetNode;
|
||||
targetNode = nextNode;
|
||||
}
|
||||
else {
|
||||
targetNode = nullptr;
|
||||
character->changeAction(GTACharacter::Idle);
|
||||
else {
|
||||
getUpTime -= dt;
|
||||
if(getUpTime < 0.f) {
|
||||
character->changeAction(GTACharacter::GettingUp);
|
||||
getUpTime = -1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (character->currentActivity == GTACharacter::GettingUp ) {
|
||||
if( character->animator->isCompleted() ) {
|
||||
character->changeAction(GTACharacter::Idle);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( action == Wander ) {
|
||||
if( targetNode == nullptr ) {
|
||||
GTAAINode::NodeType currentType = character->getCurrentVehicle()
|
||||
? GTAAINode::Vehicle : GTAAINode::Pedestrian;
|
||||
|
||||
if( action == Wander && targetNode != nullptr ) {
|
||||
auto d = targetNode->position - character->getPosition();
|
||||
float d = std::numeric_limits< float >::max();
|
||||
for( auto n = character->engine->aigraph.nodes.begin();
|
||||
n != character->engine->aigraph.nodes.end();
|
||||
++n ) {
|
||||
if( (*n)->type != currentType ) continue;
|
||||
if( (*n) == lastNode ) continue;
|
||||
float ld = glm::length( (*n)->position - character->getPosition() );
|
||||
if( ld > nodeMargin && ld < d ) {
|
||||
d = ld;
|
||||
targetNode = (*n);
|
||||
}
|
||||
}
|
||||
|
||||
if( targetNode == nullptr ) {
|
||||
character->changeAction(GTACharacter::Idle);
|
||||
}
|
||||
else {
|
||||
character->changeAction(GTACharacter::Walk);
|
||||
// Choose a new random margin
|
||||
if(character->getCurrentVehicle()) {
|
||||
std::uniform_real_distribution<float> dist(2.f, 2.5f);
|
||||
nodeMargin = dist(character->engine->randomEngine);
|
||||
}
|
||||
else {
|
||||
std::uniform_real_distribution<float> dist(1.f, 1.5f);
|
||||
nodeMargin = dist(character->engine->randomEngine);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( glm::length(getTargetPosition() - character->getPosition()) < nodeMargin ) {
|
||||
if(targetNode->connections.size() > 0) {
|
||||
std::uniform_int_distribution<int> uniform(0, targetNode->connections.size()-1);
|
||||
GTAAINode* nextNode = nullptr; size_t i = 0;
|
||||
do
|
||||
{
|
||||
nextNode = targetNode->connections[uniform(character->engine->randomEngine)];
|
||||
} while(i++ < targetNode->connections.size() && nextNode == lastNode);
|
||||
lastNode = targetNode;
|
||||
targetNode = nextNode;
|
||||
}
|
||||
else {
|
||||
targetNode = nullptr;
|
||||
character->changeAction(GTACharacter::Idle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure the AI doesn't get stuck in idle with a target node.
|
||||
if(character->currentActivity == GTACharacter::Idle) {
|
||||
character->changeAction(GTACharacter::Walk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(lastNode && character->getCurrentVehicle()) {
|
||||
auto nDir = glm::normalize(targetNode->position - lastNode->position);
|
||||
auto right = glm::cross(nDir, glm::vec3(0.f, 0.f, 1.f));
|
||||
d += right * 2.2f;
|
||||
if( action == Wander && targetNode != nullptr ) {
|
||||
auto d = targetNode->position - character->getPosition();
|
||||
|
||||
if(lastNode && character->getCurrentVehicle()) {
|
||||
auto nDir = glm::normalize(targetNode->position - lastNode->position);
|
||||
auto right = glm::cross(nDir, glm::vec3(0.f, 0.f, 1.f));
|
||||
d += right * 2.2f;
|
||||
}
|
||||
|
||||
if(character->getCurrentVehicle()) {
|
||||
auto vd = glm::inverse(character->getCurrentVehicle()->getRotation()) * d;
|
||||
float va = -atan2( vd.x, vd.y );
|
||||
if(glm::abs(va) > (3.141f/2.f)) {
|
||||
va = -va;
|
||||
}
|
||||
character->getCurrentVehicle()->setSteeringAngle(va);
|
||||
}
|
||||
else {
|
||||
float a = -atan2( d.x, d.y );
|
||||
character->rotation = glm::quat(glm::vec3(0.f, 0.f, a));
|
||||
}
|
||||
}
|
||||
|
||||
if(character->getCurrentVehicle()) {
|
||||
auto vd = glm::inverse(character->getCurrentVehicle()->getRotation()) * d;
|
||||
float va = -atan2( vd.x, vd.y );
|
||||
if(glm::abs(va) > (3.141f/2.f)) {
|
||||
va = -va;
|
||||
if(targetNode == nullptr) {
|
||||
character->getCurrentVehicle()->setThrottle(0.f);
|
||||
}
|
||||
character->getCurrentVehicle()->setSteeringAngle(va);
|
||||
}
|
||||
else {
|
||||
float a = -atan2( d.x, d.y );
|
||||
character->rotation = glm::quat(glm::vec3(0.f, 0.f, a));
|
||||
}
|
||||
}
|
||||
else {
|
||||
float targetVelocity = 5.f;
|
||||
float perc = (targetVelocity - character->getCurrentVehicle()->physBody->getLinearVelocity().length())/targetVelocity;
|
||||
perc = std::min(1.f, std::max(0.f, perc));
|
||||
|
||||
if(character->getCurrentVehicle()) {
|
||||
if(targetNode == nullptr) {
|
||||
character->getCurrentVehicle()->setThrottle(0.f);
|
||||
}
|
||||
else {
|
||||
float targetVelocity = 5.f;
|
||||
float perc = (targetVelocity - character->getCurrentVehicle()->physBody->getLinearVelocity().length())/targetVelocity;
|
||||
perc = std::min(1.f, std::max(0.f, perc));
|
||||
// Determine if the vehicle should reverse instead.
|
||||
auto td = getTargetPosition() - character->getPosition();
|
||||
auto vd = character->getCurrentVehicle()->getRotation() * glm::vec3(0.f, 1.f, 0.f);
|
||||
if(glm::dot(td, vd) < -0.25f) {
|
||||
perc *= -1.f;
|
||||
}
|
||||
|
||||
// Determine if the vehicle should reverse instead.
|
||||
auto td = getTargetPosition() - character->getPosition();
|
||||
auto vd = character->getCurrentVehicle()->getRotation() * glm::vec3(0.f, 1.f, 0.f);
|
||||
if(glm::dot(td, vd) < -0.25f) {
|
||||
perc *= -1.f;
|
||||
character->getCurrentVehicle()->setThrottle(perc);
|
||||
}
|
||||
|
||||
character->getCurrentVehicle()->setThrottle(perc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ class GTADefaultAIController : public GTAAIController
|
||||
GTAAINode* lastNode;
|
||||
|
||||
float nodeMargin; /// Minimum distance away to "reach" node.
|
||||
float getUpTime; /// Time to wait before getting up.
|
||||
|
||||
public:
|
||||
|
||||
@ -26,7 +27,7 @@ public:
|
||||
action(Wander),
|
||||
targetNode(nullptr),
|
||||
lastNode(nullptr),
|
||||
nodeMargin(0.f) {}
|
||||
nodeMargin(0.f), getUpTime(-1.f) {}
|
||||
|
||||
void update(float dt);
|
||||
|
||||
|
@ -80,6 +80,11 @@ public:
|
||||
* @return
|
||||
*/
|
||||
glm::mat4 getFrameMatrix(size_t frame) const;
|
||||
|
||||
/**
|
||||
* Returns true if the animation has finished playing.
|
||||
*/
|
||||
bool isCompleted() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -31,7 +31,8 @@ public:
|
||||
Crouch,
|
||||
VehicleDrive,
|
||||
VehicleSit,
|
||||
KnockedDown
|
||||
KnockedDown,
|
||||
GettingUp
|
||||
};
|
||||
|
||||
std::shared_ptr<LoaderIDE::PEDS_t> ped;
|
||||
|
@ -86,6 +86,11 @@ void command(const std::string& line)
|
||||
playerCharacter = gta->createPedestrian(1, plyPos);
|
||||
player = new GTAPlayerAIController(playerCharacter);
|
||||
}
|
||||
else if("knock-down" == cmd) {
|
||||
for(auto it = gta->pedestrians.begin(); it != gta->pedestrians.end(); ++it) {
|
||||
(*it)->changeAction(GTACharacter::KnockedDown);
|
||||
}
|
||||
}
|
||||
else if("list-ipl" == cmd) {
|
||||
for(std::map<std::string, std::string>::iterator it = gta->gameData.iplLocations.begin();
|
||||
it != gta->gameData.iplLocations.end();
|
||||
@ -341,7 +346,7 @@ void update(float dt)
|
||||
gta->vehicleInstances[v]->tick(dt);
|
||||
}
|
||||
|
||||
gta->dynamicsWorld->stepSimulation(dt, 1, dt);
|
||||
gta->dynamicsWorld->stepSimulation(dt, 2, dt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,7 +480,7 @@ int main(int argc, char *argv[])
|
||||
sf::Clock clock;
|
||||
|
||||
float accum = 0.f;
|
||||
float ts = 1.f / 20.f;
|
||||
float ts = 1.f / 60.f;
|
||||
|
||||
while (window.isOpen()) {
|
||||
sf::Event event;
|
||||
|
Loading…
Reference in New Issue
Block a user