diff options
author | Benoit Bolsee <benoit.bolsee@online.be> | 2008-10-01 23:16:13 +0400 |
---|---|---|
committer | Benoit Bolsee <benoit.bolsee@online.be> | 2008-10-01 23:16:13 +0400 |
commit | 8550c2b594fb1a2544b77b7f3abec84b29b1745d (patch) | |
tree | cf54081e1efe46327c6125297da4e829cabe283b /source | |
parent | 611b4b383ab56c92a3d09e670773cb66a7b61ad6 (diff) |
BGE patch: new force field constraint actuator
A new type of constraint actuator is available: Force field.
It provides a very similar service to the Fh material feature
but with some specificities:
- It is defined at the object level: each object can have
different settings and you don't need to use material.
- It can be applied in all 6 directions and not just -Z.
- It can be enabled/disabled easily (it's an actuator).
- You can have multiple force fields active at the same time
on the same object in different direction (think of a
space ship in a tunnel with a repulsive force field
on each wall).
- You can have a different damping for the rotation.
Besides that it provides the same dynamic behavior and the
parameters are self explanatory.
It works by adapting the linear and angular velocity: the
dynamic is independent of the mass. It is compatible with
all other motion actuators.
Note: linear and anysotropic friction is not yet implemented,
the only friction will come from the object damping parameters.
Support for friction will be added in a future revision.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/makesdna/DNA_actuator_types.h | 2 | ||||
-rw-r--r-- | source/blender/src/buttons_logic.c | 40 | ||||
-rw-r--r-- | source/gameengine/Converter/KX_ConvertActuators.cpp | 34 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_ConstraintActuator.cpp | 110 | ||||
-rw-r--r-- | source/gameengine/Ketsji/KX_ConstraintActuator.h | 12 |
5 files changed, 193 insertions, 5 deletions
diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index 2487216f764..0af1ec0a2c7 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -369,6 +369,7 @@ typedef struct FreeCamera { #define ACT_CONST_PERMANENT 256 #define ACT_CONST_DISTANCE 512 #define ACT_CONST_LOCAL 1024 +#define ACT_CONST_DOROTFH 2048 /* constraint mode */ #define ACT_CONST_DIRPX 1 @@ -382,6 +383,7 @@ typedef struct FreeCamera { #define ACT_CONST_TYPE_LOC 0 #define ACT_CONST_TYPE_DIST 1 #define ACT_CONST_TYPE_ORI 2 +#define ACT_CONST_TYPE_FH 3 /* editObjectActuator->type */ #define ACT_EDOB_ADD_OBJECT 0 diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c index ba8116dbc5b..052bf3f1ae4 100644 --- a/source/blender/src/buttons_logic.c +++ b/source/blender/src/buttons_logic.c @@ -2214,8 +2214,46 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh uiDefButS(block, NUM, 0, "time", xco+10, yco-84, 70, 19, &(coa->time), 0.0, 1000.0, 0, 0, "Maximum activation time in frame, 0 for unlimited"); uiDefButF(block, NUM, 0, "min", xco+80, yco-84, (width-115)/2, 19, &(coa->minloc[0]), 0.0, 180.0, 10, 1, "Minimum angle (in degree) to maintain with target direction. No correction is done if angle with target direction is between min and max"); uiDefButF(block, NUM, 0, "max", xco+80+(width-115)/2, yco-84, (width-115)/2, 19, &(coa->maxloc[0]), 0.0, 180.0, 10, 1, "Maximum angle (in degree) allowed with target direction. No correction is done if angle with target direction is between min and max"); + } else if (coa->type == ACT_CONST_TYPE_FH) { + ysize= 106; + + glRects(xco, yco-ysize, xco+width, yco); + uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1); + + str= "Direction %t|None %x0|X axis %x1|Y axis %x2|Z axis %x4|-X axis %x8|-Y axis %x16|-Z axis %x32"; + uiDefButS(block, MENU, B_REDR, str, xco+10, yco-65, 70, 19, &coa->mode, 0.0, 0.0, 0, 0, "Set the direction of the ray (in world coordinate)"); + + if(coa->mode & (ACT_CONST_DIRPX|ACT_CONST_DIRNX)) fp= coa->minloc; + else if(coa->mode & (ACT_CONST_DIRPY|ACT_CONST_DIRNY)) fp= coa->minloc+1; + else fp= coa->minloc+2; + + uiDefButF(block, NUM, 0, "damp", xco+10, yco-45, (width-70)/2, 19, &coa->maxrot[0], 0.0, 1.0, 1, 0, "Damping factor of the Fh spring force"); + uiDefButF(block, NUM, 0, "dist", xco+10+(width-70)/2, yco-45, (width-70)/2, 19, fp, 0.010, 2000.0, 10, 0, "Height of the Fh area"); + uiDefButBitS(block, TOG, ACT_CONST_DOROTFH, 0, "Rot Fh", xco+10+(width-70), yco-45, 50, 19, &coa->flag, 0.0, 0.0, 0, 0, "Keep object axis parallel to normal"); + + uiDefButF(block, NUMSLI, 0, "Fh ", xco+80, yco-65, (width-115), 19, fp+3, 0.0, 1.0, 0, 0, "Spring force within the Fh area"); + uiDefButBitS(block, TOG, ACT_CONST_NORMAL, 0, "N", xco+80+(width-115), yco-65, 25, 19, + &coa->flag, 0.0, 0.0, 0, 0, "Add a horizontal spring force on slopes"); + uiDefButBitS(block, TOG, ACT_CONST_MATERIAL, B_REDR, "M/P", xco+10, yco-84, 40, 19, + &coa->flag, 0.0, 0.0, 0, 0, "Detect material instead of property"); + if (coa->flag & ACT_CONST_MATERIAL) + { + uiDefBut(block, TEX, 1, "Material:", xco + 50, yco-84, (width-60), 19, + coa->matprop, 0, 31, 0, 0, + "Ray detects only Objects with this material"); + } + else + { + uiDefBut(block, TEX, 1, "Property:", xco + 50, yco-84, (width-60), 19, + coa->matprop, 0, 31, 0, 0, + "Ray detect only Objects with this property"); + } + uiDefButBitS(block, TOG, ACT_CONST_PERMANENT, 0, "PER", xco+10, yco-103, 40, 19, + &coa->flag, 0.0, 0.0, 0, 0, "Persistent actuator: stays active even if ray does not reach target"); + uiDefButS(block, NUM, 0, "time", xco+50, yco-103, 90, 19, &(coa->time), 0.0, 1000.0, 0, 0, "Maximum activation time in frame, 0 for unlimited"); + uiDefButF(block, NUM, 0, "rotDamp", xco+140, yco-103, (width-150), 19, &coa->maxrot[1], 0.0, 1.0, 1, 0, "Use a different damping for rotation"); } - str= "Constraint Type %t|Location %x0|Distance %x1|Orientation %x2"; + str= "Constraint Type %t|Location %x0|Distance %x1|Orientation %x2|Force field %x3"; but = uiDefButS(block, MENU, B_REDR, str, xco+40, yco-23, (width-80), 19, &coa->type, 0.0, 0.0, 0, 0, ""); yco-= ysize; break; diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 78791c53d7c..b739e3b2094 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -719,6 +719,40 @@ void BL_ConvertActuators(char* maggiename, break; } prop = conact->matprop; + } else if (conact->type == ACT_CONST_TYPE_FH) { + switch (conact->mode) { + case ACT_CONST_DIRPX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + case ACT_CONST_DIRPY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + case ACT_CONST_DIRPZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + case ACT_CONST_DIRNX: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + case ACT_CONST_DIRNY: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + case ACT_CONST_DIRNZ: + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + } + prop = conact->matprop; } else { switch (conact->flag) { case ACT_CONST_LOCX: diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index 49534ccbd4a..0210f78425e 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -112,7 +112,7 @@ KX_ConstraintActuator::~KX_ConstraintActuator() bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data) { - KX_GameObject* hitKXObj = client->m_gameobject; + m_hitObject = client->m_gameobject; bool bFound = false; @@ -131,7 +131,7 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* resu } else { - bFound = hitKXObj->GetProperty(m_property) != NULL; + bFound = m_hitObject->GetProperty(m_property) != NULL; } } // update the hit status @@ -372,7 +372,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) // logically we should cancel the speed along the ray direction as we set the // position along that axis spc = obj->GetPhysicsController(); - if (spc) { + if (spc && spc->IsDyna()) { MT_Vector3 linV = spc->GetLinearVelocity(); // cancel the projection along the ray direction MT_Scalar fallspeed = linV.dot(direction); @@ -390,6 +390,110 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) } } 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: diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h index b2ef0dae553..28b9b1e6a0b 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.h +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h @@ -38,6 +38,7 @@ #include "KX_ClientObjectInfo.h" class KX_RayCast; +class KX_GameObject; class KX_ConstraintActuator : public SCA_IActuator { @@ -65,6 +66,8 @@ protected: int m_option; // property to check char m_property[32]; + // hit object + KX_GameObject* m_hitObject; /** * Clamp <var> to <min>, <max>. Borders are included (in as far as @@ -92,6 +95,12 @@ protected: KX_ACT_CONSTRAINT_ORIX, KX_ACT_CONSTRAINT_ORIY, KX_ACT_CONSTRAINT_ORIZ, + KX_ACT_CONSTRAINT_FHPX, + KX_ACT_CONSTRAINT_FHPY, + KX_ACT_CONSTRAINT_FHPZ, + KX_ACT_CONSTRAINT_FHNX, + KX_ACT_CONSTRAINT_FHNY, + KX_ACT_CONSTRAINT_FHNZ, KX_ACT_CONSTRAINT_MAX }; // match ACT_CONST_... values from BIF_interface.h @@ -100,7 +109,8 @@ protected: KX_ACT_CONSTRAINT_MATERIAL = 128, KX_ACT_CONSTRAINT_PERMANENT = 256, KX_ACT_CONSTRAINT_DISTANCE = 512, - KX_ACT_CONSTRAINT_LOCAL = 1024 + KX_ACT_CONSTRAINT_LOCAL = 1024, + KX_ACT_CONSTRAINT_DOROTFH = 2048 }; bool IsValidMode(KX_CONSTRAINTTYPE m); bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); |