require('../core/platform/CCClass');
var js = require('../core/platform/js');
/* 动作管理类 */
/*
* @class HashElement
* @constructor--构造函数
* @private--私有
*/
var HashElement = function () {
? ? this.actions = [];//存储具体的action
? ? this.target = null; //ccobject
? ? this.actionIndex = 0;
? ? this.currentAction = null; //CCAction
? ? this.paused = false;
? ? this.lock = false;
};
/**
* !#en
* cc.ActionManager is a class that can manage actions.<br/>
* Normally you won't need to use this class directly. 99% of the cases you will use the CCNode interface,
* which uses this class's singleton object.
* But there are some cases where you might need to use this class. <br/>
* Examples:<br/>
* - When you want to run an action where the target is different from a CCNode.<br/>
* - When you want to pause / resume the actions<br/>
* !#zh
* cc.ActionManager 是可以管理动作的单例类。<br/>
* 通常你并不需要直接使用这个类,99%的情况您将使用 CCNode 的接口。<br/>
* 但也有一些情况下,您可能需要使用这个类。 <br/>
* 例如:
*? - 当你想要运行一个动作,但目标不是 CCNode 类型时。 <br/>
*? - 当你想要暂停/恢复动作时。 <br/>
* @class ActionManager
* @example {@link cocos2d/core/CCActionManager/ActionManager.js}
*/
cc.ActionManager = function () {
? ? /* object 容器,存储了所有的动作node 的 uuid,*/
? ? /* 哈希map-object 存储node */
? ? this._hashTargets = js.createMap(true);
? ? /* 数组存储node */
? ? this._arrayTargets = [];
? ? /* 所有的存储的arr中的node,都在时时update,update时时运行的node,遍历的其中一个 */
? ? this._currentTarget = null;
? ? cc.director._scheduler && cc.director._scheduler.enableForTarget(this);
};
/* 设置cc.ActionManager的原型对象 */
cc.ActionManager.prototype = {
? ? constructor: cc.ActionManager,
? ? /* 元素池,数组类型 */
? ? _elementPool: [],
? ? /* 根据target查找element */
? ? _searchElementByTarget: function (arr, target) {
? ? ? ? for (var k = 0; k < arr.length; k++) {
? ? ? ? ? ? if (target === arr[k].target)
? ? ? ? ? ? ? ? return arr[k];
? ? ? ? }
? ? ? ? return null;
? ? },
? ? /* 获取一个element info,设置target,设置pause属性 */
? ? _getElement: function (target, paused) {
? ? ? ? var element = this._elementPool.pop();
? ? ? ? /* 当element不存在的时候,new一个 */
? ? ? ? if (!element) {
? ? ? ? ? ? element = new HashElement();
? ? ? ? }
? ? ? ? element.target = target;
? ? ? ? /* !!强制转换成布尔类型 */
? ? ? ? element.paused = !!paused;
? ? ? ? /* 返回element */
? ? ? ? return element;
? ? },
? ? /* 把element元素直接放到容器,重置element属性,回收 */
? ? _putElement: function (element) {
? ? ? ? /* node的actions数组的长度为0 */
? ? ? ? element.actions.length = 0;
? ? ? ? /*? */
? ? ? ? element.actionIndex = 0;
? ? ? ? /* 元素的当前action为空 */
? ? ? ? element.currentAction = null;
? ? ? ? /* 设置暂停属性为false */
? ? ? ? element.paused = false;
? ? ? ? /* 设置target为空 */
? ? ? ? element.target = null;
? ? ? ? /* 设置lock属性为false */
? ? ? ? element.lock = false;
? ? ? ? /* 回收info,放到pool池 */
? ? ? ? this._elementPool.push(element);
? ? },
? ? /**
? ? * !#en
? ? * Adds an action with a target.<br/>
? ? * If the target is already present, then the action will be added to the existing target.
? ? * If the target is not present, a new instance of this target will be created either paused or not, and the action will be added to the newly created target.
? ? * When the target is paused, the queued actions won't be 'ticked'.
? ? * !#zh
? ? * 增加一个动作,同时还需要提供动作的目标对象,目标对象是否暂停作为参数。<br/>
? ? * 如果目标已存在,动作将会被直接添加到现有的节点中。<br/>
? ? * 如果目标不存在,将为这一目标创建一个新的实例,并将动作添加进去。<br/>
? ? * 当目标状态的 paused 为 true,动作将不会被执行
? ? *
? ? * @method addAction
? ? * @param {Action} action
? ? * @param {Node} target
? ? * @param {Boolean} paused
? ? */
? ? addAction: function (action, target, paused) {
? ? ? ? if (!action || !target) {
? ? ? ? ? ? cc.errorID(1000);
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //check if the action target already exists
? ? ? ? /* 检查操作目标是否已存在 */
? ? ? ? /* * !#zh 主要用于编辑器的 uuid,在编辑器下可用于持久化存储,在项目构建之后将变成自增的 id。
? ? ? ? */
? ? ? ? var element = this._hashTargets[target._id];
? ? ? ? //if doesn't exists, create a hashelement and push in mpTargets
? ? ? ? /* 如果不存在,则创建一个 hashelement 并推入 mpTargets */
? ? ? ? if (!element) {
? ? ? ? ? ? element = this._getElement(target, paused);//获取一个element
? ? ? ? ? ? this._hashTargets[target._id] = element;//根据node uuid 存储info object存储
? ? ? ? ? ? this._arrayTargets.push(element);//array add info
? ? ? ? }
? ? ? ? else if (!element.actions) {//当element存在,并且element的actions-动作array为空
? ? ? ? ? ? element.actions = [];
? ? ? ? }
? ? ? ? element.actions.push(action);//info的action容器添加一个action
? ? ? ? action.startWithTarget(target);//action 设置target,
? ? },
? ? /**
? ? * !#en Removes all actions from all the targets.
? ? * !#zh 移除所有对象的所有动作。
? ? * @method removeAllActions
? ? */
? ? removeAllActions: function () {
? ? ? ? var locTargets = this._arrayTargets;
? ? ? ? /* 遍历数组-info */
? ? ? ? for (var i = 0; i < locTargets.length; i++) {
? ? ? ? ? ? var element = locTargets[i];
? ? ? ? ? ? if (element)
? ? ? ? ? ? ? ? this._putElement(element);//回收elementinfo
? ? ? ? }
? ? ? ? /* 清空数组 */
? ? ? ? this._arrayTargets.length = 0;
? ? ? ? //重新创建一个map 给hashTargets赋值
? ? ? ? this._hashTargets = js.createMap(true);
? ? },
? ? /**
? ? * !#en
? ? * Removes all actions from a certain target. <br/>
? ? * All the actions that belongs to the target will be removed.
? ? * !#zh
? ? * 移除指定对象上的所有动作。<br/>
? ? * 属于该目标的所有的动作将被删除。
? ? * @method removeAllActionsFromTarget
? ? * @param {Node} target
? ? * @param {Boolean} forceDelete
? ? */
? ? removeAllActionsFromTarget: function (target, forceDelete) {
? ? ? ? // explicit null handling
? ? ? ? if (target == null)
? ? ? ? ? ? return;
? ? ? ? /* 从map中找到对应的info */
? ? ? ? var element = this._hashTargets[target._id];
? ? ? ? if (element) {
? ? ? ? ? ? /* 清空数组 */
? ? ? ? ? ? element.actions.length = 0;
? ? ? ? ? ? this._deleteHashElement(element);
? ? ? ? }
? ? },
? ? /**
? ? * !#en Removes an action given an action reference.
? ? * !#zh 移除指定的动作。
? ? * @method removeAction
? ? * @param {Action} action
? ? */
? ? removeAction: function (action) {
? ? ? ? // explicit null handling
? ? ? ? /* 空action处理 */
? ? ? ? if (!action) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? /* 获取原始目标节点。 */
? ? ? ? var target = action.getOriginalTarget();
? ? ? ? /* 从map中获取info--element */
? ? ? ? var element = this._hashTargets[target._id];
? ? ? ? /* info不存在则return */
? ? ? ? if (!element) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? /* 遍历action数组 找到对应的action */
? ? ? ? for (var i = 0; i < element.actions.length; i++) {
? ? ? ? ? ? /* 找到对应的action */
? ? ? ? ? ? if (element.actions[i] === action) {
? ? ? ? ? ? ? ? /* 删除action */
? ? ? ? ? ? ? ? element.actions.splice(i, 1);
? ? ? ? ? ? ? ? // update actionIndex in case we are in tick. looping over the actions
? ? ? ? ? ? ? ? /* 如果我们处于勾选状态,请更新actionIndex。循环操作 */
? ? ? ? ? ? ? ? if (element.actionIndex >= i)
? ? ? ? ? ? ? ? ? ? element.actionIndex--;
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
? ? },
? ? /* 根据action的tag,移除某个node的action */
? ? _removeActionByTag(tag, element, target) {
? ? ? ? /* 遍历某个具体info下的所有action */
? ? ? ? for (var i = 0, l = element.actions.length; i < l; ++i) {
? ? ? ? ? ? var action = element.actions[i];
? ? ? ? ? ? /* 某个action的tag和要找的tag一致 */
? ? ? ? ? ? if (action && action.getTag() === tag) {
? ? ? ? ? ? ? ? /* 如果target和action的target属性不一致,则跳过 */
? ? ? ? ? ? ? ? if (target && action.getOriginalTarget() !== target) {
? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? /* 从action数组中删除具体的action */
? ? ? ? ? ? ? ? this._removeActionAtIndex(i, element);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
? ? },
? ? /**
? ? * !#en Removes an action given its tag and the target.
? ? * !#zh 删除指定对象下特定标签的一个动作,将删除首个匹配到的动作。
? ? * @method removeActionByTag
? ? * @param {Number} tag
? ? * @param {Node} [target]
? ? */
? ? removeActionByTag: function (tag, target) {
? ? ? ? /* tag不合法 */
? ? ? ? if (tag === cc.Action.TAG_INVALID)
? ? ? ? ? ? cc.logID(1002);
? ? ? ? /* 哈希map容器 */
? ? ? ? let hashTargets = this._hashTargets;
? ? ? ? if (target) {
? ? ? ? ? ? var element = hashTargets[target._id];
? ? ? ? ? ? /* info找到 */
? ? ? ? ? ? if (element) {
? ? ? ? ? ? ? ? this._removeActionByTag(tag, element, target);
? ? ? ? ? ? }
? ? ? ? }/* 假如target参数为空,则遍历所有匹配key 根据找到的info进行传参删除 */
? ? ? ? else {
? ? ? ? ? ? for (let name in hashTargets) {
? ? ? ? ? ? ? ? let element = hashTargets[name];
? ? ? ? ? ? ? ? this._removeActionByTag(tag, element);
? ? ? ? ? ? }
? ? ? ? }
? ? },
? ? /**
? ? * !#en Gets an action given its tag an a target.
? ? * !#zh 通过目标对象和标签获取一个动作。
? ? * @method getActionByTag
? ? * @param {Number} tag
? ? * @param {Node} target
? ? * @return {Action|Null}? return the Action with the given tag on success
? ? */
? ? getActionByTag: function (tag, target) {
? ? ? ? /* tag不合法报错 */
? ? ? ? if (tag === cc.Action.TAG_INVALID)
? ? ? ? ? ? cc.logID(1004);
? ? ? ? /* 根据targed的id获取到info */
? ? ? ? var element = this._hashTargets[target._id];
? ? ? ? if (element) {
? ? ? ? ? ? /* info的actions数组不为空,进行遍历actions,进行tag比较 */
? ? ? ? ? ? if (element.actions != null) {
? ? ? ? ? ? ? ? for (var i = 0; i < element.actions.length; ++i) {
? ? ? ? ? ? ? ? ? ? var action = element.actions[i];
? ? ? ? ? ? ? ? ? ? if (action && action.getTag() === tag)
? ? ? ? ? ? ? ? ? ? ? ? return action;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? cc.logID(1005, tag);
? ? ? ? }
? ? ? ? return null;
? ? },
? ? /**
? ? * !#en
? ? * Returns the numbers of actions that are running in a certain target. <br/>
? ? * Composable actions are counted as 1 action. <br/>
? ? * Example: <br/>
? ? * - If you are running 1 Sequence of 7 actions, it will return 1. <br/>
? ? * - If you are running 7 Sequences of 2 actions, it will return 7.
? ? * !#zh
? ? * 返回指定对象下所有正在运行的动作数量。 <br/>
? ? * 组合动作被算作一个动作。<br/>
? ? * 例如:<br/>
? ? *? - 如果您正在运行 7 个动作组成的序列动作(Sequence),这个函数将返回 1。<br/>
? ? *? - 如果你正在运行 2 个序列动作(Sequence)和 5 个普通动作,这个函数将返回 7。<br/>
? ? *
? ? * @method getNumberOfRunningActionsInTarget
? ? * @param {Node} target
? ? * @return {Number}
? ? */
? ? /* 返回指定对象下所有正在运行的动作数量 */
? ? getNumberOfRunningActionsInTarget: function (target) {
? ? ? ? /* 找对应的info */
? ? ? ? var element = this._hashTargets[target._id];
? ? ? ? /* 返回数组的长度 */
? ? ? ? if (element)
? ? ? ? ? ? return (element.actions) element.actions.length : 0;
? ? ? ? return 0;
? ? },
? ? /**
? ? * !#en Pauses the target: all running actions and newly added actions will be paused.
? ? * !#zh 暂停指定对象:所有正在运行的动作和新添加的动作都将会暂停。
? ? * @method pauseTarget
? ? * @param {Node} target
? ? */
? ? /* 暂停某个对象的所有action */
? ? pauseTarget: function (target) {
? ? ? ? var element = this._hashTargets[target._id];
? ? ? ? if (element)
? ? ? ? ? ? element.paused = true;
? ? },
? ? /**
? ? * !#en Resumes the target. All queued actions will be resumed.
? ? * !#zh 让指定目标恢复运行。在执行序列中所有被暂停的动作将重新恢复运行。
? ? * @method resumeTarget
? ? * @param {Node} target
? ? */
? ? /* 回复action的运行 */
? ? resumeTarget: function (target) {
? ? ? ? /* 根据对象id获取info */
? ? ? ? var element = this._hashTargets[target._id];
? ? ? ? if (element)
? ? ? ? ? ? element.paused = false;
? ? },
? ? /**
? ? * !#en Pauses all running actions, returning a list of targets whose actions were paused.
? ? * !#zh 暂停所有正在运行的动作,返回一个包含了那些动作被暂停了的目标对象的列表。
? ? * @method pauseAllRunningActions
? ? * @return {Array}? a list of targets whose actions were paused.
? ? */
? ? /* 暂停所有正在运行的动作,返回一个包含了那些动作被暂停了的目标对象的列表。 */
? ? pauseAllRunningActions: function () {
? ? ? ? var idsWithActions = [];
? ? ? ? /* 存储info的数组 */
? ? ? ? var locTargets = this._arrayTargets;
? ? ? ? /* 遍历容器 */
? ? ? ? for (var i = 0; i < locTargets.length; i++) {
? ? ? ? ? ? var element = locTargets[i];
? ? ? ? ? ? /* info没pause的,设置为pause为true */
? ? ? ? ? ? if (element && !element.paused) {
? ? ? ? ? ? ? ? element.paused = true;
? ? ? ? ? ? ? ? /* 把对应都放到数组 */
? ? ? ? ? ? ? ? idsWithActions.push(element.target);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? /* 返回数组 */
? ? ? ? return idsWithActions;
? ? },
? ? /**
? ? * !#en Resume a set of targets (convenience function to reverse a pauseAllRunningActions or pauseTargets call).
? ? * !#zh 让一组指定对象恢复运行(用来逆转 pauseAllRunningActions 效果的便捷函数)。
? ? * @method resumeTargets
? ? * @param {Array} targetsToResume
? ? */
? ? resumeTargets: function (targetsToResume) {
? ? ? ? /* 参数必须是数组,不为空 */
? ? ? ? if (!targetsToResume)
? ? ? ? ? ? return;
? ? ? ? /* 遍历数组,获取所有具体对象 */
? ? ? ? for (var i = 0; i < targetsToResume.length; i++) {
? ? ? ? ? ? if (targetsToResume[i])
? ? ? ? ? ? ? ? this.resumeTarget(targetsToResume[i]);
? ? ? ? }
? ? },
? ? /**
? ? * !#en Pause a set of targets.
? ? * !#zh 暂停一组指定对象。
? ? * @method pauseTargets
? ? * @param {Array} targetsToPause
? ? */
? ? pauseTargets: function (targetsToPause) {
? ? ? ? if (!targetsToPause)
? ? ? ? ? ? return;
? ? ? ? /* 遍历存储对象的数组 */
? ? ? ? for (var i = 0; i < targetsToPause.length; i++) {
? ? ? ? ? ? if (targetsToPause[i])
? ? ? ? ? ? ? ? this.pauseTarget(targetsToPause[i]);
? ? ? ? }
? ? },
? ? /**
? ? * !#en
? ? * purges the shared action manager. It releases the retained instance. <br/>
? ? * because it uses this, so it can not be static.
? ? * !#zh
? ? * 清除共用的动作管理器。它释放了持有的实例。 <br/>
? ? * 因为它使用 this,因此它不能是静态的。
? ? * @method purgeSharedManager
? ? */
? ? purgeSharedManager: function () {
? ? ? ? /* 取消指定对象的 update 定时器。 */
? ? ? ? cc.director.getScheduler().unscheduleUpdate(this);
? ? },
? ? //protected
? ? /* 删除固定数组下标的info */
? ? _removeActionAtIndex: function (index, element) {
? ? ? ? /* 获取固定的action */
? ? ? ? var action = element.actions[index];
? ? ? ? /* 删除某个index的属性 */
? ? ? ? element.actions.splice(index, 1);
? ? ? ? // update actionIndex in case we are in tick. looping over the actions
? ? ? ? /* 如果我们处于勾选状态,请更新actionIndex。循环操作 */
? ? ? ? if (element.actionIndex >= index)
? ? ? ? ? ? element.actionIndex--;
? ? ? ? ? ? /* 当action数组为空的时候,删除这个info */
? ? ? ? if (element.actions.length === 0) {
? ? ? ? ? ? this._deleteHashElement(element);
? ? ? ? }
? ? },
? ? /* 删除map内存储的这个info */
? ? _deleteHashElement: function (element) {
? ? ? ? var ret = false;
? ? ? ? if (element && !element.lock) {
? ? ? ? ? ? if (this._hashTargets[element.target._id]) {
? ? ? ? ? ? ? ? /* 从object 删除info */
? ? ? ? ? ? ? ? delete this._hashTargets[element.target._id];
? ? ? ? ? ? ? ? var targets = this._arrayTargets;
? ? ? ? ? ? ? ? /* 遍历数组 */
? ? ? ? ? ? ? ? for (var i = 0, l = targets.length; i < l; i++) {
? ? ? ? ? ? ? ? ? ? if (targets[i] === element) {
? ? ? ? ? ? ? ? ? ? ? ? targets.splice(i, 1);//删除这个元素,从数组中
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? /* 回收info */
? ? ? ? ? ? ? ? this._putElement(element);
? ? ? ? ? ? ? ? ret = true;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return ret;
? ? },
? ? /**
? ? * !#en The ActionManager update。
? ? * !#zh ActionManager 主循环。
? ? * @method update
? ? * @param {Number} dt delta time in seconds
? ? */
? ? update: function (dt) {
? ? ? ? /* 声明locCurrTarget 临时变量存储的是info? locTargets是数组this._arrayTargets的重新赋值 */
? ? ? ? var locTargets = this._arrayTargets, locCurrTarget;
? ? ? ? for (var elt = 0; elt < locTargets.length; elt++) {
? ? ? ? ? ? this._currentTarget = locTargets[elt];
? ? ? ? ? ? /* 设置当前target info */
? ? ? ? ? ? locCurrTarget = this._currentTarget;
? ? ? ? ? ? /* action没有被暂停,并且存在actions */
? ? ? ? ? ? if (!locCurrTarget.paused && locCurrTarget.actions) {
? ? ? ? ? ? ? ? locCurrTarget.lock = true;
? ? ? ? ? ? ? ? // The 'actions' CCMutableArray may change while inside this loop.
? ? ? ? ? ? ? ? /* 在此循环内,“动作”CCMutableArray 可能会发生变化。 */
? ? ? ? ? ? ? ? for (locCurrTarget.actionIndex = 0; locCurrTarget.actionIndex < locCurrTarget.actions.length; locCurrTarget.actionIndex++) {
? ? ? ? ? ? ? ? ? ? locCurrTarget.currentAction = locCurrTarget.actions[locCurrTarget.actionIndex];
? ? ? ? ? ? ? ? ? ? if (!locCurrTarget.currentAction)
? ? ? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? ? ? //use for speed
? ? ? ? ? ? ? ? ? ? locCurrTarget.currentAction.step(dt * (locCurrTarget.currentAction._speedMethod locCurrTarget.currentAction._speed : 1));
? ? ? ? ? ? ? ? ? ? if (locCurrTarget.currentAction && locCurrTarget.currentAction.isDone()) {
? ? ? ? ? ? ? ? ? ? ? ? locCurrTarget.currentAction.stop();
? ? ? ? ? ? ? ? ? ? ? ? var action = locCurrTarget.currentAction;
? ? ? ? ? ? ? ? ? ? ? ? // Make currentAction nil to prevent removeAction from salvaging it.
? ? ? ? ? ? ? ? ? ? ? ? /* 将 currentAction 设置为 nil 以防止 removeAction 抢救它。 */
? ? ? ? ? ? ? ? ? ? ? ? locCurrTarget.currentAction = null;
? ? ? ? ? ? ? ? ? ? ? ? /* 移除指定动作 */
? ? ? ? ? ? ? ? ? ? ? ? this.removeAction(action);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? locCurrTarget.currentAction = null;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? locCurrTarget.lock = false;
? ? ? ? ? ? }
? ? ? ? ? ? // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
? ? ? ? ? ? /* 仅当周期内未安排任何操作时才删除 currentTarget(问题 #481) */
? ? ? ? ? ? if (locCurrTarget.actions.length === 0) {//回收info
? ? ? ? ? ? ? ? this._deleteHashElement(locCurrTarget) && elt--;
? ? ? ? ? ? }
? ? ? ? }
? ? }
};
/* 测试环境,拓展属性isTargetPaused_TEST ,判断某个node的动画是否是paused */
if (CC_TEST) {
? ? cc.ActionManager.prototype.isTargetPaused_TEST = function (target) {
? ? ? ? /* 获取某个info */
? ? ? ? var element = this._hashTargets[target._id];
? ? ? ? return element.paused;
? ? };
}