forked from bartvdbraak/blender
15c105c157
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.
493 lines
15 KiB
C++
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 */
|