Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/gameengine/Ketsji/KX_ConstraintActuator.cpp')
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintActuator.cpp805
1 files changed, 681 insertions, 124 deletions
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
index bd843d97199..76357e9c58f 100644
--- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
+++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
@@ -35,6 +35,7 @@
#include "MT_Point3.h"
#include "MT_Matrix3x3.h"
#include "KX_GameObject.h"
+#include "KX_RayCast.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -45,35 +46,60 @@
/* ------------------------------------------------------------------------- */
KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj,
- int dampTime,
+ int posDampTime,
+ int rotDampTime,
float minBound,
float maxBound,
+ float refDir[3],
int locrotxyz,
- PyTypeObject* T)
- : SCA_IActuator(gameobj, T)
+ int time,
+ int option,
+ char *property,
+ PyTypeObject* T) :
+ m_refDirection(refDir),
+ m_currentTime(0),
+ SCA_IActuator(gameobj, T)
{
- m_dampTime = dampTime;
+ m_posDampTime = posDampTime;
+ m_rotDampTime = rotDampTime;
m_locrot = locrotxyz;
+ m_option = option;
+ m_activeTime = time;
+ if (property) {
+ strncpy(m_property, property, sizeof(m_property));
+ m_property[sizeof(m_property)-1] = 0;
+ } else {
+ m_property[0] = 0;
+ }
/* The units of bounds are determined by the type of constraint. To */
/* make the constraint application easier and more transparent later on, */
/* I think converting the bounds to the applicable domain makes more */
/* sense. */
switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- case KX_ACT_CONSTRAINT_LOCY:
- case KX_ACT_CONSTRAINT_LOCZ:
+ case KX_ACT_CONSTRAINT_ORIX:
+ case KX_ACT_CONSTRAINT_ORIY:
+ case KX_ACT_CONSTRAINT_ORIZ:
+ {
+ MT_Scalar len = m_refDirection.length();
+ if (MT_fuzzyZero(len)) {
+ // missing a valid direction
+ std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no valid reference direction!" << std::endl;
+ m_locrot = KX_ACT_CONSTRAINT_NODEF;
+ } else {
+ m_refDirection /= len;
+ }
+ m_minimumBound = cos(minBound);
+ m_maximumBound = cos(maxBound);
+ m_minimumSine = sin(minBound);
+ m_maximumSine = sin(maxBound);
+ }
+ break;
+ default:
m_minimumBound = minBound;
m_maximumBound = maxBound;
+ m_minimumSine = 0.f;
+ m_maximumSine = 0.f;
break;
- case KX_ACT_CONSTRAINT_ROTX:
- case KX_ACT_CONSTRAINT_ROTY:
- case KX_ACT_CONSTRAINT_ROTZ:
- /* The user interface asks for degrees, we are radian. */
- m_minimumBound = MT_radians(minBound);
- m_maximumBound = MT_radians(maxBound);
- break;
- default:
- ; /* error */
}
} /* End of constructor */
@@ -83,77 +109,426 @@ KX_ConstraintActuator::~KX_ConstraintActuator()
// there's nothing to be done here, really....
} /* end of destructor */
-bool KX_ConstraintActuator::Update(double curtime, bool frame)
+bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
{
- bool result = false;
- bool bNegativeEvent = IsNegativeEvent();
- RemoveAllEvents();
-
- if (bNegativeEvent)
- return false; // do nothing on negative events
-
- /* Constraint clamps the values to the specified range, with a sort of */
- /* low-pass filtered time response, if the damp time is unequal to 0. */
-
- /* Having to retrieve location/rotation and setting it afterwards may not */
- /* be efficient enough... Somthing to look at later. */
- KX_GameObject *parent = (KX_GameObject*) GetParent();
- MT_Point3 position = parent->NodeGetWorldPosition();
- MT_Matrix3x3 rotation = parent->NodeGetWorldOrientation();
-// MT_Vector3 eulerrot = rotation.getEuler();
-
- switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- Clamp(position[0], m_minimumBound, m_maximumBound);
- result = true;
- break;
- case KX_ACT_CONSTRAINT_LOCY:
- Clamp(position[1], m_minimumBound, m_maximumBound);
- result = true;
- break;
- case KX_ACT_CONSTRAINT_LOCZ:
- Clamp(position[2], m_minimumBound, m_maximumBound);
- result = true;
- break;
+ m_hitObject = client->m_gameobject;
-// case KX_ACT_CONSTRAINT_ROTX:
-// /* The angles are Euler angles (I think that's what they are called) */
-// /* but we need to convert from/to the MT_Matrix3x3. */
-// Clamp(eulerrot[0], m_minimumBound, m_maximumBound);
-// break;
-// case KX_ACT_CONSTRAINT_ROTY:
-// Clamp(eulerrot[1], m_minimumBound, m_maximumBound);
-// break;
-// case KX_ACT_CONSTRAINT_ROTZ:
-// Clamp(eulerrot[2], m_minimumBound, m_maximumBound);
-// break;
-// default:
-// ; /* error */
- }
+ bool bFound = false;
- /* Will be replaced by a filtered clamp. */
-
+ if (m_property[0] == 0)
+ {
+ bFound = true;
+ }
+ else
+ {
+ if (m_option & KX_ACT_CONSTRAINT_MATERIAL)
+ {
+ if (client->m_auxilary_info)
+ {
+ bFound = !strcmp(m_property, ((char*)client->m_auxilary_info));
+ }
+ }
+ else
+ {
+ bFound = m_hitObject->GetProperty(m_property) != NULL;
+ }
+ }
+ // update the hit status
+ result->m_hitFound = bFound;
+ // stop looking
+ return true;
+}
- switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- case KX_ACT_CONSTRAINT_LOCY:
- case KX_ACT_CONSTRAINT_LOCZ:
- parent->NodeSetLocalPosition(position);
- break;
+/* this function is used to pre-filter the object before casting the ray on them.
+ This is useful for "X-Ray" option when we want to see "through" unwanted object.
+ */
+bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo* client)
+{
+ if (client->m_type > KX_ClientObjectInfo::ACTOR)
+ {
+ // Unknown type of object, skip it.
+ // Should not occur as the sensor objects are filtered in RayTest()
+ printf("Invalid client type %d found in ray casting\n", client->m_type);
+ return false;
+ }
+ // no X-Ray function yet
+ return true;
+}
+bool KX_ConstraintActuator::Update(double curtime, bool frame)
+{
-// case KX_ACT_CONSTRAINT_ROTX:
-// case KX_ACT_CONSTRAINT_ROTY:
-// case KX_ACT_CONSTRAINT_ROTZ:
-// rotation.setEuler(eulerrot);
-// parent->NodeSetLocalOrientation(rotation);
- break;
+ bool result = false;
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
- default:
- ; /* error */
+ if (!bNegativeEvent) {
+ /* Constraint clamps the values to the specified range, with a sort of */
+ /* low-pass filtered time response, if the damp time is unequal to 0. */
+
+ /* Having to retrieve location/rotation and setting it afterwards may not */
+ /* be efficient enough... Somthing to look at later. */
+ KX_GameObject *obj = (KX_GameObject*) GetParent();
+ MT_Point3 position = obj->NodeGetWorldPosition();
+ MT_Point3 newposition;
+ MT_Vector3 normal, direction, refDirection;
+ MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
+ MT_Scalar filter, newdistance, cosangle;
+ int axis, sign;
+
+ if (m_posDampTime) {
+ filter = m_posDampTime/(1.0+m_posDampTime);
+ } else {
+ filter = 0.0;
+ }
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_ORIX:
+ case KX_ACT_CONSTRAINT_ORIY:
+ case KX_ACT_CONSTRAINT_ORIZ:
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_ORIX:
+ direction[0] = rotation[0][0];
+ direction[1] = rotation[1][0];
+ direction[2] = rotation[2][0];
+ axis = 0;
+ break;
+ case KX_ACT_CONSTRAINT_ORIY:
+ direction[0] = rotation[0][1];
+ direction[1] = rotation[1][1];
+ direction[2] = rotation[2][1];
+ axis = 1;
+ break;
+ default:
+ direction[0] = rotation[0][2];
+ direction[1] = rotation[1][2];
+ direction[2] = rotation[2][2];
+ axis = 2;
+ break;
+ }
+ if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) {
+ // reference direction needs to be evaluated
+ // 1. get the cosine between current direction and target
+ cosangle = direction.dot(m_refDirection);
+ if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) {
+ // no change to do
+ result = true;
+ goto CHECK_TIME;
+ }
+ // 2. define a new reference direction
+ // compute local axis with reference direction as X and
+ // Y in direction X refDirection plane
+ MT_Vector3 zaxis = m_refDirection.cross(direction);
+ if (MT_fuzzyZero2(zaxis.length2())) {
+ // direction and refDirection are identical,
+ // choose any other direction to define plane
+ if (direction[0] < 0.9999)
+ zaxis = m_refDirection.cross(MT_Vector3(1.0,0.0,0.0));
+ else
+ zaxis = m_refDirection.cross(MT_Vector3(0.0,1.0,0.0));
+ }
+ MT_Vector3 yaxis = zaxis.cross(m_refDirection);
+ yaxis.normalize();
+ if (cosangle > m_minimumBound) {
+ // angle is too close to reference direction,
+ // choose a new reference that is exactly at minimum angle
+ refDirection = m_minimumBound * m_refDirection + m_minimumSine * yaxis;
+ } else {
+ // angle is too large, choose new reference direction at maximum angle
+ refDirection = m_maximumBound * m_refDirection + m_maximumSine * yaxis;
+ }
+ } else {
+ refDirection = m_refDirection;
+ }
+ // apply damping on the direction
+ direction = filter*direction + (1.0-filter)*refDirection;
+ obj->AlignAxisToVect(direction, axis);
+ result = true;
+ goto CHECK_TIME;
+ case KX_ACT_CONSTRAINT_DIRPX:
+ case KX_ACT_CONSTRAINT_DIRPY:
+ case KX_ACT_CONSTRAINT_DIRPZ:
+ case KX_ACT_CONSTRAINT_DIRNX:
+ case KX_ACT_CONSTRAINT_DIRNY:
+ case KX_ACT_CONSTRAINT_DIRNZ:
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_DIRPX:
+ normal[0] = rotation[0][0];
+ normal[1] = rotation[1][0];
+ normal[2] = rotation[2][0];
+ axis = 0; // axis according to KX_GameObject::AlignAxisToVect()
+ sign = 0; // X axis will be parrallel to direction of ray
+ break;
+ case KX_ACT_CONSTRAINT_DIRPY:
+ normal[0] = rotation[0][1];
+ normal[1] = rotation[1][1];
+ normal[2] = rotation[2][1];
+ axis = 1;
+ sign = 0;
+ break;
+ case KX_ACT_CONSTRAINT_DIRPZ:
+ normal[0] = rotation[0][2];
+ normal[1] = rotation[1][2];
+ normal[2] = rotation[2][2];
+ axis = 2;
+ sign = 0;
+ break;
+ case KX_ACT_CONSTRAINT_DIRNX:
+ normal[0] = -rotation[0][0];
+ normal[1] = -rotation[1][0];
+ normal[2] = -rotation[2][0];
+ axis = 0;
+ sign = 1;
+ break;
+ case KX_ACT_CONSTRAINT_DIRNY:
+ normal[0] = -rotation[0][1];
+ normal[1] = -rotation[1][1];
+ normal[2] = -rotation[2][1];
+ axis = 1;
+ sign = 1;
+ break;
+ case KX_ACT_CONSTRAINT_DIRNZ:
+ normal[0] = -rotation[0][2];
+ normal[1] = -rotation[1][2];
+ normal[2] = -rotation[2][2];
+ axis = 2;
+ sign = 1;
+ break;
+ }
+ normal.normalize();
+ if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
+ // direction of the ray is along the local axis
+ direction = normal;
+ } else {
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_DIRPX:
+ direction = MT_Vector3(1.0,0.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRPY:
+ direction = MT_Vector3(0.0,1.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRPZ:
+ direction = MT_Vector3(0.0,0.0,1.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRNX:
+ direction = MT_Vector3(-1.0,0.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRNY:
+ direction = MT_Vector3(0.0,-1.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_DIRNZ:
+ direction = MT_Vector3(0.0,0.0,-1.0);
+ break;
+ }
+ }
+ {
+ MT_Point3 topoint = position + (m_maximumBound) * direction;
+ PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
+ KX_IPhysicsController *spc = obj->GetPhysicsController();
+
+ if (!pe) {
+ std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no physics environment!" << std::endl;
+ goto CHECK_TIME;
+ }
+ if (!spc) {
+ // the object is not physical, we probably want to avoid hitting its own parent
+ KX_GameObject *parent = obj->GetParent();
+ if (parent) {
+ spc = parent->GetPhysicsController();
+ parent->Release();
+ }
+ }
+ KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
+ result = KX_RayCast::RayTest(pe, position, topoint, callback);
+ if (result) {
+ MT_Vector3 newnormal = callback.m_hitNormal;
+ // compute new position & orientation
+ if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) {
+ // if none option is set, the actuator does nothing but detect ray
+ // (works like a sensor)
+ goto CHECK_TIME;
+ }
+ if (m_option & KX_ACT_CONSTRAINT_NORMAL) {
+ MT_Scalar rotFilter;
+ // apply damping on the direction
+ if (m_rotDampTime) {
+ rotFilter = m_rotDampTime/(1.0+m_rotDampTime);
+ } else {
+ rotFilter = filter;
+ }
+ newnormal = rotFilter*normal - (1.0-rotFilter)*newnormal;
+ obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis);
+ if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
+ direction = newnormal;
+ direction.normalize();
+ }
+ }
+ if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
+ if (m_posDampTime) {
+ newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound;
+ } else {
+ newdistance = m_minimumBound;
+ }
+ // logically we should cancel the speed along the ray direction as we set the
+ // position along that axis
+ spc = obj->GetPhysicsController();
+ if (spc && spc->IsDyna()) {
+ MT_Vector3 linV = spc->GetLinearVelocity();
+ // cancel the projection along the ray direction
+ MT_Scalar fallspeed = linV.dot(direction);
+ if (!MT_fuzzyZero(fallspeed))
+ spc->SetLinearVelocity(linV-fallspeed*direction,false);
+ }
+ } else {
+ newdistance = (position-callback.m_hitPoint).length();
+ }
+ newposition = callback.m_hitPoint-newdistance*direction;
+ } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
+ // no contact but still keep running
+ result = true;
+ goto CHECK_TIME;
+ }
+ }
+ break;
+ case KX_ACT_CONSTRAINT_FHPX:
+ case KX_ACT_CONSTRAINT_FHPY:
+ case KX_ACT_CONSTRAINT_FHPZ:
+ case KX_ACT_CONSTRAINT_FHNX:
+ case KX_ACT_CONSTRAINT_FHNY:
+ case KX_ACT_CONSTRAINT_FHNZ:
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_FHPX:
+ normal[0] = -rotation[0][0];
+ normal[1] = -rotation[1][0];
+ normal[2] = -rotation[2][0];
+ direction = MT_Vector3(1.0,0.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHPY:
+ normal[0] = -rotation[0][1];
+ normal[1] = -rotation[1][1];
+ normal[2] = -rotation[2][1];
+ direction = MT_Vector3(0.0,1.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHPZ:
+ normal[0] = -rotation[0][2];
+ normal[1] = -rotation[1][2];
+ normal[2] = -rotation[2][2];
+ direction = MT_Vector3(0.0,0.0,1.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHNX:
+ normal[0] = rotation[0][0];
+ normal[1] = rotation[1][0];
+ normal[2] = rotation[2][0];
+ direction = MT_Vector3(-1.0,0.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHNY:
+ normal[0] = rotation[0][1];
+ normal[1] = rotation[1][1];
+ normal[2] = rotation[2][1];
+ direction = MT_Vector3(0.0,-1.0,0.0);
+ break;
+ case KX_ACT_CONSTRAINT_FHNZ:
+ normal[0] = rotation[0][2];
+ normal[1] = rotation[1][2];
+ normal[2] = rotation[2][2];
+ direction = MT_Vector3(0.0,0.0,-1.0);
+ break;
+ }
+ normal.normalize();
+ {
+ PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
+ KX_IPhysicsController *spc = obj->GetPhysicsController();
+
+ if (!pe) {
+ std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no physics environment!" << std::endl;
+ goto CHECK_TIME;
+ }
+ if (!spc || !spc->IsDyna()) {
+ // the object is not dynamic, it won't support setting speed
+ goto CHECK_TIME;
+ }
+ m_hitObject = NULL;
+ // distance of Fh area is stored in m_minimum
+ MT_Point3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction;
+ KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
+ result = KX_RayCast::RayTest(pe, position, topoint, callback);
+ // we expect a hit object
+ if (!m_hitObject)
+ result = false;
+ if (result)
+ {
+ MT_Vector3 newnormal = callback.m_hitNormal;
+ // compute new position & orientation
+ MT_Scalar distance = (callback.m_hitPoint-position).length()-spc->GetRadius();
+ // estimate the velocity of the hit point
+ MT_Point3 relativeHitPoint;
+ relativeHitPoint = (callback.m_hitPoint-m_hitObject->NodeGetWorldPosition());
+ MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint);
+ MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint;
+ MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity);
+ MT_Scalar springExtent = 1.0 - distance/m_minimumBound;
+ // Fh force is stored in m_maximum
+ MT_Scalar springForce = springExtent * m_maximumBound;
+ // damping is stored in m_refDirection [0] = damping, [1] = rot damping
+ MT_Scalar springDamp = relativeVelocityRay * m_refDirection[0];
+ MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction;
+ if (m_option & KX_ACT_CONSTRAINT_NORMAL)
+ {
+ newVelocity+=(springForce+springDamp)*(newnormal-newnormal.dot(direction)*direction);
+ }
+ spc->SetLinearVelocity(newVelocity, false);
+ if (m_option & KX_ACT_CONSTRAINT_DOROTFH)
+ {
+ MT_Vector3 angSpring = (normal.cross(newnormal))*m_maximumBound;
+ MT_Vector3 angVelocity = spc->GetAngularVelocity();
+ // remove component that is parallel to normal
+ angVelocity -= angVelocity.dot(newnormal)*newnormal;
+ MT_Vector3 angDamp = angVelocity * ((m_refDirection[1]>MT_EPSILON)?m_refDirection[1]:m_refDirection[0]);
+ spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false);
+ }
+ } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
+ // no contact but still keep running
+ result = true;
+ }
+ // don't set the position with this constraint
+ goto CHECK_TIME;
+ }
+ break;
+ case KX_ACT_CONSTRAINT_LOCX:
+ case KX_ACT_CONSTRAINT_LOCY:
+ case KX_ACT_CONSTRAINT_LOCZ:
+ newposition = position = obj->GetSGNode()->GetLocalPosition();
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_LOCX:
+ Clamp(newposition[0], m_minimumBound, m_maximumBound);
+ break;
+ case KX_ACT_CONSTRAINT_LOCY:
+ Clamp(newposition[1], m_minimumBound, m_maximumBound);
+ break;
+ case KX_ACT_CONSTRAINT_LOCZ:
+ Clamp(newposition[2], m_minimumBound, m_maximumBound);
+ break;
+ }
+ result = true;
+ if (m_posDampTime) {
+ newposition = filter*position + (1.0-filter)*newposition;
+ }
+ obj->NodeSetLocalPosition(newposition);
+ goto CHECK_TIME;
+ }
+ if (result) {
+ // set the new position but take into account parent if any
+ obj->NodeSetWorldPosition(newposition);
+ }
+ CHECK_TIME:
+ if (result && m_activeTime > 0 ) {
+ if (++m_currentTime >= m_activeTime)
+ result = false;
+ }
+ }
+ if (!result) {
+ m_currentTime = 0;
}
-
return result;
} /* end of KX_ConstraintActuator::Update(double curtime,double deltatime) */
@@ -212,14 +587,28 @@ PyParentObject KX_ConstraintActuator::Parents[] = {
};
PyMethodDef KX_ConstraintActuator::Methods[] = {
- {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, SetDamp_doc},
- {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_VARARGS, GetDamp_doc},
- {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc},
- {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetMin_doc},
- {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc},
- {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetMax_doc},
- {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc},
- {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_VARARGS, GetLimit_doc},
+ {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, (PY_METHODCHAR)SetDamp_doc},
+ {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_NOARGS, (PY_METHODCHAR)GetDamp_doc},
+ {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, (PY_METHODCHAR)SetRotDamp_doc},
+ {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_NOARGS, (PY_METHODCHAR)GetRotDamp_doc},
+ {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, (PY_METHODCHAR)SetDirection_doc},
+ {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_NOARGS, (PY_METHODCHAR)GetDirection_doc},
+ {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, (PY_METHODCHAR)SetOption_doc},
+ {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_NOARGS, (PY_METHODCHAR)GetOption_doc},
+ {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, (PY_METHODCHAR)SetTime_doc},
+ {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_NOARGS, (PY_METHODCHAR)GetTime_doc},
+ {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
+ {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc},
+ {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetMin_doc},
+ {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetMin_doc},
+ {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetDistance_doc},
+ {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetDistance_doc},
+ {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetMax_doc},
+ {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetMax_doc},
+ {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetRayLength_doc},
+ {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetRayLength_doc},
+ {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, (PY_METHODCHAR)SetLimit_doc},
+ {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_NOARGS, (PY_METHODCHAR)GetLimit_doc},
{NULL,NULL} //Sentinel
};
@@ -228,10 +617,10 @@ PyObject* KX_ConstraintActuator::_getattr(const STR_String& attr) {
}
/* 2. setDamp */
-char KX_ConstraintActuator::SetDamp_doc[] =
+const char KX_ConstraintActuator::SetDamp_doc[] =
"setDamp(duration)\n"
"\t- duration: integer\n"
-"\tSets the time with which the constraint application is delayed.\n"
+"\tSets the time constant of the orientation and distance constraint.\n"
"\tIf the duration is negative, it is set to 0.\n";
PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self,
PyObject* args,
@@ -241,23 +630,182 @@ PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self,
return NULL;
}
- m_dampTime = dampArg;
- if (m_dampTime < 0) m_dampTime = 0;
+ m_posDampTime = dampArg;
+ if (m_posDampTime < 0) m_posDampTime = 0;
Py_Return;
}
/* 3. getDamp */
-char KX_ConstraintActuator::GetDamp_doc[] =
-"GetDamp()\n"
+const char KX_ConstraintActuator::GetDamp_doc[] =
+"getDamp()\n"
+"\tReturns the damping parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self){
+ return PyInt_FromLong(m_posDampTime);
+}
+
+/* 2. setRotDamp */
+const char KX_ConstraintActuator::SetRotDamp_doc[] =
+"setRotDamp(duration)\n"
+"\t- duration: integer\n"
+"\tSets the time constant of the orientation constraint.\n"
+"\tIf the duration is negative, it is set to 0.\n";
+PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int dampArg;
+ if(!PyArg_ParseTuple(args, "i", &dampArg)) {
+ return NULL;
+ }
+
+ m_rotDampTime = dampArg;
+ if (m_rotDampTime < 0) m_rotDampTime = 0;
+
+ Py_Return;
+}
+/* 3. getRotDamp */
+const char KX_ConstraintActuator::GetRotDamp_doc[] =
+"getRotDamp()\n"
"\tReturns the damping time for application of the constraint.\n";
-PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self,
+PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self){
+ return PyInt_FromLong(m_rotDampTime);
+}
+
+/* 2. setDirection */
+const char KX_ConstraintActuator::SetDirection_doc[] =
+"setDirection(vector)\n"
+"\t- vector: 3-tuple\n"
+"\tSets the reference direction in world coordinate for the orientation constraint.\n";
+PyObject* KX_ConstraintActuator::PySetDirection(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ float x, y, z;
+ MT_Scalar len;
+ MT_Vector3 dir;
+
+ if(!PyArg_ParseTuple(args, "(fff)", &x, &y, &z)) {
+ return NULL;
+ }
+ dir[0] = x;
+ dir[1] = y;
+ dir[2] = z;
+ len = dir.length();
+ if (MT_fuzzyZero(len)) {
+ std::cout << "Invalid direction" << std::endl;
+ return NULL;
+ }
+ m_refDirection = dir/len;
+
+ Py_Return;
+}
+/* 3. getDirection */
+const char KX_ConstraintActuator::GetDirection_doc[] =
+"getDirection()\n"
+"\tReturns the reference direction of the orientation constraint as a 3-tuple.\n";
+PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self){
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_refDirection[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_refDirection[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_refDirection[2]));
+ return retVal;
+}
+
+/* 2. setOption */
+const char KX_ConstraintActuator::SetOption_doc[] =
+"setOption(option)\n"
+"\t- option: integer\n"
+"\tSets several options of the distance constraint.\n"
+"\tBinary combination of the following values:\n"
+"\t\t 64 : Activate alignment to surface\n"
+"\t\t128 : Detect material rather than property\n"
+"\t\t256 : No deactivation if ray does not hit target\n"
+"\t\t512 : Activate distance control\n";
+PyObject* KX_ConstraintActuator::PySetOption(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ int option;
+ if(!PyArg_ParseTuple(args, "i", &option)) {
+ return NULL;
+ }
+
+ m_option = option;
+
+ Py_Return;
+}
+/* 3. getOption */
+const char KX_ConstraintActuator::GetOption_doc[] =
+"getOption()\n"
+"\tReturns the option parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self){
+ return PyInt_FromLong(m_option);
+}
+
+/* 2. setTime */
+const char KX_ConstraintActuator::SetTime_doc[] =
+"setTime(duration)\n"
+"\t- duration: integer\n"
+"\tSets the activation time of the actuator.\n"
+"\tThe actuator disables itself after this many frame.\n"
+"\tIf set to 0 or negative, the actuator is not limited in time.\n";
+PyObject* KX_ConstraintActuator::PySetTime(PyObject* self,
PyObject* args,
- PyObject* kwds){
- return PyInt_FromLong(m_dampTime);
+ PyObject* kwds) {
+ int t;
+ if(!PyArg_ParseTuple(args, "i", &t)) {
+ return NULL;
+ }
+
+ if (t < 0)
+ t = 0;
+ m_activeTime = t;
+
+ Py_Return;
+}
+/* 3. getTime */
+const char KX_ConstraintActuator::GetTime_doc[] =
+"getTime()\n"
+"\tReturns the time parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self){
+ return PyInt_FromLong(m_activeTime);
}
+/* 2. setProperty */
+const char KX_ConstraintActuator::SetProperty_doc[] =
+"setProperty(property)\n"
+"\t- property: string\n"
+"\tSets the name of the property or material for the ray detection of the distance constraint.\n"
+"\tIf empty, the ray will detect any collisioning object.\n";
+PyObject* KX_ConstraintActuator::PySetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
+ char *property;
+ if (!PyArg_ParseTuple(args, "s", &property)) {
+ return NULL;
+ }
+ if (property == NULL) {
+ m_property[0] = 0;
+ } else {
+ strncpy(m_property, property, sizeof(m_property));
+ m_property[sizeof(m_property)-1] = 0;
+ }
+
+ Py_Return;
+}
+/* 3. getProperty */
+const char KX_ConstraintActuator::GetProperty_doc[] =
+"getProperty()\n"
+"\tReturns the property parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self){
+ return PyString_FromString(m_property);
+}
+
+/* 4. setDistance */
+const char KX_ConstraintActuator::SetDistance_doc[] =
+"setDistance(distance)\n"
+"\t- distance: float\n"
+"\tSets the target distance in distance constraint\n";
/* 4. setMin */
-char KX_ConstraintActuator::SetMin_doc[] =
+const char KX_ConstraintActuator::SetMin_doc[] =
"setMin(lower_bound)\n"
"\t- lower_bound: float\n"
"\tSets the lower value of the interval to which the value\n"
@@ -271,9 +819,7 @@ PyObject* KX_ConstraintActuator::PySetMin(PyObject* self,
}
switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- case KX_ACT_CONSTRAINT_LOCY:
- case KX_ACT_CONSTRAINT_LOCZ:
+ default:
m_minimumBound = minArg;
break;
case KX_ACT_CONSTRAINT_ROTX:
@@ -281,25 +827,30 @@ PyObject* KX_ConstraintActuator::PySetMin(PyObject* self,
case KX_ACT_CONSTRAINT_ROTZ:
m_minimumBound = MT_radians(minArg);
break;
- default:
- ; /* error */
}
Py_Return;
}
+/* 5. getDistance */
+const char KX_ConstraintActuator::GetDistance_doc[] =
+"getDistance()\n"
+"\tReturns the distance parameter \n";
/* 5. getMin */
-char KX_ConstraintActuator::GetMin_doc[] =
+const char KX_ConstraintActuator::GetMin_doc[] =
"getMin()\n"
"\tReturns the lower value of the interval to which the value\n"
"\tis clipped.\n";
-PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self) {
return PyFloat_FromDouble(m_minimumBound);
}
+/* 6. setRayLength */
+const char KX_ConstraintActuator::SetRayLength_doc[] =
+"setRayLength(length)\n"
+"\t- length: float\n"
+"\tSets the maximum ray length of the distance constraint\n";
/* 6. setMax */
-char KX_ConstraintActuator::SetMax_doc[] =
+const char KX_ConstraintActuator::SetMax_doc[] =
"setMax(upper_bound)\n"
"\t- upper_bound: float\n"
"\tSets the upper value of the interval to which the value\n"
@@ -313,9 +864,7 @@ PyObject* KX_ConstraintActuator::PySetMax(PyObject* self,
}
switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- case KX_ACT_CONSTRAINT_LOCY:
- case KX_ACT_CONSTRAINT_LOCZ:
+ default:
m_maximumBound = maxArg;
break;
case KX_ACT_CONSTRAINT_ROTX:
@@ -323,31 +872,41 @@ PyObject* KX_ConstraintActuator::PySetMax(PyObject* self,
case KX_ACT_CONSTRAINT_ROTZ:
m_maximumBound = MT_radians(maxArg);
break;
- default:
- ; /* error */
}
Py_Return;
}
+/* 7. getRayLength */
+const char KX_ConstraintActuator::GetRayLength_doc[] =
+"getRayLength()\n"
+"\tReturns the length of the ray\n";
/* 7. getMax */
-char KX_ConstraintActuator::GetMax_doc[] =
+const char KX_ConstraintActuator::GetMax_doc[] =
"getMax()\n"
"\tReturns the upper value of the interval to which the value\n"
"\tis clipped.\n";
-PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self) {
return PyFloat_FromDouble(m_maximumBound);
}
/* This setter/getter probably for the constraint type */
/* 8. setLimit */
-char KX_ConstraintActuator::SetLimit_doc[] =
+const char KX_ConstraintActuator::SetLimit_doc[] =
"setLimit(type)\n"
-"\t- type: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY,\n"
-"\t KX_CONSTRAINTACT_LOCZ, KX_CONSTRAINTACT_ROTX,\n"
-"\t KX_CONSTRAINTACT_ROTY, or KX_CONSTRAINTACT_ROTZ.\n"
+"\t- type: integer\n"
+"\t 1 : LocX\n"
+"\t 2 : LocY\n"
+"\t 3 : LocZ\n"
+"\t 7 : Distance along +X axis\n"
+"\t 8 : Distance along +Y axis\n"
+"\t 9 : Distance along +Z axis\n"
+"\t 10 : Distance along -X axis\n"
+"\t 11 : Distance along -Y axis\n"
+"\t 12 : Distance along -Z axis\n"
+"\t 13 : Align X axis\n"
+"\t 14 : Align Y axis\n"
+"\t 15 : Align Z axis\n"
"\tSets the type of constraint.\n";
PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self,
PyObject* args,
@@ -362,12 +921,10 @@ PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self,
Py_Return;
}
/* 9. getLimit */
-char KX_ConstraintActuator::GetLimit_doc[] =
-"getLimit(type)\n"
+const char KX_ConstraintActuator::GetLimit_doc[] =
+"getLimit()\n"
"\tReturns the type of constraint.\n";
-PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self) {
return PyInt_FromLong(m_locrot);
}