BGE logic patch: fix another incompatibility with YF.

Previous patch was not sorting the state actuators. This was causing 
some problems with YoFrankie that relies on the order of actuators
when multiple state actuators are activated at once.

Active state actuators will now be sorted per object. This doesn't
change the fact that state actuators are executed before all other
actuators as before.

Incidently, made the logic loop faster.
This commit is contained in:
2009-05-20 08:45:42 +00:00
parent dc6ae673b1
commit c0844b7938
9 changed files with 65 additions and 24 deletions

View File

@@ -67,6 +67,8 @@ void SCA_IActuator::Activate(SG_DList& head)
}
}
// this function is only used to deactivate actuators outside the logic loop
// e.g. when an object is deleted.
void SCA_IActuator::Deactivate()
{
if (QDelink())

View File

@@ -33,8 +33,7 @@
#include <vector>
/*
* Use of SG_DList : element of actuator being deactivated
* Head: SCA_LogicManager::m_removedActuators
* Use of SG_DList : None
* Use of SG_QList : element of activated actuator list of their owner
* Head: SCA_IObject::m_activeActuators
*/

View File

@@ -92,6 +92,34 @@ public:
it.add_back(this);
}
// insert in a QList at position corresponding to m_Execute_Priority
// inside a longer list that contains elements of other objects.
// Sorting is done only between the elements of the same object.
// head is the head of the combined list
// current points to the first element of the object in the list, NULL if none yet
void InsertSelfActiveQList(SG_QList& head, SG_QList** current)
{
if (!*current)
{
// first element can be put anywhere
head.QAddBack(this);
*current = this;
return;
}
// note: we assume current points actually to one o our element, skip the tests
SG_QList::iterator<SCA_ILogicBrick> it(head,*current);
if (m_Execute_Priority <= (*it)->m_Execute_Priority)
{
// this element comes before the first
*current = this;
}
else
{
for(++it; !it.end() && (*it)->m_gameobj == m_gameobj && m_Execute_Priority > (*it)->m_Execute_Priority; ++it);
}
it.add_back(this);
}
virtual bool LessComparedTo(SCA_ILogicBrick* other);
virtual PyObject* py_getattro(PyObject *attr);

View File

@@ -41,7 +41,8 @@
MT_Point3 SCA_IObject::m_sDummy=MT_Point3(0,0,0);
SG_QList SCA_IObject::m_activeBookmarkedControllers;
SCA_IObject::SCA_IObject(PyTypeObject* T): CValue(T), m_initState(0), m_state(0)
SCA_IObject::SCA_IObject(PyTypeObject* T): CValue(T), m_initState(0), m_state(0), m_firstState(NULL)
{
m_suspended = false;
}

View File

@@ -52,6 +52,7 @@ class SCA_IObject : public CValue
Py_Header;
protected:
friend class KX_StateActuator;
friend class SCA_IActuator;
friend class SCA_IController;
SCA_SensorList m_sensors;
@@ -97,6 +98,11 @@ protected:
*/
unsigned int m_state;
/**
* pointer inside state actuator list for sorting
*/
SG_QList* m_firstState;
public:
SCA_IObject(PyTypeObject* T=&Type);

View File

@@ -212,17 +212,22 @@ void SCA_LogicManager::UpdateFrame(double curtime, bool frame)
(*ie)->UpdateFrame();
SG_DList::iterator<SG_QList> io(m_activeActuators);
for (io.begin(); !io.end(); ++io)
for (io.begin(); !io.end(); )
{
SG_QList::iterator<SCA_IActuator> ia(*(*io));
for (ia.begin(); !ia.end(); ++ia)
SG_QList* ahead = *io;
// increment now so that we can remove the current element
++io;
SG_QList::iterator<SCA_IActuator> ia(*ahead);
for (ia.begin(); !ia.end(); )
{
SCA_IActuator* actua = *ia;
// increment first to allow removal of inactive actuators.
++ia;
if (!actua->Update(curtime, frame))
{
// cannot deactive the actuator now as it will disturb the list
m_removedActuators.AddBack(actua);
actua->SetActive(false);
// this actuator is not active anymore, remove
actua->QDelink();
actua->SetActive(false);
} else if (actua->IsNoLink())
{
// This actuator has no more links but it still active
@@ -235,14 +240,11 @@ void SCA_LogicManager::UpdateFrame(double curtime, bool frame)
actua->AddEvent(event);
}
}
}
for (SCA_IActuator* act = (SCA_IActuator*)m_removedActuators.Remove();
act != NULL;
act = (SCA_IActuator*)m_removedActuators.Remove())
{
act->Deactivate();
act->SetActive(false);
if (ahead->QEmpty())
{
// no more active controller, remove from main list
ahead->Delink();
}
}
}

View File

@@ -87,9 +87,6 @@ class SCA_LogicManager
GEN_Map<STR_HashedString,void*> m_map_gamemeshname_to_blendobj;
GEN_Map<CHashedPtr,void*> m_map_blendobj_to_gameobj;
// head of actuators being deactivated during the logic update
SG_DList m_removedActuators;
public:
SCA_LogicManager();
virtual ~SCA_LogicManager();

View File

@@ -73,7 +73,10 @@ KX_StateActuator::Update()
{
bool bNegativeEvent = IsNegativeEvent();
unsigned int objMask;
// execution of state actuator means that we are in the execution phase, reset this pointer
// because all the active actuator of this object will be removed for sure.
m_gameobj->m_firstState = NULL;
RemoveAllEvents();
if (bNegativeEvent) return false;
@@ -102,6 +105,8 @@ KX_StateActuator::Update()
return false;
}
// this function is only used to deactivate actuators outside the logic loop
// e.g. when an object is deleted.
void KX_StateActuator::Deactivate()
{
if (QDelink())
@@ -115,9 +120,10 @@ void KX_StateActuator::Deactivate()
void KX_StateActuator::Activate(SG_DList& head)
{
// no need to sort the state actuators
if (m_stateActuatorHead.QAddBack(this))
// sort the state actuators per object on the global list
if (QEmpty())
{
InsertSelfActiveQList(m_stateActuatorHead, &m_gameobj->m_firstState);
// add front to make sure it runs before other actuators
head.AddFront(&m_stateActuatorHead);
}

View File

@@ -49,7 +49,7 @@ public:
T* m_current;
public:
typedef iterator<T> _myT;
iterator(SG_QList& head) : m_head(head), m_current(NULL) {}
iterator(SG_QList& head, SG_QList* current=NULL) : m_head(head) { m_current = (T*)current; }
~iterator() {}
void begin()