1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-07 03:12:36 +01:00

Add AI Goal system, FollowLeader goal.

+ Add support for setting leader, e.g. Misty follows you during "Luigi's Girls".
This commit is contained in:
Daniel Evans 2015-01-22 15:00:30 +00:00
parent 0c84873be2
commit 3f40ba0e18
7 changed files with 98 additions and 3 deletions

View File

@ -28,6 +28,21 @@ public:
virtual bool update(CharacterObject* character, CharacterController* controller) = 0;
};
/**
* Available AI goals.
*/
enum Goal
{
/**
* No goal, will idle or execute external Activities.
*/
None,
/**
* Keep close to leader character
*/
FollowLeader
};
protected:
/**
@ -45,6 +60,10 @@ protected:
bool running;
// Goal related variables
Goal currentGoal;
CharacterObject* leader;
public:
CharacterController(CharacterObject* character);
@ -90,6 +109,12 @@ public:
void setRawMovement(const glm::vec3& movement);
void setRunning(bool run);
void setGoal(Goal goal) { currentGoal = goal; }
Goal getGoal() const { return currentGoal; }
void setTargetCharacter(CharacterObject* c) { leader = c; }
CharacterObject* getTargetCharacter() const { return leader; }
};
#define DECL_ACTIVITY( activity_name ) \

View File

@ -7,12 +7,15 @@
struct AIGraphNode;
class DefaultAIController : public CharacterController
{
glm::vec3 gotoPos;
public:
DefaultAIController(CharacterObject* character)
: CharacterController(character) {}
glm::vec3 getTargetPosition();
virtual void update(float dt);
};
#endif

View File

@ -24,7 +24,8 @@ void CharacterController::setActivity(CharacterController::Activity* activity)
}
CharacterController::CharacterController(CharacterObject* character)
: character(character), _currentActivity(nullptr), _nextActivity(nullptr), running(false)
: character(character), _currentActivity(nullptr), _nextActivity(nullptr), running(false),
currentGoal(None), leader(nullptr)
{
character->controller = this;
}
@ -128,6 +129,9 @@ void CharacterController::update(float dt)
}
}
// Reset raw movement between activity updates.
setRawMovement(glm::vec3());
if( updateActivity() ) {
if( _currentActivity ) {
delete _currentActivity;

View File

@ -14,3 +14,49 @@ glm::vec3 DefaultAIController::getTargetPosition()
}*/
return glm::vec3();
}
const float followRadius = 5.f;
void DefaultAIController::update(float dt)
{
switch(currentGoal)
{
case FollowLeader:
{
if( ! leader ) break;
if( getCharacter()->getCurrentVehicle() )
{
if( leader->getCurrentVehicle() != getCharacter()->getCurrentVehicle() )
{
skipActivity();
setNextActivity(new Activities::ExitVehicle);
}
// else we're already in the right spot.
}
else
{
if( leader->getCurrentVehicle() )
{
setNextActivity(new Activities::EnterVehicle(leader->getCurrentVehicle(), 1));
}
else
{
glm::vec3 dir = leader->getPosition() - getCharacter()->getPosition();
if( glm::length(dir) > followRadius )
{
if( glm::distance(gotoPos, leader->getPosition()) > followRadius )
{
gotoPos = leader->getPosition() + ( glm::normalize(-dir) * followRadius * 0.7f );
skipActivity();
setNextActivity(new Activities::GoTo(gotoPos));
}
}
}
}
}
break;
default: break;
}
CharacterController::update(dt);
}

View File

@ -81,7 +81,7 @@ void CharacterObject::createActor(const glm::vec3& size)
physShape = new btCapsuleShapeZ(size.x, size.z);
physObject->setCollisionShape(physShape);
physObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
physCharacter = new btKinematicCharacterController(physObject, physShape, 0.2f, 2);
physCharacter = new btKinematicCharacterController(physObject, physShape, 0.1f, 2);
physCharacter->setVelocityForTimeInterval(btVector3(1.f, 1.f, 0.f), 1.f);
physCharacter->setGravity(engine->dynamicsWorld->getGravity().length());
physCharacter->setJumpSpeed(5.f);

View File

@ -572,6 +572,15 @@ void game_character_exit_vehicle(const ScriptArguments& args)
}
}
void game_character_follow_character(const ScriptArguments& args)
{
auto controller = (CharacterController*)(*args[0].handle);
auto leader = (CharacterController*)(*args[1].handle);
controller->setGoal(CharacterController::FollowLeader);
controller->setTargetCharacter(leader->getCharacter());
}
void game_navigate_on_foot(const ScriptArguments& args)
{
auto controller = (CharacterController*)(*args[0].handle);
@ -867,7 +876,7 @@ ObjectModule::ObjectModule()
bindFunction(0x01D4, game_enter_as_passenger, 2, "Character Enter Vehicle as Passenger" );
bindFunction(0x01D3, game_character_exit_vehicle, 2, "Character Exit Vehicle" );
bindUnimplemented( 0x01DF, game_character_follow_character, 2, "Make Character Follow Character" );
bindFunction(0x01DF, game_character_follow_character, 2, "Make Character Follow Character");
bindFunction(0x01F3, game_vehicle_in_air, 1, "Is Vehicle In Air" );
bindFunction(0x01F4, game_vehicle_flipped, 1, "Is Car Flipped" );

View File

@ -78,6 +78,14 @@ DebugState::DebugState(RWGame* game, const glm::vec3& vp, const glm::quat& vd)
m->addEntry(Menu::lambda("Jump to Hospital", [=] {
jumpCharacter(game, game->getWorld()->state.player, glm::vec3(1123.77, -569.15, 100.0));
}, entryHeight));
m->addEntry(Menu::lambda("Add Follower", [=] {
auto spawnPos = game->getWorld()->state.player->getCharacter()->getPosition();
spawnPos += game->getWorld()->state.player->getCharacter()->getRotation() * glm::vec3(-1.f, 0.f, 0.f);
auto follower = game->getWorld()->createPedestrian(12, spawnPos);
jumpCharacter(game, follower->controller, spawnPos);
follower->controller->setGoal(CharacterController::FollowLeader);
follower->controller->setTargetCharacter(game->getWorld()->state.player->getCharacter());
}, entryHeight));
this->enterMenu(m);