BGE: Some various changes to make moving the character physics type easier:

* Undoing the previous applyMovement() changes for characters. This was causing bugs for the Motion Actuator.
  * Creating a Character Motion type for the Motion Actuator with specific controls for characters. This includes moving, rotating and jumping.
  * Adding a KX_CharacterWrapper.walkDirection to set the character's direction and speed.

Note, this also resolves the following bugs:
[#33585] "Setting dLoc of motion actuator [0,0,0] via python won't stop object" reported by Manuel Bellersen (urfoex)
[#33503] "Character physics type won´t accept more than one motion anymore" reported by Mr Larodos
This commit is contained in:
Mitchell Stokes 2013-01-30 05:55:17 +00:00
parent 26ee2a1f79
commit 9191b783bb
16 changed files with 222 additions and 17 deletions

@ -3761,6 +3761,12 @@ Types
:type: int
.. attribute:: walkDirection
The speed and direction the character is traveling in using world coordinates. This should be used instead of applyMovement() to properly move the character.
:type: list [x, y, z]
.. method:: jump()
The character jumps based on it's jump speed.

@ -1860,6 +1860,25 @@ static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr)
uiItemR(col, ptr, "integral_coefficient", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemR(col, ptr, "derivate_coefficient", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
break;
case ACT_OBJECT_CHARACTER:
split = uiLayoutSplit(layout, 0.9, FALSE);
row = uiLayoutRow(split, FALSE);
uiItemR(row, ptr, "offset_location", 0, NULL, ICON_NONE);
row = uiLayoutRow(split, TRUE);
uiItemR(row, ptr, "use_local_location", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
uiItemR(row, ptr, "use_add_character_location", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
split = uiLayoutSplit(layout, 0.9, FALSE);
row = uiLayoutRow(split, FALSE);
uiItemR(row, ptr, "offset_rotation", 0, NULL, ICON_NONE);
uiItemR(split, ptr, "use_local_rotation", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
split = uiLayoutSplit(layout, 0.9, FALSE);
row = uiLayoutRow(split, FALSE);
split = uiLayoutSplit(row, 0.7, FALSE);
uiItemL(split, "", ICON_NONE); /*Just use this for some spacing */
uiItemR(split, ptr, "use_character_jump", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
break;
}
}

@ -277,10 +277,13 @@ typedef struct bActuator {
#define ACT_ANG_VEL_LOCAL 32
//#define ACT_ADD_LIN_VEL_LOCAL 64
#define ACT_ADD_LIN_VEL 64
#define ACT_ADD_CHAR_LOC 128
#define ACT_CHAR_JUMP 256
/* objectactuator->type */
#define ACT_OBJECT_NORMAL 0
#define ACT_OBJECT_SERVO 1
#define ACT_OBJECT_NORMAL 0
#define ACT_OBJECT_SERVO 1
#define ACT_OBJECT_CHARACTER 2
/* actuator->type */
#define ACT_OBJECT 0

@ -389,6 +389,12 @@ static void rna_ObjectActuator_type_set(struct PointerRNA *ptr, int value)
oa->forcerot[1] = 0.5f;
oa->forcerot[2] = 0.0f;
break;
case ACT_OBJECT_CHARACTER:
memset(oa, 0, sizeof(bObjectActuator));
oa->flag = ACT_DLOC_LOCAL | ACT_DROT_LOCAL;
oa->type = ACT_OBJECT_CHARACTER;
break;
}
}
}
@ -701,6 +707,7 @@ static void rna_def_object_actuator(BlenderRNA *brna)
static EnumPropertyItem prop_type_items[] = {
{ACT_OBJECT_NORMAL, "OBJECT_NORMAL", 0, "Simple Motion", ""},
{ACT_OBJECT_SERVO, "OBJECT_SERVO", 0, "Servo Control", ""},
{ACT_OBJECT_CHARACTER, "OBJECT_CHARACTER", 0, "Character Motion", ""},
{0, NULL, 0, NULL, NULL}
};
@ -867,6 +874,11 @@ static void rna_def_object_actuator(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Add", "Toggles between ADD and SET linV");
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop = RNA_def_property(srna, "use_add_character_location", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_ADD_CHAR_LOC);
RNA_def_property_ui_text(prop, "Add", "Toggles between ADD and SET character location");
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop = RNA_def_property(srna, "use_servo_limit_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_X);
RNA_def_property_ui_text(prop, "X", "Set limit to force along the X axis");
@ -881,6 +893,11 @@ static void rna_def_object_actuator(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_Z);
RNA_def_property_ui_text(prop, "Z", "Set limit to force along the Z axis");
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop = RNA_def_property(srna, "use_character_jump", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CHAR_JUMP);
RNA_def_property_ui_text(prop, "Jump", "Makes the character jump using the settings in the physics properties");
RNA_def_property_update(prop, NC_LOGIC, NULL);
}
static void rna_def_camera_actuator(BlenderRNA *brna)

@ -180,7 +180,10 @@ void BL_ConvertActuators(const char* maggiename,
bitLocalFlag.LinearVelocity = bool((obact->flag & ACT_LIN_VEL_LOCAL)!=0);
bitLocalFlag.AngularVelocity = bool((obact->flag & ACT_ANG_VEL_LOCAL)!=0);
bitLocalFlag.ServoControl = bool(obact->type == ACT_OBJECT_SERVO);
bitLocalFlag.CharacterMotion = bool(obact->type == ACT_OBJECT_CHARACTER);
bitLocalFlag.CharacterJump = bool((obact->flag & ACT_CHAR_JUMP)!=0);
bitLocalFlag.AddOrSetLinV = bool((obact->flag & ACT_ADD_LIN_VEL)!=0);
bitLocalFlag.AddOrSetCharLoc = bool((obact->flag & ACT_ADD_CHAR_LOC)!=0);
if (obact->reference && bitLocalFlag.ServoControl)
{
obref = converter->FindGameObject(obact->reference);

@ -75,6 +75,11 @@ void KX_BulletPhysicsController::SetLinVelocityMin(float val)
CcdPhysicsController::SetLinVelocityMin(val);
}
void KX_BulletPhysicsController::Jump()
{
CcdPhysicsController::Jump();
}
float KX_BulletPhysicsController::GetLinVelocityMax()
{
return (float)CcdPhysicsController::GetLinVelocityMax();
@ -119,6 +124,11 @@ void KX_BulletPhysicsController::RelativeTranslate(const MT_Vector3& dloc,bool l
}
void KX_BulletPhysicsController::SetWalkDirection(const MT_Vector3& dloc,bool local)
{
CcdPhysicsController::SetWalkDirection(dloc[0],dloc[1],dloc[2],local);
}
void KX_BulletPhysicsController::RelativeRotate(const MT_Matrix3x3& drot,bool local)
{
float rotval[9];
@ -155,6 +165,13 @@ MT_Vector3 KX_BulletPhysicsController::GetVelocity(const MT_Point3& pos)
return MT_Vector3(linVel[0],linVel[1],linVel[2]);
}
MT_Vector3 KX_BulletPhysicsController::GetWalkDirection()
{
float dir[3];
CcdPhysicsController::GetWalkDirection(dir[0], dir[1], dir[2]);
return MT_Vector3(dir[0], dir[1], dir[2]);
}
void KX_BulletPhysicsController::SetAngularVelocity(const MT_Vector3& ang_vel,bool local)
{
CcdPhysicsController::SetAngularVelocity(ang_vel.x(),ang_vel.y(),ang_vel.z(),local);

@ -40,11 +40,14 @@ public:
virtual void RelativeRotate(const MT_Matrix3x3& drot,bool local);
virtual void ApplyTorque(const MT_Vector3& torque,bool local);
virtual void ApplyForce(const MT_Vector3& force,bool local);
virtual void SetWalkDirection(const MT_Vector3& dir,bool local);
virtual MT_Vector3 GetLinearVelocity();
virtual MT_Vector3 GetAngularVelocity();
virtual MT_Vector3 GetVelocity(const MT_Point3& pos);
virtual MT_Vector3 GetWalkDirection();
virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local);
virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local);
virtual void Jump();
virtual void getOrientation(MT_Quaternion& orn);
virtual void setOrientation(const MT_Matrix3x3& orn);
virtual void setPosition(const MT_Point3& pos);

@ -5,6 +5,7 @@
#include "KX_CharacterWrapper.h"
#include "PHY_ICharacter.h"
#include "KX_PyMath.h"
KX_CharacterWrapper::KX_CharacterWrapper(PHY_ICharacter* character) :
PyObjectPlus(),
@ -47,6 +48,7 @@ PyAttributeDef KX_CharacterWrapper::Attributes[] = {
KX_PYATTRIBUTE_RW_FUNCTION("gravity", KX_CharacterWrapper, pyattr_get_gravity, pyattr_set_gravity),
KX_PYATTRIBUTE_RW_FUNCTION("maxJumps", KX_CharacterWrapper, pyattr_get_max_jumps, pyattr_set_max_jumps),
KX_PYATTRIBUTE_RO_FUNCTION("jumpCount", KX_CharacterWrapper, pyattr_get_jump_count),
KX_PYATTRIBUTE_RW_FUNCTION("walkDirection", KX_CharacterWrapper, pyattr_get_walk_dir, pyattr_set_walk_dir),
{ NULL } //Sentinel
};
@ -108,6 +110,33 @@ PyObject *KX_CharacterWrapper::pyattr_get_jump_count(void *self_v, const KX_PYAT
return PyLong_FromLong(self->m_character->GetJumpCount());
}
PyObject *KX_CharacterWrapper::pyattr_get_walk_dir(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_CharacterWrapper* self = static_cast<KX_CharacterWrapper*>(self_v);
PHY__Vector3 vec = self->m_character->GetWalkDirection();
MT_Vector3 retval = MT_Vector3(vec[0], vec[1], vec[2]);
return PyObjectFrom(retval);
}
int KX_CharacterWrapper::pyattr_set_walk_dir(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
{
KX_CharacterWrapper* self = static_cast<KX_CharacterWrapper*>(self_v);
MT_Vector3 dir;
if (!PyVecTo(value, dir)) {
PyErr_SetString(PyExc_TypeError, "KX_CharacterWrapper.walkDirection: expected a vector");
return PY_SET_ATTR_FAIL;
}
PHY__Vector3 vec;
vec[0] = dir[0];
vec[1] = dir[1];
vec[2] = dir[2];
self->m_character->SetWalkDirection(vec);
return PY_SET_ATTR_SUCCESS;
}
PyMethodDef KX_CharacterWrapper::Methods[] = {
KX_PYMETHODTABLE_NOARGS(KX_CharacterWrapper, jump),
{NULL,NULL} //Sentinel

@ -29,6 +29,8 @@ public:
static PyObject* pyattr_get_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_jump_count(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_walk_dir(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_walk_dir(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
#endif // WITH_PYTHON
private:

@ -70,11 +70,14 @@ public:
virtual void RelativeRotate(const MT_Matrix3x3& drot,bool local)=0;
virtual void ApplyTorque(const MT_Vector3& torque,bool local)=0;
virtual void ApplyForce(const MT_Vector3& force,bool local)=0;
virtual void SetWalkDirection(const MT_Vector3& dir,bool local)=0;
virtual MT_Vector3 GetLinearVelocity()=0;
virtual MT_Vector3 GetAngularVelocity()=0;
virtual MT_Vector3 GetVelocity(const MT_Point3& pos)=0;
virtual MT_Vector3 GetWalkDirection()=0;
virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local)=0;
virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local)=0;
virtual void Jump()=0;
virtual void resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) = 0;
virtual void getOrientation(MT_Quaternion& orn)=0;

@ -81,6 +81,16 @@ KX_ObjectActuator(
m_pid = m_torque;
}
if (m_bitLocalFlag.CharacterMotion)
{
KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent());
if (!parent->GetPhysicsController() || !parent->GetPhysicsController()->IsCharacter())
{
printf("Character motion enabled on non-character object (%s), falling back to simple motion.\n", parent->GetName().Ptr());
m_bitLocalFlag.CharacterMotion = false;
}
}
if (m_reference)
m_reference->RegisterActuator(this);
UpdateFuzzyFlags();
@ -116,10 +126,10 @@ bool KX_ObjectActuator::Update()
m_active_combined_velocity = false;
}
// Explicitly stop the movement if we're using a character (apply movement is a little different for characters)
if (parent->GetPhysicsController() && parent->GetPhysicsController()->IsCharacter()) {
// Explicitly stop the movement if we're using character motion
if (m_bitLocalFlag.CharacterMotion) {
MT_Vector3 vec(0.0, 0.0, 0.0);
parent->ApplyMovement(vec, true);
parent->GetPhysicsController()->SetWalkDirection(vec, true);
}
m_linear_damping_active = false;
@ -205,7 +215,30 @@ bool KX_ObjectActuator::Update()
m_previous_error = e;
m_error_accumulator = I;
parent->ApplyForce(m_force,(m_bitLocalFlag.LinearVelocity) != 0);
} else
} else if(m_bitLocalFlag.CharacterMotion)
{
MT_Vector3 dir = m_dloc;
if (m_bitLocalFlag.AddOrSetCharLoc) {
MT_Vector3 old_dir = parent->GetPhysicsController()->GetWalkDirection();
MT_Scalar mag = old_dir.length();
if (mag < MT_EPSILON)
mag = dir.length();
dir = (dir + old_dir).normalized() * mag;
}
// We always want to set the walk direction since a walk direction of (0, 0, 0) should stop the character
parent->GetPhysicsController()->SetWalkDirection(dir, (m_bitLocalFlag.DLoc) != 0);
if (!m_bitLocalFlag.ZeroDRot)
{
parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
}
if (m_bitLocalFlag.CharacterJump)
{
parent->GetPhysicsController()->Jump();
}
}else
{
if (!m_bitLocalFlag.ZeroForce)
{

@ -54,7 +54,12 @@ struct KX_LocalFlags {
LinearVelocity(false),
AngularVelocity(false),
AddOrSetLinV(false),
AddOrSetCharLoc(false),
ServoControl(false),
CharacterMotion(false),
CharacterJump(false),
ZeroForce(false),
ZeroTorque(false),
ZeroDRot(false),
ZeroDLoc(false),
ZeroLinearVelocity(false),
@ -69,7 +74,10 @@ struct KX_LocalFlags {
bool LinearVelocity;
bool AngularVelocity;
bool AddOrSetLinV;
bool AddOrSetCharLoc;
bool ServoControl;
bool CharacterMotion;
bool CharacterJump;
bool ZeroForce;
bool ZeroTorque;
bool ZeroDRot;

@ -115,6 +115,11 @@ void BlenderBulletCharacterController::jump()
m_jumps++;
}
const btVector3& BlenderBulletCharacterController::getWalkDirection()
{
return m_walkDirection;
}
CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci)
:m_cci(ci)
{
@ -926,20 +931,27 @@ void CcdPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dloc
if (local)
dloc = xform.getBasis()*dloc;
if (m_characterController)
{
m_characterController->setWalkDirection(dloc/GetPhysicsEnvironment()->getNumTimeSubSteps());
}
else
{
xform.setOrigin(xform.getOrigin() + dloc);
SetCenterOfMassTransform(xform);
}
xform.setOrigin(xform.getOrigin() + dloc);
SetCenterOfMassTransform(xform);
}
}
void CcdPhysicsController::SetWalkDirection(float dirX,float dirY,float dirZ,bool local)
{
if (m_object && m_characterController)
{
btVector3 dir(dirX,dirY,dirZ);
btTransform xform = m_object->getWorldTransform();
if (local)
dir = xform.getBasis()*dir;
m_characterController->setWalkDirection(dir/GetPhysicsEnvironment()->getNumTimeSubSteps());
}
}
void CcdPhysicsController::RelativeRotate(const float rotval[9],bool local)
{
if (m_object)
@ -1267,6 +1279,13 @@ void CcdPhysicsController::applyImpulse(float attachX,float attachY,float attac
}
}
void CcdPhysicsController::Jump()
{
if (m_object && m_characterController)
m_characterController->jump();
}
void CcdPhysicsController::SetActive(bool active)
{
}
@ -1323,6 +1342,24 @@ void CcdPhysicsController::GetVelocity(const float posX,const float posY,const
linvZ = 0.f;
}
}
void CcdPhysicsController::GetWalkDirection(float& dirX,float& dirY,float& dirZ)
{
if (m_object && m_characterController)
{
const btVector3 dir = m_characterController->getWalkDirection();
dirX = dir.x();
dirY = dir.y();
dirZ = dir.z();
}
else
{
dirX = 0.f;
dirY = 0.f;
dirZ = 0.f;
}
}
void CcdPhysicsController::getReactionForce(float& forceX,float& forceY,float& forceZ)
{
}

@ -417,6 +417,8 @@ public:
virtual bool canJump() const;
virtual void jump();
const btVector3& getWalkDirection();
};
///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution.
@ -424,7 +426,7 @@ class CcdPhysicsController : public PHY_IPhysicsController
{
protected:
btCollisionObject* m_object;
btKinematicCharacterController* m_characterController;
BlenderBulletCharacterController* m_characterController;
class PHY_IMotionState* m_MotionState;
@ -517,6 +519,7 @@ protected:
// kinematic methods
virtual void RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local);
virtual void SetWalkDirection(float dirX,float dirY,float dirZ,bool local);
virtual void RelativeRotate(const float drot[9],bool local);
virtual void getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal);
virtual void setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal);
@ -531,6 +534,7 @@ protected:
virtual void SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local);
virtual void SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local);
virtual void applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ);
virtual void Jump();
virtual void SetActive(bool active);
// reading out information from physics
@ -538,6 +542,7 @@ protected:
virtual void GetAngularVelocity(float& angVelX,float& angVelY,float& angVelZ);
virtual void GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ);
virtual void getReactionForce(float& forceX,float& forceY,float& forceZ);
virtual void GetWalkDirection(float& dirX,float& dirY,float& dirZ);
// dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted
virtual void setRigidBody(bool rigid);

@ -310,6 +310,22 @@ public:
{
return m_controller->getJumpCount();
}
virtual void SetWalkDirection(PHY__Vector3 dir)
{
btVector3 vec = btVector3(dir[0], dir[1], dir[2]);
m_controller->setWalkDirection(vec);
}
virtual PHY__Vector3 GetWalkDirection()
{
btVector3 vec = m_controller->getWalkDirection();
PHY__Vector3 retval;
retval[0] = vec[0];
retval[1] = vec[1];
retval[2] = vec[2];
return retval;
}
};
class CcdOverlapFilterCallBack : public btOverlapFilterCallback

@ -15,6 +15,7 @@
class PHY_ICharacter
{
public:
virtual ~PHY_ICharacter(){};
virtual void Jump()= 0;
virtual bool OnGround()= 0;
@ -27,6 +28,9 @@ public:
virtual int GetJumpCount()= 0;
virtual void SetWalkDirection(PHY__Vector3 dir)=0;
virtual PHY__Vector3 GetWalkDirection()=0;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_ICharacter")
#endif