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:
-rw-r--r--projectfiles_vc7/blender/render/BRE_render.vcproj8
-rw-r--r--projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj12
-rw-r--r--source/blender/blenkernel/intern/sca.c3
-rw-r--r--source/blender/blenloader/intern/writefile.c3
-rw-r--r--source/blender/makesdna/DNA_actuator_types.h38
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h7
-rw-r--r--source/blender/render/intern/source/convertblender.c1
-rw-r--r--source/blender/src/buttons_logic.c300
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.cpp130
-rw-r--r--source/gameengine/Converter/KX_ConvertSensors.cpp14
-rw-r--r--source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp76
-rw-r--r--source/gameengine/GameLogic/SCA_ActuatorEventManager.h52
-rw-r--r--source/gameengine/GameLogic/SCA_ActuatorSensor.cpp196
-rw-r--r--source/gameengine/GameLogic/SCA_ActuatorSensor.h74
-rw-r--r--source/gameengine/GameLogic/SCA_EventManager.cpp4
-rw-r--r--source/gameengine/GameLogic/SCA_EventManager.h4
-rw-r--r--source/gameengine/GameLogic/SCA_IObject.cpp34
-rw-r--r--source/gameengine/GameLogic/SCA_ISensor.cpp1
-rw-r--r--source/gameengine/GameLogic/SCA_ISensor.h3
-rw-r--r--source/gameengine/GameLogic/SCA_JoystickSensor.cpp8
-rw-r--r--source/gameengine/GameLogic/SCA_KeyboardSensor.cpp17
-rw-r--r--source/gameengine/GameLogic/SCA_LogicManager.cpp4
-rw-r--r--source/gameengine/GameLogic/SCA_MouseSensor.cpp12
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.cpp7
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintActuator.cpp576
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintActuator.h59
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp34
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h9
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.cpp8
-rw-r--r--source/gameengine/Ketsji/KX_NearSensor.cpp5
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.cpp363
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.h19
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.cpp10
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp3
-rw-r--r--source/gameengine/Ketsji/KX_TouchSensor.cpp12
35 files changed, 1738 insertions, 368 deletions
diff --git a/projectfiles_vc7/blender/render/BRE_render.vcproj b/projectfiles_vc7/blender/render/BRE_render.vcproj
index 4869dd606f1..4331d6e1579 100644
--- a/projectfiles_vc7/blender/render/BRE_render.vcproj
+++ b/projectfiles_vc7/blender/render/BRE_render.vcproj
@@ -74,7 +74,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\..\..\lib\windows\sdl\include;..\..\..\..\build\msvc_7\intern\guardedalloc\include;..\..\..\source\blender;..\..\..\source\blender\misc;..\..\..\source\blender\imbuf;..\..\..\source\blender\yafray;..\..\..\source\blender\blenlib;..\..\..\source\blender\include;..\..\..\source\blender\python;..\..\..\source\blender\blenkernel;..\..\..\source\blender\quicktime;..\..\..\source\blender\blenloader;..\..\..\source\blender\makesdna;..\..\..\source\blender\radiosity\extern\include;..\..\..\source\blender\render\intern\include;..\..\..\source\blender\render\extern\include;..\..\..\source\kernel;..\..\..\source\kernel\gen_messaging"
- PreprocessorDefinitions="_DEBUG;WIN32;_LIB;WITH_QUICKTIME;WITH_OPENEXR"
+ PreprocessorDefinitions="_DEBUG;WIN32;_LIB;WITH_QUICKTIME;WITH_OPENEXR;_USE_MATH_DEFINES"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
DefaultCharIsUnsigned="TRUE"
@@ -176,6 +176,9 @@
RelativePath="..\..\..\source\blender\render\intern\source\strand.c">
</File>
<File
+ RelativePath="..\..\..\source\blender\render\intern\source\sunsky.c">
+ </File>
+ <File
RelativePath="..\..\..\source\blender\render\intern\source\texture.c">
</File>
<File
@@ -246,6 +249,9 @@
RelativePath="..\..\..\source\blender\render\intern\include\strand.h">
</File>
<File
+ RelativePath="..\..\..\source\blender\render\intern\include\sunsky.h">
+ </File>
+ <File
RelativePath="..\..\..\source\blender\render\intern\include\texture.h">
</File>
<File
diff --git a/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj b/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj
index e0405b4d7c7..7e2db4f564f 100644
--- a/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj
+++ b/projectfiles_vc7/gameengine/gamelogic/SCA_GameLogic.vcproj
@@ -333,6 +333,12 @@
RelativePath="..\..\..\source\gameengine\GameLogic\SCA_2DFilterActuator.cpp">
</File>
<File
+ RelativePath="..\..\..\source\gameengine\GameLogic\SCA_ActuatorEventManager.cpp">
+ </File>
+ <File
+ RelativePath="..\..\..\source\gameengine\GameLogic\SCA_ActuatorSensor.cpp">
+ </File>
+ <File
RelativePath="..\..\..\source\gameengine\GameLogic\SCA_AlwaysEventManager.cpp">
</File>
<File
@@ -445,6 +451,12 @@
RelativePath="..\..\..\source\gameengine\GameLogic\SCA_2DFilterActuator.h">
</File>
<File
+ RelativePath="..\..\..\source\gameengine\GameLogic\SCA_ActuatorEventManager.h">
+ </File>
+ <File
+ RelativePath="..\..\..\source\gameengine\GameLogic\SCA_ActuatorSensor.h">
+ </File>
+ <File
RelativePath="..\..\..\source\gameengine\GameLogic\SCA_AlwaysEventManager.h">
</File>
<File
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index 16ca5d7542d..fcf1c7ce311 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -150,6 +150,9 @@ void init_sensor(bSensor *sens)
case SENS_PROPERTY:
sens->data= MEM_callocN(sizeof(bPropertySensor), "propsens");
break;
+ case SENS_ACTUATOR:
+ sens->data= MEM_callocN(sizeof(bActuatorSensor), "actsens");
+ break;
case SENS_MOUSE:
ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens");
ms->type= LEFTMOUSE;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 9f28e13ff7b..ca91f1dc346 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -603,6 +603,9 @@ static void write_sensors(WriteData *wd, ListBase *lb)
case SENS_PROPERTY:
writestruct(wd, DATA, "bPropertySensor", 1, sens->data);
break;
+ case SENS_ACTUATOR:
+ writestruct(wd, DATA, "bActuatorSensor", 1, sens->data);
+ break;
case SENS_COLLISION:
writestruct(wd, DATA, "bCollisionSensor", 1, sens->data);
break;
diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h
index 51f03a676e4..3cf80a4efa6 100644
--- a/source/blender/makesdna/DNA_actuator_types.h
+++ b/source/blender/makesdna/DNA_actuator_types.h
@@ -98,8 +98,8 @@ typedef struct bPropertyActuator {
} bPropertyActuator;
typedef struct bObjectActuator {
- short flag, type;
- int damping;
+ short flag, type, otype;
+ short damping;
float forceloc[3], forcerot[3];
float loc[3], rot[3];
float dloc[3], drot[3];
@@ -124,10 +124,13 @@ typedef struct bCameraActuator {
} bCameraActuator ;
typedef struct bConstraintActuator {
+ short type, mode;
short flag, damp;
- float slow;
+ short time, rotdamp;
+ int pad;
float minloc[3], maxloc[3];
float minrot[3], maxrot[3];
+ char matprop[32];
} bConstraintActuator;
typedef struct bGroupActuator {
@@ -249,20 +252,19 @@ typedef struct FreeCamera {
/* objectactuator->flag */
#define ACT_FORCE_LOCAL 1
#define ACT_TORQUE_LOCAL 2
+#define ACT_SERVO_LIMIT_X 2
#define ACT_DLOC_LOCAL 4
+#define ACT_SERVO_LIMIT_Y 4
#define ACT_DROT_LOCAL 8
+#define ACT_SERVO_LIMIT_Z 8
#define ACT_LIN_VEL_LOCAL 16
#define ACT_ANG_VEL_LOCAL 32
//#define ACT_ADD_LIN_VEL_LOCAL 64
#define ACT_ADD_LIN_VEL 64
-#define ACT_CLAMP_VEL 128
-#define ACT_OBJECT_FORCE 0
-#define ACT_OBJECT_TORQUE 1
-#define ACT_OBJECT_DLOC 2
-#define ACT_OBJECT_DROT 3
-#define ACT_OBJECT_LINV 4
-#define ACT_OBJECT_ANGV 5
+/* objectactuator->type */
+#define ACT_OBJECT_NORMAL 0
+#define ACT_OBJECT_SERVO 1
/* actuator->type */
#define ACT_OBJECT 0
@@ -358,6 +360,22 @@ typedef struct FreeCamera {
#define ACT_CONST_ROTX 8
#define ACT_CONST_ROTY 16
#define ACT_CONST_ROTZ 32
+#define ACT_CONST_NORMAL 64
+#define ACT_CONST_MATERIAL 128
+#define ACT_CONST_PERMANENT 256
+#define ACT_CONST_DISTANCE 512
+/* constraint mode */
+#define ACT_CONST_DIRPX 1
+#define ACT_CONST_DIRPY 2
+#define ACT_CONST_DIRPZ 4
+#define ACT_CONST_DIRMX 8
+#define ACT_CONST_DIRMY 16
+#define ACT_CONST_DIRMZ 32
+
+/* constraint type */
+#define ACT_CONST_TYPE_LOC 0
+#define ACT_CONST_TYPE_DIST 1
+#define ACT_CONST_TYPE_ORI 2
/* editObjectActuator->type */
#define ACT_EDOB_ADD_OBJECT 0
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
index ae7b92bb06c..c0306f43730 100644
--- a/source/blender/makesdna/DNA_sensor_types.h
+++ b/source/blender/makesdna/DNA_sensor_types.h
@@ -82,6 +82,12 @@ typedef struct bPropertySensor {
char maxvalue[32];
} bPropertySensor;
+typedef struct bActuatorSensor {
+ int type;
+ int pad;
+ char name[32];
+} bActuatorSensor;
+
typedef struct bCollisionSensor {
char name[32]; /* property name */
char materialName[32]; /* material */
@@ -197,6 +203,7 @@ typedef struct bJoystickSensor {
#define SENS_RAY 9
#define SENS_MESSAGE 10
#define SENS_JOYSTICK 11
+#define SENS_ACTUATOR 12
/* sensor->flag */
#define SENS_SHOW 1
#define SENS_DEL 2
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index daee892ad9a..f9ec0e9d843 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -114,6 +114,7 @@
#include "sss.h"
#include "strand.h"
#include "zbuf.h"
+#include "sunsky.h"
#ifndef DISABLE_YAFRAY /* disable yafray */
diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c
index 5065ba1fc2a..be8483b7e04 100644
--- a/source/blender/src/buttons_logic.c
+++ b/source/blender/src/buttons_logic.c
@@ -681,6 +681,8 @@ static char *sensor_name(int type)
return "Keyboard";
case SENS_PROPERTY:
return "Property";
+ case SENS_ACTUATOR:
+ return "Actuator";
case SENS_MOUSE:
return "Mouse";
case SENS_COLLISION:
@@ -704,7 +706,7 @@ static char *sensor_pup(void)
/* the number needs to match defines in game.h */
return "Sensors %t|Always %x0|Keyboard %x3|Mouse %x5|"
"Touch %x1|Collision %x6|Near %x2|Radar %x7|"
- "Property %x4|Random %x8|Ray %x9|Message %x10|Joystick %x11";
+ "Property %x4|Random %x8|Ray %x9|Message %x10|Joystick %x11|Actuator %x12";
}
static char *controller_name(int type)
@@ -1003,6 +1005,7 @@ static int get_col_sensor(int type)
case SENS_NEAR: return TH_BUT_SETTING1;
case SENS_KEYBOARD: return TH_BUT_SETTING2;
case SENS_PROPERTY: return TH_BUT_NUM;
+ case SENS_ACTUATOR: return TH_BUT_NUM;
case SENS_MOUSE: return TH_BUT_TEXTFIELD;
case SENS_RADAR: return TH_BUT_POPUP;
case SENS_RANDOM: return TH_BUT_NEUTRAL;
@@ -1067,6 +1070,7 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short
bRaySensor *raySens = NULL;
bMessageSensor *mes = NULL;
bJoystickSensor *joy = NULL;
+ bActuatorSensor *as = NULL;
short ysize;
char *str;
@@ -1277,6 +1281,22 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short
yco-= ysize;
break;
}
+ case SENS_ACTUATOR:
+ {
+ ysize= 48;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize,
+ (float)xco+width, (float)yco, 1);
+
+ draw_default_sensor_header(sens, block, xco, yco, width);
+ as= sens->data;
+
+ uiDefBut(block, TEX, 1, "Act: ", xco+30,yco-44,width-60, 19,
+ as->name, 0, 31, 0, 0, "Actuator name, actuator active state modifications will be detected");
+ yco-= ysize;
+ break;
+ }
case SENS_MOUSE:
{
ms= sens->data;
@@ -1537,6 +1557,37 @@ static void set_col_actuator(int item, int medium)
}
+static void change_object_actuator(void *act, void *arg)
+{
+ bObjectActuator *oa = act;
+ int i;
+
+ if (oa->type != oa->otype) {
+ switch (oa->type) {
+ case ACT_OBJECT_NORMAL:
+ memset(oa, 0, sizeof(bObjectActuator));
+ oa->flag = ACT_FORCE_LOCAL|ACT_TORQUE_LOCAL|ACT_DLOC_LOCAL|ACT_DROT_LOCAL;
+ oa->type = ACT_OBJECT_NORMAL;
+ break;
+
+ case ACT_OBJECT_SERVO:
+ memset(oa, 0, sizeof(bObjectActuator));
+ oa->flag = ACT_LIN_VEL_LOCAL;
+ oa->type = ACT_OBJECT_SERVO;
+ oa->forcerot[0] = 30.0f;
+ oa->forcerot[1] = 0.5f;
+ oa->forcerot[2] = 0.0f;
+ break;
+ }
+ }
+}
+
+void update_object_actuator_PID(void *act, void *arg)
+{
+ bObjectActuator *oa = act;
+ oa->forcerot[0] = 60.0f*oa->forcerot[1];
+}
+
char *get_state_name(Object *ob, short bit)
{
bController *cont;
@@ -1578,6 +1629,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
short ysize = 0, wval;
char *str;
int myline, stbit;
+ uiBut *but;
/* yco is at the top of the rect, draw downwards */
uiBlockSetEmboss(block, UI_EMBOSSM);
@@ -1587,57 +1639,100 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
{
case ACT_OBJECT:
{
- ysize= 152;
-
- glRects(xco, yco-ysize, xco+width, yco);
- uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
-
oa = act->data;
wval = (width-100)/3;
-
- uiDefBut(block, LABEL, 0, "Force", xco, yco-22, 55, 19, NULL, 0, 0, 0, 0, "Sets the force");
- uiDefButF(block, NUM, 0, "", xco+45, yco-22, wval, 19, oa->forceloc, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+wval, yco-22, wval, 19, oa->forceloc+1, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-22, wval, 19, oa->forceloc+2, -10000.0, 10000.0, 10, 0, "");
-
- uiDefBut(block, LABEL, 0, "Torque", xco, yco-41, 55, 19, NULL, 0, 0, 0, 0, "Sets the torque");
- uiDefButF(block, NUM, 0, "", xco+45, yco-41, wval, 19, oa->forcerot, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+wval, yco-41, wval, 19, oa->forcerot+1, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-41, wval, 19, oa->forcerot+2, -10000.0, 10000.0, 10, 0, "");
-
- uiDefBut(block, LABEL, 0, "dLoc", xco, yco-64, 45, 19, NULL, 0, 0, 0, 0, "Sets the dLoc");
- uiDefButF(block, NUM, 0, "", xco+45, yco-64, wval, 19, oa->dloc, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+wval, yco-64, wval, 19, oa->dloc+1, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-64, wval, 19, oa->dloc+2, -10000.0, 10000.0, 10, 0, "");
-
- uiDefBut(block, LABEL, 0, "dRot", xco, yco-83, 45, 19, NULL, 0, 0, 0, 0, "Sets the dRot");
- uiDefButF(block, NUM, 0, "", xco+45, yco-83, wval, 19, oa->drot, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+wval, yco-83, wval, 19, oa->drot+1, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-83, wval, 19, oa->drot+2, -10000.0, 10000.0, 10, 0, "");
-
- uiDefBut(block, LABEL, 0, "linV", xco, yco-106, 45, 19, NULL, 0, 0, 0, 0, "Sets the linear velocity");
- uiDefButF(block, NUM, 0, "", xco+45, yco-106, wval, 19, oa->linearvelocity, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+wval, yco-106, wval, 19, oa->linearvelocity+1, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-106, wval, 19, oa->linearvelocity+2, -10000.0, 10000.0, 10, 0, "");
-
- uiDefBut(block, LABEL, 0, "angV", xco, yco-125, 45, 19, NULL, 0, 0, 0, 0, "Sets the angular velocity");
- uiDefButF(block, NUM, 0, "", xco+45, yco-125, wval, 19, oa->angularvelocity, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+wval, yco-125, wval, 19, oa->angularvelocity+1, -10000.0, 10000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-125, wval, 19, oa->angularvelocity+2, -10000.0, 10000.0, 10, 0, "");
-
- uiDefBut(block, LABEL, 0, "damp", xco, yco-148, 45, 19, NULL, 0, 0, 0, 0, "Number of frames to reach the target velocity");
- uiDefButI(block, NUM, 0, "", xco+45, yco-148, wval, 19, &oa->damping, 0.0, 1000.0, 100, 0, "");
- uiDefButBitS(block, TOG, ACT_CLAMP_VEL, 0, "clamp",xco+45+wval, yco-148, wval, 19, &oa->flag, 0.0, 0.0, 0, 0, "Toggles between SET and CLAMP Velocity");
-
- uiDefButBitS(block, TOG, ACT_FORCE_LOCAL, 0, "L", xco+45+3*wval, yco-22, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
- uiDefButBitS(block, TOG, ACT_TORQUE_LOCAL, 0, "L", xco+45+3*wval, yco-41, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
- uiDefButBitS(block, TOG, ACT_DLOC_LOCAL, 0, "L", xco+45+3*wval, yco-64, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
- uiDefButBitS(block, TOG, ACT_DROT_LOCAL, 0, "L", xco+45+3*wval, yco-83, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
- uiDefButBitS(block, TOG, ACT_LIN_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-106, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
- uiDefButBitS(block, TOG, ACT_ANG_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-125, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
-
- uiDefButBitS(block, TOG, ACT_ADD_LIN_VEL, 0, "add",xco+45+3*wval+15, yco-106, 35, 19, &oa->flag, 0.0, 0.0, 0, 0, "Toggles between ADD and SET linV");
-
+ if (oa->type == ACT_OBJECT_NORMAL)
+ {
+ ysize= 175;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefBut(block, LABEL, 0, "Force", xco, yco-45, 55, 19, NULL, 0, 0, 0, 0, "Sets the force");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-45, wval, 19, oa->forceloc, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-45, wval, 19, oa->forceloc+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-45, wval, 19, oa->forceloc+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "Torque", xco, yco-64, 55, 19, NULL, 0, 0, 0, 0, "Sets the torque");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-64, wval, 19, oa->forcerot, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-64, wval, 19, oa->forcerot+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-64, wval, 19, oa->forcerot+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "dLoc", xco, yco-87, 45, 19, NULL, 0, 0, 0, 0, "Sets the dLoc");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-87, wval, 19, oa->dloc, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-87, wval, 19, oa->dloc+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-87, wval, 19, oa->dloc+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "dRot", xco, yco-106, 45, 19, NULL, 0, 0, 0, 0, "Sets the dRot");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-106, wval, 19, oa->drot, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-106, wval, 19, oa->drot+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-106, wval, 19, oa->drot+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "linV", xco, yco-129, 45, 19, NULL, 0, 0, 0, 0, "Sets the linear velocity");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-129, wval, 19, oa->linearvelocity, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-129, wval, 19, oa->linearvelocity+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-129, wval, 19, oa->linearvelocity+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "angV", xco, yco-148, 45, 19, NULL, 0, 0, 0, 0, "Sets the angular velocity");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-148, wval, 19, oa->angularvelocity, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-148, wval, 19, oa->angularvelocity+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-148, wval, 19, oa->angularvelocity+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "damp", xco, yco-171, 45, 19, NULL, 0, 0, 0, 0, "Number of frames to reach the target velocity");
+ uiDefButI(block, NUM, 0, "", xco+45, yco-171, wval, 19, &oa->damping, 0.0, 1000.0, 100, 0, "");
+
+ uiDefButBitS(block, TOG, ACT_FORCE_LOCAL, 0, "L", xco+45+3*wval, yco-45, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitS(block, TOG, ACT_TORQUE_LOCAL, 0, "L", xco+45+3*wval, yco-64, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitS(block, TOG, ACT_DLOC_LOCAL, 0, "L", xco+45+3*wval, yco-87, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitS(block, TOG, ACT_DROT_LOCAL, 0, "L", xco+45+3*wval, yco-106, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitS(block, TOG, ACT_LIN_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-129, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitS(block, TOG, ACT_ANG_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-148, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+
+ uiDefButBitS(block, TOG, ACT_ADD_LIN_VEL, 0, "add",xco+45+3*wval+15, yco-129, 35, 19, &oa->flag, 0.0, 0.0, 0, 0, "Toggles between ADD and SET linV");
+
+ } else if (oa->type == ACT_OBJECT_SERVO)
+ {
+ ysize= 172;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefBut(block, LABEL, 0, "linV", xco, yco-45, 45, 19, NULL, 0, 0, 0, 0, "Sets the target linear velocity, it will be achieve by automatic application of force. Null velocity is a valid target");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-45, wval, 19, oa->linearvelocity, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-45, wval, 19, oa->linearvelocity+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-45, wval, 19, oa->linearvelocity+2, -10000.0, 10000.0, 10, 0, "");
+ uiDefButBitS(block, TOG, ACT_LIN_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-45, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Velocity is defined in local coordinates");
+
+ uiDefBut(block, LABEL, 0, "Limit", xco, yco-68, 45, 19, NULL, 0, 0, 0, 0, "Select if the force need to be limited along certain axis (local or global depending on LinV Local flag)");
+ uiDefButBitS(block, TOG, ACT_SERVO_LIMIT_X, B_REDR, "X", xco+45, yco-68, wval, 19, &oa->flag, 0.0, 0.0, 0, 0, "Set limit to force along the X axis");
+ uiDefButBitS(block, TOG, ACT_SERVO_LIMIT_Y, B_REDR, "Y", xco+45+wval, yco-68, wval, 19, &oa->flag, 0.0, 0.0, 0, 0, "Set limit to force along the Y axis");
+ uiDefButBitS(block, TOG, ACT_SERVO_LIMIT_Z, B_REDR, "Z", xco+45+2*wval, yco-68, wval, 19, &oa->flag, 0.0, 0.0, 0, 0, "Set limit to force along the Z axis");
+ uiDefBut(block, LABEL, 0, "Max", xco, yco-87, 45, 19, NULL, 0, 0, 0, 0, "Set the upper limit for force");
+ uiDefBut(block, LABEL, 0, "Min", xco, yco-106, 45, 19, NULL, 0, 0, 0, 0, "Set the lower limit for force");
+ if (oa->flag & ACT_SERVO_LIMIT_X) {
+ uiDefButF(block, NUM, 0, "", xco+45, yco-87, wval, 19, oa->dloc, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-106, wval, 19, oa->drot, -10000.0, 10000.0, 10, 0, "");
+ }
+ if (oa->flag & ACT_SERVO_LIMIT_Y) {
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-87, wval, 19, oa->dloc+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-106, wval, 19, oa->drot+1, -10000.0, 10000.0, 10, 0, "");
+ }
+ if (oa->flag & ACT_SERVO_LIMIT_Z) {
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-87, wval, 19, oa->dloc+2, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-106, wval, 19, oa->drot+2, -10000.0, 10000.0, 10, 0, "");
+ }
+ uiDefBut(block, LABEL, 0, "Servo", xco, yco-129, 45, 19, NULL, 0, 0, 0, 0, "Coefficients of the PID servo controller");
+ uiDefButF(block, NUMSLI, B_REDR, "P: ", xco+45, yco-129, wval*3, 19, oa->forcerot, 0.00, 200.0, 100, 0, "Proportional coefficient, typical value is 60x Integral coefficient");
+ uiDefBut(block, LABEL, 0, "Slow", xco, yco-148, 45, 19, NULL, 0, 0, 0, 0, "Low value of I coefficient correspond to slow response");
+ but = uiDefButF(block, NUMSLI, B_REDR, " I : ", xco+45, yco-148, wval*3, 19, oa->forcerot+1, 0.0, 3.0, 1, 0, "Integral coefficient, low value (0.01) for slow response, high value (0.5) for fast response");
+ uiButSetFunc(but, update_object_actuator_PID, oa, NULL);
+ uiDefBut(block, LABEL, 0, "Fast", xco+45+3*wval, yco-148, 45, 19, NULL, 0, 0, 0, 0, "High value of I coefficient correspond to fast response");
+ uiDefButF(block, NUMSLI, B_REDR, "D: ", xco+45, yco-167, wval*3, 19, oa->forcerot+2, -100.0, 100.0, 100, 0, "Derivate coefficient, not required, high values can cause instability");
+ }
+ str= "Motion Type %t|Simple motion %x0|Servo Control %x1";
+ but = uiDefButS(block, MENU, B_REDR, str, xco+40, yco-23, (width-80), 19, &oa->type, 0.0, 0.0, 0, 0, "");
+ oa->otype = oa->type;
+ uiButSetFunc(but, change_object_actuator, oa, NULL);
yco-= ysize;
break;
}
@@ -1930,34 +2025,97 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
break;
case ACT_CONSTRAINT:
+ coa= act->data;
- ysize= 44;
+ if (coa->type == ACT_CONST_TYPE_LOC) {
+ ysize= 69;
- glRects(xco, yco-ysize, xco+width, yco);
- uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ /* str= "Limit %t|None %x0|Loc X %x1|Loc Y %x2|Loc Z %x4|Rot X %x8|Rot Y %x16|Rot Z %x32"; */
+ /* coa->flag &= ~(63); */
+ str= "Limit %t|None %x0|Loc X %x1|Loc Y %x2|Loc Z %x4";
+ coa->flag &= ~(7);
+ coa->time = 0;
+ uiDefButS(block, MENU, 1, str, xco+10, yco-65, 70, 19, &coa->flag, 0.0, 0.0, 0, 0, "");
- coa= act->data;
+ uiDefButS(block, NUM, 0, "Damp:", xco+10, yco-45, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Min", xco+80, yco-45, (width-90)/2, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Max", xco+80+(width-90)/2, yco-45, (width-90)/2, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(coa->flag & ACT_CONST_LOCX) fp= coa->minloc;
+ else if(coa->flag & ACT_CONST_LOCY) fp= coa->minloc+1;
+ else if(coa->flag & ACT_CONST_LOCZ) fp= coa->minloc+2;
+ else if(coa->flag & ACT_CONST_ROTX) fp= coa->minrot;
+ else if(coa->flag & ACT_CONST_ROTY) fp= coa->minrot+1;
+ else fp= coa->minrot+2;
+
+ uiDefButF(block, NUM, 0, "", xco+80, yco-65, (width-90)/2, 19, fp, -2000.0, 2000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+80+(width-90)/2, yco-65, (width-90)/2, 19, fp+3, -2000.0, 2000.0, 10, 0, "");
+ } else if (coa->type == ACT_CONST_TYPE_DIST) {
+ 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");
-/* str= "Limit %t|None %x0|Loc X %x1|Loc Y %x2|Loc Z %x4|Rot X %x8|Rot Y %x16|Rot Z %x32"; */
- str= "Limit %t|None %x0|Loc X %x1|Loc Y %x2|Loc Z %x4";
- uiDefButS(block, MENU, 1, str, xco+10, yco-40, 70, 19, &coa->flag, 0.0, 0.0, 0, 0, "");
-
- uiDefButS(block, NUM, 0, "Damp:", xco+10, yco-20, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "");
- uiDefBut(block, LABEL, 0, "Min", xco+80, yco-20, (width-90)/2, 19, NULL, 0.0, 0.0, 0, 0, "");
- uiDefBut(block, LABEL, 0, "Max", xco+80+(width-90)/2, yco-20, (width-90)/2, 19, NULL, 0.0, 0.0, 0, 0, "");
-
- if(coa->flag & ACT_CONST_LOCX) fp= coa->minloc;
- else if(coa->flag & ACT_CONST_LOCY) fp= coa->minloc+1;
- else if(coa->flag & ACT_CONST_LOCZ) fp= coa->minloc+2;
- else if(coa->flag & ACT_CONST_ROTX) fp= coa->minrot;
- else if(coa->flag & ACT_CONST_ROTY) fp= coa->minrot+1;
- else fp= coa->minrot+2;
+ uiDefButS(block, NUM, 0, "Damp:", xco+10, yco-45, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Range", xco+80, yco-45, (width-115)/2, 19, NULL, 0.0, 0.0, 0, 0, "Set the maximum length of ray");
+ uiDefButBitS(block, TOG, ACT_CONST_DISTANCE, B_REDR, "Dist", xco+80+(width-115)/2, yco-45, (width-115)/2, 19, &coa->flag, 0.0, 0.0, 0, 0, "Force distance of object to point of impact of ray");
+
+ if(coa->mode & (ACT_CONST_DIRPX|ACT_CONST_DIRMX)) fp= coa->minloc;
+ else if(coa->mode & (ACT_CONST_DIRPY|ACT_CONST_DIRMY)) fp= coa->minloc+1;
+ else fp= coa->minloc+2;
+
+ uiDefButF(block, NUM, 0, "", xco+80, yco-65, (width-115)/2, 19, fp+3, 0.0, 2000.0, 10, 0, "Maximum length of ray");
+ if (coa->flag & ACT_CONST_DISTANCE)
+ uiDefButF(block, NUM, 0, "", xco+80+(width-115)/2, yco-65, (width-115)/2, 19, fp, -2000.0, 2000.0, 10, 0, "Keep this distance to target");
+ uiDefButBitS(block, TOG, ACT_CONST_NORMAL, 0, "N", xco+80+(width-115), yco-65, 25, 19,
+ &coa->flag, 0.0, 0.0, 0, 0, "Set object axis along the normal at hit position");
+ 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, (width-60)/2, 19, &(coa->time), 0.0, 1000.0, 0, 0, "Maximum activation time in frame, 0 for unlimited");
+ uiDefButS(block, NUM, 0, "rotDamp", xco+50+(width-60)/2, yco-103, (width-60)/2, 19, &(coa->rotdamp), 0.0, 100.0, 0, 0, "Use a different damping for orientation");
+ } else if (coa->type == ACT_CONST_TYPE_ORI) {
+ ysize= 87;
+
+ 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";
+ uiDefButS(block, MENU, B_REDR, str, xco+10, yco-65, 70, 19, &coa->mode, 0.0, 0.0, 0, 0, "Select the axis to be aligned along the reference direction");
- uiDefButF(block, NUM, 0, "", xco+80, yco-40, (width-90)/2, 19, fp, -2000.0, 2000.0, 10, 0, "");
- uiDefButF(block, NUM, 0, "", xco+80+(width-90)/2, yco-40, (width-90)/2, 19, fp+3, -2000.0, 2000.0, 10, 0, "");
+ uiDefButS(block, NUM, 0, "Damp:", xco+10, yco-45, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "X", xco+80, yco-45, (width-115)/3, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Y", xco+80+(width-115)/3, yco-45, (width-115)/3, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Z", xco+80+2*(width-115)/3, yco-45, (width-115)/3, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefButF(block, NUM, 0, "", xco+80, yco-65, (width-115)/3, 19, &coa->maxrot[0], -2000.0, 2000.0, 10, 0, "X component of reference direction");
+ uiDefButF(block, NUM, 0, "", xco+80+(width-115)/3, yco-65, (width-115)/3, 19, &coa->maxrot[1], -2000.0, 2000.0, 10, 0, "Y component of reference direction");
+ uiDefButF(block, NUM, 0, "", xco+80+2*(width-115)/3, yco-65, (width-115)/3, 19, &coa->maxrot[2], -2000.0, 2000.0, 10, 0, "Z component of reference direction");
+ uiDefButS(block, NUM, 0, "time", xco+10, yco-84, 70+(width-115)/3, 19, &(coa->time), 0.0, 1000.0, 0, 0, "Maximum activation time in frame, 0 for unlimited");
+ }
+ str= "Constraint Type %t|Location %x0|Distance %x1|Orientation %x2";
+ 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;
case ACT_SCENE:
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
index ea26c55a44e..6e05ea31fe8 100644
--- a/source/gameengine/Converter/KX_ConvertActuators.cpp
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -159,7 +159,7 @@ void BL_ConvertActuators(char* maggiename,
bitLocalFlag.DRot = bool((obact->flag & ACT_DROT_LOCAL)!=0);
bitLocalFlag.LinearVelocity = bool((obact->flag & ACT_LIN_VEL_LOCAL)!=0);
bitLocalFlag.AngularVelocity = bool((obact->flag & ACT_ANG_VEL_LOCAL)!=0);
- bitLocalFlag.ClampVelocity = bool((obact->flag & ACT_CLAMP_VEL)!=0);
+ bitLocalFlag.ServoControl = bool(obact->type == ACT_OBJECT_SERVO);
bitLocalFlag.AddOrSetLinV = bool((obact->flag & ACT_ADD_LIN_VEL)!=0);
@@ -619,51 +619,105 @@ void BL_ConvertActuators(char* maggiename,
case ACT_CONSTRAINT:
{
float min = 0.0, max = 0.0;
+ char *prop = NULL;
KX_ConstraintActuator::KX_CONSTRAINTTYPE locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF;
bConstraintActuator *conact
= (bConstraintActuator*) bact->data;
/* convert settings... degrees in the ui become radians */
/* internally */
- switch (conact->flag) {
- case ACT_CONST_LOCX:
- locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCX;
- min = conact->minloc[0];
- max = conact->maxloc[0];
- break;
- case ACT_CONST_LOCY:
- locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCY;
- min = conact->minloc[1];
- max = conact->maxloc[1];
- break;
- case ACT_CONST_LOCZ:
- locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCZ;
- min = conact->minloc[2];
- max = conact->maxloc[2];
- break;
- case ACT_CONST_ROTX:
- locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX;
- min = MT_2_PI * conact->minrot[0] / 360.0;
- max = MT_2_PI * conact->maxrot[0] / 360.0;
- break;
- case ACT_CONST_ROTY:
- locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY;
- min = MT_2_PI * conact->minrot[1] / 360.0;
- max = MT_2_PI * conact->maxrot[1] / 360.0;
- break;
- case ACT_CONST_ROTZ:
- locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ;
- min = MT_2_PI * conact->minrot[2] / 360.0;
- max = MT_2_PI * conact->maxrot[2] / 360.0;
- break;
- default:
- ; /* error */
+ if (conact->type == ACT_CONST_TYPE_ORI) {
+ switch (conact->mode) {
+ case ACT_CONST_DIRPX:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIX;
+ break;
+ case ACT_CONST_DIRPY:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIY;
+ break;
+ case ACT_CONST_DIRPZ:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIZ;
+ break;
+ }
+ } else if (conact->type == ACT_CONST_TYPE_DIST) {
+ switch (conact->mode) {
+ case ACT_CONST_DIRPX:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPX;
+ min = conact->minloc[0];
+ max = conact->maxloc[0];
+ break;
+ case ACT_CONST_DIRPY:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPY;
+ min = conact->minloc[1];
+ max = conact->maxloc[1];
+ break;
+ case ACT_CONST_DIRPZ:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPZ;
+ min = conact->minloc[2];
+ max = conact->maxloc[2];
+ break;
+ case ACT_CONST_DIRMX:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRMX;
+ min = conact->minloc[0];
+ max = conact->maxloc[0];
+ break;
+ case ACT_CONST_DIRMY:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRMY;
+ min = conact->minloc[1];
+ max = conact->maxloc[1];
+ break;
+ case ACT_CONST_DIRMZ:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRMZ;
+ min = conact->minloc[2];
+ max = conact->maxloc[2];
+ break;
+ }
+ prop = conact->matprop;
+ } else {
+ switch (conact->flag) {
+ case ACT_CONST_LOCX:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCX;
+ min = conact->minloc[0];
+ max = conact->maxloc[0];
+ break;
+ case ACT_CONST_LOCY:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCY;
+ min = conact->minloc[1];
+ max = conact->maxloc[1];
+ break;
+ case ACT_CONST_LOCZ:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCZ;
+ min = conact->minloc[2];
+ max = conact->maxloc[2];
+ break;
+ case ACT_CONST_ROTX:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX;
+ min = MT_2_PI * conact->minrot[0] / 360.0;
+ max = MT_2_PI * conact->maxrot[0] / 360.0;
+ break;
+ case ACT_CONST_ROTY:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY;
+ min = MT_2_PI * conact->minrot[1] / 360.0;
+ max = MT_2_PI * conact->maxrot[1] / 360.0;
+ break;
+ case ACT_CONST_ROTZ:
+ locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ;
+ min = MT_2_PI * conact->minrot[2] / 360.0;
+ max = MT_2_PI * conact->maxrot[2] / 360.0;
+ break;
+ default:
+ ; /* error */
+ }
}
KX_ConstraintActuator *tmpconact
= new KX_ConstraintActuator(gameobj,
- conact->damp,
- min,
- max,
- locrot);
+ conact->damp,
+ conact->rotdamp,
+ min,
+ max,
+ conact->maxrot,
+ locrot,
+ conact->time,
+ conact->flag,
+ prop);
baseact = tmpconact;
break;
}
diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp
index e7e4eeae7d2..7c9df688d45 100644
--- a/source/gameengine/Converter/KX_ConvertSensors.cpp
+++ b/source/gameengine/Converter/KX_ConvertSensors.cpp
@@ -64,6 +64,7 @@ probably misplaced */
#include "KX_MouseFocusSensor.h"
#include "SCA_JoystickSensor.h"
#include "KX_NetworkMessageSensor.h"
+#include "SCA_ActuatorSensor.h"
#include "SCA_PropertySensor.h"
@@ -538,6 +539,19 @@ void BL_ConvertSensors(struct Object* blenderobject,
break;
}
+ case SENS_ACTUATOR:
+ {
+ bActuatorSensor* blenderactsensor = (bActuatorSensor*) sens->data;
+ // we will reuse the property event manager, there is nothing special with this sensor
+ SCA_EventManager* eventmgr
+ = logicmgr->FindEventManager(SCA_EventManager::ACTUATOR_EVENTMGR);
+ if (eventmgr)
+ {
+ STR_String propname=blenderactsensor->name;
+ gamesensor = new SCA_ActuatorSensor(eventmgr,gameobj,propname);
+ }
+ break;
+ }
case SENS_RADAR:
{
diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp
new file mode 100644
index 00000000000..28ca1fd673f
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp
@@ -0,0 +1,76 @@
+/**
+ * $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.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "SCA_ISensor.h"
+#include "SCA_ActuatorEventManager.h"
+#include "SCA_ActuatorSensor.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+SCA_ActuatorEventManager::SCA_ActuatorEventManager(class SCA_LogicManager* logicmgr)
+ : SCA_EventManager(ACTUATOR_EVENTMGR),
+ m_logicmgr(logicmgr)
+{
+}
+
+
+
+SCA_ActuatorEventManager::~SCA_ActuatorEventManager()
+{
+
+}
+
+
+
+void SCA_ActuatorEventManager::RegisterSensor(SCA_ISensor* sensor)
+{
+ m_sensors.push_back(sensor);
+}
+
+
+
+void SCA_ActuatorEventManager::NextFrame()
+{
+ // check for changed actuator
+ for (vector<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++)
+ {
+ (*it)->Activate(m_logicmgr,NULL);
+ }
+}
+
+void SCA_ActuatorEventManager::UpdateFrame()
+{
+ // update the state of actuator before executing them
+ for (vector<SCA_ISensor*>::const_iterator it = m_sensors.begin();!(it==m_sensors.end());it++)
+ {
+ ((SCA_ActuatorSensor*)(*it))->Update();
+ }
+} \ No newline at end of file
diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h
new file mode 100644
index 00000000000..b5108764197
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h
@@ -0,0 +1,52 @@
+/**
+ * $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.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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_ACTUATOREVENTMANAGER
+#define __KX_ACTUATOREVENTMANAGER
+
+#include "SCA_EventManager.h"
+
+#include <vector>
+
+using namespace std;
+
+class SCA_ActuatorEventManager : public SCA_EventManager
+{
+ class SCA_LogicManager* m_logicmgr;
+
+public:
+ SCA_ActuatorEventManager(class SCA_LogicManager* logicmgr);
+ virtual ~SCA_ActuatorEventManager();
+ virtual void NextFrame();
+ virtual void UpdateFrame();
+ virtual void RegisterSensor(SCA_ISensor* sensor);
+ //SCA_LogicManager* GetLogicManager() { return m_logicmgr;}
+};
+
+#endif //__KX_ACTUATOREVENTMANAGER
+
diff --git a/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp
new file mode 100644
index 00000000000..9645bfbed4a
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp
@@ -0,0 +1,196 @@
+/**
+ * Actuator sensor
+ *
+ * $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.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 <iostream>
+#include "SCA_ActuatorSensor.h"
+#include "SCA_EventManager.h"
+#include "SCA_LogicManager.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+SCA_ActuatorSensor::SCA_ActuatorSensor(SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const STR_String& actname,
+ PyTypeObject* T )
+ : SCA_ISensor(gameobj,eventmgr,T),
+ m_checkactname(actname)
+{
+ m_actuator = GetParent()->FindActuator(m_checkactname);
+ Init();
+}
+
+void SCA_ActuatorSensor::Init()
+{
+ m_lastresult = m_invert?true:false;
+ m_midresult = m_lastresult;
+ m_reset = true;
+}
+
+CValue* SCA_ActuatorSensor::GetReplica()
+{
+ SCA_ActuatorSensor* replica = new SCA_ActuatorSensor(*this);
+ // m_range_expr must be recalculated on replica!
+ CValue::AddDataToReplica(replica);
+ replica->Init();
+
+ return replica;
+}
+
+void SCA_ActuatorSensor::ReParent(SCA_IObject* parent)
+{
+ m_actuator = parent->FindActuator(m_checkactname);
+ SCA_ISensor::ReParent(parent);
+}
+
+bool SCA_ActuatorSensor::IsPositiveTrigger()
+{
+ bool result = m_lastresult;
+ if (m_invert)
+ result = !result;
+
+ return result;
+}
+
+
+
+SCA_ActuatorSensor::~SCA_ActuatorSensor()
+{
+}
+
+
+
+bool SCA_ActuatorSensor::Evaluate(CValue* event)
+{
+ if (m_actuator)
+ {
+ bool result = m_actuator->IsActive();
+ bool reset = m_reset && m_level;
+
+ m_reset = false;
+ if (m_lastresult != result || m_midresult != result)
+ {
+ m_lastresult = m_midresult = result;
+ return true;
+ }
+ return (reset) ? true : false;
+ }
+ return false;
+}
+
+void SCA_ActuatorSensor::Update()
+{
+ if (m_actuator)
+ {
+ m_midresult = m_actuator->IsActive();
+ }
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject SCA_ActuatorSensor::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "SCA_ActuatorSensor",
+ sizeof(SCA_ActuatorSensor),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+PyParentObject SCA_ActuatorSensor::Parents[] = {
+ &SCA_ActuatorSensor::Type,
+ &SCA_ISensor::Type,
+ &SCA_ILogicBrick::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyMethodDef SCA_ActuatorSensor::Methods[] = {
+ {"getActuator", (PyCFunction) SCA_ActuatorSensor::sPyGetActuator, METH_VARARGS, GetActuator_doc},
+ {"setActuator", (PyCFunction) SCA_ActuatorSensor::sPySetActuator, METH_VARARGS, SetActuator_doc},
+ {NULL,NULL} //Sentinel
+};
+
+PyObject* SCA_ActuatorSensor::_getattr(const STR_String& attr) {
+ _getattr_up(SCA_ISensor); /* implicit return! */
+}
+
+/* 3. getActuator */
+char SCA_ActuatorSensor::GetActuator_doc[] =
+"getActuator()\n"
+"\tReturn the Actuator with which the sensor operates.\n";
+PyObject* SCA_ActuatorSensor::PyGetActuator(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ return PyString_FromString(m_checkactname);
+}
+
+/* 4. setActuator */
+char SCA_ActuatorSensor::SetActuator_doc[] =
+"setActuator(name)\n"
+"\t- name: string\n"
+"\tSets the Actuator with which to operate. If there is no Actuator\n"
+"\tof this name, the call is ignored.\n";
+PyObject* SCA_ActuatorSensor::PySetActuator(PyObject* self, PyObject* args, PyObject* kwds)
+{
+ /* We should query whether the name exists. Or should we create a prop */
+ /* on the fly? */
+ char *actNameArg = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &actNameArg)) {
+ return NULL;
+ }
+
+ SCA_IActuator* act = GetParent()->FindActuator(STR_String(actNameArg));
+ if (act) {
+ m_checkactname = actNameArg;
+ m_actuator = act;
+ } else {
+ ; /* error: bad actuator name */
+ }
+ Py_Return;
+}
+
+/* eof */
diff --git a/source/gameengine/GameLogic/SCA_ActuatorSensor.h b/source/gameengine/GameLogic/SCA_ActuatorSensor.h
new file mode 100644
index 00000000000..6086c5bfce0
--- /dev/null
+++ b/source/gameengine/GameLogic/SCA_ActuatorSensor.h
@@ -0,0 +1,74 @@
+/**
+ * Actuator sensor
+ *
+ * $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.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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_ACTUATORSENSOR
+#define __KX_ACTUATORSENSOR
+
+#include "SCA_ISensor.h"
+#include "SCA_IActuator.h"
+
+class SCA_ActuatorSensor : public SCA_ISensor
+{
+ Py_Header;
+ STR_String m_checkactname;
+ bool m_lastresult;
+ bool m_midresult;
+ protected:
+ SCA_IActuator* m_actuator;
+public:
+ SCA_ActuatorSensor(class SCA_EventManager* eventmgr,
+ SCA_IObject* gameobj,
+ const STR_String& actname,
+ PyTypeObject* T=&Type );
+
+ virtual ~SCA_ActuatorSensor();
+ virtual CValue* GetReplica();
+ virtual void Init();
+ virtual bool Evaluate(CValue* event);
+ virtual bool IsPositiveTrigger();
+ virtual void ReParent(SCA_IObject* parent);
+ void Update();
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ virtual PyObject* _getattr(const STR_String& attr);
+
+ /* 3. setProperty */
+ KX_PYMETHOD_DOC(SCA_ActuatorSensor,SetActuator);
+ /* 4. getProperty */
+ KX_PYMETHOD_DOC(SCA_ActuatorSensor,GetActuator);
+
+};
+
+#endif
+
diff --git a/source/gameengine/GameLogic/SCA_EventManager.cpp b/source/gameengine/GameLogic/SCA_EventManager.cpp
index 1ca88182ddc..0169864a133 100644
--- a/source/gameengine/GameLogic/SCA_EventManager.cpp
+++ b/source/gameengine/GameLogic/SCA_EventManager.cpp
@@ -72,7 +72,9 @@ void SCA_EventManager::EndFrame()
{
}
-
+void SCA_EventManager::UpdateFrame()
+{
+}
int SCA_EventManager::GetType()
{
diff --git a/source/gameengine/GameLogic/SCA_EventManager.h b/source/gameengine/GameLogic/SCA_EventManager.h
index 89731497f6f..9cc1718cd1e 100644
--- a/source/gameengine/GameLogic/SCA_EventManager.h
+++ b/source/gameengine/GameLogic/SCA_EventManager.h
@@ -49,7 +49,8 @@ public:
RAY_EVENTMGR,
RADAR_EVENTMGR,
NETWORK_EVENTMGR,
- JOY_EVENTMGR
+ JOY_EVENTMGR,
+ ACTUATOR_EVENTMGR
};
SCA_EventManager(EVENT_MANAGER_TYPE mgrtype);
@@ -58,6 +59,7 @@ public:
virtual void RemoveSensor(class SCA_ISensor* sensor);
virtual void NextFrame(double curtime, double fixedtime);
virtual void NextFrame();
+ virtual void UpdateFrame();
virtual void EndFrame();
virtual void RegisterSensor(class SCA_ISensor* sensor)=0;
int GetType();
diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp
index 826e7bbdf0e..27e7d5faada 100644
--- a/source/gameengine/GameLogic/SCA_IObject.cpp
+++ b/source/gameengine/GameLogic/SCA_IObject.cpp
@@ -157,15 +157,15 @@ bool SCA_IObject::GetIgnoreActivityCulling()
void SCA_IObject::ReParentLogic()
{
- SCA_SensorList& oldsensors = GetSensors();
-
- int sen = 0;
- SCA_SensorList::iterator its;
- for (its = oldsensors.begin(); !(its==oldsensors.end()); ++its)
+ SCA_ActuatorList& oldactuators = GetActuators();
+ int act = 0;
+ SCA_ActuatorList::iterator ita;
+ for (ita = oldactuators.begin(); !(ita==oldactuators.end()); ++ita)
{
- SCA_ISensor* newsensor = (SCA_ISensor*)(*its)->GetReplica();
- newsensor->ReParent(this);
- oldsensors[sen++] = newsensor;
+ SCA_IActuator* newactuator = (SCA_IActuator*) (*ita)->GetReplica();
+ newactuator->ReParent(this);
+ newactuator->SetActive(false);
+ oldactuators[act++] = newactuator;
}
SCA_ControllerList& oldcontrollers = GetControllers();
@@ -178,17 +178,17 @@ void SCA_IObject::ReParentLogic()
oldcontrollers[con++]=newcontroller;
}
- SCA_ActuatorList& oldactuators = GetActuators();
-
- int act = 0;
- SCA_ActuatorList::iterator ita;
- for (ita = oldactuators.begin(); !(ita==oldactuators.end()); ++ita)
+ // convert sensors last so that actuators are already available for Actuator sensor
+ SCA_SensorList& oldsensors = GetSensors();
+ int sen = 0;
+ SCA_SensorList::iterator its;
+ for (its = oldsensors.begin(); !(its==oldsensors.end()); ++its)
{
- SCA_IActuator* newactuator = (SCA_IActuator*) (*ita)->GetReplica();
- newactuator->ReParent(this);
- newactuator->SetActive(false);
- oldactuators[act++] = newactuator;
+ SCA_ISensor* newsensor = (SCA_ISensor*)(*its)->GetReplica();
+ newsensor->ReParent(this);
+ oldsensors[sen++] = newsensor;
}
+
// a new object cannot be client of any actuator
m_registeredActuators.clear();
diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp
index 1b163deb7bb..68341b57435 100644
--- a/source/gameengine/GameLogic/SCA_ISensor.cpp
+++ b/source/gameengine/GameLogic/SCA_ISensor.cpp
@@ -56,6 +56,7 @@ SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
m_suspended = false;
m_invert = false;
m_level = false;
+ m_reset = false;
m_pos_ticks = 0;
m_neg_ticks = 0;
m_pos_pulsemode = false;
diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h
index 3527b87ebdb..f2ed6a803c2 100644
--- a/source/gameengine/GameLogic/SCA_ISensor.h
+++ b/source/gameengine/GameLogic/SCA_ISensor.h
@@ -64,6 +64,9 @@ class SCA_ISensor : public SCA_ILogicBrick
/** detect level instead of edge*/
bool m_level;
+ /** sensor has been reset */
+ bool m_reset;
+
/** Sensor must ignore updates? */
bool m_suspended;
diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
index 8668c22f044..3fb439eb25b 100644
--- a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
@@ -70,6 +70,7 @@ std::cout << " hat flag " << m_hatf << std::endl;
void SCA_JoystickSensor::Init()
{
m_istrig=(m_invert)?1:0;
+ m_reset = true;
}
SCA_JoystickSensor::~SCA_JoystickSensor()
@@ -79,9 +80,10 @@ SCA_JoystickSensor::~SCA_JoystickSensor()
CValue* SCA_JoystickSensor::GetReplica()
{
- CValue* replica = new SCA_JoystickSensor(*this);
+ SCA_JoystickSensor* replica = new SCA_JoystickSensor(*this);
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
+ replica->Init();
return replica;
}
@@ -99,7 +101,9 @@ bool SCA_JoystickSensor::Evaluate(CValue* event)
{
SCA_Joystick *js = m_pJoystickMgr->GetJoystickDevice();
bool result = false;
+ bool reset = m_reset && m_level;
+ m_reset = false;
switch(m_joymode)
{
case KX_JOYSENSORMODE_AXIS:
@@ -240,6 +244,8 @@ bool SCA_JoystickSensor::Evaluate(CValue* event)
if(!js->IsTrig()){
m_istrig = 0;
}
+ if (reset)
+ result = true;
return result;
}
diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
index 43ce25f94df..a7a6fa93db4 100644
--- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
@@ -78,14 +78,15 @@ void SCA_KeyboardSensor::Init()
// However, if the target key is pressed when the sensor is reactivated, it
// will not generated an event (see remark in Evaluate()).
m_val = (m_invert)?1:0;
+ m_reset = true;
}
CValue* SCA_KeyboardSensor::GetReplica()
{
- CValue* replica = new SCA_KeyboardSensor(*this);
+ SCA_KeyboardSensor* replica = new SCA_KeyboardSensor(*this);
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
-
+ replica->Init();
return replica;
}
@@ -120,8 +121,8 @@ bool SCA_KeyboardSensor::TriggerOnAllKeys()
bool SCA_KeyboardSensor::Evaluate(CValue* eventval)
{
bool result = false;
+ bool reset = m_reset && m_level;
SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
-
// cerr << "SCA_KeyboardSensor::Eval event, sensing for "<< m_hotkey << " at device " << inputdev << "\n";
/* See if we need to do logging: togPropState exists and is
@@ -134,7 +135,7 @@ bool SCA_KeyboardSensor::Evaluate(CValue* eventval)
LogKeystrokes();
}
-
+ m_reset = false;
/* Now see whether events must be bounced. */
if (m_bAllKeys)
@@ -176,8 +177,8 @@ bool SCA_KeyboardSensor::Evaluate(CValue* eventval)
{
if (m_val == 0)
{
+ m_val = 1;
if (m_level) {
- m_val = 1;
result = true;
}
}
@@ -229,9 +230,9 @@ bool SCA_KeyboardSensor::Evaluate(CValue* eventval)
{
if (m_val == 0)
{
+ m_val = 1;
if (m_level)
{
- m_val = 1;
result = true;
}
}
@@ -240,7 +241,9 @@ bool SCA_KeyboardSensor::Evaluate(CValue* eventval)
}
}
}
-
+ if (reset)
+ // force an event
+ result = true;
return result;
}
diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp
index fb1a2c29eb6..f50161cbecb 100644
--- a/source/gameengine/GameLogic/SCA_LogicManager.cpp
+++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp
@@ -271,6 +271,10 @@ void SCA_LogicManager::UpdateFrame(double curtime, bool frame)
}
m_removedActuators.clear();
+ // About to run actuators, but before update the sensors for those which depends on actuators
+ for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin(); !(ie==m_eventmanagers.end()); ie++)
+ (*ie)->UpdateFrame();
+
for (set<SmartActuatorPtr>::iterator ia = m_activeActuators.begin();!(ia==m_activeActuators.end());ia++)
{
//SCA_IActuator* actua = *ia;
diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.cpp b/source/gameengine/GameLogic/SCA_MouseSensor.cpp
index 42d35837489..2298ddb0743 100644
--- a/source/gameengine/GameLogic/SCA_MouseSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_MouseSensor.cpp
@@ -84,6 +84,7 @@ SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr,
void SCA_MouseSensor::Init()
{
m_val = (m_invert)?1:0; /* stores the latest attribute */
+ m_reset = true;
}
SCA_MouseSensor::~SCA_MouseSensor()
@@ -95,9 +96,10 @@ SCA_MouseSensor::~SCA_MouseSensor()
CValue* SCA_MouseSensor::GetReplica()
{
- CValue* replica = new SCA_MouseSensor(*this);
+ SCA_MouseSensor* replica = new SCA_MouseSensor(*this);
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
+ replica->Init();
return replica;
}
@@ -132,6 +134,7 @@ SCA_IInputDevice::KX_EnumInputs SCA_MouseSensor::GetHotKey()
bool SCA_MouseSensor::Evaluate(CValue* event)
{
bool result = false;
+ bool reset = m_reset && m_level;
SCA_IInputDevice* mousedev = m_pMouseMgr->GetInputDevice();
@@ -143,7 +146,7 @@ bool SCA_MouseSensor::Evaluate(CValue* event)
/* both MOUSEX and MOUSEY. Treat all of these as key-presses. */
/* So, treat KX_MOUSESENSORMODE_POSITION as */
/* KX_MOUSESENSORMODE_POSITIONX || KX_MOUSESENSORMODE_POSITIONY */
-
+ m_reset = false;
switch (m_mousemode) {
case KX_MOUSESENSORMODE_LEFTBUTTON:
case KX_MOUSESENSORMODE_MIDDLEBUTTON:
@@ -168,9 +171,9 @@ bool SCA_MouseSensor::Evaluate(CValue* event)
{
if (m_val == 0)
{
+ m_val = 1;
if (m_level)
{
- m_val = 1;
result = true;
}
}
@@ -222,6 +225,9 @@ bool SCA_MouseSensor::Evaluate(CValue* event)
; /* error */
}
+ if (reset)
+ // force an event
+ result = true;
return result;
}
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
index 655e9060238..c50c011cc63 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
@@ -78,6 +78,7 @@ void SCA_PropertySensor::Init()
{
m_recentresult = false;
m_lastresult = m_invert?true:false;
+ m_reset = true;
}
void SCA_PropertySensor::PrecalculateRangeExpression()
@@ -111,6 +112,7 @@ CValue* SCA_PropertySensor::GetReplica()
SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
// m_range_expr must be recalculated on replica!
CValue::AddDataToReplica(replica);
+ replica->Init();
replica->m_range_expr = NULL;
if (replica->m_checktype==KX_PROPSENSOR_INTERVAL)
@@ -153,14 +155,15 @@ SCA_PropertySensor::~SCA_PropertySensor()
bool SCA_PropertySensor::Evaluate(CValue* event)
{
bool result = CheckPropertyCondition();
+ bool reset = m_reset && m_level;
+ m_reset = false;
if (m_lastresult!=result)
{
m_lastresult = result;
return true;
}
-
- return false;
+ return (reset) ? true : false;
}
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
index bd843d97199..80288a72485 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,54 @@
/* ------------------------------------------------------------------------- */
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;
+ }
+ }
+ break;
+ default:
m_minimumBound = minBound;
m_maximumBound = maxBound;
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 +103,239 @@ 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, MT_Point3& hit_point, MT_Vector3& hit_normal, 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();
+ KX_GameObject* hitKXObj = client->m_gameobject;
- 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;
-
-// 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 */
+ if (client->m_type > KX_ClientObjectInfo::ACTOR)
+ {
+ // false hit
+ return false;
}
+ 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 = hitKXObj->GetProperty(m_property) != NULL;
+ }
+ }
- switch (m_locrot) {
- case KX_ACT_CONSTRAINT_LOCX:
- case KX_ACT_CONSTRAINT_LOCY:
- case KX_ACT_CONSTRAINT_LOCZ:
- parent->NodeSetLocalPosition(position);
- break;
+ return bFound;
+}
+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 direction;
+ MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
+ MT_Scalar filter, newdistance;
+ int axis, sign;
+
+ if (m_posDampTime) {
+ filter = m_posDampTime/(1.0+m_posDampTime);
+ }
+ 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;
+ case KX_ACT_CONSTRAINT_ORIZ:
+ direction[0] = rotation[0][2];
+ direction[1] = rotation[1][2];
+ direction[2] = rotation[2][2];
+ axis = 2;
+ break;
+ }
+ // apply damping on the direction
+ if (m_posDampTime) {
+ direction = filter*direction + (1.0-filter)*m_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_DIRMX:
+ case KX_ACT_CONSTRAINT_DIRMY:
+ case KX_ACT_CONSTRAINT_DIRMZ:
+ switch (m_locrot) {
+ case KX_ACT_CONSTRAINT_DIRPX:
+ direction[0] = rotation[0][0];
+ direction[1] = rotation[1][0];
+ direction[2] = rotation[2][0];
+ axis = 0; // axis according to KX_GameObject::AlignAxisToVect()
+ sign = 1; // X axis will be anti parrallel to normal
+ break;
+ case KX_ACT_CONSTRAINT_DIRPY:
+ direction[0] = rotation[0][1];
+ direction[1] = rotation[1][1];
+ direction[2] = rotation[2][1];
+ axis = 1;
+ sign = 1;
+ break;
+ case KX_ACT_CONSTRAINT_DIRPZ:
+ direction[0] = rotation[0][2];
+ direction[1] = rotation[1][2];
+ direction[2] = rotation[2][2];
+ axis = 2;
+ sign = 1;
+ break;
+ case KX_ACT_CONSTRAINT_DIRMX:
+ direction[0] = -rotation[0][0];
+ direction[1] = -rotation[1][0];
+ direction[2] = -rotation[2][0];
+ axis = 0;
+ sign = 0;
+ break;
+ case KX_ACT_CONSTRAINT_DIRMY:
+ direction[0] = -rotation[0][1];
+ direction[1] = -rotation[1][1];
+ direction[2] = -rotation[2][1];
+ axis = 1;
+ sign = 0;
+ break;
+ case KX_ACT_CONSTRAINT_DIRMZ:
+ direction[0] = -rotation[0][2];
+ direction[1] = -rotation[1][2];
+ direction[2] = -rotation[2][2];
+ axis = 2;
+ sign = 0;
+ break;
+ }
+ direction.normalize();
+ {
+ MT_Point3 topoint = position + (m_maximumBound) * direction;
+ MT_Point3 resultpoint;
+ MT_Vector3 resultnormal;
+ 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();
+ }
+ }
+ result = KX_RayCast::RayTest(spc, pe, position, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_ConstraintActuator>(this));
+
+ if (result) {
+ // 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) {
+ // the new orientation must be so that the axis is parallel to normal
+ if (sign)
+ resultnormal = -resultnormal;
+ // apply damping on the direction
+ if (m_rotDampTime) {
+ MT_Scalar rotFilter = 1.0/(1.0+m_rotDampTime);
+ resultnormal = (-m_rotDampTime*rotFilter)*direction + rotFilter*resultnormal;
+ } else if (m_posDampTime) {
+ resultnormal = -filter*direction + (1.0-filter)*resultnormal;
+ }
+ obj->AlignAxisToVect(resultnormal, axis);
+ direction = -resultnormal;
+ }
+ if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
+ if (m_posDampTime) {
+ newdistance = filter*(position-resultpoint).length()+(1.0-filter)*m_minimumBound;
+ } else {
+ newdistance = m_minimumBound;
+ }
+ } else {
+ newdistance = (position-resultpoint).length();
+ }
+ newposition = resultpoint-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_LOCX:
+ case KX_ACT_CONSTRAINT_LOCY:
+ case KX_ACT_CONSTRAINT_LOCZ:
+ newposition = position;
+ 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;
+ }
+ break;
+ }
+ 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) */
@@ -214,10 +396,24 @@ 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},
+ {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, SetRotDamp_doc},
+ {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_VARARGS, GetRotDamp_doc},
+ {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, SetDirection_doc},
+ {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_VARARGS, GetDirection_doc},
+ {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, SetOption_doc},
+ {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_VARARGS, GetOption_doc},
+ {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, SetTime_doc},
+ {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_VARARGS, GetTime_doc},
+ {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
+ {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
{"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc},
{"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetMin_doc},
+ {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetDistance_doc},
+ {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetDistance_doc},
{"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc},
{"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetMax_doc},
+ {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetRayLength_doc},
+ {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetRayLength_doc},
{"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc},
{"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_VARARGS, GetLimit_doc},
{NULL,NULL} //Sentinel
@@ -231,7 +427,7 @@ PyObject* KX_ConstraintActuator::_getattr(const STR_String& attr) {
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,21 +437,192 @@ 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"
-"\tReturns the damping time for application of the constraint.\n";
+"getDamp()\n"
+"\tReturns the damping parameter.\n";
PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self,
PyObject* args,
PyObject* kwds){
- return PyInt_FromLong(m_dampTime);
+ return PyInt_FromLong(m_posDampTime);
}
+/* 2. setRotDamp */
+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 */
+char KX_ConstraintActuator::GetRotDamp_doc[] =
+"getRotDamp()\n"
+"\tReturns the damping time for application of the constraint.\n";
+PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self,
+ PyObject* args,
+ PyObject* kwds){
+ return PyInt_FromLong(m_rotDampTime);
+}
+
+/* 2. setDirection */
+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 */
+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* args,
+ PyObject* kwds){
+ 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 */
+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 */
+char KX_ConstraintActuator::GetOption_doc[] =
+"getOption()\n"
+"\tReturns the option parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self,
+ PyObject* args,
+ PyObject* kwds){
+ return PyInt_FromLong(m_option);
+}
+
+/* 2. setTime */
+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) {
+ int t;
+ if(!PyArg_ParseTuple(args, "i", &t)) {
+ return NULL;
+ }
+
+ if (t < 0)
+ t = 0;
+ m_activeTime = t;
+
+ Py_Return;
+}
+/* 3. getTime */
+char KX_ConstraintActuator::GetTime_doc[] =
+"getTime()\n"
+"\tReturns the time parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self,
+ PyObject* args,
+ PyObject* kwds){
+ return PyInt_FromLong(m_activeTime);
+}
+
+/* 2. setProperty */
+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 */
+char KX_ConstraintActuator::GetProperty_doc[] =
+"getProperty()\n"
+"\tReturns the property parameter.\n";
+PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self,
+ PyObject* args,
+ PyObject* kwds){
+ return PyString_FromString(m_property);
+}
+
+/* 4. setDistance */
+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[] =
"setMin(lower_bound)\n"
@@ -271,9 +638,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,12 +646,14 @@ PyObject* KX_ConstraintActuator::PySetMin(PyObject* self,
case KX_ACT_CONSTRAINT_ROTZ:
m_minimumBound = MT_radians(minArg);
break;
- default:
- ; /* error */
}
Py_Return;
}
+/* 5. getDistance */
+char KX_ConstraintActuator::GetDistance_doc[] =
+"getDistance()\n"
+"\tReturns the distance parameter \n";
/* 5. getMin */
char KX_ConstraintActuator::GetMin_doc[] =
"getMin()\n"
@@ -298,6 +665,11 @@ PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self,
return PyFloat_FromDouble(m_minimumBound);
}
+/* 6. setRayLength */
+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[] =
"setMax(upper_bound)\n"
@@ -313,9 +685,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,12 +693,14 @@ PyObject* KX_ConstraintActuator::PySetMax(PyObject* self,
case KX_ACT_CONSTRAINT_ROTZ:
m_maximumBound = MT_radians(maxArg);
break;
- default:
- ; /* error */
}
Py_Return;
}
+/* 7. getRayLength */
+char KX_ConstraintActuator::GetRayLength_doc[] =
+"getRayLength()\n"
+"\tReturns the length of the ray\n";
/* 7. getMax */
char KX_ConstraintActuator::GetMax_doc[] =
"getMax()\n"
@@ -345,9 +717,19 @@ PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self,
/* 8. setLimit */
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,
@@ -363,7 +745,7 @@ PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self,
}
/* 9. getLimit */
char KX_ConstraintActuator::GetLimit_doc[] =
-"getLimit(type)\n"
+"getLimit()\n"
"\tReturns the type of constraint.\n";
PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self,
PyObject* args,
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h
index a21a5f30de6..5a1d4d23217 100644
--- a/source/gameengine/Ketsji/KX_ConstraintActuator.h
+++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h
@@ -34,19 +34,31 @@
#include "SCA_IActuator.h"
#include "MT_Scalar.h"
+#include "MT_Vector3.h"
+#include "KX_ClientObjectInfo.h"
class KX_ConstraintActuator : public SCA_IActuator
{
Py_Header;
protected:
// Damp time (int),
- int m_dampTime;
- // min (float),
+ int m_posDampTime;
+ int m_rotDampTime;
+ // min (float)
float m_minimumBound;
- // max (float),
+ // max (float)
float m_maximumBound;
+ // reference direction
+ MT_Vector3 m_refDirection;
// locrotxyz choice (pick one): only one choice allowed at a time!
int m_locrot;
+ // active time of actuator
+ int m_activeTime;
+ int m_currentTime;
+ // option
+ int m_option;
+ // property to check
+ char m_property[32];
/**
* Clamp <var> to <min>, <max>. Borders are included (in as far as
@@ -56,6 +68,7 @@ protected:
public:
+ // m_locrot
enum KX_CONSTRAINTTYPE {
KX_ACT_CONSTRAINT_NODEF = 0,
KX_ACT_CONSTRAINT_LOCX,
@@ -64,16 +77,37 @@ protected:
KX_ACT_CONSTRAINT_ROTX,
KX_ACT_CONSTRAINT_ROTY,
KX_ACT_CONSTRAINT_ROTZ,
+ KX_ACT_CONSTRAINT_DIRPX,
+ KX_ACT_CONSTRAINT_DIRPY,
+ KX_ACT_CONSTRAINT_DIRPZ,
+ KX_ACT_CONSTRAINT_DIRMX,
+ KX_ACT_CONSTRAINT_DIRMY,
+ KX_ACT_CONSTRAINT_DIRMZ,
+ KX_ACT_CONSTRAINT_ORIX,
+ KX_ACT_CONSTRAINT_ORIY,
+ KX_ACT_CONSTRAINT_ORIZ,
KX_ACT_CONSTRAINT_MAX
};
-
+ // match ACT_CONST_... values from BIF_interface.h
+ enum KX_CONSTRAINTOPT {
+ KX_ACT_CONSTRAINT_NORMAL = 64,
+ KX_ACT_CONSTRAINT_MATERIAL = 128,
+ KX_ACT_CONSTRAINT_PERMANENT = 256,
+ KX_ACT_CONSTRAINT_DISTANCE = 512
+ };
bool IsValidMode(KX_CONSTRAINTTYPE m);
+ bool RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data);
KX_ConstraintActuator(SCA_IObject* gameobj,
- int damptime,
+ int posDamptime,
+ int rotDampTime,
float min,
float max,
+ float refDir[3],
int locrot,
+ int time,
+ int option,
+ char *property,
PyTypeObject* T=&Type);
virtual ~KX_ConstraintActuator();
virtual CValue* GetReplica() {
@@ -94,13 +128,26 @@ protected:
KX_PYMETHOD_DOC(KX_ConstraintActuator,SetDamp);
KX_PYMETHOD_DOC(KX_ConstraintActuator,GetDamp);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetRotDamp);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,GetRotDamp);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetDirection);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,GetDirection);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetOption);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,GetOption);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetTime);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,GetTime);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,SetProperty);
+ KX_PYMETHOD_DOC(KX_ConstraintActuator,GetProperty);
KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMin);
KX_PYMETHOD_DOC(KX_ConstraintActuator,GetMin);
+ static char SetDistance_doc[];
+ static char GetDistance_doc[];
KX_PYMETHOD_DOC(KX_ConstraintActuator,SetMax);
KX_PYMETHOD_DOC(KX_ConstraintActuator,GetMax);
+ static char SetRayLength_doc[];
+ static char GetRayLength_doc[];
KX_PYMETHOD_DOC(KX_ConstraintActuator,SetLimit);
KX_PYMETHOD_DOC(KX_ConstraintActuator,GetLimit);
-
};
#endif //__KX_CONSTRAINTACTUATOR
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index c4925cb772c..d6d2254850a 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -644,6 +644,15 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis)
NodeSetLocalOrientation(orimat);
}
+MT_Scalar KX_GameObject::GetMass()
+{
+ if (m_pPhysicsController1)
+ {
+ return m_pPhysicsController1->GetMass();
+ }
+ return 0.0;
+}
+
MT_Vector3 KX_GameObject::GetLinearVelocity(bool local)
{
MT_Vector3 velocity(0.0,0.0,0.0), locvel;
@@ -735,6 +744,31 @@ void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale)
GetSGNode()->RelativeScale(scale);
}
+void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans)
+{
+ SG_Node* parent = m_pSGNode->GetSGParent();
+ if (parent != NULL)
+ {
+ // Make sure the objects have some scale
+ MT_Vector3 scale = parent->GetWorldScaling();
+ if (fabs(scale[0]) < FLT_EPSILON ||
+ fabs(scale[1]) < FLT_EPSILON ||
+ fabs(scale[2]) < FLT_EPSILON)
+ {
+ return;
+ }
+ scale[0] = 1.0/scale[0];
+ scale[1] = 1.0/scale[1];
+ scale[2] = 1.0/scale[2];
+ MT_Matrix3x3 invori = parent->GetWorldOrientation().inverse();
+ MT_Vector3 newpos = invori*(trans-parent->GetWorldPosition())*scale;
+ NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2]));
+ }
+ else
+ {
+ NodeSetLocalPosition(trans);
+ }
+}
void KX_GameObject::NodeUpdateGS(double time,bool bInitiator)
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index 31b56df5368..5e44a36515d 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -258,6 +258,12 @@ public:
bool local=false
);
+ /**
+ * Return the mass of the object
+ */
+ MT_Scalar
+ GetMass();
+
/**
* Return the angular velocity of the game object.
*/
@@ -332,6 +338,9 @@ public:
void NodeSetRelativeScale( const MT_Vector3& scale );
+ // adapt local position so that world position is set to desired position
+ void NodeSetWorldPosition(const MT_Point3& trans);
+
void
NodeUpdateGS(
double time,
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
index f89d32bbe66..db0bef8b7e1 100644
--- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
@@ -77,15 +77,17 @@ void KX_MouseFocusSensor::Init()
m_mouse_over_in_previous_frame = (m_invert)?true:false;
m_positive_event = false;
m_hitObject = 0;
+ m_reset = true;
}
bool KX_MouseFocusSensor::Evaluate(CValue* event)
{
bool result = false;
bool obHasFocus = false;
+ bool reset = m_reset && m_level;
// cout << "evaluate focus mouse sensor "<<endl;
-
+ m_reset = false;
if (m_focusmode) {
/* Focus behaviour required. Test mouse-on. The rest is
* equivalent to handling a key. */
@@ -102,6 +104,10 @@ bool KX_MouseFocusSensor::Evaluate(CValue* event)
result = true;
}
}
+ if (reset) {
+ // force an event
+ result = true;
+ }
} else {
/* No focus behaviour required: revert to the basic mode. This
* mode is never used, because the converter never makes this
diff --git a/source/gameengine/Ketsji/KX_NearSensor.cpp b/source/gameengine/Ketsji/KX_NearSensor.cpp
index 4086ac53f2a..d69871275b9 100644
--- a/source/gameengine/Ketsji/KX_NearSensor.cpp
+++ b/source/gameengine/Ketsji/KX_NearSensor.cpp
@@ -102,10 +102,7 @@ CValue* KX_NearSensor::GetReplica()
{
KX_NearSensor* replica = new KX_NearSensor(*this);
replica->m_colliders = new CListValue();
- replica->m_bCollision = false;
- replica->m_bTriggered= false;
- replica->m_hitObject = NULL;
- replica->m_bLastTriggered = false;
+ replica->Init();
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
index 03ae14997ab..9ac0b4d4703 100644
--- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
@@ -68,8 +68,15 @@ KX_ObjectActuator(
m_bitLocalFlag (flag),
m_active_combined_velocity (false),
m_linear_damping_active(false),
- m_angular_damping_active(false)
+ m_angular_damping_active(false),
+ m_error_accumulator(0.0,0.0,0.0),
+ m_previous_error(0.0,0.0,0.0)
{
+ if (m_bitLocalFlag.ServoControl)
+ {
+ // in servo motion, the force is local if the target velocity is local
+ m_bitLocalFlag.Force = m_bitLocalFlag.LinearVelocity;
+ }
UpdateFuzzyFlags();
}
@@ -87,105 +94,151 @@ bool KX_ObjectActuator::Update()
// it should reconcile the externally set velocity with it's
// own velocity.
if (m_active_combined_velocity) {
- parent->ResolveCombinedVelocities(
- m_linear_velocity,
- m_angular_velocity,
- (m_bitLocalFlag.LinearVelocity) != 0,
- (m_bitLocalFlag.AngularVelocity) != 0
- );
+ if (parent)
+ parent->ResolveCombinedVelocities(
+ m_linear_velocity,
+ m_angular_velocity,
+ (m_bitLocalFlag.LinearVelocity) != 0,
+ (m_bitLocalFlag.AngularVelocity) != 0
+ );
m_active_combined_velocity = false;
}
m_linear_damping_active = false;
+ m_angular_damping_active = false;
+ m_error_accumulator.setValue(0.0,0.0,0.0);
+ m_previous_error.setValue(0.0,0.0,0.0);
return false;
- } else
- if (parent)
+ } else if (parent)
{
- if (!m_bitLocalFlag.ZeroForce)
+ if (m_bitLocalFlag.ServoControl)
{
- if (m_bitLocalFlag.ClampVelocity && !m_bitLocalFlag.ZeroLinearVelocity)
+ // In this mode, we try to reach a target speed using force
+ // As we don't know the friction, we must implement a generic
+ // servo control to achieve the speed in a configurable
+ // v = current velocity
+ // V = target velocity
+ // e = V-v = speed error
+ // dt = time interval since previous update
+ // I = sum(e(t)*dt)
+ // dv = e(t) - e(t-1)
+ // KP, KD, KI : coefficient
+ // F = KP*e+KI*I+KD*dv
+ MT_Scalar mass = parent->GetMass();
+ if (mass < MT_EPSILON)
+ return false;
+ MT_Vector3 v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
+ MT_Vector3 e = m_linear_velocity - v;
+ MT_Vector3 dv = e - m_previous_error;
+ MT_Vector3 I = m_error_accumulator + e;
+
+ m_force = m_torque.x()*e+m_torque.y()*I+m_torque.z()*dv;
+ // to automatically adapt the PID coefficient to mass;
+ m_force *= mass;
+ if (m_bitLocalFlag.Torque)
{
- // The user is requesting not to exceed the velocity set in m_linear_velocity
- // The verification is done by projecting the actual speed along the linV direction
- // and comparing it with the linV vector length
- MT_Vector3 linV;
- linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
- if (linV.dot(m_linear_velocity) < m_linear_length2)
- parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
- } else
+ if (m_force[0] > m_dloc[0])
+ {
+ m_force[0] = m_dloc[0];
+ I[0] = m_error_accumulator[0];
+ } else if (m_force[0] < m_drot[0])
+ {
+ m_force[0] = m_drot[0];
+ I[0] = m_error_accumulator[0];
+ }
+ }
+ if (m_bitLocalFlag.DLoc)
{
- parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
+ if (m_force[1] > m_dloc[1])
+ {
+ m_force[1] = m_dloc[1];
+ I[1] = m_error_accumulator[1];
+ } else if (m_force[1] < m_drot[1])
+ {
+ m_force[1] = m_drot[1];
+ I[1] = m_error_accumulator[1];
+ }
}
- }
- if (!m_bitLocalFlag.ZeroTorque)
+ if (m_bitLocalFlag.DRot)
+ {
+ if (m_force[2] > m_dloc[2])
+ {
+ m_force[2] = m_dloc[2];
+ I[2] = m_error_accumulator[2];
+ } else if (m_force[2] < m_drot[2])
+ {
+ m_force[2] = m_drot[2];
+ I[2] = m_error_accumulator[2];
+ }
+ }
+ m_previous_error = e;
+ m_error_accumulator = I;
+ parent->ApplyForce(m_force,(m_bitLocalFlag.LinearVelocity) != 0);
+ } else
{
- if (m_bitLocalFlag.ClampVelocity && !m_bitLocalFlag.ZeroAngularVelocity)
+ if (!m_bitLocalFlag.ZeroForce)
{
- // The user is requesting not to exceed the velocity set in m_angular_velocity
- // The verification is done by projecting the actual speed in the
- MT_Vector3 angV;
- angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
- if (angV.dot(m_angular_velocity) < m_angular_velocity.length2())
- parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
- } else
+ parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
+ }
+ if (!m_bitLocalFlag.ZeroTorque)
{
parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
}
- }
- if (!m_bitLocalFlag.ZeroDLoc)
- {
- parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0);
- }
- if (!m_bitLocalFlag.ZeroDRot)
- {
- parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
- }
- if (!m_bitLocalFlag.ZeroLinearVelocity && !m_bitLocalFlag.ClampVelocity)
- {
- if (m_bitLocalFlag.AddOrSetLinV) {
- parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
- } else {
+ if (!m_bitLocalFlag.ZeroDLoc)
+ {
+ parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0);
+ }
+ if (!m_bitLocalFlag.ZeroDRot)
+ {
+ parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
+ }
+ if (!m_bitLocalFlag.ZeroLinearVelocity)
+ {
+ if (m_bitLocalFlag.AddOrSetLinV) {
+ parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
+ } else {
+ m_active_combined_velocity = true;
+ if (m_damping > 0) {
+ MT_Vector3 linV;
+ if (!m_linear_damping_active) {
+ // delta and the start speed (depends on the existing speed in that direction)
+ linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
+ // keep only the projection along the desired direction
+ m_current_linear_factor = linV.dot(m_linear_velocity)/m_linear_length2;
+ m_linear_damping_active = true;
+ }
+ if (m_current_linear_factor < 1.0)
+ m_current_linear_factor += 1.0/m_damping;
+ if (m_current_linear_factor > 1.0)
+ m_current_linear_factor = 1.0;
+ linV = m_current_linear_factor * m_linear_velocity;
+ parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0);
+ } else {
+ parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
+ }
+ }
+ }
+ if (!m_bitLocalFlag.ZeroAngularVelocity)
+ {
m_active_combined_velocity = true;
if (m_damping > 0) {
- MT_Vector3 linV;
- if (!m_linear_damping_active) {
+ MT_Vector3 angV;
+ if (!m_angular_damping_active) {
// delta and the start speed (depends on the existing speed in that direction)
- linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
+ angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
// keep only the projection along the desired direction
- m_current_linear_factor = linV.dot(m_linear_velocity)/m_linear_length2;
- m_linear_damping_active = true;
+ m_current_angular_factor = angV.dot(m_angular_velocity)/m_angular_length2;
+ m_angular_damping_active = true;
}
- if (m_current_linear_factor < 1.0)
- m_current_linear_factor += 1.0/m_damping;
- if (m_current_linear_factor > 1.0)
- m_current_linear_factor = 1.0;
- linV = m_current_linear_factor * m_linear_velocity;
- parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0);
+ if (m_current_angular_factor < 1.0)
+ m_current_angular_factor += 1.0/m_damping;
+ if (m_current_angular_factor > 1.0)
+ m_current_angular_factor = 1.0;
+ angV = m_current_angular_factor * m_angular_velocity;
+ parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0);
} else {
- parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
- }
- }
- }
- if (!m_bitLocalFlag.ZeroAngularVelocity && !m_bitLocalFlag.ClampVelocity)
- {
- m_active_combined_velocity = true;
- if (m_damping > 0) {
- MT_Vector3 angV;
- if (!m_angular_damping_active) {
- // delta and the start speed (depends on the existing speed in that direction)
- angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
- // keep only the projection along the desired direction
- m_current_angular_factor = angV.dot(m_angular_velocity)/m_angular_length2;
- m_angular_damping_active = true;
+ parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0);
}
- if (m_current_angular_factor < 1.0)
- m_current_angular_factor += 1.0/m_damping;
- if (m_current_angular_factor > 1.0)
- m_current_angular_factor = 1.0;
- angV = m_current_angular_factor * m_angular_velocity;
- parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0);
- } else {
- parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0);
}
}
@@ -263,8 +316,17 @@ PyMethodDef KX_ObjectActuator::Methods[] = {
{"setLinearVelocity", (PyCFunction) KX_ObjectActuator::sPySetLinearVelocity, METH_VARARGS},
{"getAngularVelocity", (PyCFunction) KX_ObjectActuator::sPyGetAngularVelocity, METH_VARARGS},
{"setAngularVelocity", (PyCFunction) KX_ObjectActuator::sPySetAngularVelocity, METH_VARARGS},
- {"setVelocityDamping", (PyCFunction) KX_ObjectActuator::sPySetVelocityDamping, METH_VARARGS},
- {"getVelocityDamping", (PyCFunction) KX_ObjectActuator::sPyGetVelocityDamping, METH_VARARGS},
+ {"setDamping", (PyCFunction) KX_ObjectActuator::sPySetDamping, METH_VARARGS},
+ {"getDamping", (PyCFunction) KX_ObjectActuator::sPyGetDamping, METH_VARARGS},
+ {"setForceLimitX", (PyCFunction) KX_ObjectActuator::sPySetForceLimitX, METH_VARARGS},
+ {"getForceLimitX", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitX, METH_VARARGS},
+ {"setForceLimitY", (PyCFunction) KX_ObjectActuator::sPySetForceLimitY, METH_VARARGS},
+ {"getForceLimitY", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitY, METH_VARARGS},
+ {"setForceLimitZ", (PyCFunction) KX_ObjectActuator::sPySetForceLimitZ, METH_VARARGS},
+ {"getForceLimitZ", (PyCFunction) KX_ObjectActuator::sPyGetForceLimitZ, METH_VARARGS},
+ {"setPID", (PyCFunction) KX_ObjectActuator::sPyGetPID, METH_VARARGS},
+ {"getPID", (PyCFunction) KX_ObjectActuator::sPySetPID, METH_VARARGS},
+
{NULL,NULL} //Sentinel
@@ -411,7 +473,6 @@ PyObject* KX_ObjectActuator::PyGetLinearVelocity(PyObject* self,
PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1]));
PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2]));
PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.LinearVelocity));
- PyList_SetItem(retVal, 4, BoolToPyArg(m_bitLocalFlag.ClampVelocity));
return retVal;
}
@@ -422,14 +483,12 @@ PyObject* KX_ObjectActuator::PySetLinearVelocity(PyObject* self,
PyObject* kwds) {
float vecArg[3];
int bToggle = 0;
- int bClamp = 0;
- if (!PyArg_ParseTuple(args, "fffi|i", &vecArg[0], &vecArg[1],
- &vecArg[2], &bToggle, &bClamp)) {
+ if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
+ &vecArg[2], &bToggle)) {
return NULL;
}
m_linear_velocity.setValue(vecArg);
m_bitLocalFlag.LinearVelocity = PyArgToBool(bToggle);
- m_bitLocalFlag.ClampVelocity = PyArgToBool(bClamp);
UpdateFuzzyFlags();
Py_Return;
}
@@ -445,7 +504,6 @@ PyObject* KX_ObjectActuator::PyGetAngularVelocity(PyObject* self,
PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1]));
PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2]));
PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.AngularVelocity));
- PyList_SetItem(retVal, 4, BoolToPyArg(m_bitLocalFlag.ClampVelocity));
return retVal;
}
@@ -455,22 +513,20 @@ PyObject* KX_ObjectActuator::PySetAngularVelocity(PyObject* self,
PyObject* kwds) {
float vecArg[3];
int bToggle = 0;
- int bClamp = 0;
- if (!PyArg_ParseTuple(args, "fffi|i", &vecArg[0], &vecArg[1],
- &vecArg[2], &bToggle, &bClamp)) {
+ if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
+ &vecArg[2], &bToggle)) {
return NULL;
}
m_angular_velocity.setValue(vecArg);
m_bitLocalFlag.AngularVelocity = PyArgToBool(bToggle);
- m_bitLocalFlag.ClampVelocity = PyArgToBool(bClamp);
UpdateFuzzyFlags();
Py_Return;
}
-/* 13. setVelocityDamping */
-PyObject* KX_ObjectActuator::PySetVelocityDamping(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+/* 13. setDamping */
+PyObject* KX_ObjectActuator::PySetDamping(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
int damping = 0;
if (!PyArg_ParseTuple(args, "i", &damping) || damping < 0 || damping > 1000) {
return NULL;
@@ -480,11 +536,124 @@ PyObject* KX_ObjectActuator::PySetVelocityDamping(PyObject* self,
}
/* 13. getVelocityDamping */
-PyObject* KX_ObjectActuator::PyGetVelocityDamping(PyObject* self,
- PyObject* args,
- PyObject* kwds) {
+PyObject* KX_ObjectActuator::PyGetDamping(PyObject* self,
+ PyObject* args,
+ PyObject* kwds) {
return Py_BuildValue("i",m_damping);
}
+/* 6. getForceLimitX */
+PyObject* KX_ObjectActuator::PyGetForceLimitX(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[0]));
+ PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.Torque));
+
+ return retVal;
+}
+/* 7. setForceLimitX */
+PyObject* KX_ObjectActuator::PySetForceLimitX(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[2];
+ int bToggle = 0;
+ if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) {
+ return NULL;
+ }
+ m_drot[0] = vecArg[0];
+ m_dloc[0] = vecArg[1];
+ m_bitLocalFlag.Torque = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 6. getForceLimitY */
+PyObject* KX_ObjectActuator::PyGetForceLimitY(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[1]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[1]));
+ PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DLoc));
+
+ return retVal;
+}
+/* 7. setForceLimitY */
+PyObject* KX_ObjectActuator::PySetForceLimitY(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[2];
+ int bToggle = 0;
+ if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) {
+ return NULL;
+ }
+ m_drot[1] = vecArg[0];
+ m_dloc[1] = vecArg[1];
+ m_bitLocalFlag.DLoc = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 6. getForceLimitZ */
+PyObject* KX_ObjectActuator::PyGetForceLimitZ(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[2]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[2]));
+ PyList_SetItem(retVal, 2, BoolToPyArg(m_bitLocalFlag.DRot));
+
+ return retVal;
+}
+/* 7. setForceLimitZ */
+PyObject* KX_ObjectActuator::PySetForceLimitZ(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[2];
+ int bToggle = 0;
+ if(!PyArg_ParseTuple(args, "ffi", &vecArg[0], &vecArg[1], &bToggle)) {
+ return NULL;
+ }
+ m_drot[2] = vecArg[0];
+ m_dloc[2] = vecArg[1];
+ m_bitLocalFlag.DRot = PyArgToBool(bToggle);
+ Py_Return;
+}
+
+/* 4. getPID */
+PyObject* KX_ObjectActuator::PyGetPID(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ PyObject *retVal = PyList_New(3);
+
+ PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_torque[0]));
+ PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_torque[1]));
+ PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_torque[2]));
+
+ return retVal;
+}
+/* 5. setPID */
+PyObject* KX_ObjectActuator::PySetPID(PyObject* self,
+ PyObject* args,
+ PyObject* kwds)
+{
+ float vecArg[3];
+ if (!PyArg_ParseTuple(args, "fff", &vecArg[0], &vecArg[1], &vecArg[2])) {
+ return NULL;
+ }
+ m_torque.setValue(vecArg);
+ Py_Return;
+}
+
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h
index ec6dab5cd48..bb74756551f 100644
--- a/source/gameengine/Ketsji/KX_ObjectActuator.h
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.h
@@ -47,7 +47,6 @@ struct KX_LocalFlags {
LinearVelocity(false),
AngularVelocity(false),
AddOrSetLinV(false),
- ClampVelocity(false),
ZeroForce(false),
ZeroDRot(false),
ZeroDLoc(false),
@@ -63,7 +62,7 @@ struct KX_LocalFlags {
unsigned short LinearVelocity : 1;
unsigned short AngularVelocity : 1;
unsigned short AddOrSetLinV : 1;
- unsigned short ClampVelocity : 1;
+ unsigned short ServoControl : 1;
unsigned short ZeroForce : 1;
unsigned short ZeroTorque : 1;
unsigned short ZeroDRot : 1;
@@ -84,9 +83,13 @@ class KX_ObjectActuator : public SCA_IActuator
MT_Vector3 m_angular_velocity;
MT_Scalar m_linear_length2;
MT_Scalar m_angular_length2;
+ // used in damping
MT_Scalar m_current_linear_factor;
MT_Scalar m_current_angular_factor;
short m_damping;
+ // used in servo control
+ MT_Vector3 m_previous_error;
+ MT_Vector3 m_error_accumulator;
KX_LocalFlags m_bitLocalFlag;
// A hack bool -- oh no sorry everyone
@@ -164,8 +167,16 @@ public:
KX_PYMETHOD(KX_ObjectActuator,SetLinearVelocity);
KX_PYMETHOD(KX_ObjectActuator,GetAngularVelocity);
KX_PYMETHOD(KX_ObjectActuator,SetAngularVelocity);
- KX_PYMETHOD(KX_ObjectActuator,SetVelocityDamping);
- KX_PYMETHOD(KX_ObjectActuator,GetVelocityDamping);
+ KX_PYMETHOD(KX_ObjectActuator,SetDamping);
+ KX_PYMETHOD(KX_ObjectActuator,GetDamping);
+ KX_PYMETHOD(KX_ObjectActuator,GetForceLimitX);
+ KX_PYMETHOD(KX_ObjectActuator,SetForceLimitX);
+ KX_PYMETHOD(KX_ObjectActuator,GetForceLimitY);
+ KX_PYMETHOD(KX_ObjectActuator,SetForceLimitY);
+ KX_PYMETHOD(KX_ObjectActuator,GetForceLimitZ);
+ KX_PYMETHOD(KX_ObjectActuator,SetForceLimitZ);
+ KX_PYMETHOD(KX_ObjectActuator,GetPID);
+ KX_PYMETHOD(KX_ObjectActuator,SetPID);
};
#endif //__KX_OBJECTACTUATOR
diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp
index e847c59bae1..a416c8c9f89 100644
--- a/source/gameengine/Ketsji/KX_RaySensor.cpp
+++ b/source/gameengine/Ketsji/KX_RaySensor.cpp
@@ -72,6 +72,7 @@ void KX_RaySensor::Init()
m_bTriggered = (m_invert)?true:false;
m_rayHit = false;
m_hitObject = NULL;
+ m_reset = true;
}
KX_RaySensor::~KX_RaySensor()
@@ -83,9 +84,10 @@ KX_RaySensor::~KX_RaySensor()
CValue* KX_RaySensor::GetReplica()
{
- CValue* replica = new KX_RaySensor(*this);
+ KX_RaySensor* replica = new KX_RaySensor(*this);
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
+ replica->Init();
return replica;
}
@@ -151,6 +153,7 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_
bool KX_RaySensor::Evaluate(CValue* event)
{
bool result = false;
+ bool reset = m_reset && m_level;
m_rayHit = false;
m_hitObject = NULL;
m_hitPosition = MT_Vector3(0,0,0);
@@ -162,6 +165,7 @@ bool KX_RaySensor::Evaluate(CValue* event)
MT_Matrix3x3 invmat = matje.inverse();
MT_Vector3 todir;
+ m_reset = false;
switch (m_axis)
{
case 1: // X
@@ -263,7 +267,9 @@ bool KX_RaySensor::Evaluate(CValue* event)
}
}
-
+ if (reset)
+ // force an event
+ result = true;
return result;
}
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index a7e91e27df3..337b1af6df7 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -48,6 +48,7 @@
#include "SCA_KeyboardManager.h"
#include "SCA_MouseManager.h"
#include "SCA_PropertyEventManager.h"
+#include "SCA_ActuatorEventManager.h"
#include "KX_Camera.h"
#include "SCA_JoystickManager.h"
@@ -143,6 +144,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
SCA_AlwaysEventManager* alwaysmgr = new SCA_AlwaysEventManager(m_logicmgr);
SCA_PropertyEventManager* propmgr = new SCA_PropertyEventManager(m_logicmgr);
+ SCA_ActuatorEventManager* actmgr = new SCA_ActuatorEventManager(m_logicmgr);
SCA_RandomEventManager* rndmgr = new SCA_RandomEventManager(m_logicmgr);
KX_RayEventManager* raymgr = new KX_RayEventManager(m_logicmgr);
@@ -152,6 +154,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
m_logicmgr->RegisterEventManager(alwaysmgr);
m_logicmgr->RegisterEventManager(propmgr);
+ m_logicmgr->RegisterEventManager(actmgr);
m_logicmgr->RegisterEventManager(m_keyboardmgr);
m_logicmgr->RegisterEventManager(m_mousemgr);
m_logicmgr->RegisterEventManager(m_timemgr);
diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp
index 5311f059f03..ce3aa1de2ef 100644
--- a/source/gameengine/Ketsji/KX_TouchSensor.cpp
+++ b/source/gameengine/Ketsji/KX_TouchSensor.cpp
@@ -61,7 +61,9 @@ void KX_TouchSensor::EndFrame() {
bool KX_TouchSensor::Evaluate(CValue* event)
{
bool result = false;
+ bool reset = m_reset && m_level;
+ m_reset = false;
if (m_bTriggered != m_bLastTriggered)
{
m_bLastTriggered = m_bTriggered;
@@ -69,7 +71,9 @@ bool KX_TouchSensor::Evaluate(CValue* event)
m_hitObject = NULL;
result = true;
}
-
+ if (reset)
+ // force an event
+ result = true;
return result;
}
@@ -103,6 +107,7 @@ void KX_TouchSensor::Init()
m_bTriggered = false;
m_bLastTriggered = (m_invert)?true:false;
m_hitObject = NULL;
+ m_reset = true;
}
KX_TouchSensor::~KX_TouchSensor()
@@ -115,10 +120,7 @@ CValue* KX_TouchSensor::GetReplica()
{
KX_TouchSensor* replica = new KX_TouchSensor(*this);
replica->m_colliders = new CListValue();
- replica->m_bCollision = false;
- replica->m_bTriggered= false;
- replica->m_hitObject = NULL;
- replica->m_bLastTriggered = false;
+ replica->Init();
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
return replica;