blender/source/gameengine/Ketsji/KX_ObjectActuator.cpp
Benoit Bolsee 15c105c157 BGE patch: Add damping and clamping option to motion actuator.
This patch introduces two options for the motion actuator:

damping: number of frames to reach the target velocity. It takes
into account the startup velocityin the target velocity direction
and add 1/damping fraction of target velocity until the full 
velocity is reached. Works only with linear and angular velocity.
It will be extended to delta and force motion method in a future
release.

clamping: apply the force and torque as long as the target velocity
is not reached. If this option is set, the velocity specified 
in linV or angV are not applied to the object but used as target
velocity. You should also specify a force in force or torque field: 
the force will be applied as long as the velocity along the axis of
the vector set in linV or angV is not reached. Works best in low
friction environment.
2008-06-24 19:37:43 +00:00

493 lines
15 KiB
C++

/**
* Do translation/rotation actions
*
* $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 "KX_ObjectActuator.h"
#include "KX_GameObject.h"
#include "KX_IPhysicsController.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* ------------------------------------------------------------------------- */
/* Native functions */
/* ------------------------------------------------------------------------- */
KX_ObjectActuator::
KX_ObjectActuator(
SCA_IObject* gameobj,
const MT_Vector3& force,
const MT_Vector3& torque,
const MT_Vector3& dloc,
const MT_Vector3& drot,
const MT_Vector3& linV,
const MT_Vector3& angV,
const short damping,
const KX_LocalFlags& flag,
PyTypeObject* T
) :
SCA_IActuator(gameobj,T),
m_force(force),
m_torque(torque),
m_dloc(dloc),
m_drot(drot),
m_linear_velocity(linV),
m_angular_velocity(angV),
m_linear_length2(0.0),
m_current_linear_factor(0.0),
m_current_angular_factor(0.0),
m_damping(damping),
m_bitLocalFlag (flag),
m_active_combined_velocity (false),
m_linear_damping_active(false),
m_angular_damping_active(false)
{
UpdateFuzzyFlags();
}
bool KX_ObjectActuator::Update()
{
bool bNegativeEvent = IsNegativeEvent();
RemoveAllEvents();
KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent());
if (bNegativeEvent) {
// If we previously set the linear velocity we now have to inform
// the physics controller that we no longer wish to apply it and that
// 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
);
m_active_combined_velocity = false;
}
m_linear_damping_active = false;
return false;
} else
if (parent)
{
if (!m_bitLocalFlag.ZeroForce)
{
if (m_bitLocalFlag.ClampVelocity && !m_bitLocalFlag.ZeroLinearVelocity)
{
// 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
{
parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
}
}
if (!m_bitLocalFlag.ZeroTorque)
{
if (m_bitLocalFlag.ClampVelocity && !m_bitLocalFlag.ZeroAngularVelocity)
{
// 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->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 {
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_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;
}
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);
}
}
}
return true;
}
CValue* KX_ObjectActuator::GetReplica()
{
KX_ObjectActuator* replica = new KX_ObjectActuator(*this);//m_float,GetName());
replica->ProcessReplica();
// this will copy properties and so on...
CValue::AddDataToReplica(replica);
return replica;
}
/* some 'standard' utilities... */
bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type)
{
bool res = false;
res = (type > KX_OBJECT_ACT_NODEF) && (type < KX_OBJECT_ACT_MAX);
return res;
}
/* ------------------------------------------------------------------------- */
/* Python functions */
/* ------------------------------------------------------------------------- */
/* Integration hooks ------------------------------------------------------- */
PyTypeObject KX_ObjectActuator::Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"KX_ObjectActuator",
sizeof(KX_ObjectActuator),
0,
PyDestructor,
0,
__getattr,
__setattr,
0, //&MyPyCompare,
__repr,
0, //&cvalue_as_number,
0,
0,
0,
0
};
PyParentObject KX_ObjectActuator::Parents[] = {
&KX_ObjectActuator::Type,
&SCA_IActuator::Type,
&SCA_ILogicBrick::Type,
&CValue::Type,
NULL
};
PyMethodDef KX_ObjectActuator::Methods[] = {
{"getForce", (PyCFunction) KX_ObjectActuator::sPyGetForce, METH_VARARGS},
{"setForce", (PyCFunction) KX_ObjectActuator::sPySetForce, METH_VARARGS},
{"getTorque", (PyCFunction) KX_ObjectActuator::sPyGetTorque, METH_VARARGS},
{"setTorque", (PyCFunction) KX_ObjectActuator::sPySetTorque, METH_VARARGS},
{"getDLoc", (PyCFunction) KX_ObjectActuator::sPyGetDLoc, METH_VARARGS},
{"setDLoc", (PyCFunction) KX_ObjectActuator::sPySetDLoc, METH_VARARGS},
{"getDRot", (PyCFunction) KX_ObjectActuator::sPyGetDRot, METH_VARARGS},
{"setDRot", (PyCFunction) KX_ObjectActuator::sPySetDRot, METH_VARARGS},
{"getLinearVelocity", (PyCFunction) KX_ObjectActuator::sPyGetLinearVelocity, METH_VARARGS},
{"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},
{NULL,NULL} //Sentinel
};
PyObject* KX_ObjectActuator::_getattr(const STR_String& attr) {
_getattr_up(SCA_IActuator);
};
/* 1. set ------------------------------------------------------------------ */
/* Removed! */
/* 2. getForce */
PyObject* KX_ObjectActuator::PyGetForce(PyObject* self,
PyObject* args,
PyObject* kwds)
{
PyObject *retVal = PyList_New(4);
PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_force[0]));
PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_force[1]));
PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_force[2]));
PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.Force));
return retVal;
}
/* 3. setForce */
PyObject* KX_ObjectActuator::PySetForce(PyObject* self,
PyObject* args,
PyObject* kwds)
{
float vecArg[3];
int bToggle = 0;
if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
&vecArg[2], &bToggle)) {
return NULL;
}
m_force.setValue(vecArg);
m_bitLocalFlag.Force = PyArgToBool(bToggle);
UpdateFuzzyFlags();
Py_Return;
}
/* 4. getTorque */
PyObject* KX_ObjectActuator::PyGetTorque(PyObject* self,
PyObject* args,
PyObject* kwds)
{
PyObject *retVal = PyList_New(4);
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]));
PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.Torque));
return retVal;
}
/* 5. setTorque */
PyObject* KX_ObjectActuator::PySetTorque(PyObject* self,
PyObject* args,
PyObject* kwds)
{
float vecArg[3];
int bToggle = 0;
if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
&vecArg[2], &bToggle)) {
return NULL;
}
m_torque.setValue(vecArg);
m_bitLocalFlag.Torque = PyArgToBool(bToggle);
UpdateFuzzyFlags();
Py_Return;
}
/* 6. getDLoc */
PyObject* KX_ObjectActuator::PyGetDLoc(PyObject* self,
PyObject* args,
PyObject* kwds)
{
PyObject *retVal = PyList_New(4);
PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_dloc[0]));
PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_dloc[1]));
PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_dloc[2]));
PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.DLoc));
return retVal;
}
/* 7. setDLoc */
PyObject* KX_ObjectActuator::PySetDLoc(PyObject* self,
PyObject* args,
PyObject* kwds)
{
float vecArg[3];
int bToggle = 0;
if(!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
&vecArg[2], &bToggle)) {
return NULL;
}
m_dloc.setValue(vecArg);
m_bitLocalFlag.DLoc = PyArgToBool(bToggle);
UpdateFuzzyFlags();
Py_Return;
}
/* 8. getDRot */
PyObject* KX_ObjectActuator::PyGetDRot(PyObject* self,
PyObject* args,
PyObject* kwds)
{
PyObject *retVal = PyList_New(4);
PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_drot[0]));
PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_drot[1]));
PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_drot[2]));
PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.DRot));
return retVal;
}
/* 9. setDRot */
PyObject* KX_ObjectActuator::PySetDRot(PyObject* self,
PyObject* args,
PyObject* kwds)
{
float vecArg[3];
int bToggle = 0;
if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
&vecArg[2], &bToggle)) {
return NULL;
}
m_drot.setValue(vecArg);
m_bitLocalFlag.DRot = PyArgToBool(bToggle);
UpdateFuzzyFlags();
Py_Return;
}
/* 10. getLinearVelocity */
PyObject* KX_ObjectActuator::PyGetLinearVelocity(PyObject* self,
PyObject* args,
PyObject* kwds) {
PyObject *retVal = PyList_New(4);
PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_linear_velocity[0]));
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;
}
/* 11. setLinearVelocity */
PyObject* KX_ObjectActuator::PySetLinearVelocity(PyObject* self,
PyObject* args,
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)) {
return NULL;
}
m_linear_velocity.setValue(vecArg);
m_bitLocalFlag.LinearVelocity = PyArgToBool(bToggle);
m_bitLocalFlag.ClampVelocity = PyArgToBool(bClamp);
UpdateFuzzyFlags();
Py_Return;
}
/* 12. getAngularVelocity */
PyObject* KX_ObjectActuator::PyGetAngularVelocity(PyObject* self,
PyObject* args,
PyObject* kwds) {
PyObject *retVal = PyList_New(4);
PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_angular_velocity[0]));
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;
}
/* 13. setAngularVelocity */
PyObject* KX_ObjectActuator::PySetAngularVelocity(PyObject* self,
PyObject* args,
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)) {
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) {
int damping = 0;
if (!PyArg_ParseTuple(args, "i", &damping) || damping < 0 || damping > 1000) {
return NULL;
}
m_damping = damping;
Py_Return;
}
/* 13. getVelocityDamping */
PyObject* KX_ObjectActuator::PyGetVelocityDamping(PyObject* self,
PyObject* args,
PyObject* kwds) {
return Py_BuildValue("i",m_damping);
}
/* eof */