BGE Animations: Various fixes and bits of cleanup to get the action actuator to behave more like it did in trunk. The Pepper version is still more sensitive to pulses than the trunk version, but this is more accurate. I might try to address this, but I'm not sure.

This commit is contained in:
Mitchell Stokes 2011-07-05 05:22:02 +00:00
parent afd77d081a
commit ceabc6d119
8 changed files with 168 additions and 85 deletions

@ -61,6 +61,49 @@ extern "C" {
#include "RNA_define.h"
}
BL_ActionActuator::BL_ActionActuator(SCA_IObject* gameobj,
const STR_String& propname,
const STR_String& framepropname,
float starttime,
float endtime,
struct bAction *action,
short playtype,
short blendin,
short priority,
short layer,
float layer_weight,
short ipo_flags,
short end_reset,
float stride)
: SCA_IActuator(gameobj, KX_ACT_ACTION),
m_lastpos(0, 0, 0),
m_blendframe(0),
m_flag(0),
m_startframe (starttime),
m_endframe(endtime) ,
m_starttime(0),
m_localtime(starttime),
m_lastUpdate(-1),
m_blendin(blendin),
m_blendstart(0),
m_stridelength(stride),
m_playtype(playtype),
m_priority(priority),
m_layer(layer),
m_layer_weight(layer_weight),
m_ipo_flags(ipo_flags),
m_pose(NULL),
m_blendpose(NULL),
m_userpose(NULL),
m_action(action),
m_propname(propname),
m_framepropname(framepropname)
{
if (!end_reset)
m_flag |= ACT_FLAG_CONTINUE;
};
BL_ActionActuator::~BL_ActionActuator()
{
if (m_pose)
@ -92,6 +135,7 @@ CValue* BL_ActionActuator::GetReplica() {
return replica;
}
#if 0
bool BL_ActionActuator::ClampLocalTime()
{
if (m_startframe < m_endframe)
@ -143,7 +187,7 @@ void BL_ActionActuator::SetLocalTime(float curtime)
else
m_localtime = m_endframe - delta_time;
}
#endif
bool BL_ActionActuator::Update(double curtime, bool frame)
{
bool bNegativeEvent = false;
@ -156,10 +200,6 @@ bool BL_ActionActuator::Update(double curtime, bool frame)
if (!m_action)
return false;
// Don't do anything if we're not "active"
if (!frame)
return true;
// Convert playmode
if (m_playtype == ACT_ACTION_LOOP_END)
play_mode = BL_Action::ACT_MODE_LOOP;
@ -173,32 +213,56 @@ bool BL_ActionActuator::Update(double curtime, bool frame)
play_mode = BL_Action::ACT_MODE_PLAY;
start = end = prop->GetNumber();
m_is_going = false;
}
// Handle events
if (frame)
{
bNegativeEvent = m_negevent;
bPositiveEvent = m_posevent;
RemoveAllEvents();
if (!m_is_going && bPositiveEvent)
{
m_is_going = true;
if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, play_mode, m_layer_weight, m_ipo_flags) && m_end_reset)
obj->SetActionFrame(m_layer, m_localtime);
}
else if (m_is_going && bNegativeEvent)
if (bPositiveEvent)
{
if (m_playtype == ACT_ACTION_LOOP_STOP)
if (m_flag & ACT_FLAG_ACTIVE && m_flag & ACT_FLAG_CONTINUE)
start = m_localtime = obj->GetActionFrame(m_layer);
if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, play_mode, m_layer_weight, m_ipo_flags))
{
if (!m_end_reset)
m_flag |= ACT_FLAG_ACTIVE;
if (m_flag & ACT_FLAG_CONTINUE)
obj->SetActionFrame(m_layer, m_localtime);
if (m_playtype == ACT_ACTION_PLAY)
m_flag |= ACT_FLAG_PLAY_END;
else
m_flag &= ~ACT_FLAG_PLAY_END;
}
else
return false;
}
else if ((m_flag & ACT_FLAG_ACTIVE) && bNegativeEvent)
{
obj->StopAction(m_layer);
bAction *curr_action = obj->GetCurrentAction(m_layer);
if (curr_action && curr_action != m_action)
{
// Someone changed the action on us, so we wont mess with it
// Hopefully there wont be too many problems with two actuators using
// the same action...
m_flag &= ~ACT_FLAG_ACTIVE;
return false;
}
if (m_playtype == ACT_ACTION_LOOP_STOP)
{
m_localtime = obj->GetActionFrame(m_layer);
obj->StopAction(m_layer); // Stop the action after getting the frame
// We're done
m_flag &= ~ACT_FLAG_ACTIVE;
return false;
}
else if (m_playtype == ACT_ACTION_LOOP_END)
{
@ -207,7 +271,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame)
obj->StopAction(m_layer);
obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags);
return true;
m_flag |= ACT_FLAG_PLAY_END;
}
else if (m_playtype == ACT_ACTION_FLIPPER)
{
@ -217,14 +281,12 @@ bool BL_ActionActuator::Update(double curtime, bool frame)
obj->StopAction(m_layer);
obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags);
return true;
m_flag |= ACT_FLAG_PLAY_END;
}
m_is_going = false;
}
// Handle a frame property if it's defined
if (m_is_going && m_framepropname[0] != 0)
if ((m_flag & ACT_FLAG_ACTIVE) && m_framepropname[0] != 0)
{
CValue* oldprop = obj->GetProperty(m_framepropname);
CValue* newval = new CFloatValue(obj->GetActionFrame(m_layer));
@ -235,10 +297,11 @@ bool BL_ActionActuator::Update(double curtime, bool frame)
newval->Release();
}
// Handle a finished animation
if (m_is_going && obj->IsActionDone(m_layer))
if ((m_flag & ACT_FLAG_PLAY_END) && obj->IsActionDone(m_layer))
{
m_is_going = false;
m_flag &= ~ACT_FLAG_ACTIVE;
obj->StopAction(m_layer);
return false;
}
@ -740,7 +803,7 @@ PyAttributeDef BL_ActionActuator::Attributes[] = {
KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ActionActuator, m_localtime, CheckFrame),
KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ActionActuator, m_propname),
KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ActionActuator, m_framepropname),
KX_PYATTRIBUTE_BOOL_RW("useContinue", BL_ActionActuator, m_end_reset),
KX_PYATTRIBUTE_RW_FUNCTION("useContinue", BL_ActionActuator, pyattr_get_use_continue, pyattr_set_use_continue),
KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ActionActuator, m_blendframe, CheckBlendTime),
KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ActionActuator,m_playtype,CheckType),
{ NULL } //Sentinel
@ -800,4 +863,22 @@ PyObject* BL_ActionActuator::pyattr_get_channel_names(void *self_v, const KX_PYA
return ret;
}
PyObject* BL_ActionActuator::pyattr_get_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v);
return PyBool_FromLong(self->m_flag & ACT_FLAG_CONTINUE);
}
int BL_ActionActuator::pyattr_set_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
{
BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v);
if (PyObject_IsTrue(value))
self->m_flag |= ACT_FLAG_CONTINUE;
else
self->m_flag &= ~ACT_FLAG_CONTINUE;
return PY_SET_ATTR_SUCCESS;
}
#endif // WITH_PYTHON

@ -56,35 +56,8 @@ public:
float layer_weight,
short ipo_flags,
short end_reset,
float stride)
: SCA_IActuator(gameobj, KX_ACT_ACTION),
float stride);
m_lastpos(0, 0, 0),
m_blendframe(0),
m_flag(0),
m_startframe (starttime),
m_endframe(endtime) ,
m_starttime(0),
m_localtime(starttime),
m_lastUpdate(-1),
m_blendin(blendin),
m_blendstart(0),
m_stridelength(stride),
m_playtype(playtype),
m_priority(priority),
m_layer(layer),
m_layer_weight(layer_weight),
m_ipo_flags(ipo_flags),
m_end_reset(end_reset),
m_is_going(false),
m_pose(NULL),
m_blendpose(NULL),
m_userpose(NULL),
m_action(action),
m_propname(propname),
m_framepropname(framepropname)
{
};
virtual ~BL_ActionActuator();
virtual bool Update(double curtime, bool frame);
virtual CValue* GetReplica();
@ -103,6 +76,9 @@ public:
static PyObject* pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_channel_names(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
/* attribute check */
static int CheckFrame(void *self, const PyAttributeDef*)
{
@ -147,9 +123,9 @@ public:
protected:
void SetStartTime(float curtime);
void SetLocalTime(float curtime);
bool ClampLocalTime();
//void SetStartTime(float curtime);
//void SetLocalTime(float curtime);
//bool ClampLocalTime();
MT_Point3 m_lastpos;
float m_blendframe;
@ -172,8 +148,6 @@ protected:
short m_priority;
short m_layer;
short m_ipo_flags;
bool m_end_reset;
bool m_is_going;
struct bPose* m_pose;
struct bPose* m_blendpose;
struct bPose* m_userpose;
@ -183,10 +157,13 @@ protected:
};
enum {
ACT_FLAG_REVERSE = 0x00000001,
ACT_FLAG_LOCKINPUT = 0x00000002,
ACT_FLAG_KEYUP = 0x00000004,
ACT_FLAG_ACTIVE = 0x00000008
ACT_FLAG_REVERSE = 1<<0,
ACT_FLAG_LOCKINPUT = 1<<1,
ACT_FLAG_KEYUP = 1<<2,
ACT_FLAG_ACTIVE = 1<<3,
ACT_FLAG_CONTINUE = 1<<4,
ACT_FLAG_PLAY_END = 1<<5
};
#endif

@ -62,8 +62,7 @@ BL_Action::BL_Action(class KX_GameObject* gameobj)
m_blendinpose(NULL),
m_sg_contr(NULL),
m_ptrrna(NULL),
m_done(true),
m_bcalc_local_time(true)
m_done(true)
{
if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
{
@ -197,6 +196,11 @@ void BL_Action::InitIPO()
m_sg_contr->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, m_ipo_flags & ACT_IPOFLAG_LOCAL);
}
bAction *BL_Action::GetAction()
{
return (IsDone()) ? NULL : m_action;
}
float BL_Action::GetFrame()
{
return m_localtime;
@ -204,14 +208,24 @@ float BL_Action::GetFrame()
void BL_Action::SetFrame(float frame)
{
float dt;
// Clamp the frame to the start and end frame
if (frame < min(m_startframe, m_endframe))
frame = min(m_startframe, m_endframe);
else if (frame > max(m_startframe, m_endframe))
frame = max(m_startframe, m_endframe);
m_localtime = frame;
m_bcalc_local_time = false;
// We don't set m_localtime directly since it's recalculated
// in the next update. So, we modify the value (m_starttime)
// used to calculate m_localtime the next time SetLocalTime() is called.
dt = frame-m_startframe;
if (m_endframe < m_startframe)
dt = -dt;
m_starttime -= dt / (KX_KetsjiEngine::GetAnimFrameRate()*m_speed);
}
void BL_Action::SetLocalTime(float curtime)
@ -263,16 +277,8 @@ void BL_Action::Update(float curtime)
if (m_done)
return;
// We only want to calculate the current time if we weren't given a frame (e.g., from SetFrame())
if (m_bcalc_local_time)
{
curtime -= KX_KetsjiEngine::GetSuspendedDelta();
SetLocalTime(curtime);
}
else
{
m_bcalc_local_time = true;
}
// Handle wrap around
if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe))

@ -66,7 +66,6 @@ private:
short m_ipo_flags;
bool m_done;
bool m_bcalc_local_time;
void InitIPO();
void SetLocalTime(float curtime);
@ -91,6 +90,7 @@ public:
// Accessors
float GetFrame();
struct bAction *GetAction();
// Mutators
void SetFrame(float frame);

@ -56,6 +56,12 @@ void BL_ActionManager::SetActionFrame(short layer, float frame)
m_layers[layer]->SetFrame(frame);
}
struct bAction *BL_ActionManager::GetCurrentAction(short layer)
{
if (m_layers[layer])
return m_layers[layer]->GetAction();
}
bool BL_ActionManager::PlayAction(const char* name,
float start,
float end,

@ -56,6 +56,8 @@ public:
float GetActionFrame(short layer);
void SetActionFrame(short layer, float frame);
struct bAction *GetCurrentAction(short layer);
void StopAction(short layer);
bool IsActionDone(short layer);
void Update(float);

@ -399,6 +399,11 @@ void KX_GameObject::SetActionFrame(short layer, float frame)
GetActionManager()->SetActionFrame(layer, frame);
}
bAction *KX_GameObject::GetCurrentAction(short layer)
{
return GetActionManager()->GetCurrentAction(layer);
}
void KX_GameObject::ProcessReplica()
{
SCA_IObject::ProcessReplica();

@ -65,6 +65,7 @@ class PHY_IGraphicController;
class PHY_IPhysicsEnvironment;
class BL_ActionManager;
struct Object;
struct bAction;
#ifdef WITH_PYTHON
/* utility conversion function */
@ -232,6 +233,11 @@ public:
*/
void SetActionFrame(short layer, float frame);
/**
* Gets the currently running action on the given layer
*/
bAction *GetCurrentAction(short layer);
/**
* Remove an action from the object's action manager
*/