forked from bartvdbraak/blender
Added:
- obstacle culling for correct simulation in 3d - flag for steering actuator termination on reaching target - path recalculation period - advance by waypoints (for path following)
This commit is contained in:
parent
700c32e738
commit
c92d0dfdf6
@ -544,6 +544,9 @@ class WORLD_PT_game_physics_obstacles(WorldButtonsPanel):
|
||||
wide_ui = context.region.width > narrowui
|
||||
|
||||
layout.prop(gs, "obstacle_simulation", text = "Type")
|
||||
if gs.obstacle_simulation != 'None':
|
||||
layout.prop(gs, "level_height", text="Level height")
|
||||
|
||||
|
||||
classes = [
|
||||
PHYSICS_PT_game_physics,
|
||||
|
@ -473,6 +473,7 @@ Scene *add_scene(char *name)
|
||||
sce->gm.matmode = GAME_MAT_MULTITEX;
|
||||
|
||||
sce->gm.obstacleSimulation= OBSTSIMULATION_NONE;
|
||||
sce->gm.levelHeight = 2.f;
|
||||
|
||||
sound_create_scene(sce);
|
||||
|
||||
|
@ -4276,6 +4276,10 @@ static void draw_actuator_steering(uiLayout *layout, PointerRNA *ptr)
|
||||
row = uiLayoutRow(layout, 0);
|
||||
uiItemR(row, ptr, "acceleration", 0, NULL, 0);
|
||||
uiItemR(row, ptr, "turnspeed", 0, NULL, 0);
|
||||
row = uiLayoutRow(layout, 0);
|
||||
uiItemR(row, ptr, "selfterminated", 0, NULL, 0);
|
||||
if (RNA_enum_get(ptr, "mode")==ACT_STEERING_PATHFOLLOWING)
|
||||
uiItemR(row, ptr, "updateperiod", 0, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -215,12 +215,14 @@ typedef struct bArmatureActuator {
|
||||
} bArmatureActuator;
|
||||
|
||||
typedef struct bSteeringActuator {
|
||||
char pad[4];
|
||||
char pad[7];
|
||||
char flag;
|
||||
int type; /* 0=seek, 1=flee, 2=path following */
|
||||
float dist;
|
||||
float velocity;
|
||||
float acceleration;
|
||||
float turnspeed;
|
||||
int updateTime;
|
||||
struct Object *target;
|
||||
struct Object *navmesh;
|
||||
} bSteeringActuator;
|
||||
@ -518,6 +520,8 @@ typedef struct FreeCamera {
|
||||
#define ACT_STEERING_SEEK 0
|
||||
#define ACT_STEERING_FLEE 1
|
||||
#define ACT_STEERING_PATHFOLLOWING 2
|
||||
/* steeringactuator->flag */
|
||||
#define ACT_STEERING_SELFTERMINATED 1
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -451,11 +451,12 @@ typedef struct GameData {
|
||||
* bit 3: (gameengine): Activity culling is enabled.
|
||||
* bit 5: (gameengine) : enable Bullet DBVT tree for view frustrum culling
|
||||
*/
|
||||
short mode, flag, matmode, pad[6];
|
||||
short mode, flag, matmode/*, pad[2]*/;
|
||||
short occlusionRes; /* resolution of occlusion Z buffer in pixel */
|
||||
short physicsEngine;
|
||||
short ticrate, maxlogicstep, physubstep, maxphystep;
|
||||
short obstacleSimulation;
|
||||
float levelHeight;
|
||||
|
||||
/* standalone player */
|
||||
struct GameFraming framing;
|
||||
|
@ -1897,6 +1897,17 @@ static void rna_def_steering_actuator(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Target Object", "Set target object");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "selfterminated", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_STEERING_SELFTERMINATED);
|
||||
RNA_def_property_ui_text(prop, "Self terminated", "Terminate when target is reached");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "updateperiod", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "updateTime");
|
||||
RNA_def_property_ui_range(prop, -1, 100000, 1, 1);
|
||||
RNA_def_property_ui_text(prop, "Update period", "Path update period");
|
||||
RNA_def_property_update(prop, NC_LOGIC, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "navmesh", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Object");
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "navmesh");
|
||||
|
@ -1760,6 +1760,13 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
|
||||
RNA_def_property_enum_items(prop, obstacle_simulation_items);
|
||||
RNA_def_property_ui_text(prop, "Obstacle simulation", "Simulation used for obstacle avoidance in the game engine");
|
||||
RNA_def_property_update(prop, NC_SCENE, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "level_height", PROP_FLOAT, PROP_ACCELERATION);
|
||||
RNA_def_property_float_sdna(prop, NULL, "levelHeight");
|
||||
RNA_def_property_range(prop, 0.0f, 200.0f);
|
||||
RNA_def_property_ui_text(prop, "Level height", "Max difference in heights of obstacles to enable their interaction");
|
||||
RNA_def_property_update(prop, NC_SCENE, NULL);
|
||||
|
||||
}
|
||||
|
||||
static void rna_def_scene_render_layer(BlenderRNA *brna)
|
||||
|
@ -1057,9 +1057,11 @@ void BL_ConvertActuators(char* maggiename,
|
||||
break;
|
||||
}
|
||||
|
||||
bool selfTerminated = (stAct->flag & ACT_STEERING_SELFTERMINATED) !=0;
|
||||
KX_SteeringActuator *tmpstact
|
||||
= new KX_SteeringActuator(gameobj, mode, targetob, navmeshob,stAct->dist,
|
||||
stAct->velocity, stAct->acceleration, stAct->turnspeed,
|
||||
selfTerminated, stAct->updateTime,
|
||||
scene->GetObstacleSimulation());
|
||||
baseact = tmpstact;
|
||||
break;
|
||||
|
@ -334,6 +334,25 @@ void KX_NavMeshObject::DrawNavMesh()
|
||||
return;
|
||||
MT_Vector3 color(0.f, 0.f, 0.f);
|
||||
|
||||
enum RenderMode {DETAILED_TRIS, WALLS};
|
||||
static const RenderMode renderMode = DETAILED_TRIS;
|
||||
switch (renderMode)
|
||||
{
|
||||
case WALLS :
|
||||
for (int pi=0; pi<m_navMesh->getPolyCount(); pi++)
|
||||
{
|
||||
const dtStatPoly* poly = m_navMesh->getPoly(pi);
|
||||
|
||||
for (int i = 0, j = (int)poly->nv-1; i < (int)poly->nv; j = i++)
|
||||
{
|
||||
if (poly->n[j]) continue;
|
||||
const float* vj = m_navMesh->getVertex(poly->v[j]);
|
||||
const float* vi = m_navMesh->getVertex(poly->v[i]);
|
||||
KX_RasterizerDrawDebugLine(MT_Vector3(vj[0], vj[2], vj[1]), MT_Vector3(vi[0], vi[2], vi[1]), color);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DETAILED_TRIS :
|
||||
for (int i = 0; i < m_navMesh->getPolyDetailCount(); ++i)
|
||||
{
|
||||
const dtStatPoly* p = m_navMesh->getPoly(i);
|
||||
@ -360,6 +379,8 @@ void KX_NavMeshObject::DrawNavMesh()
|
||||
KX_RasterizerDrawDebugLine(tri[k], tri[(k+1)%3], color);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int KX_NavMeshObject::FindPath(const MT_Point3& from, const MT_Point3& to, float* path, int maxPathLen)
|
||||
|
@ -166,7 +166,8 @@ static float interpolateToi(float a, const float* dir, const float* toi, const i
|
||||
return 0;
|
||||
}
|
||||
|
||||
KX_ObstacleSimulation::KX_ObstacleSimulation()
|
||||
KX_ObstacleSimulation::KX_ObstacleSimulation(MT_Scalar levelHeight)
|
||||
: m_levelHeight(levelHeight)
|
||||
{
|
||||
|
||||
}
|
||||
@ -285,12 +286,51 @@ void KX_ObstacleSimulation::DrawObstacles()
|
||||
else if (m_obstacles[i]->m_shape==KX_OBSTACLE_CIRCLE)
|
||||
{
|
||||
KX_RasterizerDrawDebugCircle(m_obstacles[i]->m_pos, m_obstacles[i]->m_rad, bluecolor,
|
||||
normal.normalized(), SECTORS_NUM);
|
||||
normal, SECTORS_NUM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KX_ObstacleSimulationTOI::KX_ObstacleSimulationTOI():
|
||||
static MT_Point3 nearestPointToObstacle(MT_Point3& pos ,KX_Obstacle* obstacle)
|
||||
{
|
||||
switch (obstacle->m_shape)
|
||||
{
|
||||
case KX_OBSTACLE_SEGMENT :
|
||||
{
|
||||
MT_Vector3 ab = obstacle->m_pos2 - obstacle->m_pos;
|
||||
if (!ab.fuzzyZero())
|
||||
{
|
||||
MT_Vector3 abdir = ab.normalized();
|
||||
MT_Vector3 v = pos - obstacle->m_pos;
|
||||
MT_Scalar proj = abdir.dot(v);
|
||||
CLAMP(proj, 0, ab.length());
|
||||
MT_Point3 res = obstacle->m_pos + abdir*proj;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
case KX_OBSTACLE_CIRCLE :
|
||||
default:
|
||||
return obstacle->m_pos;
|
||||
}
|
||||
}
|
||||
|
||||
bool KX_ObstacleSimulation::FilterObstacle(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, KX_Obstacle* otherObst)
|
||||
{
|
||||
//filter obstacles by type
|
||||
if ( (otherObst == activeObst) ||
|
||||
(otherObst->m_type==KX_OBSTACLE_NAV_MESH && otherObst->m_gameObj!=activeNavMeshObj) )
|
||||
return false;
|
||||
|
||||
//filter obstacles by position
|
||||
MT_Point3 p = nearestPointToObstacle(activeObst->m_pos, otherObst);
|
||||
if ( fabs(activeObst->m_pos.z() - p.z()) > m_levelHeight)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
KX_ObstacleSimulationTOI::KX_ObstacleSimulationTOI(MT_Scalar levelHeight):
|
||||
KX_ObstacleSimulation(levelHeight),
|
||||
m_avoidSteps(32),
|
||||
m_minToi(0.5f),
|
||||
m_maxToi(1.2f),
|
||||
@ -360,8 +400,8 @@ void KX_ObstacleSimulationTOI::AdjustObstacleVelocity(KX_Obstacle* activeObst, K
|
||||
for (int i = 0; i < nobs; ++i)
|
||||
{
|
||||
KX_Obstacle* ob = m_obstacles[i];
|
||||
if ( (ob==activeObst) ||
|
||||
(ob->m_type==KX_OBSTACLE_NAV_MESH && ob->m_gameObj!=activeNavMeshObj) )
|
||||
bool res = FilterObstacle(activeObst, activeNavMeshObj, ob);
|
||||
if (!res)
|
||||
continue;
|
||||
|
||||
float htmin,htmax;
|
||||
|
@ -73,9 +73,12 @@ class KX_ObstacleSimulation
|
||||
protected:
|
||||
std::vector<KX_Obstacle*> m_obstacles;
|
||||
|
||||
MT_Scalar m_levelHeight;
|
||||
|
||||
virtual KX_Obstacle* CreateObstacle();
|
||||
bool FilterObstacle(KX_Obstacle* activeObstacle, KX_NavMeshObject* activeNavMeshObj, KX_Obstacle* otherObstacle);
|
||||
public:
|
||||
KX_ObstacleSimulation();
|
||||
KX_ObstacleSimulation(MT_Scalar levelHeight);
|
||||
virtual ~KX_ObstacleSimulation();
|
||||
|
||||
void DrawObstacles();
|
||||
@ -114,7 +117,7 @@ protected:
|
||||
std::vector<TOICircle*> m_toiCircles; // TOI circles (one per active agent)
|
||||
virtual KX_Obstacle* CreateObstacle();
|
||||
public:
|
||||
KX_ObstacleSimulationTOI();
|
||||
KX_ObstacleSimulationTOI(MT_Scalar levelHeight);
|
||||
~KX_ObstacleSimulationTOI();
|
||||
virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj,
|
||||
MT_Vector3& velocity, MT_Scalar maxDeltaSpeed,MT_Scalar maxDeltaAngle);
|
||||
|
@ -214,7 +214,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
|
||||
switch (scene->gm.obstacleSimulation)
|
||||
{
|
||||
case OBSTSIMULATION_TOI:
|
||||
m_obstacleSimulation = new KX_ObstacleSimulationTOI;
|
||||
m_obstacleSimulation = new KX_ObstacleSimulationTOI((MT_Scalar)scene->gm.levelHeight);
|
||||
break;
|
||||
default:
|
||||
m_obstacleSimulation = NULL;
|
||||
|
@ -52,6 +52,8 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj,
|
||||
MT_Scalar velocity,
|
||||
MT_Scalar acceleration,
|
||||
MT_Scalar turnspeed,
|
||||
bool isSelfTerminated,
|
||||
int pathUpdatePeriod,
|
||||
KX_ObstacleSimulation* simulation) :
|
||||
SCA_IActuator(gameobj, KX_ACT_STEERING),
|
||||
m_mode(mode),
|
||||
@ -60,10 +62,14 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj,
|
||||
m_velocity(velocity),
|
||||
m_acceleration(acceleration),
|
||||
m_turnspeed(turnspeed),
|
||||
m_isSelfTerminated(isSelfTerminated),
|
||||
m_pathUpdatePeriod(pathUpdatePeriod),
|
||||
m_updateTime(0),
|
||||
m_isActive(false),
|
||||
m_simulation(simulation),
|
||||
m_obstacle(NULL)
|
||||
m_obstacle(NULL),
|
||||
m_pathLen(0),
|
||||
m_wayPointIdx(-1)
|
||||
{
|
||||
m_navmesh = static_cast<KX_NavMeshObject*>(navmesh);
|
||||
if (m_navmesh)
|
||||
@ -147,6 +153,7 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
|
||||
if (m_posevent && !m_isActive)
|
||||
{
|
||||
delta = 0;
|
||||
m_pathUpdateTime = -1;
|
||||
m_updateTime = curtime;
|
||||
m_isActive = true;
|
||||
}
|
||||
@ -156,61 +163,89 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
|
||||
|
||||
RemoveAllEvents();
|
||||
|
||||
if (bNegativeEvent || !delta)
|
||||
return false; // do nothing on negative events
|
||||
if (!delta)
|
||||
return true;
|
||||
|
||||
if (!m_target)
|
||||
return false;
|
||||
if (bNegativeEvent || !m_target)
|
||||
return false; // do nothing on negative events
|
||||
|
||||
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 = true;
|
||||
bool apply_steerforce = false;
|
||||
bool terminate = true;
|
||||
|
||||
switch (m_mode) {
|
||||
case KX_STEERING_SEEK:
|
||||
if (vectotarg.length2()>m_distance*m_distance)
|
||||
{
|
||||
apply_steerforce = true;
|
||||
terminate = false;
|
||||
steervec = vectotarg;
|
||||
steervec.normalize();
|
||||
apply_steerforce = true;
|
||||
}
|
||||
break;
|
||||
case KX_STEERING_FLEE:
|
||||
if (vectotarg.length2()<m_distance*m_distance)
|
||||
{
|
||||
apply_steerforce = true;
|
||||
terminate = false;
|
||||
steervec = -vectotarg;
|
||||
steervec.normalize();
|
||||
apply_steerforce = true;
|
||||
}
|
||||
break;
|
||||
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);
|
||||
terminate = false;
|
||||
|
||||
float path[MAX_PATH_LENGTH*3];
|
||||
int pathlen = m_navmesh->FindPath(mypos, targpos, path, MAX_PATH_LENGTH);
|
||||
if (pathlen > 1)
|
||||
static const MT_Scalar WAYPOINT_RADIUS(1.);
|
||||
|
||||
if (m_pathUpdateTime<0 || (m_pathUpdatePeriod>=0 &&
|
||||
curtime - m_pathUpdateTime>((double)m_pathUpdatePeriod/1000)))
|
||||
{
|
||||
//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();
|
||||
m_pathUpdateTime = curtime;
|
||||
m_pathLen = m_navmesh->FindPath(mypos, targpos, m_path, MAX_PATH_LENGTH);
|
||||
m_wayPointIdx = m_pathLen > 1 ? 1 : -1;
|
||||
}
|
||||
|
||||
if (m_wayPointIdx>0)
|
||||
{
|
||||
MT_Vector3 waypoint(&m_path[3*m_wayPointIdx]);
|
||||
if ((waypoint-mypos).length2()<WAYPOINT_RADIUS*WAYPOINT_RADIUS)
|
||||
{
|
||||
m_wayPointIdx++;
|
||||
if (m_wayPointIdx>=m_pathLen)
|
||||
{
|
||||
m_wayPointIdx = -1;
|
||||
terminate = true;
|
||||
}
|
||||
else
|
||||
waypoint.setValue(&m_path[3*m_wayPointIdx]);
|
||||
}
|
||||
|
||||
steervec = waypoint - mypos;
|
||||
apply_steerforce = true;
|
||||
|
||||
//debug draw
|
||||
static const MT_Vector3 PATH_COLOR(1,0,0);
|
||||
m_navmesh->DrawPath(m_path, m_pathLen, PATH_COLOR);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (apply_steerforce)
|
||||
{
|
||||
bool isdyna = obj->IsDynamic();
|
||||
if (isdyna)
|
||||
steervec.z() = 0;
|
||||
if (!steervec.fuzzyZero())
|
||||
steervec.normalize();
|
||||
MT_Vector3 newvel = m_velocity*steervec;
|
||||
|
||||
//adjust velocity to avoid obstacles
|
||||
@ -222,14 +257,23 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
|
||||
KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(0.,1.,0.));
|
||||
}
|
||||
|
||||
if (isdyna)
|
||||
{
|
||||
//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);
|
||||
}
|
||||
else
|
||||
{
|
||||
MT_Vector3 movement = delta*newvel;
|
||||
obj->ApplyMovement(movement, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (terminate && m_isSelfTerminated)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -43,6 +43,7 @@ class KX_GameObject;
|
||||
class KX_NavMeshObject;
|
||||
struct KX_Obstacle;
|
||||
class KX_ObstacleSimulation;
|
||||
const int MAX_PATH_LENGTH = 128;
|
||||
|
||||
class KX_SteeringActuator : public SCA_IActuator
|
||||
{
|
||||
@ -61,6 +62,12 @@ class KX_SteeringActuator : public SCA_IActuator
|
||||
KX_Obstacle* m_obstacle;
|
||||
double m_updateTime;
|
||||
bool m_isActive;
|
||||
bool m_isSelfTerminated;
|
||||
float m_path[MAX_PATH_LENGTH*3];
|
||||
int m_pathLen;
|
||||
int m_pathUpdatePeriod;
|
||||
double m_pathUpdateTime;
|
||||
int m_wayPointIdx;
|
||||
public:
|
||||
enum KX_STEERINGACT_MODE
|
||||
{
|
||||
@ -79,6 +86,8 @@ public:
|
||||
MT_Scalar velocity,
|
||||
MT_Scalar acceleration,
|
||||
MT_Scalar turnspeed,
|
||||
bool isSelfTerminated,
|
||||
int pathUpdatePeriod,
|
||||
KX_ObstacleSimulation* simulation);
|
||||
virtual ~KX_SteeringActuator();
|
||||
virtual bool Update(double curtime, bool frame);
|
||||
|
Loading…
Reference in New Issue
Block a user