forked from bartvdbraak/blender
added obstacle avoidance code; object movement is implemented via setting velocity
This commit is contained in:
parent
1be4a74f6c
commit
0932f365bf
@ -555,6 +555,10 @@
|
||||
RelativePath="..\..\..\source\gameengine\Ketsji\KX_NavMeshObject.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\source\gameengine\Ketsji\KX_ObstacleSimulation.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\source\gameengine\Ketsji\KX_PhysicsObjectWrapper.cpp"
|
||||
>
|
||||
@ -864,6 +868,10 @@
|
||||
RelativePath="..\..\..\source\gameengine\Ketsji\KX_NavMeshObject.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\source\gameengine\Ketsji\KX_ObstacleSimulation.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\source\gameengine\Ketsji\KX_OdePhysicsController.h"
|
||||
>
|
||||
|
@ -4272,7 +4272,7 @@ static void draw_actuator_steering(uiLayout *layout, PointerRNA *ptr)
|
||||
|
||||
row = uiLayoutRow(layout, 0);
|
||||
uiItemR(row, ptr, "distance", 0, NULL, 0);
|
||||
uiItemR(row, ptr, "movement", 0, NULL, 0);
|
||||
uiItemR(row, ptr, "velocity", 0, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -218,7 +218,7 @@ typedef struct bSteeringActuator {
|
||||
char pad[4];
|
||||
int type; /* 0=seek, 1=flee, 2=path following */
|
||||
float dist;
|
||||
float movement;
|
||||
float velocity;
|
||||
struct Object *target;
|
||||
struct Object *navmesh;
|
||||
} bSteeringActuator;
|
||||
|
@ -1866,10 +1866,10 @@ static void rna_def_steering_actuator(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Behavior", "");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "movement", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "movement");
|
||||
prop= RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "velocity");
|
||||
RNA_def_property_range(prop, 0.0, 1000.0);
|
||||
RNA_def_property_ui_text(prop, "Move", "Movement value");
|
||||
RNA_def_property_ui_text(prop, "Velocity", "Velocity magnitude");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
|
||||
|
@ -173,6 +173,7 @@ extern "C" {
|
||||
#include "BL_DeformableGameObject.h"
|
||||
|
||||
#include "KX_NavMeshObject.h"
|
||||
#include "KX_ObstacleSimulation.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -2638,6 +2639,20 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
|
||||
converter->RegisterWorldInfo(worldinfo);
|
||||
kxscene->SetWorldInfo(worldinfo);
|
||||
|
||||
//create object representations for obstacle simulation
|
||||
KX_ObstacleSimulation* obssimulation = kxscene->GetObstacleSimulation();
|
||||
if (obssimulation)
|
||||
{
|
||||
for ( i=0;i<objectlist->GetCount();i++)
|
||||
{
|
||||
KX_GameObject* gameobj = static_cast<KX_GameObject*>(objectlist->GetValue(i));
|
||||
if (gameobj->IsDynamic())
|
||||
{
|
||||
obssimulation->AddObstacleForObj(gameobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define CONVERT_LOGIC
|
||||
#ifdef CONVERT_LOGIC
|
||||
// convert logic bricks, sensors, controllers and actuators
|
||||
@ -2689,9 +2704,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
|
||||
pathfinder->BuildNavMesh();
|
||||
pathfinder->SetVisible(0, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Calculate the scene btree -
|
||||
// too slow - commented out.
|
||||
|
@ -1059,7 +1059,7 @@ void BL_ConvertActuators(char* maggiename,
|
||||
|
||||
KX_SteeringActuator *tmpstact
|
||||
= new KX_SteeringActuator(gameobj, mode, targetob, navmeshob,
|
||||
stAct->movement, stAct->dist);
|
||||
stAct->velocity, stAct->dist, scene->GetObstacleSimulation());
|
||||
baseact = tmpstact;
|
||||
break;
|
||||
}
|
||||
|
245
source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
Normal file
245
source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
/**
|
||||
* Simulation for obstacle avoidance behavior
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version. The Blender
|
||||
* Foundation also sells licenses for use in proprietary software under
|
||||
* the Blender License. See http://www.blender.org/BL/ for information
|
||||
* about this.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "KX_ObstacleSimulation.h"
|
||||
#include "KX_GameObject.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "math.h"
|
||||
#define M_PI 3.14159265358979323846
|
||||
|
||||
int sweepCircleCircle(const MT_Vector3& pos0, const MT_Scalar r0, const MT_Vector2& v,
|
||||
const MT_Vector3& pos1, const MT_Scalar r1,
|
||||
float& tmin, float& tmax)
|
||||
{
|
||||
static const float EPS = 0.0001f;
|
||||
MT_Vector2 c0(pos0.x(), pos0.y());
|
||||
MT_Vector2 c1(pos1.x(), pos1.y());
|
||||
MT_Vector2 s = c1 - c0;
|
||||
MT_Scalar r = r0+r1;
|
||||
float c = s.length2() - r*r;
|
||||
float a = v.length2();
|
||||
if (a < EPS) return 0; // not moving
|
||||
|
||||
// Overlap, calc time to exit.
|
||||
float b = MT_dot(v,s);
|
||||
float d = b*b - a*c;
|
||||
if (d < 0.0f) return 0; // no intersection.
|
||||
tmin = (b - sqrtf(d)) / a;
|
||||
tmax = (b + sqrtf(d)) / a;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
KX_ObstacleSimulation::KX_ObstacleSimulation()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KX_ObstacleSimulation::~KX_ObstacleSimulation()
|
||||
{
|
||||
for (size_t i=0; i<m_obstacles.size(); i++)
|
||||
{
|
||||
KX_Obstacle* obs = m_obstacles[i];
|
||||
delete obs;
|
||||
}
|
||||
m_obstacles.clear();
|
||||
}
|
||||
void KX_ObstacleSimulation::AddObstacleForObj(KX_GameObject* gameobj)
|
||||
{
|
||||
KX_Obstacle* obstacle = new KX_Obstacle();
|
||||
struct Object* blenderobject = gameobj->GetBlenderObject();
|
||||
obstacle->m_rad = blenderobject->inertia; //.todo use radius of collision shape bound sphere
|
||||
obstacle->m_gameObj = gameobj;
|
||||
m_obstacles.push_back(obstacle);
|
||||
}
|
||||
|
||||
void KX_ObstacleSimulation::UpdateObstacles()
|
||||
{
|
||||
for (size_t i=0; i<m_obstacles.size(); i++)
|
||||
{
|
||||
KX_Obstacle* obs = m_obstacles[i];
|
||||
obs->m_pos = obs->m_gameObj->NodeGetWorldPosition();
|
||||
obs->m_vel.x() = obs->m_gameObj->GetLinearVelocity().x();
|
||||
obs->m_vel.y() = obs->m_gameObj->GetLinearVelocity().y();
|
||||
}
|
||||
}
|
||||
|
||||
KX_Obstacle* KX_ObstacleSimulation::GetObstacle(KX_GameObject* gameobj)
|
||||
{
|
||||
for (size_t i=0; i<m_obstacles.size(); i++)
|
||||
{
|
||||
if (m_obstacles[i]->m_gameObj == gameobj)
|
||||
return m_obstacles[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void KX_ObstacleSimulation::AdjustObstacleVelocity(KX_Obstacle* activeObst, MT_Vector3& velocity)
|
||||
{
|
||||
}
|
||||
|
||||
KX_ObstacleSimulationTOI::KX_ObstacleSimulationTOI():
|
||||
m_avoidSteps(32),
|
||||
m_minToi(0.5f),
|
||||
m_maxToi(1.2f),
|
||||
m_angleWeight(4.0f),
|
||||
m_toiWeight(1.0f),
|
||||
m_collisionWeight(100.0f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KX_ObstacleSimulationTOI::~KX_ObstacleSimulationTOI()
|
||||
{
|
||||
for (size_t i=0; i<m_toiCircles.size(); i++)
|
||||
{
|
||||
TOICircle* toi = m_toiCircles[i];
|
||||
delete toi;
|
||||
}
|
||||
m_toiCircles.clear();
|
||||
}
|
||||
|
||||
void KX_ObstacleSimulationTOI::AddObstacleForObj(KX_GameObject* gameobj)
|
||||
{
|
||||
KX_ObstacleSimulation::AddObstacleForObj(gameobj);
|
||||
m_toiCircles.push_back(new TOICircle());
|
||||
}
|
||||
|
||||
void KX_ObstacleSimulationTOI::AdjustObstacleVelocity(KX_Obstacle* activeObst, MT_Vector3& velocity)
|
||||
{
|
||||
int nobs = m_obstacles.size();
|
||||
int obstidx = std::find(m_obstacles.begin(), m_obstacles.end(), activeObst) - m_obstacles.begin();
|
||||
if (obstidx == nobs)
|
||||
return;
|
||||
TOICircle* tc = m_toiCircles[obstidx];
|
||||
|
||||
MT_Vector2 vel(velocity.x(), velocity.y());
|
||||
float vmax = (float) velocity.length();
|
||||
float odir = (float) atan2(velocity.y(), velocity.x());
|
||||
|
||||
MT_Vector2 ddir = vel;
|
||||
ddir.normalize();
|
||||
|
||||
float bestScore = FLT_MAX;
|
||||
float bestDir = odir;
|
||||
float bestToi = 0;
|
||||
|
||||
tc->n = m_avoidSteps;
|
||||
tc->minToi = m_minToi;
|
||||
tc->maxToi = m_maxToi;
|
||||
|
||||
const int iforw = m_avoidSteps/2;
|
||||
const float aoff = (float)iforw / (float)m_avoidSteps;
|
||||
|
||||
for (int iter = 0; iter < m_avoidSteps; ++iter)
|
||||
{
|
||||
// Calculate sample velocity
|
||||
const float ndir = ((float)iter/(float)m_avoidSteps) - aoff;
|
||||
const float dir = odir+ndir*M_PI*2;
|
||||
MT_Vector2 svel;
|
||||
svel.x() = cosf(dir) * vmax;
|
||||
svel.y() = sinf(dir) * vmax;
|
||||
|
||||
// Find min time of impact and exit amongst all obstacles.
|
||||
float tmin = m_maxToi;
|
||||
float tmine = 0;
|
||||
for (int i = 0; i < nobs; ++i)
|
||||
{
|
||||
if (i==obstidx)
|
||||
continue;
|
||||
KX_Obstacle* ob = m_obstacles[i];
|
||||
|
||||
float htmin,htmax;
|
||||
|
||||
MT_Vector2 vab;
|
||||
if (ob->m_vel.length2() < 0.01f*0.01f)
|
||||
{
|
||||
// Stationary, use VO
|
||||
vab = svel;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Moving, use RVO
|
||||
vab = 2*svel - vel - ob->m_vel;
|
||||
}
|
||||
|
||||
if (!sweepCircleCircle(activeObst->m_pos, activeObst->m_rad,
|
||||
vab, ob->m_pos, ob->m_rad, htmin, htmax))
|
||||
continue;
|
||||
|
||||
if (htmin > 0.0f)
|
||||
{
|
||||
// The closest obstacle is somewhere ahead of us, keep track of nearest obstacle.
|
||||
if (htmin < tmin)
|
||||
tmin = htmin;
|
||||
}
|
||||
else if (htmax > 0.0f)
|
||||
{
|
||||
// The agent overlaps the obstacle, keep track of first safe exit.
|
||||
if (htmax > tmine)
|
||||
tmine = htmax;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate sample penalties and final score.
|
||||
const float apen = m_angleWeight * fabsf(ndir);
|
||||
const float tpen = m_toiWeight * (1.0f/(0.0001f+tmin/m_maxToi));
|
||||
const float cpen = m_collisionWeight * (tmine/m_minToi)*(tmine/m_minToi);
|
||||
const float score = apen + tpen + cpen;
|
||||
|
||||
// Update best score.
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestDir = dir;
|
||||
bestToi = tmin;
|
||||
bestScore = score;
|
||||
}
|
||||
|
||||
tc->dir[iter] = dir;
|
||||
tc->toi[iter] = tmin;
|
||||
tc->toie[iter] = tmine;
|
||||
}
|
||||
|
||||
// Adjust speed when time of impact is less than min TOI.
|
||||
if (bestToi < m_minToi)
|
||||
vmax *= bestToi/m_minToi;
|
||||
|
||||
// New steering velocity.
|
||||
vel.x() = cosf(bestDir) * vmax;
|
||||
vel.y() = sinf(bestDir) * vmax;
|
||||
|
||||
velocity.x() = vel.x();
|
||||
velocity.y() = vel.y();
|
||||
}
|
98
source/gameengine/Ketsji/KX_ObstacleSimulation.h
Normal file
98
source/gameengine/Ketsji/KX_ObstacleSimulation.h
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Simulation for obstacle avoidance behavior
|
||||
* (based on Cane Project - http://code.google.com/p/cane by Mikko Mononen (c) 2009)
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version. The Blender
|
||||
* Foundation also sells licenses for use in proprietary software under
|
||||
* the Blender License. See http://www.blender.org/BL/ for information
|
||||
* about this.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
||||
* All rights reserved.
|
||||
*
|
||||
* The Original Code is: all of this file.
|
||||
*
|
||||
* Contributor(s): none yet.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __KX_OBSTACLESIMULATION
|
||||
#define __KX_OBSTACLESIMULATION
|
||||
|
||||
#include <vector>
|
||||
#include "MT_Point2.h"
|
||||
#include "MT_Point3.h"
|
||||
|
||||
class KX_GameObject;
|
||||
|
||||
struct KX_Obstacle
|
||||
{
|
||||
MT_Point3 m_pos;
|
||||
MT_Scalar m_rad;
|
||||
MT_Vector2 m_vel;
|
||||
KX_GameObject* m_gameObj;
|
||||
};
|
||||
|
||||
class KX_ObstacleSimulation
|
||||
{
|
||||
protected:
|
||||
std::vector<KX_Obstacle*> m_obstacles;
|
||||
public:
|
||||
KX_ObstacleSimulation();
|
||||
virtual ~KX_ObstacleSimulation();
|
||||
|
||||
virtual void AddObstacleForObj(KX_GameObject* gameobj);
|
||||
KX_Obstacle* GetObstacle(KX_GameObject* gameobj);
|
||||
void UpdateObstacles();
|
||||
virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, MT_Vector3& velocity);
|
||||
|
||||
}; /* end of class KX_ObstacleSimulation*/
|
||||
|
||||
static const int AVOID_MAX_STEPS = 128;
|
||||
struct TOICircle
|
||||
{
|
||||
TOICircle() : n(0), minToi(0), maxToi(1) {}
|
||||
float toi[AVOID_MAX_STEPS]; // Time of impact (seconds)
|
||||
float toie[AVOID_MAX_STEPS]; // Time of exit (seconds)
|
||||
float dir[AVOID_MAX_STEPS]; // Direction (radians)
|
||||
int n; // Number of samples
|
||||
float minToi, maxToi; // Min/max TOI (seconds)
|
||||
};
|
||||
|
||||
class KX_ObstacleSimulationTOI: public KX_ObstacleSimulation
|
||||
{
|
||||
protected:
|
||||
int m_avoidSteps; // Number of sample steps
|
||||
float m_minToi; // Min TOI
|
||||
float m_maxToi; // Max TOI
|
||||
float m_angleWeight; // Sample selection angle weight
|
||||
float m_toiWeight; // Sample selection TOI weight
|
||||
float m_collisionWeight; // Sample selection collision weight
|
||||
|
||||
std::vector<TOICircle*> m_toiCircles; // TOI circles (one per active agent)
|
||||
public:
|
||||
KX_ObstacleSimulationTOI();
|
||||
~KX_ObstacleSimulationTOI();
|
||||
virtual void AddObstacleForObj(KX_GameObject* gameobj);
|
||||
virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, MT_Vector3& velocity);
|
||||
};
|
||||
|
||||
#endif
|
@ -85,6 +85,7 @@
|
||||
#include "BL_DeformableGameObject.h"
|
||||
#include "KX_SoftBodyDeformer.h"
|
||||
|
||||
#include "KX_ObstacleSimulation.h"
|
||||
// to get USE_BULLET!
|
||||
#include "KX_ConvertPhysicsObject.h"
|
||||
|
||||
@ -210,6 +211,8 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
|
||||
|
||||
m_bucketmanager=new RAS_BucketManager();
|
||||
|
||||
m_obstacleSimulation = new KX_ObstacleSimulationTOI;//KX_ObstacleSimulation;
|
||||
|
||||
#ifndef DISABLE_PYTHON
|
||||
m_attr_dict = PyDict_New(); /* new ref */
|
||||
m_draw_call_pre = NULL;
|
||||
@ -221,6 +224,9 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
|
||||
|
||||
KX_Scene::~KX_Scene()
|
||||
{
|
||||
if (m_obstacleSimulation)
|
||||
delete m_obstacleSimulation;
|
||||
|
||||
// The release of debug properties used to be in SCA_IScene::~SCA_IScene
|
||||
// It's still there but we remove all properties here otherwise some
|
||||
// reference might be hanging and causing late release of objects
|
||||
@ -1460,6 +1466,10 @@ void KX_Scene::LogicBeginFrame(double curtime)
|
||||
// all object is the tempObjectList should have a clock
|
||||
}
|
||||
}
|
||||
|
||||
//prepare obstacle simulation for new frame
|
||||
m_obstacleSimulation->UpdateObstacles();
|
||||
|
||||
m_logicmgr->BeginFrame(curtime, 1.0/KX_KetsjiEngine::GetTicRate());
|
||||
}
|
||||
|
||||
|
@ -83,6 +83,7 @@ class SCA_JoystickManager;
|
||||
class btCollisionShape;
|
||||
class KX_BlenderSceneConverter;
|
||||
struct KX_ClientObjectInfo;
|
||||
class KX_ObstacleSimulation;
|
||||
|
||||
/* for ID freeing */
|
||||
#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->flag & LIB_DOIT))
|
||||
@ -277,6 +278,8 @@ protected:
|
||||
|
||||
RAS_2DFilterManager m_filtermanager;
|
||||
|
||||
KX_ObstacleSimulation* m_obstacleSimulation;
|
||||
|
||||
public:
|
||||
KX_Scene(class SCA_IInputDevice* keyboarddevice,
|
||||
class SCA_IInputDevice* mousedevice,
|
||||
@ -541,6 +544,8 @@ public:
|
||||
void Update2DFilter(vector<STR_String>& propNames, void* gameObj, RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, int pass, STR_String& text);
|
||||
void Render2DFilters(RAS_ICanvas* canvas);
|
||||
|
||||
KX_ObstacleSimulation* GetObstacleSimulation() {return m_obstacleSimulation;};
|
||||
|
||||
#ifndef DISABLE_PYTHON
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Python interface ---------------------------------------------------- */
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "KX_SteeringActuator.h"
|
||||
#include "KX_GameObject.h"
|
||||
#include "KX_NavMeshObject.h"
|
||||
#include "KX_ObstacleSimulation.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Native functions */
|
||||
@ -44,19 +45,27 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj,
|
||||
int mode,
|
||||
KX_GameObject *target,
|
||||
KX_GameObject *navmesh,
|
||||
MT_Scalar movement,
|
||||
MT_Scalar distance) :
|
||||
MT_Scalar velocity,
|
||||
MT_Scalar distance,
|
||||
KX_ObstacleSimulation* simulation) :
|
||||
SCA_IActuator(gameobj, KX_ACT_STEERING),
|
||||
m_mode(mode),
|
||||
m_target(target),
|
||||
m_movement(movement),
|
||||
m_distance(distance)
|
||||
m_velocity(velocity),
|
||||
m_distance(distance),
|
||||
m_updateTime(0),
|
||||
m_isActive(false),
|
||||
m_simulation(simulation),
|
||||
m_obstacle(NULL)
|
||||
{
|
||||
m_navmesh = static_cast<KX_NavMeshObject*>(navmesh);
|
||||
if (m_navmesh)
|
||||
m_navmesh->RegisterActuator(this);
|
||||
if (m_target)
|
||||
m_target->RegisterActuator(this);
|
||||
|
||||
if (m_simulation)
|
||||
m_obstacle = m_simulation->GetObstacle((KX_GameObject*)gameobj);
|
||||
}
|
||||
|
||||
KX_SteeringActuator::~KX_SteeringActuator()
|
||||
@ -121,64 +130,92 @@ void KX_SteeringActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
|
||||
}
|
||||
}
|
||||
|
||||
bool KX_SteeringActuator::Update()
|
||||
bool KX_SteeringActuator::Update(double curtime, bool frame)
|
||||
{
|
||||
bool bNegativeEvent = IsNegativeEvent();
|
||||
RemoveAllEvents();
|
||||
if (frame)
|
||||
{
|
||||
double delta = curtime - m_updateTime;
|
||||
m_updateTime = curtime;
|
||||
|
||||
if (m_posevent && !m_isActive)
|
||||
{
|
||||
delta = 0;
|
||||
m_updateTime = curtime;
|
||||
m_isActive = true;
|
||||
}
|
||||
bool bNegativeEvent = IsNegativeEvent();
|
||||
if (bNegativeEvent)
|
||||
m_isActive = false;
|
||||
|
||||
if (bNegativeEvent)
|
||||
return false; // do nothing on negative events
|
||||
RemoveAllEvents();
|
||||
|
||||
KX_GameObject *obj = (KX_GameObject*) GetParent();
|
||||
const MT_Point3& mypos = obj->NodeGetWorldPosition();
|
||||
const MT_Point3& targpos = m_target->NodeGetWorldPosition();
|
||||
MT_Vector3 vectotarg = targpos - mypos;
|
||||
MT_Vector3 steervec = MT_Vector3(0, 0, 0);
|
||||
bool apply_steerforce = false;
|
||||
if (bNegativeEvent || !delta)
|
||||
return false; // do nothing on negative events
|
||||
|
||||
switch (m_mode) {
|
||||
case KX_STEERING_SEEK:
|
||||
if (vectotarg.length2()>m_distance*m_distance)
|
||||
{
|
||||
apply_steerforce = true;
|
||||
steervec = vectotarg;
|
||||
steervec.normalize();
|
||||
}
|
||||
break;
|
||||
case KX_STEERING_FLEE:
|
||||
if (vectotarg.length2()<m_distance*m_distance)
|
||||
{
|
||||
apply_steerforce = true;
|
||||
steervec = -vectotarg;
|
||||
steervec.normalize();
|
||||
}
|
||||
case KX_STEERING_PATHFOLLOWING:
|
||||
if (m_navmesh && vectotarg.length2()>m_distance*m_distance)
|
||||
{
|
||||
static const int MAX_PATH_LENGTH = 128;
|
||||
static const MT_Vector3 PATH_COLOR(1,0,0);
|
||||
KX_GameObject *obj = (KX_GameObject*) GetParent();
|
||||
const MT_Point3& mypos = obj->NodeGetWorldPosition();
|
||||
const MT_Point3& targpos = m_target->NodeGetWorldPosition();
|
||||
MT_Vector3 vectotarg = targpos - mypos;
|
||||
MT_Vector3 steervec = MT_Vector3(0, 0, 0);
|
||||
bool apply_steerforce = false;
|
||||
|
||||
float path[MAX_PATH_LENGTH*3];
|
||||
int pathlen = m_navmesh->FindPath(mypos, targpos, path, MAX_PATH_LENGTH);
|
||||
if (pathlen > 1)
|
||||
switch (m_mode) {
|
||||
case KX_STEERING_SEEK:
|
||||
if (vectotarg.length2()>m_distance*m_distance)
|
||||
{
|
||||
//debug draw
|
||||
m_navmesh->DrawPath(path, pathlen, PATH_COLOR);
|
||||
|
||||
apply_steerforce = true;
|
||||
MT_Vector3 waypoint(&path[3]);
|
||||
steervec = waypoint - mypos;
|
||||
steervec.z() = 0;
|
||||
steervec = vectotarg;
|
||||
steervec.normalize();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case KX_STEERING_FLEE:
|
||||
if (vectotarg.length2()<m_distance*m_distance)
|
||||
{
|
||||
apply_steerforce = true;
|
||||
steervec = -vectotarg;
|
||||
steervec.normalize();
|
||||
}
|
||||
case KX_STEERING_PATHFOLLOWING:
|
||||
if (m_navmesh && vectotarg.length2()>m_distance*m_distance)
|
||||
{
|
||||
static const int MAX_PATH_LENGTH = 128;
|
||||
static const MT_Vector3 PATH_COLOR(1,0,0);
|
||||
|
||||
if (apply_steerforce)
|
||||
{
|
||||
MT_Vector3 vel = m_movement*steervec;
|
||||
obj->ApplyMovement(vel, false);
|
||||
float path[MAX_PATH_LENGTH*3];
|
||||
int pathlen = m_navmesh->FindPath(mypos, targpos, path, MAX_PATH_LENGTH);
|
||||
if (pathlen > 1)
|
||||
{
|
||||
//debug draw
|
||||
m_navmesh->DrawPath(path, pathlen, PATH_COLOR);
|
||||
|
||||
apply_steerforce = true;
|
||||
MT_Vector3 waypoint(&path[3]);
|
||||
steervec = waypoint - mypos;
|
||||
steervec.z() = 0;
|
||||
steervec.normalize();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (apply_steerforce)
|
||||
{
|
||||
MT_Vector3 newvel = m_velocity*steervec;
|
||||
|
||||
//adjust velocity to avoid obstacles
|
||||
if (m_simulation && m_obstacle)
|
||||
{
|
||||
m_simulation->AdjustObstacleVelocity(m_obstacle, newvel);
|
||||
}
|
||||
|
||||
//temporary solution: set 2D steering velocity directly to obj
|
||||
//correct way is to apply physical force
|
||||
//MT_Vector3 movement = delta*m_velocity*steervec;
|
||||
//obj->ApplyMovement(movement, false);
|
||||
MT_Vector3 curvel = obj->GetLinearVelocity();
|
||||
newvel.z() = curvel.z();
|
||||
obj->setLinearVelocity(newvel, false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -41,6 +41,8 @@
|
||||
|
||||
class KX_GameObject;
|
||||
class KX_NavMeshObject;
|
||||
struct KX_Obstacle;
|
||||
class KX_ObstacleSimulation;
|
||||
|
||||
class KX_SteeringActuator : public SCA_IActuator
|
||||
{
|
||||
@ -49,10 +51,14 @@ class KX_SteeringActuator : public SCA_IActuator
|
||||
/** Target object */
|
||||
KX_GameObject *m_target;
|
||||
KX_NavMeshObject *m_navmesh;
|
||||
|
||||
int m_mode;
|
||||
MT_Scalar m_distance;
|
||||
MT_Scalar m_movement;
|
||||
MT_Scalar m_velocity;
|
||||
KX_ObstacleSimulation* m_simulation;
|
||||
|
||||
KX_Obstacle* m_obstacle;
|
||||
double m_updateTime;
|
||||
bool m_isActive;
|
||||
public:
|
||||
enum KX_STEERINGACT_MODE
|
||||
{
|
||||
@ -68,9 +74,10 @@ public:
|
||||
KX_GameObject *target,
|
||||
KX_GameObject *navmesh,
|
||||
MT_Scalar movement,
|
||||
MT_Scalar distance);
|
||||
MT_Scalar distance,
|
||||
KX_ObstacleSimulation* simulation);
|
||||
virtual ~KX_SteeringActuator();
|
||||
virtual bool Update();
|
||||
virtual bool Update(double curtime, bool frame);
|
||||
|
||||
virtual CValue* GetReplica();
|
||||
virtual void ProcessReplica();
|
||||
|
Loading…
Reference in New Issue
Block a user