diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index 6ff15b31cc0..91c052bcbda 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -472,6 +472,8 @@ void init_actuator(bActuator *act) sta->turnspeed = 120.f; sta->dist = 1.f; sta->velocity= 3.f; + sta->flag = ACT_STEERING_AUTOMATICFACING; + sta->facingaxis = 1; default: ; /* this is very severe... I cannot make any memory for this */ /* logic brick... */ diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 76e210e7549..929a29974de 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -4348,6 +4348,12 @@ static void draw_actuator_steering(uiLayout *layout, PointerRNA *ptr) uiItemR(row, ptr, "acceleration", 0, NULL, 0); uiItemR(row, ptr, "turnspeed", 0, NULL, 0); row = uiLayoutRow(layout, 0); + uiItemR(row, ptr, "facing", 0, NULL, 0); + if (RNA_boolean_get(ptr, "facing")) + { + uiItemR(row, ptr, "facingaxis", 0, NULL, 0); + } + row = uiLayoutRow(layout, 0); uiItemR(row, ptr, "selfterminated", 0, NULL, 0); if (RNA_enum_get(ptr, "mode")==ACT_STEERING_PATHFOLLOWING) { diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index 627335a7666..4caee19e399 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -224,8 +224,9 @@ typedef struct bArmatureActuator { } bArmatureActuator; typedef struct bSteeringActuator { - char pad[7]; + char pad[5]; char flag; + short facingaxis; int type; /* 0=seek, 1=flee, 2=path following */ float dist; float velocity; @@ -525,6 +526,7 @@ typedef struct bActuator { /* steeringactuator->flag */ #define ACT_STEERING_SELFTERMINATED 1 #define ACT_STEERING_ENABLEVISUALIZATION 2 +#define ACT_STEERING_AUTOMATICFACING 4 #endif diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 4a5596f7a5e..16c640b8695 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -1892,6 +1892,15 @@ static void rna_def_steering_actuator(BlenderRNA *brna) {ACT_STEERING_PATHFOLLOWING, "PATHFOLLOWING", 0, "Path following", ""}, {0, NULL, 0, NULL, NULL}}; + static EnumPropertyItem facingaxis_items[] ={ + {1, "X", 0, "X", ""}, + {2, "Y", 0, "Y", ""}, + {3, "Z", 0, "Z", ""}, + {4, "-X", 0, "-X", ""}, + {5, "-Y", 0, "-Y", ""}, + {6, "-Z", 0, "-Z", ""}, + {0, NULL, 0, NULL, NULL}}; + srna= RNA_def_struct(brna, "SteeringActuator", "Actuator"); RNA_def_struct_ui_text(srna, "Steering Actuator", ""); RNA_def_struct_sdna_from(srna, "bSteeringActuator", "data"); @@ -1956,6 +1965,18 @@ static void rna_def_steering_actuator(BlenderRNA *brna) RNA_def_property_ui_text(prop, "NavMesh Object", "Navigation mesh"); RNA_def_property_pointer_funcs(prop, NULL, "rna_SteeringActuator_navmesh_set", NULL, NULL); RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop= RNA_def_property(srna, "facing", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_STEERING_AUTOMATICFACING); + RNA_def_property_ui_text(prop, "Facing", "Enable automatic facing"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop= RNA_def_property(srna, "facingaxis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "facingaxis"); + RNA_def_property_enum_items(prop, facingaxis_items); + RNA_def_property_ui_text(prop, "Axis", "Axis for automatic facing"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + } void RNA_def_actuator(BlenderRNA *brna) diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 2c6dab910d8..727df53853c 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -1059,11 +1059,12 @@ void BL_ConvertActuators(char* maggiename, bool selfTerminated = (stAct->flag & ACT_STEERING_SELFTERMINATED) !=0; bool enableVisualization = (stAct->flag & ACT_STEERING_ENABLEVISUALIZATION) !=0; + short facingMode = (stAct->flag & ACT_STEERING_AUTOMATICFACING) ? stAct->facingaxis : 0; KX_SteeringActuator *tmpstact = new KX_SteeringActuator(gameobj, mode, targetob, navmeshob,stAct->dist, stAct->velocity, stAct->acceleration, stAct->turnspeed, selfTerminated, stAct->updateTime, - scene->GetObstacleSimulation(), enableVisualization); + scene->GetObstacleSimulation(), facingMode, enableVisualization); baseact = tmpstact; break; } diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp index e093ddb4072..dfba4482ce9 100644 --- a/source/gameengine/Ketsji/KX_SteeringActuator.cpp +++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp @@ -38,6 +38,7 @@ #include "KX_NavMeshObject.h" #include "KX_ObstacleSimulation.h" #include "KX_PythonInit.h" +#include "KX_PyMath.h" /* ------------------------------------------------------------------------- */ @@ -55,6 +56,7 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, bool isSelfTerminated, int pathUpdatePeriod, KX_ObstacleSimulation* simulation, + short facingmode, bool enableVisualization) : SCA_IActuator(gameobj, KX_ACT_STEERING), m_mode(mode), @@ -69,9 +71,11 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, m_isActive(false), m_simulation(simulation), m_enableVisualization(enableVisualization), + m_facingMode(facingmode), m_obstacle(NULL), m_pathLen(0), - m_wayPointIdx(-1) + m_wayPointIdx(-1), + m_steerVec(MT_Vector3(0, 0, 0)) { m_navmesh = static_cast(navmesh); if (m_navmesh) @@ -81,6 +85,13 @@ KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, if (m_simulation) m_obstacle = m_simulation->GetObstacle((KX_GameObject*)gameobj); + KX_GameObject* parent = ((KX_GameObject*)gameobj)->GetParent(); + if (m_facingMode>0 && parent) + { + m_parentlocalmat = parent->GetSGNode()->GetLocalOrientation(); + } + else + m_parentlocalmat.setIdentity(); } KX_SteeringActuator::~KX_SteeringActuator() @@ -175,7 +186,7 @@ bool KX_SteeringActuator::Update(double curtime, bool frame) MT_Vector3 vectotarg = targpos - mypos; MT_Vector3 vectotarg2d = vectotarg; vectotarg2d.z() = 0; - MT_Vector3 steervec = MT_Vector3(0, 0, 0); + m_steerVec = MT_Vector3(0, 0, 0); bool apply_steerforce = false; bool terminate = true; @@ -184,8 +195,8 @@ bool KX_SteeringActuator::Update(double curtime, bool frame) if (vectotarg2d.length2()>m_distance*m_distance) { terminate = false; - steervec = vectotarg; - steervec.normalize(); + m_steerVec = vectotarg; + m_steerVec.normalize(); apply_steerforce = true; } break; @@ -193,8 +204,8 @@ bool KX_SteeringActuator::Update(double curtime, bool frame) if (vectotarg2d.length2()IsDynamic(); if (isdyna) - steervec.z() = 0; - if (!steervec.fuzzyZero()) - steervec.normalize(); - MT_Vector3 newvel = m_velocity*steervec; + m_steerVec.z() = 0; + if (!m_steerVec.fuzzyZero()) + m_steerVec.normalize(); + MT_Vector3 newvel = m_velocity*m_steerVec; //adjust velocity to avoid obstacles if (m_simulation && m_obstacle /*&& !newvel.fuzzyZero()*/) @@ -264,6 +275,7 @@ bool KX_SteeringActuator::Update(double curtime, bool frame) KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(0.,1.,0.)); } + HandleActorFace(newvel); if (isdyna) { //temporary solution: set 2D steering velocity directly to obj @@ -295,6 +307,96 @@ bool KX_SteeringActuator::Update(double curtime, bool frame) return true; } +const MT_Vector3& KX_SteeringActuator::GetSteeringVec() +{ + if (m_isActive) + return m_steerVec; + else + return MT_Vector3(0, 0, 0); +} + +void KX_SteeringActuator::HandleActorFace(MT_Vector3& velocity) +{ + if (m_facingMode==0) + return; + MT_Vector3 dir = velocity; + if (dir.fuzzyZero()) + return; + dir.normalize(); + MT_Vector3 up(0,0,1); + MT_Vector3 left; + MT_Matrix3x3 mat; + switch (m_facingMode) + { + case 1: // TRACK X + { + left = dir.safe_normalized(); + dir = -(left.cross(up)).safe_normalized(); + break; + }; + case 2: // TRACK Y + { + left = (dir.cross(up)).safe_normalized(); + break; + } + + case 3: // track Z + { + left = up.safe_normalized(); + up = dir.safe_normalized(); + dir = left; + left = (dir.cross(up)).safe_normalized(); + break; + } + + case 4: // TRACK -X + { + left = -dir.safe_normalized(); + dir = -(left.cross(up)).safe_normalized(); + break; + }; + case 5: // TRACK -Y + { + left = (-dir.cross(up)).safe_normalized(); + dir = -dir; + break; + } + case 6: // track -Z + { + left = up.safe_normalized(); + up = -dir.safe_normalized(); + dir = left; + left = (dir.cross(up)).safe_normalized(); + break; + } + } + mat.setValue ( + left[0], dir[0],up[0], + left[1], dir[1],up[1], + left[2], dir[2],up[2] + ); + + KX_GameObject* curobj = (KX_GameObject*) GetParent(); + + KX_GameObject* parentObject = curobj->GetParent(); + if(parentObject) + { + MT_Point3 localpos; + localpos = curobj->GetSGNode()->GetLocalPosition(); + MT_Matrix3x3 parentmatinv; + parentmatinv = parentObject->NodeGetWorldOrientation ().inverse (); + mat = parentmatinv * mat; + mat = m_parentlocalmat * mat; + curobj->NodeSetLocalOrientation(mat); + curobj->NodeSetLocalPosition(localpos); + } + else + { + curobj->NodeSetLocalOrientation(mat); + } + +} + #ifndef DISABLE_PYTHON /* ------------------------------------------------------------------------- */ @@ -338,6 +440,7 @@ PyAttributeDef KX_SteeringActuator::Attributes[] = { KX_PYATTRIBUTE_FLOAT_RW("turnspeed", 0.0f, 720.0f, KX_SteeringActuator, m_turnspeed), KX_PYATTRIBUTE_BOOL_RW("selfterminated", KX_SteeringActuator, m_isSelfTerminated), KX_PYATTRIBUTE_BOOL_RW("enableVisualization", KX_SteeringActuator, m_enableVisualization), + KX_PYATTRIBUTE_RO_FUNCTION("steeringVec", KX_SteeringActuator, pyattr_get_steeringVec), KX_PYATTRIBUTE_INT_RW("pathUpdatePeriod", -1, 100000, true, KX_SteeringActuator, m_pathUpdatePeriod), { NULL } //Sentinel }; @@ -404,6 +507,13 @@ int KX_SteeringActuator::pyattr_set_navmesh(void *self, const struct KX_PYATTRIB return PY_SET_ATTR_SUCCESS; } +PyObject* KX_SteeringActuator::pyattr_get_steeringVec(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_SteeringActuator* actuator = static_cast(self); + const MT_Vector3& steeringVec = actuator->GetSteeringVec(); + return PyObjectFrom(steeringVec); +} + #endif // DISABLE_PYTHON /* eof */ diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.h b/source/gameengine/Ketsji/KX_SteeringActuator.h index b07d906dba3..78fb29f4124 100644 --- a/source/gameengine/Ketsji/KX_SteeringActuator.h +++ b/source/gameengine/Ketsji/KX_SteeringActuator.h @@ -38,6 +38,7 @@ #include "SCA_IActuator.h" #include "SCA_LogicManager.h" +#include "MT_Matrix3x3.h" class KX_GameObject; class KX_NavMeshObject; @@ -64,11 +65,15 @@ class KX_SteeringActuator : public SCA_IActuator bool m_isActive; bool m_isSelfTerminated; bool m_enableVisualization; + short m_facingMode; float m_path[MAX_PATH_LENGTH*3]; int m_pathLen; int m_pathUpdatePeriod; double m_pathUpdateTime; int m_wayPointIdx; + MT_Matrix3x3 m_parentlocalmat; + MT_Vector3 m_steerVec; + void HandleActorFace(MT_Vector3& velocity); public: enum KX_STEERINGACT_MODE { @@ -90,6 +95,7 @@ public: bool isSelfTerminated, int pathUpdatePeriod, KX_ObstacleSimulation* simulation, + short facingmode, bool enableVisualization); virtual ~KX_SteeringActuator(); virtual bool Update(double curtime, bool frame); @@ -98,6 +104,7 @@ public: virtual void ProcessReplica(); virtual void Relink(GEN_Map *obj_map); virtual bool UnlinkObject(SCA_IObject* clientobj); + const MT_Vector3& GetSteeringVec(); #ifndef DISABLE_PYTHON @@ -110,6 +117,7 @@ public: static int pyattr_set_target(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_steeringVec(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); #endif // DISABLE_PYTHON