2010-07-14 11:03:54 +08:00
|
|
|
/****************************************************************************
|
2011-03-19 10:34:26 +08:00
|
|
|
Copyright (c) 2010-2011 cocos2d-x.org
|
|
|
|
Copyright (c) 2008-2010 Ricardo Quesada
|
2011-03-19 14:45:51 +08:00
|
|
|
|
2010-07-14 11:03:54 +08:00
|
|
|
http://www.cocos2d-x.org
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "CCScheduler.h"
|
|
|
|
#include "ccMacros.h"
|
|
|
|
#include "support/data_support/utlist.h"
|
2010-09-24 18:10:32 +08:00
|
|
|
#include "support/data_support/ccCArray.h"
|
2011-03-07 17:11:57 +08:00
|
|
|
#include "CCMutableArray.h"
|
2011-06-20 17:31:38 +08:00
|
|
|
#include "CCScriptSupport.h"
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
#include <assert.h>
|
2011-06-20 17:31:38 +08:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2010-08-04 15:46:12 +08:00
|
|
|
namespace cocos2d {
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
// data structures
|
|
|
|
|
2010-08-02 10:58:00 +08:00
|
|
|
// A list double-linked list used for "updates with priority"
|
|
|
|
typedef struct _listEntry
|
|
|
|
{
|
|
|
|
struct _listEntry *prev, *next;
|
|
|
|
SelectorProtocol *target; // not retained (retained by hashUpdateEntry)
|
2010-08-18 14:57:36 +08:00
|
|
|
int priority;
|
2010-08-02 10:58:00 +08:00
|
|
|
bool paused;
|
|
|
|
|
2010-07-14 11:03:54 +08:00
|
|
|
} tListEntry;
|
|
|
|
|
2010-08-02 10:58:00 +08:00
|
|
|
typedef struct _hashUpdateEntry
|
|
|
|
{
|
|
|
|
tListEntry **list; // Which list does it belong to ?
|
|
|
|
tListEntry *entry; // entry in the list
|
|
|
|
SelectorProtocol *target; // hash key (retained)
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} tHashUpdateEntry;
|
|
|
|
|
|
|
|
// Hash Element used for "selectors with interval"
|
|
|
|
typedef struct _hashSelectorEntry
|
|
|
|
{
|
2010-08-18 14:57:36 +08:00
|
|
|
ccArray *timers;
|
2010-08-02 10:58:00 +08:00
|
|
|
SelectorProtocol *target; // hash key (retained)
|
2010-08-18 14:57:36 +08:00
|
|
|
unsigned int timerIndex;
|
2010-08-02 10:58:00 +08:00
|
|
|
CCTimer *currentTimer;
|
|
|
|
bool currentTimerSalvaged;
|
|
|
|
bool paused;
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} tHashSelectorEntry;
|
2010-07-14 11:03:54 +08:00
|
|
|
|
2011-06-20 17:31:38 +08:00
|
|
|
// Hash Element used for "script functions with interval"
|
|
|
|
typedef struct _hashScriptFuncEntry
|
|
|
|
{
|
|
|
|
CCTimer *timer;
|
|
|
|
bool paused;
|
|
|
|
string funcName;
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} tHashScriptFuncEntry;
|
|
|
|
|
2010-07-14 11:03:54 +08:00
|
|
|
// implementation CCTimer
|
|
|
|
|
2011-06-20 17:31:38 +08:00
|
|
|
CCTimer::CCTimer()
|
|
|
|
: m_pTarget(NULL)
|
|
|
|
, m_scriptFunc("")
|
|
|
|
, m_fInterval(0.0f)
|
|
|
|
, m_fElapsed(0.0f)
|
|
|
|
, m_pfnSelector(NULL)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-07-14 11:03:54 +08:00
|
|
|
CCTimer* CCTimer::timerWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector)
|
|
|
|
{
|
|
|
|
CCTimer *pTimer = new CCTimer();
|
|
|
|
|
|
|
|
pTimer->initWithTarget(pTarget, pfnSelector);
|
|
|
|
pTimer->autorelease();
|
|
|
|
|
|
|
|
return pTimer;
|
|
|
|
}
|
|
|
|
|
2011-06-20 17:31:38 +08:00
|
|
|
CCTimer* CCTimer::timerWithScriptFuncName(const char* pszFuncName, ccTime fSeconds)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
CCTimer *pTimer = new CCTimer();
|
|
|
|
|
2011-06-20 17:31:38 +08:00
|
|
|
pTimer->initWithScriptFuncName(pszFuncName, fSeconds);
|
2010-07-14 11:03:54 +08:00
|
|
|
pTimer->autorelease();
|
|
|
|
|
|
|
|
return pTimer;
|
|
|
|
}
|
2011-06-20 17:31:38 +08:00
|
|
|
|
|
|
|
CCTimer* CCTimer::timerWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector, ccTime fSeconds)
|
2011-05-31 14:04:14 +08:00
|
|
|
{
|
|
|
|
CCTimer *pTimer = new CCTimer();
|
2011-06-20 17:31:38 +08:00
|
|
|
|
|
|
|
pTimer->initWithTarget(pTarget, pfnSelector, fSeconds);
|
2011-05-31 14:04:14 +08:00
|
|
|
pTimer->autorelease();
|
2011-06-20 17:31:38 +08:00
|
|
|
|
2011-05-31 14:04:14 +08:00
|
|
|
return pTimer;
|
|
|
|
}
|
|
|
|
|
2011-06-20 17:31:38 +08:00
|
|
|
bool CCTimer::initWithScriptFuncName(const char *pszFuncName, cocos2d::ccTime fSeconds)
|
2011-05-31 14:04:14 +08:00
|
|
|
{
|
2011-06-20 17:31:38 +08:00
|
|
|
m_scriptFunc = string(pszFuncName);
|
2011-05-31 14:04:14 +08:00
|
|
|
m_fInterval = fSeconds;
|
2011-06-20 17:31:38 +08:00
|
|
|
m_fElapsed = -1;
|
|
|
|
|
2011-05-31 14:04:14 +08:00
|
|
|
return true;
|
|
|
|
}
|
2011-06-20 17:31:38 +08:00
|
|
|
|
2010-07-14 11:03:54 +08:00
|
|
|
|
2010-09-04 13:39:37 +08:00
|
|
|
bool CCTimer::initWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
return initWithTarget(pTarget, pfnSelector, 0);
|
|
|
|
}
|
|
|
|
|
2010-09-04 13:39:37 +08:00
|
|
|
bool CCTimer::initWithTarget(SelectorProtocol *pTarget, SEL_SCHEDULE pfnSelector, ccTime fSeconds)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
m_pTarget = pTarget;
|
|
|
|
m_pfnSelector = pfnSelector;
|
|
|
|
m_fElapsed = -1;
|
|
|
|
m_fInterval = fSeconds;
|
|
|
|
|
2010-09-04 13:39:37 +08:00
|
|
|
return true;
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCTimer::update(ccTime dt)
|
|
|
|
{
|
|
|
|
if (m_fElapsed == -1)
|
|
|
|
{
|
|
|
|
m_fElapsed = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_fElapsed += dt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_fElapsed >= m_fInterval)
|
|
|
|
{
|
|
|
|
if (m_pfnSelector)
|
|
|
|
{
|
|
|
|
(m_pTarget->*m_pfnSelector)(m_fElapsed);
|
|
|
|
m_fElapsed = 0;
|
|
|
|
}
|
2011-05-31 14:04:14 +08:00
|
|
|
else if (m_scriptFunc.size())
|
|
|
|
{
|
2011-06-20 17:31:38 +08:00
|
|
|
// call script function
|
2011-06-21 11:47:57 +08:00
|
|
|
CCScriptEngineManager::sharedScriptEngineManager()->getScriptEngine()->executeSchedule(m_scriptFunc.c_str(), m_fElapsed);
|
2011-05-31 14:04:14 +08:00
|
|
|
m_fElapsed = 0;
|
|
|
|
}
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// implementation of CCScheduler
|
|
|
|
|
|
|
|
static CCScheduler *pSharedScheduler;
|
|
|
|
|
|
|
|
CCScheduler::CCScheduler(void)
|
2011-06-10 17:51:37 +08:00
|
|
|
: m_fTimeScale(0.0)
|
2011-04-01 16:06:53 +08:00
|
|
|
, m_pUpdatesNegList(NULL)
|
2011-06-10 17:51:37 +08:00
|
|
|
, m_pUpdates0List(NULL)
|
2011-04-01 16:06:53 +08:00
|
|
|
, m_pUpdatesPosList(NULL)
|
2011-06-10 17:51:37 +08:00
|
|
|
, m_pHashForUpdates(NULL)
|
|
|
|
, m_pHashForSelectors(NULL)
|
|
|
|
, m_pCurrentTarget(NULL)
|
|
|
|
, m_bCurrentTargetSalvaged(false)
|
2011-06-20 17:31:38 +08:00
|
|
|
, m_pHashForScriptFunctions(NULL)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
assert(pSharedScheduler == NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
CCScheduler::~CCScheduler(void)
|
|
|
|
{
|
|
|
|
unscheduleAllSelectors();
|
|
|
|
|
|
|
|
pSharedScheduler = NULL;
|
|
|
|
}
|
|
|
|
|
2010-11-16 15:12:09 +08:00
|
|
|
CCScheduler* CCScheduler::sharedScheduler(void)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
if (! pSharedScheduler)
|
|
|
|
{
|
|
|
|
pSharedScheduler = new CCScheduler();
|
|
|
|
pSharedScheduler->init();
|
|
|
|
}
|
|
|
|
|
|
|
|
return pSharedScheduler;
|
|
|
|
}
|
|
|
|
|
2010-09-04 13:39:37 +08:00
|
|
|
bool CCScheduler::init(void)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
m_fTimeScale = 1.0f;
|
|
|
|
|
|
|
|
// used to trigger CCTimer#update
|
|
|
|
// m_pfnUpdateSelector = &CCScheduler::update;
|
|
|
|
// impMethod = (TICK_IMP) [CCTimer instanceMethodForSelector:updateSelector];
|
|
|
|
|
|
|
|
// updates with priority
|
|
|
|
m_pUpdates0List = NULL;
|
|
|
|
m_pUpdatesNegList = NULL;
|
|
|
|
m_pUpdatesPosList = NULL;
|
|
|
|
m_pHashForUpdates = NULL;
|
2011-06-20 17:31:38 +08:00
|
|
|
m_pHashForScriptFunctions = NULL;
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
// selectors with interval
|
|
|
|
m_pCurrentTarget = NULL;
|
|
|
|
m_bCurrentTargetSalvaged = false;
|
|
|
|
m_pHashForSelectors = NULL;
|
|
|
|
|
2010-09-04 13:39:37 +08:00
|
|
|
return true;
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::removeHashElement(_hashSelectorEntry *pElement)
|
|
|
|
{
|
2010-08-18 14:57:36 +08:00
|
|
|
ccArrayFree(pElement->timers);
|
2010-08-30 15:45:39 +08:00
|
|
|
pElement->target->selectorProtocolRelease();
|
2010-08-18 14:57:36 +08:00
|
|
|
pElement->target = NULL;
|
2010-07-14 11:03:54 +08:00
|
|
|
HASH_DEL(m_pHashForSelectors, pElement);
|
|
|
|
free(pElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::scheduleTimer(CCTimer *pTimer)
|
|
|
|
{
|
2011-06-10 17:51:37 +08:00
|
|
|
CC_UNUSED_PARAM(pTimer);
|
2010-07-14 11:03:54 +08:00
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::unscheduleTimer(CCTimer *pTimer)
|
|
|
|
{
|
2011-06-10 17:51:37 +08:00
|
|
|
//CC_UNUSED_PARAM(pTimer);
|
|
|
|
pTimer = NULL;
|
|
|
|
assert(false);
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::unscheduleAllTimers()
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
}
|
2011-06-20 17:31:38 +08:00
|
|
|
|
2010-07-14 11:03:54 +08:00
|
|
|
void CCScheduler::scheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget, float fInterval, bool bPaused)
|
|
|
|
{
|
2011-05-31 14:04:14 +08:00
|
|
|
//assert(pfnSelector);
|
2010-12-29 10:30:42 +08:00
|
|
|
assert(pTarget);
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
tHashSelectorEntry *pElement = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForSelectors, &pTarget, pElement);
|
|
|
|
|
|
|
|
if (! pElement)
|
|
|
|
{
|
2011-06-20 17:31:38 +08:00
|
|
|
pElement = (tHashSelectorEntry *)calloc(sizeof(*pElement), 1);
|
2010-07-14 11:03:54 +08:00
|
|
|
pElement->target = pTarget;
|
2010-08-20 15:56:24 +08:00
|
|
|
if (pTarget)
|
|
|
|
{
|
2010-08-30 15:45:39 +08:00
|
|
|
pTarget->selectorProtocolRetain();
|
2010-08-20 15:56:24 +08:00
|
|
|
}
|
2010-07-14 11:03:54 +08:00
|
|
|
HASH_ADD_INT(m_pHashForSelectors, target, pElement);
|
|
|
|
|
|
|
|
// Is this the 1st element ? Then set the pause level to all the selectors of this target
|
|
|
|
pElement->paused = bPaused;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(pElement->paused == bPaused);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pElement->timers == NULL)
|
|
|
|
{
|
2010-08-18 14:57:36 +08:00
|
|
|
pElement->timers = ccArrayNew(10);
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
2010-12-28 15:05:55 +08:00
|
|
|
else
|
2010-09-24 18:10:32 +08:00
|
|
|
{
|
2010-12-28 15:05:55 +08:00
|
|
|
for (unsigned int i = 0; i < pElement->timers->num; ++i)
|
2010-09-24 18:10:32 +08:00
|
|
|
{
|
2010-12-28 15:05:55 +08:00
|
|
|
CCTimer *timer = (CCTimer*)pElement->timers->arr[i];
|
2011-06-20 17:31:38 +08:00
|
|
|
|
2010-12-28 15:05:55 +08:00
|
|
|
if (pfnSelector == timer->m_pfnSelector)
|
|
|
|
{
|
|
|
|
CCLOG("CCSheduler#scheduleSelector. Selector already scheduled.");
|
|
|
|
timer->m_fInterval = fInterval;
|
|
|
|
return;
|
2011-06-20 17:31:38 +08:00
|
|
|
}
|
2010-09-24 18:10:32 +08:00
|
|
|
}
|
2010-12-28 15:05:55 +08:00
|
|
|
ccArrayEnsureExtraCapacity(pElement->timers, 1);
|
2010-09-24 18:10:32 +08:00
|
|
|
}
|
|
|
|
|
2010-12-28 15:05:55 +08:00
|
|
|
CCTimer *pTimer = new CCTimer();
|
2011-06-20 17:31:38 +08:00
|
|
|
pTimer->initWithTarget(pTarget, pfnSelector, fInterval);
|
|
|
|
ccArrayAppendObject(pElement->timers, pTimer);
|
|
|
|
pTimer->release();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::scheduleScriptFunc(const char *pszFuncName, ccTime fInterval, bool bPaused)
|
|
|
|
{
|
|
|
|
//assert(pfnSelector);
|
|
|
|
assert(pszFuncName);
|
|
|
|
|
|
|
|
tHashScriptFuncEntry *pElement = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForScriptFunctions, &pszFuncName, pElement);
|
|
|
|
|
|
|
|
if (! pElement)
|
2011-05-31 14:04:14 +08:00
|
|
|
{
|
2011-06-20 17:31:38 +08:00
|
|
|
pElement = (tHashScriptFuncEntry *)calloc(sizeof(*pElement), 1);
|
|
|
|
pElement->funcName = string(pszFuncName);
|
|
|
|
pElement->timer = new CCTimer();
|
|
|
|
pElement->timer->initWithScriptFuncName(pszFuncName, fInterval);
|
|
|
|
pElement->paused = bPaused;
|
|
|
|
|
|
|
|
HASH_ADD_INT(m_pHashForScriptFunctions, funcName, pElement);
|
2011-05-31 14:04:14 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-20 17:31:38 +08:00
|
|
|
assert(pElement->paused == bPaused);
|
|
|
|
}
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
2011-06-20 17:31:38 +08:00
|
|
|
|
2010-07-14 11:03:54 +08:00
|
|
|
void CCScheduler::unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget)
|
|
|
|
{
|
|
|
|
// explicity handle nil arguments when removing an object
|
2010-12-29 10:30:42 +08:00
|
|
|
if (pTarget == 0 || pfnSelector == 0)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-05-31 14:04:14 +08:00
|
|
|
//assert(pTarget);
|
|
|
|
//assert(pfnSelector);
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
tHashSelectorEntry *pElement = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForSelectors, &pTarget, pElement);
|
|
|
|
|
|
|
|
if (pElement)
|
|
|
|
{
|
2010-08-18 14:57:36 +08:00
|
|
|
for (unsigned int i = 0; i < pElement->timers->num; ++i)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
2010-08-31 11:20:37 +08:00
|
|
|
CCTimer *pTimer = (CCTimer*)(pElement->timers->arr[i]);
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
if (pfnSelector == pTimer->m_pfnSelector)
|
|
|
|
{
|
|
|
|
if (pTimer == pElement->currentTimer && (! pElement->currentTimerSalvaged))
|
|
|
|
{
|
|
|
|
pElement->currentTimer->retain();
|
|
|
|
pElement->currentTimerSalvaged = true;
|
|
|
|
}
|
|
|
|
|
2010-08-18 14:57:36 +08:00
|
|
|
ccArrayRemoveObjectAtIndex(pElement->timers, i );
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
// update timerIndex in case we are in tick:, looping over the actions
|
|
|
|
if (pElement->timerIndex >= i)
|
|
|
|
{
|
|
|
|
pElement->timerIndex--;
|
|
|
|
}
|
|
|
|
|
2010-08-18 14:57:36 +08:00
|
|
|
if (pElement->timers->num == 0)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
if (m_pCurrentTarget == pElement)
|
|
|
|
{
|
|
|
|
m_bCurrentTargetSalvaged = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
removeHashElement(pElement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-20 17:31:38 +08:00
|
|
|
void CCScheduler::unscheduleScriptFunc(const char *pfzFuncName)
|
|
|
|
{
|
|
|
|
// explicity handle nil arguments when removing an object
|
|
|
|
if (pfzFuncName == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tHashScriptFuncEntry *pElement = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForScriptFunctions, &pfzFuncName, pElement);
|
|
|
|
|
|
|
|
if (pElement)
|
|
|
|
{
|
|
|
|
pElement->timer->release();
|
|
|
|
|
|
|
|
HASH_DEL(m_pHashForSelectors, pElement);
|
|
|
|
free(pElement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-02 10:58:00 +08:00
|
|
|
void CCScheduler::priorityIn(tListEntry **ppList, SelectorProtocol *pTarget, int nPriority, bool bPaused)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
2010-08-04 11:10:55 +08:00
|
|
|
tListEntry *pListElement = (tListEntry *)malloc(sizeof(*pListElement));
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
pListElement->target = pTarget;
|
|
|
|
pListElement->priority = nPriority;
|
|
|
|
pListElement->paused = bPaused;
|
|
|
|
pListElement->next = pListElement->prev = NULL;
|
|
|
|
// listElement->impMethod = (TICK_IMP) [target methodForSelector:updateSelector];
|
|
|
|
|
|
|
|
// empey list ?
|
|
|
|
if (! *ppList)
|
|
|
|
{
|
|
|
|
DL_APPEND(*ppList, pListElement);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bool bAdded = false;
|
|
|
|
|
|
|
|
for (tListEntry *pElement = *ppList; pElement; pElement = pElement->next)
|
|
|
|
{
|
|
|
|
if (nPriority < pElement->priority)
|
|
|
|
{
|
|
|
|
if (pElement == *ppList)
|
|
|
|
{
|
|
|
|
DL_PREPEND(*ppList, pListElement);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pListElement->next = pElement;
|
|
|
|
pListElement->prev = pElement->prev;
|
|
|
|
|
|
|
|
pElement->prev->next = pListElement;
|
|
|
|
pElement->prev = pListElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
bAdded = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not added? priority has the higher value. Append it.
|
|
|
|
if (! bAdded)
|
|
|
|
{
|
|
|
|
DL_APPEND(*ppList, pListElement);
|
|
|
|
}
|
|
|
|
}
|
2010-08-04 11:02:33 +08:00
|
|
|
|
|
|
|
// update hash entry for quick access
|
2010-08-04 11:10:55 +08:00
|
|
|
tHashUpdateEntry *pHashElement = (tHashUpdateEntry *)calloc(sizeof(*pHashElement), 1);
|
2010-08-04 11:02:33 +08:00
|
|
|
pHashElement->target = pTarget;
|
2010-08-30 15:45:39 +08:00
|
|
|
pTarget->selectorProtocolRetain();
|
2010-08-04 11:02:33 +08:00
|
|
|
pHashElement->list = ppList;
|
|
|
|
pHashElement->entry = pListElement;
|
|
|
|
HASH_ADD_INT(m_pHashForUpdates, target, pHashElement);
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::appendIn(_listEntry **ppList, SelectorProtocol *pTarget, bool bPaused)
|
|
|
|
{
|
2010-08-04 11:10:55 +08:00
|
|
|
tListEntry *pListElement = (tListEntry *)malloc(sizeof(*pListElement));
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
pListElement->target = pTarget;
|
|
|
|
pListElement->paused = bPaused;
|
|
|
|
// listElement->impMethod = (TICK_IMP) [target methodForSelector:updateSelector];
|
|
|
|
|
|
|
|
DL_APPEND(*ppList, pListElement);
|
|
|
|
|
|
|
|
// update hash entry for quicker access
|
|
|
|
tHashUpdateEntry *pHashElement = (tHashUpdateEntry *)calloc(sizeof(*pHashElement), 1);
|
2010-08-18 14:57:36 +08:00
|
|
|
pHashElement->target = pTarget;
|
2010-08-30 15:45:39 +08:00
|
|
|
pTarget->selectorProtocolRetain();
|
2010-07-14 11:03:54 +08:00
|
|
|
pHashElement->list = ppList;
|
|
|
|
pHashElement->entry = pListElement;
|
|
|
|
HASH_ADD_INT(m_pHashForUpdates, target, pHashElement);
|
|
|
|
}
|
|
|
|
|
2010-08-02 10:58:00 +08:00
|
|
|
void CCScheduler::scheduleUpdateForTarget(SelectorProtocol *pTarget, int nPriority, bool bPaused)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
#if COCOS2D_DEBUG >= 1
|
|
|
|
tHashUpdateEntry *pHashElement = NULL;
|
2010-12-06 09:51:21 +08:00
|
|
|
HASH_FIND_INT(m_pHashForUpdates, &pTarget, pHashElement);
|
2010-07-14 11:03:54 +08:00
|
|
|
assert(pHashElement == NULL);
|
|
|
|
#endif
|
|
|
|
|
2010-08-02 10:58:00 +08:00
|
|
|
// most of the updates are going to be 0, that's way there
|
2010-07-14 11:03:54 +08:00
|
|
|
// is an special list for updates with priority 0
|
|
|
|
if (nPriority == 0)
|
|
|
|
{
|
|
|
|
appendIn(&m_pUpdates0List, pTarget, bPaused);
|
|
|
|
} else
|
|
|
|
if (nPriority < 0)
|
|
|
|
{
|
|
|
|
priorityIn(&m_pUpdatesNegList, pTarget, nPriority, bPaused);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// priority > 0
|
|
|
|
priorityIn(&m_pUpdatesPosList, pTarget, nPriority, bPaused);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-05 14:38:42 +08:00
|
|
|
void CCScheduler::unscheduleUpdateForTarget(const SelectorProtocol *pTarget)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
if (pTarget == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tHashUpdateEntry *pElement = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForUpdates, &pTarget, pElement);
|
|
|
|
if (pElement)
|
|
|
|
{
|
|
|
|
// list entry
|
|
|
|
DL_DELETE(*pElement->list, pElement->entry);
|
|
|
|
free(pElement->entry);
|
|
|
|
|
|
|
|
// hash entry
|
2010-08-30 15:45:39 +08:00
|
|
|
pElement->target->selectorProtocolRelease();
|
2010-08-18 14:57:36 +08:00
|
|
|
pElement->target = NULL;
|
2010-07-14 11:03:54 +08:00
|
|
|
HASH_DEL(m_pHashForUpdates, pElement);
|
|
|
|
free(pElement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::unscheduleAllSelectors(void)
|
|
|
|
{
|
|
|
|
// Custom Selectors
|
2011-06-03 15:22:50 +08:00
|
|
|
tHashSelectorEntry *pElement = NULL;
|
|
|
|
tHashSelectorEntry *pNextElement = NULL;
|
2010-07-14 11:03:54 +08:00
|
|
|
for (pElement = m_pHashForSelectors; pElement != NULL;)
|
|
|
|
{
|
2011-06-03 15:22:50 +08:00
|
|
|
// pElement may be removed in unscheduleAllSelectorsForTarget
|
|
|
|
pNextElement = (tHashSelectorEntry *)pElement->hh.next;
|
2010-07-14 11:03:54 +08:00
|
|
|
unscheduleAllSelectorsForTarget(pElement->target);
|
2011-06-03 15:22:50 +08:00
|
|
|
|
|
|
|
pElement = pNextElement;
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Updates selectors
|
|
|
|
tListEntry *pEntry, *pTmp;
|
|
|
|
DL_FOREACH_SAFE(m_pUpdates0List, pEntry, pTmp)
|
|
|
|
{
|
|
|
|
unscheduleUpdateForTarget(pEntry->target);
|
|
|
|
}
|
|
|
|
DL_FOREACH_SAFE(m_pUpdatesNegList, pEntry, pTmp)
|
|
|
|
{
|
|
|
|
unscheduleUpdateForTarget(pEntry->target);
|
|
|
|
}
|
|
|
|
DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, pTmp)
|
|
|
|
{
|
|
|
|
unscheduleUpdateForTarget(pEntry->target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::unscheduleAllSelectorsForTarget(SelectorProtocol *pTarget)
|
|
|
|
{
|
|
|
|
// explicit NULL handling
|
|
|
|
if (pTarget == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Custom Selectors
|
|
|
|
tHashSelectorEntry *pElement = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForSelectors, &pTarget, pElement);
|
|
|
|
|
|
|
|
if (pElement)
|
|
|
|
{
|
2010-08-18 14:57:36 +08:00
|
|
|
if (ccArrayContainsObject(pElement->timers, pElement->currentTimer)
|
2010-07-14 11:03:54 +08:00
|
|
|
&& (! pElement->currentTimerSalvaged))
|
|
|
|
{
|
|
|
|
pElement->currentTimer->retain();
|
|
|
|
pElement->currentTimerSalvaged = true;
|
|
|
|
}
|
2010-08-18 14:57:36 +08:00
|
|
|
ccArrayRemoveAllObjects(pElement->timers);
|
2010-07-14 11:03:54 +08:00
|
|
|
|
|
|
|
if (m_pCurrentTarget == pElement)
|
|
|
|
{
|
|
|
|
m_bCurrentTargetSalvaged = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
removeHashElement(pElement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// update selector
|
|
|
|
unscheduleUpdateForTarget(pTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::resumeTarget(SelectorProtocol *pTarget)
|
|
|
|
{
|
|
|
|
assert(pTarget != NULL);
|
|
|
|
|
|
|
|
// custom selectors
|
|
|
|
tHashSelectorEntry *pElement = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForSelectors, &pTarget, pElement);
|
|
|
|
if (pElement)
|
|
|
|
{
|
|
|
|
pElement->paused = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update selector
|
|
|
|
tHashUpdateEntry *pElementUpdate = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForUpdates, &pTarget, pElementUpdate);
|
|
|
|
if (pElementUpdate)
|
|
|
|
{
|
|
|
|
assert(pElementUpdate->entry != NULL);
|
|
|
|
pElementUpdate->entry->paused = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCScheduler::pauseTarget(SelectorProtocol *pTarget)
|
|
|
|
{
|
|
|
|
assert(pTarget != NULL);
|
|
|
|
|
|
|
|
// custom selectors
|
|
|
|
tHashSelectorEntry *pElement = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForSelectors, &pTarget, pElement);
|
|
|
|
if (pElement)
|
|
|
|
{
|
|
|
|
pElement->paused = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update selector
|
|
|
|
tHashUpdateEntry *pElementUpdate = NULL;
|
|
|
|
HASH_FIND_INT(m_pHashForUpdates, &pTarget, pElementUpdate);
|
|
|
|
if (pElementUpdate)
|
|
|
|
{
|
|
|
|
assert(pElementUpdate->entry != NULL);
|
|
|
|
pElementUpdate->entry->paused = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// main loop
|
|
|
|
void CCScheduler::tick(ccTime dt)
|
|
|
|
{
|
|
|
|
if (m_fTimeScale != 1.0f)
|
|
|
|
{
|
|
|
|
dt *= m_fTimeScale;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate all over the Updates selectors
|
|
|
|
tListEntry *pEntry, *pTmp;
|
|
|
|
|
|
|
|
// updates with priority < 0
|
|
|
|
DL_FOREACH_SAFE(m_pUpdatesNegList, pEntry, pTmp)
|
|
|
|
{
|
|
|
|
if (! pEntry->paused)
|
|
|
|
{
|
|
|
|
pEntry->target->update(dt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// updates with priority == 0
|
|
|
|
DL_FOREACH_SAFE(m_pUpdates0List, pEntry, pTmp)
|
|
|
|
{
|
|
|
|
if (! pEntry->paused)
|
|
|
|
{
|
2011-06-20 17:31:38 +08:00
|
|
|
pEntry->target->update(dt);
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// updates with priority > 0
|
|
|
|
DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, pTmp)
|
|
|
|
{
|
|
|
|
if (! pEntry->paused)
|
|
|
|
{
|
2011-06-20 17:31:38 +08:00
|
|
|
pEntry->target->update(dt);
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interate all over the custom selectors
|
|
|
|
for (tHashSelectorEntry *elt = m_pHashForSelectors; elt != NULL; )
|
|
|
|
{
|
|
|
|
m_pCurrentTarget = elt;
|
|
|
|
m_bCurrentTargetSalvaged = false;
|
|
|
|
|
|
|
|
if (! m_pCurrentTarget->paused)
|
|
|
|
{
|
|
|
|
// The 'timers' array may change while inside this loop
|
2010-08-18 14:57:36 +08:00
|
|
|
for (elt->timerIndex = 0; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
2010-08-31 11:20:37 +08:00
|
|
|
elt->currentTimer = (CCTimer*)(elt->timers->arr[elt->timerIndex]);
|
2010-07-14 11:03:54 +08:00
|
|
|
elt->currentTimerSalvaged = false;
|
|
|
|
|
|
|
|
elt->currentTimer->update(dt);
|
|
|
|
|
|
|
|
if (elt->currentTimerSalvaged)
|
|
|
|
{
|
2010-08-02 10:58:00 +08:00
|
|
|
// The currentTimer told the remove itself. To prevent the timer from
|
|
|
|
// accidentally deallocating itself before finishing its step, we retained
|
2010-07-14 11:03:54 +08:00
|
|
|
// it. Now that step is done, it's safe to release it.
|
|
|
|
elt->currentTimer->release();
|
|
|
|
}
|
|
|
|
|
|
|
|
elt->currentTimer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-02 10:58:00 +08:00
|
|
|
// elt, at this moment, is still valid
|
2010-07-14 11:03:54 +08:00
|
|
|
// so it is safe to ask this here (issue #490)
|
|
|
|
elt = (tHashSelectorEntry *)elt->hh.next;
|
|
|
|
|
|
|
|
// only delete currentTarget if no actions were scheduled during the cycle (issue #481)
|
2010-08-18 14:57:36 +08:00
|
|
|
if (m_bCurrentTargetSalvaged && m_pCurrentTarget->timers->num == 0)
|
2010-07-14 11:03:54 +08:00
|
|
|
{
|
|
|
|
removeHashElement(m_pCurrentTarget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pCurrentTarget = NULL;
|
2011-06-20 17:31:38 +08:00
|
|
|
|
|
|
|
// Interate all script functions
|
|
|
|
for (tHashScriptFuncEntry *elt = m_pHashForScriptFunctions; elt != NULL; )
|
|
|
|
{
|
|
|
|
|
|
|
|
if (! elt->paused)
|
|
|
|
{
|
|
|
|
elt->timer->update(dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
elt = (tHashScriptFuncEntry *)elt->hh.next;
|
|
|
|
}
|
2010-07-14 11:03:54 +08:00
|
|
|
}
|
2010-08-02 12:00:06 +08:00
|
|
|
|
|
|
|
void CCScheduler::purgeSharedScheduler(void)
|
|
|
|
{
|
|
|
|
pSharedScheduler->release();
|
2010-12-28 15:05:55 +08:00
|
|
|
pSharedScheduler = NULL;
|
2010-08-02 12:00:06 +08:00
|
|
|
}
|
2010-08-04 15:46:12 +08:00
|
|
|
}//namespace cocos2d
|