复制后面的代码覆盖CCScheduler.cpp和CCScheduler.h ,因为我使用了pthread.h,所以用vs开发的程序猿要注意加包含目录和依赖库,xcode开发的就不用了。
用法:CCDirector::sharedDirector()->getScheduler()->performFunctionInCocosThread(this, callfuncO_selector(CLayerShopBack::func), obj); obj是传给CLayerShopBack::func函数的数据,大家一看就知道怎么用了。
使用范围:因为我用2.x版本开发项目,接入android的sdk后,需要java中调用c++函数更新界面,虽然我在java中用了cocos2dxglsurface,但是好像还是有问题,所以才写了这个方法,把java调c++函数传过来的数据给obj (CCDirector::sharedDirector()->getScheduler()->performFunctionInCocosThread(this, callfuncO_selector(CLayerShopBack::func), obj); ) 然后在CLayerShopBack::func里面更新界面。。。因为我之前用的schedule方式,java调c++函数,设置一个标识,然后schedule监听到这个标识改变就说明要更新界面了,这样感觉很麻烦,所以我才封装了那个函数,使用更方便了。 我是参考3.x版本来写的。当然这个函数可以用在需要的地方。
代码如下:
//CCScheduler.h
#ifndef CCSCHEDULER_H
#define CCSCHEDULER_H
#include “cocoa/CCObject.h”
#include “support/data_support/uthash.h”
#include <pthread.h>
#include
NS_CC_BEGIN
/**
- @addtogroup global
- @{
*/
// Priority level reserved for system services.
#define kCCPrioritySystem INT_MIN
// Minimum priority level for user scheduling.
#define kCCPriorityNonSystemMin (kCCPrioritySystem+1)
class CCSet;
//
// CCTimer
//
/** @brief Light-weight timer */
//
class CC_DLL CCTimer : public CCObject
{
public:
CCTimer(void);
/** get interval in seconds /
float getInterval(void) const;
/* set interval in seconds */
void setInterval(float fInterval);
SEL_SCHEDULE getSelector() const;
/** Initializes a timer with a target and a selector. */
bool initWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector);
/** Initializes a timer with a target, a selector and an interval in seconds, repeat in number of times to repeat, delay in seconds. */
bool initWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector, float fSeconds, unsigned int nRepeat, float fDelay);
/** Initializes a timer with a script callback function and an interval in seconds. */
bool initWithScriptHandler(int nHandler, float fSeconds);
/** triggers the timer */
void update(float dt);
public:
/** Allocates a timer with a target and a selector. /
static CCTimer timerWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector);
/** Allocates a timer with a target, a selector and an interval in seconds. /
static CCTimer timerWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector, float fSeconds);
/** Allocates a timer with a script callback function and an interval in seconds. /
static CCTimer timerWithScriptHandler(int nHandler, float fSeconds);
inline int getScriptHandler() { return m_nScriptHandler; };
protected:
CCObject *m_pTarget;
float m_fElapsed;
bool m_bRunForever;
bool m_bUseDelay;
unsigned int m_uTimesExecuted;
unsigned int m_uRepeat; //0 = once, 1 is 2 x executed
float m_fDelay;
float m_fInterval;
SEL_SCHEDULE m_pfnSelector;
int m_nScriptHandler;
};
//
// CCScheduler
//
struct _listEntry;
struct _hashSelectorEntry;
struct _hashUpdateEntry;
class CCArray;
/** @brief Scheduler is responsible for triggering the scheduled callbacks.
You should not use NSTimer. Instead use this class.
There are 2 different types of callbacks (selectors):
- update selector: the ‘update’ selector will be called every frame. You can customize the priority.
- custom selector: A custom selector will be called every frame, or with a custom interval of time
The ‘custom selectors’ should be avoided when possible. It is faster, and consumes less memory to use the ‘update selector’.
*/
typedef struct worker
{
/回调函数,任务运行时会调用此函数,注意也可声明成其它形式/
void (CCObject::*process) (CCObject *arg);
CCObject arg;/回调函数的参数/
CCObject pTarget;
} Worker;
class CC_DLL CCScheduler : public CCObject
{
public:
CCScheduler();
~CCScheduler(void);
inline float getTimeScale(void) { return m_fTimeScale; }
/** Modifies the time of all scheduled callbacks.
You can use this property to create a ‘slow motion’ or ‘fast forward’ effect.
Default is 1.0. To create a ‘slow motion’ effect, use values below 1.0.
To create a ‘fast forward’ effect, use values higher than 1.0.
@since v0.8
@warning It will affect EVERY scheduled selector / action.
*/
inline void setTimeScale(float fTimeScale) { m_fTimeScale = fTimeScale; }
/** ‘update’ the scheduler.
You should NEVER call this method, unless you know what you are doing.
*/
void update(float dt);
/** The scheduled method will be called every ‘interval’ seconds.
If paused is YES, then it won’t be called until it is resumed.
If ‘interval’ is 0, it will be called every frame, but if so, it’s recommended to use ‘scheduleUpdateForTarget:’ instead.
If the selector is already scheduled, then only the interval parameter will be updated without re-scheduling it again.
repeat let the action be repeated repeat + 1 times, use kCCRepeatForever to let the action run continuously
delay is the amount of time the action will wait before it’ll start
@since v0.99.3, repeat and delay added in v1.1
*/
void scheduleSelector(SEL_SCHEDULE pfnSelector, CCObject *pTarget, float fInterval, unsigned int repeat, float delay, bool bPaused);
/** calls scheduleSelector with kCCRepeatForever and a 0 delay /
void scheduleSelector(SEL_SCHEDULE pfnSelector, CCObject pTarget, float fInterval, bool bPaused);
/ Schedules the ‘update’ selector for a given target with a given priority.
The ‘update’ selector will be called every frame.
The lower the priority, the earlier it is called.
@since v0.99.3
*/
void scheduleUpdateForTarget(CCObject *pTarget, int nPriority, bool bPaused);
/** Unschedule a selector for a given target.
If you want to unschedule the “update”, use unscheudleUpdateForTarget.
@since v0.99.3
*/
void unscheduleSelector(SEL_SCHEDULE pfnSelector, CCObject *pTarget);
/** Unschedules the update selector for a given target
@since v0.99.3
*/
void unscheduleUpdateForTarget(const CCObject *pTarget);
/** Unschedules all selectors for a given target.
This also includes the “update” selector.
@since v0.99.3
*/
void unscheduleAllForTarget(CCObject *pTarget);
/** Unschedules all selectors from all targets.
You should NEVER call this method, unless you know what you are doing.
@since v0.99.3
*/
void unscheduleAll(void);
/** Unschedules all selectors from all targets with a minimum priority.
You should only call this with kCCPriorityNonSystemMin or higher.
@since v2.0.0
*/
void unscheduleAllWithMinPriority(int nMinPriority);
/** The scheduled script callback will be called every ‘interval’ seconds.
If paused is YES, then it won’t be called until it is resumed.
If ‘interval’ is 0, it will be called every frame.
return schedule script entry ID, used for unscheduleScriptFunc().
*/
unsigned int scheduleScriptFunc(unsigned int nHandler, float fInterval, bool bPaused);
/** Unschedule a script entry. */
void unscheduleScriptEntry(unsigned int uScheduleScriptEntryID);
/** Pauses the target.
All scheduled selectors/update for a given target won’t be ‘ticked’ until the target is resumed.
If the target is not present, nothing happens.
@since v0.99.3
*/
void pauseTarget(CCObject *pTarget);
/** Resumes the target.
The ‘target’ will be unpaused, so all schedule selectors/update will be ‘ticked’ again.
If the target is not present, nothing happens.
@since v0.99.3
*/
void resumeTarget(CCObject *pTarget);
/** Returns whether or not the target is paused
@since v1.0.0
*/
bool isTargetPaused(CCObject *pTarget);
/** Pause all selectors from all targets.
You should NEVER call this method, unless you know what you are doing.
@since v2.0.0
/
CCSet pauseAllTargets();
/** Pause all selectors from all targets with a minimum priority.
You should only call this with kCCPriorityNonSystemMin or higher.
@since v2.0.0
/
CCSet pauseAllTargetsWithMinPriority(int nMinPriority);
/** Resume selectors on a set of targets.
This can be useful for undoing a call to pauseAllSelectors.
@since v2.0.0
/
void resumeTargets(CCSet targetsToResume);
//自己添加
void performFunctionInCocosThread(CCObject* pTarget,void (CCObject::func)(CCObject arg),CCObject* arg);
CCNode* seekNodeByAddress(CCNode* root, int addr);
private:
void removeHashElement(struct _hashSelectorEntry *pElement);
void removeUpdateFromHash(struct _listEntry *entry);
// update specific
void priorityIn(struct _listEntry **ppList, CCObject *pTarget, int nPriority, bool bPaused);
void appendIn(struct _listEntry **ppList, CCObject *pTarget, bool bPaused);
protected:
float m_fTimeScale;
//
// “updates with priority” stuff
//
struct _listEntry *m_pUpdatesNegList; // list of priority < 0
struct _listEntry *m_pUpdates0List; // list priority == 0
struct _listEntry *m_pUpdatesPosList; // list priority > 0
struct _hashUpdateEntry *m_pHashForUpdates; // hash used to fetch quickly the list entries for pause,delete,etc
// Used for “selectors with interval”
struct _hashSelectorEntry *m_pHashForTimers;
struct _hashSelectorEntry m_pCurrentTarget;
bool m_bCurrentTargetSalvaged;
// If true unschedule will not remove anything from a hash. Elements will only be marked for deletion.
bool m_bUpdateHashLocked;
CCArray m_pScriptHandlerEntries;
std::vector<Worker*> _functionsToPerform;
pthread_mutex_t _performMutex; //互斥锁
};
// end of global group
/// @}
NS_CC_END
#endif // CCSCHEDULER_H
#include “CCScheduler.h”
#include “ccMacros.h”
#include “CCDirector.h”
#include “support/data_support/utlist.h”
#include “support/data_support/ccCArray.h”
#include “cocoa/CCArray.h”
#include “script_support/CCScriptSupport.h”
using namespace std;
NS_CC_BEGIN
// data structures
// A list double-linked list used for “updates with priority”
typedef struct _listEntry
{
struct _listEntry *prev, *next;
CCObject *target; // not retained (retained by hashUpdateEntry)
int priority;
bool paused;
bool markedForDeletion; // selector will no longer be called and entry will be removed at end of the next tick
} tListEntry;
typedef struct _hashUpdateEntry
{
tListEntry **list; // Which list does it belong to ?
tListEntry *entry; // entry in the list
CCObject *target; // hash key (retained)
UT_hash_handle hh;
} tHashUpdateEntry;
// Hash Element used for “selectors with interval”
typedef struct _hashSelectorEntry
{
ccArray *timers;
CCObject *target; // hash key (retained)
unsigned int timerIndex;
CCTimer *currentTimer;
bool currentTimerSalvaged;
bool paused;
UT_hash_handle hh;
} tHashTimerEntry;
// implementation CCTimer
CCTimer::CCTimer()
: m_pTarget(NULL)
, m_fElapsed(-1)
, m_bRunForever(false)
, m_bUseDelay(false)
, m_uTimesExecuted(0)
, m_uRepeat(0)
, m_fDelay(0.0f)
, m_fInterval(0.0f)
, m_pfnSelector(NULL)
, m_nScriptHandler(0)
{
}
CCTimer* CCTimer::timerWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector)
{
CCTimer *pTimer = new CCTimer();
pTimer->initWithTarget(pTarget, pfnSelector, 0.0f, kCCRepeatForever, 0.0f);
pTimer->autorelease();
return pTimer;
}
CCTimer* CCTimer::timerWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector, float fSeconds)
{
CCTimer *pTimer = new CCTimer();
pTimer->initWithTarget(pTarget, pfnSelector, fSeconds, kCCRepeatForever, 0.0f);
pTimer->autorelease();
return pTimer;
}
CCTimer* CCTimer::timerWithScriptHandler(int nHandler, float fSeconds)
{
CCTimer *pTimer = new CCTimer();
pTimer->initWithScriptHandler(nHandler, fSeconds);
pTimer->autorelease();
return pTimer;
}
bool CCTimer::initWithScriptHandler(int nHandler, float fSeconds)
{
m_nScriptHandler = nHandler;
m_fElapsed = -1;
m_fInterval = fSeconds;
return true;
}
bool CCTimer::initWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector)
{
return initWithTarget(pTarget, pfnSelector, 0, kCCRepeatForever, 0.0f);
}
bool CCTimer::initWithTarget(CCObject *pTarget, SEL_SCHEDULE pfnSelector, float fSeconds, unsigned int nRepeat, float fDelay)
{
m_pTarget = pTarget;
m_pfnSelector = pfnSelector;
m_fElapsed = -1;
m_fInterval = fSeconds;
m_fDelay = fDelay;
m_bUseDelay = (fDelay > 0.0f) ? true : false;
m_uRepeat = nRepeat;
m_bRunForever = (nRepeat == kCCRepeatForever) ? true : false;
return true;
}
void CCTimer::update(float dt)
{
if (m_fElapsed == -1)
{
m_fElapsed = 0;
m_uTimesExecuted = 0;
}
else
{
if (m_bRunForever && !m_bUseDelay)
{//standard timer usage
m_fElapsed += dt;
if (m_fElapsed >= m_fInterval)
{
if (m_pTarget && m_pfnSelector)
{
(m_pTarget->*m_pfnSelector)(m_fElapsed);
}
if (m_nScriptHandler)
{
CCScriptEngineManager::sharedManager()->getScriptEngine()->executeSchedule(m_nScriptHandler, m_fElapsed);
}
m_fElapsed = 0;
}
}
else
{//advanced usage
m_fElapsed += dt;
if (m_bUseDelay)
{
if( m_fElapsed >= m_fDelay )
{
if (m_pTarget && m_pfnSelector)
{
(m_pTarget->*m_pfnSelector)(m_fElapsed);
}
if (m_nScriptHandler)
{
CCScriptEngineManager::sharedManager()->getScriptEngine()->executeSchedule(m_nScriptHandler, m_fElapsed);
}
m_fElapsed = m_fElapsed - m_fDelay;
m_uTimesExecuted += 1;
m_bUseDelay = false;
}
}
else
{
if (m_fElapsed >= m_fInterval)
{
if (m_pTarget && m_pfnSelector)
{
(m_pTarget->*m_pfnSelector)(m_fElapsed);
}
if (m_nScriptHandler)
{
CCScriptEngineManager::sharedManager()->getScriptEngine()->executeSchedule(m_nScriptHandler, m_fElapsed);
}
m_fElapsed = 0;
m_uTimesExecuted += 1;
}
}
if (!m_bRunForever && m_uTimesExecuted > m_uRepeat)
{ //unschedule timer
CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(m_pfnSelector, m_pTarget);
}
}
}
}
float CCTimer::getInterval() const
{
return m_fInterval;
}
void CCTimer::setInterval(float fInterval)
{
m_fInterval = fInterval;
}
SEL_SCHEDULE CCTimer::getSelector() const
{
return m_pfnSelector;
}
// implementation of CCScheduler
CCScheduler::CCScheduler(void)
: m_fTimeScale(1.0f)
, m_pUpdatesNegList(NULL)
, m_pUpdates0List(NULL)
, m_pUpdatesPosList(NULL)
, m_pHashForUpdates(NULL)
, m_pHashForTimers(NULL)
, m_pCurrentTarget(NULL)
, m_bCurrentTargetSalvaged(false)
, m_bUpdateHashLocked(false)
, m_pScriptHandlerEntries(NULL)
{
pthread_mutex_init (&(this->_performMutex), NULL);
_functionsToPerform.clear();
}
CCScheduler::~CCScheduler(void)
{
unscheduleAll();
CC_SAFE_RELEASE(m_pScriptHandlerEntries);
for (int i=0; i<_functionsToPerform.size(); i++) {
free(_functionsToPerform.at(i));
}
pthread_mutex_destroy(&(this->_performMutex));
}
void CCScheduler::removeHashElement(_hashSelectorEntry *pElement)
{
cocos2d::CCObject *target = pElement->target;
ccArrayFree(pElement->timers);
HASH_DEL(m_pHashForTimers, pElement);
free(pElement);
// make sure the target is released after we have removed the hash element
// otherwise we access invalid memory when the release call deletes the target
// and the target calls removeAllSelectors() during its destructor
target->release();
}
void CCScheduler::scheduleSelector(SEL_SCHEDULE pfnSelector, CCObject *pTarget, float fInterval, bool bPaused)
{
this->scheduleSelector(pfnSelector, pTarget, fInterval, kCCRepeatForever, 0.0f, bPaused);
}
void CCScheduler::scheduleSelector(SEL_SCHEDULE pfnSelector, CCObject *pTarget, float fInterval, unsigned int repeat, float delay, bool bPaused)
{
CCAssert(pfnSelector, “Argument selector must be non-NULL”);
CCAssert(pTarget, “Argument target must be non-NULL”);
tHashTimerEntry *pElement = NULL;
HASH_FIND_INT(m_pHashForTimers, &pTarget, pElement);
if (! pElement)
{
pElement = (tHashTimerEntry *)calloc(sizeof(*pElement), 1);
pElement->target = pTarget;
if (pTarget)
{
pTarget->retain();
}
HASH_ADD_INT(m_pHashForTimers, target, pElement);
// Is this the 1st element ? Then set the pause level to all the selectors of this target
pElement->paused = bPaused;
}
else
{
CCAssert(pElement->paused == bPaused, “”);
}
if (pElement->timers == NULL)
{
pElement->timers = ccArrayNew(10);
}
else
{
for (unsigned int i = 0; i < pElement->timers->num; ++i)
{
CCTimer *timer = (CCTimer*)pElement->timers->arr*;
if (pfnSelector == timer->getSelector())
{
CCLOG("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer->getInterval(), fInterval);
timer->setInterval(fInterval);
return;
}
}
ccArrayEnsureExtraCapacity(pElement->timers, 1);
}
CCTimer *pTimer = new CCTimer();
pTimer->initWithTarget(pTarget, pfnSelector, fInterval, repeat, delay);
ccArrayAppendObject(pElement->timers, pTimer);
pTimer->release();
}
void CCScheduler::unscheduleSelector(SEL_SCHEDULE pfnSelector, CCObject *pTarget)
{
// explicity handle nil arguments when removing an object
if (pTarget == 0 || pfnSelector == 0)
{
return;
}
//CCAssert(pTarget);
//CCAssert(pfnSelector);
tHashTimerEntry *pElement = NULL;
HASH_FIND_INT(m_pHashForTimers, &pTarget, pElement);
if (pElement)
{
for (unsigned int i = 0; i < pElement->timers->num; ++i)
{
CCTimer *pTimer = (CCTimer*)(pElement->timers->arr*);
if* (pfnSelector == pTimer->getSelector())
{
if (pTimer == pElement->currentTimer && (! pElement->currentTimerSalvaged))
{
pElement->currentTimer->retain();
pElement->currentTimerSalvaged = true;
}
ccArrayRemoveObjectAtIndex(pElement->timers, i, true);
// update timerIndex in case we are in tick:, looping over the actions
if (pElement->timerIndex >= i)
{
pElement->timerIndex–;
}
if (pElement->timers->num == 0)
{
if (m_pCurrentTarget == pElement)
{
m_bCurrentTargetSalvaged = true;
}
else
{
removeHashElement(pElement);
}
}
return;
}
}
}
}
void CCScheduler::priorityIn(tListEntry **ppList, CCObject *pTarget, int nPriority, bool bPaused)
{
tListEntry *pListElement = (tListEntry *)malloc(sizeof(*pListElement));
pListElement->target = pTarget;
pListElement->priority = nPriority;
pListElement->paused = bPaused;
pListElement->next = pListElement->prev = NULL;
pListElement->markedForDeletion = false;
// empty 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);
}
}
// update hash entry for quick access
tHashUpdateEntry *pHashElement = (tHashUpdateEntry *)calloc(sizeof(*pHashElement), 1);
pHashElement->target = pTarget;
pTarget->retain();
pHashElement->list = ppList;
pHashElement->entry = pListElement;
HASH_ADD_INT(m_pHashForUpdates, target, pHashElement);
}
void CCScheduler::appendIn(_listEntry **ppList, CCObject *pTarget, bool bPaused)
{
tListEntry *pListElement = (tListEntry *)malloc(sizeof(*pListElement));
pListElement->target = pTarget;
pListElement->paused = bPaused;
pListElement->markedForDeletion = false;
DL_APPEND(*ppList, pListElement);
// update hash entry for quicker access
tHashUpdateEntry *pHashElement = (tHashUpdateEntry *)calloc(sizeof(*pHashElement), 1);
pHashElement->target = pTarget;
pTarget->retain();
pHashElement->list = ppList;
pHashElement->entry = pListElement;
HASH_ADD_INT(m_pHashForUpdates, target, pHashElement);
}
void CCScheduler::scheduleUpdateForTarget(CCObject *pTarget, int nPriority, bool bPaused)
{
tHashUpdateEntry *pHashElement = NULL;
HASH_FIND_INT(m_pHashForUpdates, &pTarget, pHashElement);
if (pHashElement)
{
#if COCOS2D_DEBUG >= 1
CCAssert(pHashElement->entry->markedForDeletion,"");
#endif
// TODO: check if priority has changed!
pHashElement->entry->markedForDeletion = false;
return;
}
// most of the updates are going to be 0, that’s way there
// 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);
}
}
void CCScheduler::removeUpdateFromHash(struct _listEntry *entry)
{
tHashUpdateEntry *element = NULL;
HASH_FIND_INT(m_pHashForUpdates, &entry->target, element);
if (element)
{
// list entry
DL_DELETE(*element->list, element->entry);
free(element->entry);
// hash entry
CCObject* pTarget = element->target;
HASH_DEL(m_pHashForUpdates, element);
free(element);
// target#release should be the last one to prevent
// a possible double-free. eg: If the might want to remove it itself from there
pTarget->release();
}
}
void CCScheduler::unscheduleUpdateForTarget(const CCObject *pTarget)
{
if (pTarget == NULL)
{
return;
}
tHashUpdateEntry *pElement = NULL;
HASH_FIND_INT(m_pHashForUpdates, &pTarget, pElement);
if (pElement)
{
if (m_bUpdateHashLocked)
{
pElement->entry->markedForDeletion = true;
}
else
{
this->removeUpdateFromHash(pElement->entry);
}
}
}
void CCScheduler::unscheduleAll(void)
{
unscheduleAllWithMinPriority(kCCPrioritySystem);
}
void CCScheduler::unscheduleAllWithMinPriority(int nMinPriority)
{
// Custom Selectors
tHashTimerEntry *pElement = NULL;
tHashTimerEntry *pNextElement = NULL;
for (pElement = m_pHashForTimers; pElement != NULL;)
{
// pElement may be removed in unscheduleAllSelectorsForTarget
pNextElement = (tHashTimerEntry *)pElement->hh.next;
unscheduleAllForTarget(pElement->target);
pElement = pNextElement;
}
// Updates selectors
tListEntry *pEntry, *pTmp;
if(nMinPriority < 0)
{
DL_FOREACH_SAFE(m_pUpdatesNegList, pEntry, pTmp)
{
if(pEntry->priority >= nMinPriority)
{
unscheduleUpdateForTarget(pEntry->target);
}
}
}
if(nMinPriority <= 0)
{
DL_FOREACH_SAFE(m_pUpdates0List, pEntry, pTmp)
{
unscheduleUpdateForTarget(pEntry->target);
}
}
DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, pTmp)
{
if(pEntry->priority >= nMinPriority)
{
unscheduleUpdateForTarget(pEntry->target);
}
}
if (m_pScriptHandlerEntries)
{
m_pScriptHandlerEntries->removeAllObjects();
}
}
void CCScheduler::unscheduleAllForTarget(CCObject *pTarget)
{
// explicit NULL handling
if (pTarget == NULL)
{
return;
}
// Custom Selectors
tHashTimerEntry *pElement = NULL;
HASH_FIND_INT(m_pHashForTimers, &pTarget, pElement);
if (pElement)
{
if (ccArrayContainsObject(pElement->timers, pElement->currentTimer)
&& (! pElement->currentTimerSalvaged))
{
pElement->currentTimer->retain();
pElement->currentTimerSalvaged = true;
}
ccArrayRemoveAllObjects(pElement->timers);
if (m_pCurrentTarget == pElement)
{
m_bCurrentTargetSalvaged = true;
}
else
{
removeHashElement(pElement);
}
}
// update selector
unscheduleUpdateForTarget(pTarget);
}
unsigned int CCScheduler::scheduleScriptFunc(unsigned int nHandler, float fInterval, bool bPaused)
{
CCSchedulerScriptHandlerEntry* pEntry = CCSchedulerScriptHandlerEntry::create(nHandler, fInterval, bPaused);
if (!m_pScriptHandlerEntries)
{
m_pScriptHandlerEntries = CCArray::createWithCapacity(20);
m_pScriptHandlerEntries->retain();
}
m_pScriptHandlerEntries->addObject(pEntry);
return pEntry->getEntryId();
}
void CCScheduler::unscheduleScriptEntry(unsigned int uScheduleScriptEntryID)
{
for (int i = m_pScriptHandlerEntries->count() - 1; i >= 0; i–)
{
CCSchedulerScriptHandlerEntry* pEntry = static_cast<CCSchedulerScriptHandlerEntry*>(m_pScriptHandlerEntries->objectAtIndex(i));
if (pEntry->getEntryId() == (int)uScheduleScriptEntryID)
{
pEntry->markedForDeletion();
break;
}
}
}
void CCScheduler::resumeTarget(CCObject *pTarget)
{
CCAssert(pTarget != NULL, “”);
// custom selectors
tHashTimerEntry *pElement = NULL;
HASH_FIND_INT(m_pHashForTimers, &pTarget, pElement);
if (pElement)
{
pElement->paused = false;
}
// update selector
tHashUpdateEntry *pElementUpdate = NULL;
HASH_FIND_INT(m_pHashForUpdates, &pTarget, pElementUpdate);
if (pElementUpdate)
{
CCAssert(pElementUpdate->entry != NULL, “”);
pElementUpdate->entry->paused = false;
}
}
void CCScheduler::pauseTarget(CCObject *pTarget)
{
CCAssert(pTarget != NULL, “”);
// custom selectors
tHashTimerEntry *pElement = NULL;
HASH_FIND_INT(m_pHashForTimers, &pTarget, pElement);
if (pElement)
{
pElement->paused = true;
}
// update selector
tHashUpdateEntry *pElementUpdate = NULL;
HASH_FIND_INT(m_pHashForUpdates, &pTarget, pElementUpdate);
if (pElementUpdate)
{
CCAssert(pElementUpdate->entry != NULL, “”);
pElementUpdate->entry->paused = true;
}
}
bool CCScheduler::isTargetPaused(CCObject *pTarget)
{
CCAssert( pTarget != NULL, “target must be non nil” );
// Custom selectors
tHashTimerEntry *pElement = NULL;
HASH_FIND_INT(m_pHashForTimers, &pTarget, pElement);
if( pElement )
{
return pElement->paused;
}
// We should check update selectors if target does not have custom selectors
tHashUpdateEntry *elementUpdate = NULL;
HASH_FIND_INT(m_pHashForUpdates, &pTarget, elementUpdate);
if ( elementUpdate )
{
return elementUpdate->entry->paused;
}
return false; // should never get here
}
CCSet* CCScheduler::pauseAllTargets()
{
return pauseAllTargetsWithMinPriority(kCCPrioritySystem);
}
CCSet* CCScheduler::pauseAllTargetsWithMinPriority(int nMinPriority)
{
CCSet* idsWithSelectors = new CCSet();// setWithCapacity:50];
idsWithSelectors->autorelease();
// Custom Selectors
for(tHashTimerEntry element = m_pHashForTimers; element != NULL;
element = (tHashTimerEntry)element->hh.next)
{
element->paused = true;
idsWithSelectors->addObject(element->target);
}
// Updates selectors
tListEntry *entry, *tmp;
if(nMinPriority < 0)
{
DL_FOREACH_SAFE( m_pUpdatesNegList, entry, tmp )
{
if(entry->priority >= nMinPriority)
{
entry->paused = true;
idsWithSelectors->addObject(entry->target);
}
}
}
if(nMinPriority <= 0)
{
DL_FOREACH_SAFE( m_pUpdates0List, entry, tmp )
{
entry->paused = true;
idsWithSelectors->addObject(entry->target);
}
}
DL_FOREACH_SAFE( m_pUpdatesPosList, entry, tmp )
{
if(entry->priority >= nMinPriority)
{
entry->paused = true;
idsWithSelectors->addObject(entry->target);
}
}
return idsWithSelectors;
}
void CCScheduler::resumeTargets(CCSet* pTargetsToResume)
{
CCSetIterator iter;
for (iter = pTargetsToResume->begin(); iter != pTargetsToResume->end(); ++iter)
{
resumeTarget(*iter);
}
}
//自己添加
void CCScheduler::performFunctionInCocosThread(CCObject* pTarget,void (CCObject::func)(CCObject arg),CCObject* arg)
{
pthread_mutex_lock (&(this->_performMutex));
/构造一个新任务/
Worker *worker =
(Worker *) malloc (sizeof (Worker));
worker->process = func;
worker->arg = arg;
worker->pTarget = pTarget;
_functionsToPerform.push_back(worker);
pthread_mutex_unlock (&(this->_performMutex));
}
CCNode* CCScheduler::seekNodeByAddress(CCNode* root, int addr)
{
if (!root)
{
return NULL;
}
if ((int)root==addr)
{
return root;
}
const CCArray* arrayRootChildren = root->getChildren();
CCObject* pObj=NULL;
//正向
CCARRAY_FOREACH(arrayRootChildren,pObj)
{
CCNode* child=(CCNode*)pObj;
CCNode* res = seekNodeByAddress(child,addr);
if (res != NULL)
{
return res;
}
}
return NULL;
}
// main loop
void CCScheduler::update(float dt)
{
m_bUpdateHashLocked = true;
if (m_fTimeScale != 1.0f)
{
dt *= m_fTimeScale;
}
// Iterate over all the Updates’ selectors
tListEntry *pEntry, *pTmp;
// updates with priority < 0
DL_FOREACH_SAFE(m_pUpdatesNegList, pEntry, pTmp)
{
if ((! pEntry->paused) && (! pEntry->markedForDeletion))
{
pEntry->target->update(dt);
}
}
// updates with priority == 0
DL_FOREACH_SAFE(m_pUpdates0List, pEntry, pTmp)
{
if ((! pEntry->paused) && (! pEntry->markedForDeletion))
{
pEntry->target->update(dt);
}
}
// updates with priority > 0
DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, pTmp)
{
if ((! pEntry->paused) && (! pEntry->markedForDeletion))
{
pEntry->target->update(dt);
}
}
// Iterate over all the custom selectors
for (tHashTimerEntry *elt = m_pHashForTimers; elt != NULL; )
{
m_pCurrentTarget = elt;
m_bCurrentTargetSalvaged = false;
if (! m_pCurrentTarget->paused)
{
// The ‘timers’ array may change while inside this loop
for (elt->timerIndex = 0; elt->timerIndex < elt->timers->num; ++(elt->timerIndex))
{
elt->currentTimer = (CCTimer*)(elt->timers->arr);
elt->currentTimerSalvaged = false;
elt->currentTimer->update(dt);
if (elt->currentTimerSalvaged)
{
// The currentTimer told the remove itself. To prevent the timer from
// accidentally deallocating itself before finishing its step, we retained
// it. Now that step is done, it’s safe to release it.
elt->currentTimer->release();
}
elt->currentTimer = NULL;
}
}
// elt, at this moment, is still valid
// so it is safe to ask this here (issue #490)
elt = (tHashTimerEntry *)elt->hh.next;
// only delete currentTarget if no actions were scheduled during the cycle (issue #481)
if (m_bCurrentTargetSalvaged && m_pCurrentTarget->timers->num == 0)
{
removeHashElement(m_pCurrentTarget);
}
}
// Iterate over all the script callbacks
if (m_pScriptHandlerEntries)
{
for (int i = m_pScriptHandlerEntries->count() - 1; i >= 0; i–)
{
CCSchedulerScriptHandlerEntry* pEntry = static_cast<CCSchedulerScriptHandlerEntry*>(m_pScriptHandlerEntries->objectAtIndex(i));
if (pEntry->isMarkedForDeletion())
{
m_pScriptHandlerEntries->removeObjectAtIndex(i);
}
else if (!pEntry->isPaused())
{
pEntry->getTimer()->update(dt);
}
}
}
// delete all updates that are marked for deletion
// updates with priority < 0
DL_FOREACH_SAFE(m_pUpdatesNegList, pEntry, pTmp)
{
if (pEntry->markedForDeletion)
{
this->removeUpdateFromHash(pEntry);
}
}
// updates with priority == 0
DL_FOREACH_SAFE(m_pUpdates0List, pEntry, pTmp)
{
if (pEntry->markedForDeletion)
{
this->removeUpdateFromHash(pEntry);
}
}
// updates with priority > 0
DL_FOREACH_SAFE(m_pUpdatesPosList, pEntry, pTmp)
{
if (pEntry->markedForDeletion)
{
this->removeUpdateFromHash(pEntry);
}
}
m_bUpdateHashLocked = false;
m_pCurrentTarget = NULL;
if( !_functionsToPerform.empty() ) {
pthread_mutex_lock (&(this->_performMutex));
for (int i=0; i<_functionsToPerform.size(); i++) {
Worker* worker=_functionsToPerform.at(i);
CCObject* node=this->seekNodeByAddress((CCNode*)CCDirector::sharedDirector()->getRunningScene(),(int)worker->pTarget);
if (node) {
(node->*(worker->process))(worker->arg);
}
}
for (int i=0; i<_functionsToPerform.size(); i++) {
free(_functionsToPerform.at(i));
}
_functionsToPerform.clear();
pthread_mutex_unlock (&(this->_performMutex));
}
}
NS_CC_END