mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-18 16:32:32 +02:00
Initial shift to AIController controlling
This commit is contained in:
parent
34400e19ab
commit
532738077e
@ -11,22 +11,60 @@ struct GTACharacter;
|
||||
*/
|
||||
class GTAAIController
|
||||
{
|
||||
public:
|
||||
|
||||
enum Activity {
|
||||
Idle,
|
||||
GoTo,
|
||||
};
|
||||
|
||||
struct ActivityParameter {
|
||||
glm::vec3 position;
|
||||
|
||||
ActivityParameter( ) {}
|
||||
|
||||
ActivityParameter( const glm::vec3& position ) :
|
||||
position( position ) {}
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The character being controlled.
|
||||
*/
|
||||
GTACharacter* character;
|
||||
|
||||
|
||||
Activity _currentActivity;
|
||||
Activity _nextActivity;
|
||||
|
||||
ActivityParameter _currentParameter;
|
||||
ActivityParameter _nextParameter;
|
||||
|
||||
bool updateActivity();
|
||||
void setActivity(Activity activity, const ActivityParameter& _parameter );
|
||||
|
||||
public:
|
||||
|
||||
GTAAIController(GTACharacter* character);
|
||||
|
||||
Activity getCurrentActivity() const { return _currentActivity; }
|
||||
const ActivityParameter& getCurrentActivityParameter() const { return _currentParameter; }
|
||||
|
||||
Activity getNextActivity() const { return _nextActivity; }
|
||||
const ActivityParameter& getNextActivityParameter() const { return _nextParameter; }
|
||||
|
||||
/**
|
||||
* @brief setNextActivity Sets the next Activity with a parameter.
|
||||
* @param activity
|
||||
* @param position
|
||||
*/
|
||||
void setNextActivity( Activity activity, const ActivityParameter& parameter );
|
||||
|
||||
/**
|
||||
* @brief update Updates the controller.
|
||||
* @param dt
|
||||
*/
|
||||
virtual void update(float dt) = 0;
|
||||
virtual void update(float dt);
|
||||
|
||||
virtual glm::vec3 getTargetPosition() = 0;
|
||||
};
|
||||
|
@ -7,30 +7,11 @@
|
||||
struct GTAAINode;
|
||||
class GTADefaultAIController : public GTAAIController
|
||||
{
|
||||
enum Action
|
||||
{
|
||||
Wander
|
||||
};
|
||||
|
||||
Action action;
|
||||
|
||||
GTAAINode* targetNode;
|
||||
GTAAINode* lastNode;
|
||||
|
||||
float nodeMargin; /// Minimum distance away to "reach" node.
|
||||
float getUpTime; /// Time to wait before getting up.
|
||||
|
||||
public:
|
||||
|
||||
GTADefaultAIController(GTACharacter* character)
|
||||
: GTAAIController(character),
|
||||
action(Wander),
|
||||
targetNode(nullptr),
|
||||
lastNode(nullptr),
|
||||
nodeMargin(0.f), getUpTime(-1.f) {}
|
||||
|
||||
void update(float dt);
|
||||
|
||||
: GTAAIController(character) {}
|
||||
|
||||
glm::vec3 getTargetPosition();
|
||||
};
|
||||
|
||||
|
@ -44,9 +44,13 @@ private:
|
||||
void createActor(const glm::vec3& size = glm::vec3(0.35f, 0.35f, 1.3f));
|
||||
void destroyActor();
|
||||
|
||||
// Incredibly hacky "move in this direction".
|
||||
bool _hasTargetPosition;
|
||||
glm::vec3 _targetPosition;
|
||||
|
||||
public:
|
||||
|
||||
enum Activity {
|
||||
enum Action {
|
||||
None,
|
||||
Idle,
|
||||
Walk,
|
||||
@ -84,16 +88,16 @@ public:
|
||||
|
||||
Type type() { return Character; }
|
||||
|
||||
Activity currentActivity;
|
||||
Action currentActivity;
|
||||
|
||||
void enterActivity(Activity act);
|
||||
void enterAction(Action act);
|
||||
|
||||
void tick(float dt);
|
||||
|
||||
/**
|
||||
* @brief updateCharacter updates internall bullet Character.
|
||||
*/
|
||||
void updateCharacter();
|
||||
void updateCharacter(float dt);
|
||||
|
||||
virtual void setPosition(const glm::vec3& pos);
|
||||
|
||||
@ -114,6 +118,8 @@ public:
|
||||
* (taking into account the current vehicle)
|
||||
*/
|
||||
void resetToAINode();
|
||||
|
||||
void setTargetPosition( const glm::vec3& target );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,8 +1,59 @@
|
||||
#include <ai/GTAAIController.hpp>
|
||||
#include <objects/GTACharacter.hpp>
|
||||
|
||||
bool GTAAIController::updateActivity()
|
||||
{
|
||||
switch( _currentActivity ) {
|
||||
default: break;
|
||||
|
||||
case GoTo: {
|
||||
/* TODO: Use the ai nodes to navigate to the position */
|
||||
glm::vec3 targetDirection = _currentParameter.position - character->getPosition();
|
||||
|
||||
if( glm::length(targetDirection) < 0.01f ) {
|
||||
character->enterAction(GTACharacter::Idle);
|
||||
return true;
|
||||
}
|
||||
|
||||
character->setTargetPosition( _currentParameter.position );
|
||||
|
||||
glm::quat r( glm::vec3{ 0.f, 0.f, atan2(targetDirection.y, targetDirection.x) - glm::half_pi<float>() } );
|
||||
character->rotation = r;
|
||||
character->enterAction(GTACharacter::Walk);
|
||||
} break;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GTAAIController::setActivity(GTAAIController::Activity activity, const ActivityParameter ¶meter)
|
||||
{
|
||||
_currentActivity = activity;
|
||||
_currentParameter = parameter;
|
||||
}
|
||||
|
||||
GTAAIController::GTAAIController(GTACharacter* character)
|
||||
: character(character)
|
||||
: character(character), _currentActivity(Idle), _nextActivity(Idle)
|
||||
{
|
||||
character->controller = this;
|
||||
}
|
||||
|
||||
void GTAAIController::setNextActivity(GTAAIController::Activity activity, const ActivityParameter ¶meter)
|
||||
{
|
||||
if( _currentActivity == Idle ) {
|
||||
setActivity(activity, parameter);
|
||||
_nextActivity = Idle;
|
||||
}
|
||||
else {
|
||||
_nextParameter = parameter;
|
||||
_nextActivity = activity;
|
||||
}
|
||||
}
|
||||
|
||||
void GTAAIController::update(float dt)
|
||||
{
|
||||
if(updateActivity()) {
|
||||
setActivity(Idle, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,142 +1,16 @@
|
||||
#include "ai/GTADefaultAIController.hpp"
|
||||
#include <objects/GTACharacter.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <engine/Animator.hpp>
|
||||
#include <objects/GTAVehicle.hpp>
|
||||
|
||||
void GTADefaultAIController::update(float dt)
|
||||
{
|
||||
if( character->currentActivity == GTACharacter::KnockedDown ) {
|
||||
if( getUpTime < 0.f ) {
|
||||
getUpTime = 1.5f;
|
||||
}
|
||||
else {
|
||||
getUpTime -= dt;
|
||||
if(getUpTime < 0.f) {
|
||||
character->enterActivity(GTACharacter::GettingUp);
|
||||
getUpTime = -1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (character->currentActivity == GTACharacter::GettingUp ) {
|
||||
if( character->animator->isCompleted() ) {
|
||||
character->enterActivity(GTACharacter::Idle);
|
||||
}
|
||||
}
|
||||
else {
|
||||
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->enterActivity(GTACharacter::Idle);
|
||||
}
|
||||
else {
|
||||
character->enterActivity(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->enterActivity(GTACharacter::Idle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure the AI doesn't get stuck in idle with a target node.
|
||||
if(character->currentActivity == GTACharacter::Idle) {
|
||||
character->enterActivity(GTACharacter::Walk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
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;
|
||||
}
|
||||
|
||||
character->getCurrentVehicle()->setThrottle(perc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 GTADefaultAIController::getTargetPosition()
|
||||
{
|
||||
if(targetNode) {
|
||||
/*if(targetNode) {
|
||||
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));
|
||||
return targetNode->position + right * 2.2f;
|
||||
}
|
||||
return targetNode->position;
|
||||
}
|
||||
}*/
|
||||
return glm::vec3();
|
||||
}
|
||||
|
@ -65,10 +65,10 @@ void GTAPlayerAIController::update(float dt)
|
||||
if( character->currentActivity != GTACharacter::Jump )
|
||||
{
|
||||
if( glm::length(direction) > 0.001f ) {
|
||||
character->enterActivity(running ? GTACharacter::Run : GTACharacter::Walk);
|
||||
character->enterAction(running ? GTACharacter::Run : GTACharacter::Walk);
|
||||
}
|
||||
else {
|
||||
character->enterActivity(GTACharacter::Idle);
|
||||
character->enterAction(GTACharacter::Idle);
|
||||
}
|
||||
|
||||
if( character->getCurrentVehicle() ) {
|
||||
|
@ -7,7 +7,9 @@
|
||||
|
||||
GTACharacter::GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, Model* model, std::shared_ptr<CharacterData> data)
|
||||
: GameObject(engine, pos, rot, model),
|
||||
currentVehicle(nullptr), currentSeat(0), ped(data), physCharacter(nullptr),
|
||||
currentVehicle(nullptr), currentSeat(0),
|
||||
_hasTargetPosition(false),
|
||||
ped(data), physCharacter(nullptr),
|
||||
controller(nullptr), currentActivity(None)
|
||||
{
|
||||
mHealth = 100.f;
|
||||
@ -30,7 +32,7 @@ GTACharacter::GTACharacter(GameWorld* engine, const glm::vec3& pos, const glm::q
|
||||
animator->setModel(model);
|
||||
|
||||
createActor();
|
||||
enterActivity(Idle);
|
||||
enterAction(Idle);
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +41,7 @@ GTACharacter::~GTACharacter()
|
||||
destroyActor();
|
||||
}
|
||||
|
||||
void GTACharacter::enterActivity(GTACharacter::Activity act)
|
||||
void GTACharacter::enterAction(GTACharacter::Action act)
|
||||
{
|
||||
if(currentActivity != act) {
|
||||
currentActivity = act;
|
||||
@ -66,7 +68,8 @@ void GTACharacter::createActor(const glm::vec3& size)
|
||||
physObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
physCharacter = new btKinematicCharacterController(physObject, physShape, 0.2f, 2);
|
||||
physCharacter->setVelocityForTimeInterval(btVector3(1.f, 1.f, 0.f), 1.f);
|
||||
|
||||
physCharacter->setGravity(engine->dynamicsWorld->getGravity().length());
|
||||
|
||||
engine->dynamicsWorld->addCollisionObject(physObject, btBroadphaseProxy::KinematicFilter, btBroadphaseProxy::StaticFilter);
|
||||
engine->dynamicsWorld->addAction(physCharacter);
|
||||
}
|
||||
@ -92,7 +95,7 @@ void GTACharacter::tick(float dt)
|
||||
}
|
||||
|
||||
if(currentVehicle) {
|
||||
enterActivity(VehicleSit);
|
||||
enterAction(VehicleSit);
|
||||
}
|
||||
|
||||
switch(currentActivity) {
|
||||
@ -136,7 +139,7 @@ void GTACharacter::tick(float dt)
|
||||
|
||||
|
||||
animator->tick(dt);
|
||||
updateCharacter();
|
||||
updateCharacter(dt);
|
||||
|
||||
// Ensure the character doesn't need to be reset
|
||||
if(getPosition().z < -100.f) {
|
||||
@ -144,7 +147,7 @@ void GTACharacter::tick(float dt)
|
||||
}
|
||||
}
|
||||
|
||||
void GTACharacter::updateCharacter()
|
||||
void GTACharacter::updateCharacter(float dt)
|
||||
{
|
||||
if(physCharacter) {
|
||||
// Check to see if the character should be knocked down.
|
||||
@ -181,7 +184,7 @@ void GTACharacter::updateCharacter()
|
||||
if(object->type() == Vehicle) {
|
||||
GTAVehicle* vehicle = static_cast<GTAVehicle*>(object);
|
||||
if(vehicle->physBody->getLinearVelocity().length() > 0.1f) {
|
||||
enterActivity(KnockedDown);
|
||||
enterAction(KnockedDown);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -194,16 +197,44 @@ void GTACharacter::updateCharacter()
|
||||
{
|
||||
if(physCharacter->onGround())
|
||||
{
|
||||
enterActivity(GTACharacter::Idle);
|
||||
enterAction(GTACharacter::Idle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glm::vec3 direction = rotation * animator->getRootTranslation();
|
||||
physCharacter->setWalkDirection(btVector3(direction.x, direction.y, direction.z));
|
||||
|
||||
glm::vec3 walkDir;
|
||||
glm::vec3 animTranslate = animator->getRootTranslation();
|
||||
|
||||
btVector3 Pos = physCharacter->getGhostObject()->getWorldTransform().getOrigin();
|
||||
position = glm::vec3(Pos.x(), Pos.y(), Pos.z());
|
||||
|
||||
if( _hasTargetPosition ) {
|
||||
auto beforedelta = _targetPosition - position;
|
||||
|
||||
glm::quat faceDir( glm::vec3( 0.f, 0.f, atan2(beforedelta.y, beforedelta.x) - glm::half_pi<float>() ) );
|
||||
glm::vec3 direction = faceDir * animTranslate;
|
||||
|
||||
auto positiondelta = _targetPosition - (position + direction);
|
||||
if( glm::length(beforedelta) < glm::length(positiondelta) ) {
|
||||
// Warp the character to the target position if we are about to overstep.
|
||||
physObject->getWorldTransform().setOrigin(btVector3(
|
||||
_targetPosition.x,
|
||||
_targetPosition.y,
|
||||
_targetPosition.z));
|
||||
_hasTargetPosition = false;
|
||||
}
|
||||
else {
|
||||
walkDir = direction;
|
||||
}
|
||||
}
|
||||
else {
|
||||
walkDir = rotation * animTranslate;
|
||||
}
|
||||
|
||||
physCharacter->setWalkDirection(btVector3(walkDir.x, walkDir.y, walkDir.z));
|
||||
|
||||
Pos = physCharacter->getGhostObject()->getWorldTransform().getOrigin();
|
||||
position = glm::vec3(Pos.x(), Pos.y(), Pos.z());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -239,7 +270,7 @@ bool GTACharacter::enterVehicle(GTAVehicle* vehicle, size_t seat)
|
||||
enterVehicle(nullptr, 0);
|
||||
vehicle->setOccupant(seat, this);
|
||||
setCurrentVehicle(vehicle, seat);
|
||||
enterActivity(VehicleSit);
|
||||
enterAction(VehicleSit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -286,7 +317,7 @@ bool GTACharacter::takeDamage(const GameObject::DamageInfo& dmg)
|
||||
void GTACharacter::jump()
|
||||
{
|
||||
physCharacter->jump();
|
||||
enterActivity(GTACharacter::Jump);
|
||||
enterAction(GTACharacter::Jump);
|
||||
}
|
||||
|
||||
void GTACharacter::resetToAINode()
|
||||
@ -319,3 +350,9 @@ void GTACharacter::resetToAINode()
|
||||
}
|
||||
}
|
||||
|
||||
void GTACharacter::setTargetPosition(const glm::vec3 &target)
|
||||
{
|
||||
_targetPosition = target;
|
||||
_hasTargetPosition = true;
|
||||
}
|
||||
|
||||
|
@ -124,13 +124,6 @@ std::map<std::string, std::function<void (std::string)>> Commands = {
|
||||
}
|
||||
}
|
||||
},
|
||||
{"knock-down",
|
||||
[&](std::string) {
|
||||
for(auto it = gta->pedestrians.begin(); it != gta->pedestrians.end(); ++it) {
|
||||
(*it)->enterActivity(GTACharacter::KnockedDown);
|
||||
}
|
||||
}
|
||||
},
|
||||
{"vehicle-test",
|
||||
[&](std::string) {
|
||||
glm::vec3 hit, normal;
|
||||
|
@ -1,2 +1,8 @@
|
||||
#define BOOST_TEST_MODULE gtfw
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#include "test_globals.hpp"
|
||||
|
||||
std::ostream& operator<<( std::ostream& stream, const glm::vec3& v ) {
|
||||
stream << v.x << " " << v.y << " " << v.z;
|
||||
return stream;
|
||||
}
|
||||
|
64
tests/test_character.cpp
Normal file
64
tests/test_character.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <objects/GTACharacter.hpp>
|
||||
#include <ai/GTADefaultAIController.hpp>
|
||||
#include "test_globals.hpp"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(CharacterTests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_create)
|
||||
{
|
||||
{
|
||||
auto character = Global::get().e->createPedestrian(1, {100.f, 100.f, 50.f});
|
||||
|
||||
BOOST_REQUIRE( character != nullptr );
|
||||
|
||||
auto controller = new GTADefaultAIController(character);
|
||||
|
||||
// Check the initial activity is Idle.
|
||||
BOOST_CHECK_EQUAL( controller->getCurrentActivity(), GTAAIController::Idle );
|
||||
|
||||
// Check that Idle activities are instantly displaced.
|
||||
controller->setNextActivity(GTAAIController::GoTo, glm::vec3{ 1000.f, 0.f, 0.f });
|
||||
BOOST_CHECK_EQUAL( controller->getCurrentActivity(), GTAAIController::GoTo );
|
||||
BOOST_CHECK_EQUAL( controller->getNextActivity(), GTAAIController::Idle );
|
||||
|
||||
Global::get().e->destroyObject(character);
|
||||
delete controller;
|
||||
}
|
||||
{
|
||||
GTAAIController::ActivityParameter ap { glm::vec3 { 1.f, 2.f, 3.f } };
|
||||
|
||||
BOOST_CHECK_EQUAL( ap.position, glm::vec3( 1.f, 2.f, 3.f ) );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_activities)
|
||||
{
|
||||
{
|
||||
auto character = Global::get().e->createPedestrian(1, {0.f, 0.f, 0.f});
|
||||
|
||||
BOOST_REQUIRE( character != nullptr );
|
||||
|
||||
auto controller = new GTADefaultAIController(character);
|
||||
|
||||
controller->setNextActivity( GTAAIController::GoTo, { glm::vec3{ 10.f, 0.f, 0.f } } );
|
||||
|
||||
BOOST_CHECK_EQUAL( controller->getCurrentActivity(), GTAAIController::GoTo );
|
||||
BOOST_CHECK_EQUAL( controller->getCurrentActivityParameter().position, glm::vec3( 10.f, 0.f, 0.f ) );
|
||||
|
||||
for(float t = 0.f; t < 11.f; t+=(1.f/60.f)) {
|
||||
controller->update(1.f/60.f);
|
||||
character->tick(1.f/60.f);
|
||||
Global::get().e->dynamicsWorld->stepSimulation(1.f/60.f);
|
||||
}
|
||||
|
||||
// This check will undoubtably break in the future, please improve.
|
||||
BOOST_CHECK_CLOSE( glm::distance(character->getPosition(), {10.f, 0.f, 0.f}), 0.038f, 1.0f );
|
||||
|
||||
Global::get().e->destroyObject(character);
|
||||
delete controller;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -3,9 +3,22 @@
|
||||
|
||||
#include <SFML/Window.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
|
||||
#define ENV_GAME_PATH_NAME ("OPENRW_GAME_PATH")
|
||||
|
||||
std::ostream& operator<<( std::ostream& stream, glm::vec3 const& v );
|
||||
|
||||
namespace boost { namespace test_tools {
|
||||
template<>
|
||||
struct print_log_value<glm::vec3> {
|
||||
void operator()( std::ostream& s , glm::vec3 const& v )
|
||||
{
|
||||
s << glm::to_string(v);
|
||||
}
|
||||
};
|
||||
}}
|
||||
|
||||
class Global
|
||||
{
|
||||
public:
|
||||
@ -25,6 +38,8 @@ public:
|
||||
++it) {
|
||||
e->defineItems(it->second);
|
||||
}
|
||||
|
||||
e->dynamicsWorld->setGravity(btVector3(0.f, 0.f, 0.f));
|
||||
}
|
||||
|
||||
~Global() {
|
||||
|
Loading…
Reference in New Issue
Block a user