1
0
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:
Daniel Evans 2013-10-02 01:27:48 +01:00
parent f7ae75876e
commit 657ae86ea4
7 changed files with 133 additions and 86 deletions

View File

@ -181,3 +181,8 @@ glm::mat4 Animator::getFrameMatrix(size_t frame) const
}
}
}
bool Animator::isCompleted() const
{
return serverTime >= animation->duration;
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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

View File

@ -31,7 +31,8 @@ public:
Crouch,
VehicleDrive,
VehicleSit,
KnockedDown
KnockedDown,
GettingUp
};
std::shared_ptr<LoaderIDE::PEDS_t> ped;

View File

@ -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;