1 /**************************************************************************** 2 Copyright (c) 2008-2010 Ricardo Quesada 3 Copyright (c) 2011-2012 cocos2d-x.org 4 Copyright (c) 2013-2014 Chukong Technologies Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 cc.g_NumberOfDraws = 0; 28 29 //---------------------------------------------------------------------------------------------------------------------- 30 31 /** 32 * <p> 33 * ATTENTION: USE cc.director INSTEAD OF cc.Director.<br/> 34 * cc.director is a singleton object which manage your game's logic flow.<br/> 35 * Since the cc.director is a singleton, you don't need to call any constructor or create functions,<br/> 36 * the standard way to use it is by calling:<br/> 37 * - cc.director.methodName(); <br/> 38 * 39 * It creates and handle the main Window and manages how and when to execute the Scenes.<br/> 40 * <br/> 41 * The cc.director is also responsible for:<br/> 42 * - initializing the OpenGL context<br/> 43 * - setting the OpenGL pixel format (default on is RGB565)<br/> 44 * - setting the OpenGL pixel format (default on is RGB565)<br/> 45 * - setting the OpenGL buffer depth (default one is 0-bit)<br/> 46 - setting the color for clear screen (default one is BLACK)<br/> 47 * - setting the projection (default one is 3D)<br/> 48 * - setting the orientation (default one is Portrait)<br/> 49 * <br/> 50 * <br/> 51 * The cc.director also sets the default OpenGL context:<br/> 52 * - GL_TEXTURE_2D is enabled<br/> 53 * - GL_VERTEX_ARRAY is enabled<br/> 54 * - GL_COLOR_ARRAY is enabled<br/> 55 * - GL_TEXTURE_COORD_ARRAY is enabled<br/> 56 * </p> 57 * <p> 58 * cc.director also synchronizes timers with the refresh rate of the display.<br/> 59 * Features and Limitations:<br/> 60 * - Scheduled timers & drawing are synchronizes with the refresh rate of the display<br/> 61 * - Only supports animation intervals of 1/60 1/30 & 1/15<br/> 62 * </p> 63 * @class 64 * @name cc.Director 65 */ 66 cc.Director = cc.Class.extend(/** @lends cc.Director# */{ 67 //Variables 68 _landscape: false, 69 _nextDeltaTimeZero: false, 70 _paused: false, 71 _purgeDirectorInNextLoop: false, 72 _sendCleanupToScene: false, 73 _animationInterval: 0.0, 74 _oldAnimationInterval: 0.0, 75 _projection: 0, 76 _contentScaleFactor: 1.0, 77 78 _deltaTime: 0.0, 79 80 _winSizeInPoints: null, 81 82 _lastUpdate: null, 83 _nextScene: null, 84 _notificationNode: null, 85 _openGLView: null, 86 _scenesStack: null, 87 _projectionDelegate: null, 88 _runningScene: null, 89 90 _totalFrames: 0, 91 _secondsPerFrame: 0, 92 93 _dirtyRegion: null, 94 95 _scheduler: null, 96 _actionManager: null, 97 _eventProjectionChanged: null, 98 _eventAfterUpdate: null, 99 _eventAfterVisit: null, 100 _eventAfterDraw: null, 101 102 ctor: function () { 103 var self = this; 104 self._lastUpdate = Date.now(); 105 cc.eventManager.addCustomListener(cc.game.EVENT_SHOW, function () { 106 self._lastUpdate = Date.now(); 107 }); 108 }, 109 110 init: function () { 111 // scenes 112 this._oldAnimationInterval = this._animationInterval = 1.0 / cc.defaultFPS; 113 this._scenesStack = []; 114 // Set default projection (3D) 115 this._projection = cc.Director.PROJECTION_DEFAULT; 116 // projection delegate if "Custom" projection is used 117 this._projectionDelegate = null; 118 119 // FPS 120 this._totalFrames = 0; 121 this._lastUpdate = Date.now(); 122 123 //Paused? 124 this._paused = false; 125 126 //purge? 127 this._purgeDirectorInNextLoop = false; 128 129 this._winSizeInPoints = cc.size(0, 0); 130 131 this._openGLView = null; 132 this._contentScaleFactor = 1.0; 133 134 //scheduler 135 this._scheduler = new cc.Scheduler(); 136 //action manager 137 if(cc.ActionManager){ 138 this._actionManager = new cc.ActionManager(); 139 this._scheduler.scheduleUpdate(this._actionManager, cc.Scheduler.PRIORITY_SYSTEM, false); 140 }else{ 141 this._actionManager = null; 142 } 143 144 this._eventAfterUpdate = new cc.EventCustom(cc.Director.EVENT_AFTER_UPDATE); 145 this._eventAfterUpdate.setUserData(this); 146 this._eventAfterVisit = new cc.EventCustom(cc.Director.EVENT_AFTER_VISIT); 147 this._eventAfterVisit.setUserData(this); 148 this._eventAfterDraw = new cc.EventCustom(cc.Director.EVENT_AFTER_DRAW); 149 this._eventAfterDraw.setUserData(this); 150 this._eventProjectionChanged = new cc.EventCustom(cc.Director.EVENT_PROJECTION_CHANGED); 151 this._eventProjectionChanged.setUserData(this); 152 153 return true; 154 }, 155 156 /** 157 * calculates delta time since last time it was called 158 */ 159 calculateDeltaTime: function () { 160 var now = Date.now(); 161 162 // new delta time. 163 if (this._nextDeltaTimeZero) { 164 this._deltaTime = 0; 165 this._nextDeltaTimeZero = false; 166 } else { 167 this._deltaTime = (now - this._lastUpdate) / 1000; 168 } 169 170 if ((cc.game.config[cc.game.CONFIG_KEY.debugMode] > 0) && (this._deltaTime > 0.2)) 171 this._deltaTime = 1 / 60.0; 172 173 this._lastUpdate = now; 174 }, 175 176 /** 177 * Converts a view coordinate to an WebGL coordinate<br/> 178 * Useful to convert (multi) touches coordinates to the current layout (portrait or landscape)<br/> 179 * Implementation can be found in CCDirectorWebGL 180 * @function 181 * @param {cc.Point} uiPoint 182 * @return {cc.Point} 183 */ 184 convertToGL: function (uiPoint) { 185 var docElem = document.documentElement; 186 var view = cc.view; 187 var box = element.getBoundingClientRect(); 188 box.left += window.pageXOffset - docElem.clientLeft; 189 box.top += window.pageYOffset - docElem.clientTop; 190 var x = view._devicePixelRatio * (uiPoint.x - box.left); 191 var y = view._devicePixelRatio * (box.top + box.height - uiPoint.y); 192 return view._isRotated ? {x: view._viewPortRect.width - y, y: x} : {x: x, y: y}; 193 }, 194 195 /** 196 * Converts an WebGL coordinate to a view coordinate<br/> 197 * Useful to convert node points to window points for calls such as glScissor<br/> 198 * Implementation can be found in CCDirectorWebGL 199 * @function 200 * @param {cc.Point} glPoint 201 * @return {cc.Point} 202 */ 203 convertToUI: function (glPoint) { 204 var docElem = document.documentElement; 205 var view = cc.view; 206 var box = element.getBoundingClientRect(); 207 box.left += window.pageXOffset - docElem.clientLeft; 208 box.top += window.pageYOffset - docElem.clientTop; 209 var uiPoint = {x: 0, y: 0}; 210 if (view._isRotated) { 211 uiPoint.x = box.left + glPoint.y / view._devicePixelRatio; 212 uiPoint.y = box.top + box.height - (view._viewPortRect.width - glPoint.x) / view._devicePixelRatio; 213 } 214 else { 215 uiPoint.x = box.left + glPoint.x / view._devicePixelRatio; 216 uiPoint.y = box.top + box.height - glPoint.y / view._devicePixelRatio; 217 } 218 return uiPoint; 219 }, 220 221 /** 222 * Draw the scene. This method is called every frame. Don't call it manually. 223 */ 224 drawScene: function () { 225 var renderer = cc.renderer; 226 227 // calculate "global" dt 228 this.calculateDeltaTime(); 229 230 //tick before glClear: issue #533 231 if (!this._paused) { 232 this._scheduler.update(this._deltaTime); 233 cc.eventManager.dispatchEvent(this._eventAfterUpdate); 234 } 235 236 /* to avoid flickr, nextScene MUST be here: after tick and before draw. 237 XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */ 238 if (this._nextScene) { 239 this.setNextScene(); 240 } 241 242 if (this._beforeVisitScene) 243 this._beforeVisitScene(); 244 245 // draw the scene 246 if (this._runningScene) { 247 if (renderer.childrenOrderDirty) { 248 cc.renderer.clearRenderCommands(); 249 cc.renderer.assignedZ = 0; 250 this._runningScene._renderCmd._curLevel = 0; //level start from 0; 251 this._runningScene.visit(); 252 renderer.resetFlag(); 253 } 254 else if (renderer.transformDirty()) { 255 renderer.transform(); 256 } 257 } 258 259 renderer.clear(); 260 261 // draw the notifications node 262 if (this._notificationNode) 263 this._notificationNode.visit(); 264 265 cc.eventManager.dispatchEvent(this._eventAfterVisit); 266 cc.g_NumberOfDraws = 0; 267 268 if (this._afterVisitScene) 269 this._afterVisitScene(); 270 271 renderer.rendering(cc._renderContext); 272 this._totalFrames++; 273 274 cc.eventManager.dispatchEvent(this._eventAfterDraw); 275 276 this._calculateMPF(); 277 }, 278 279 _beforeVisitScene: null, 280 _afterVisitScene: null, 281 282 /** 283 * End the life of director in the next frame 284 */ 285 end: function () { 286 this._purgeDirectorInNextLoop = true; 287 }, 288 289 /** 290 * Returns the size in pixels of the surface. It could be different than the screen size.<br/> 291 * High-res devices might have a higher surface size than the screen size. 292 * @return {Number} 293 */ 294 getContentScaleFactor: function () { 295 return this._contentScaleFactor; 296 }, 297 298 /** 299 * This object will be visited after the main scene is visited.<br/> 300 * This object MUST implement the "visit" selector.<br/> 301 * Useful to hook a notification object 302 * @return {cc.Node} 303 */ 304 getNotificationNode: function () { 305 return this._notificationNode; 306 }, 307 308 /** 309 * Returns the size of the WebGL view in points.<br/> 310 * It takes into account any possible rotation (device orientation) of the window 311 * @return {cc.Size} 312 */ 313 getWinSize: function () { 314 return cc.size(this._winSizeInPoints); 315 }, 316 317 /** 318 * Returns the size of the OpenGL view in pixels.<br/> 319 * It takes into account any possible rotation (device orientation) of the window.<br/> 320 * On Mac winSize and winSizeInPixels return the same value. 321 * @return {cc.Size} 322 */ 323 getWinSizeInPixels: function () { 324 return cc.size(this._winSizeInPoints.width * this._contentScaleFactor, this._winSizeInPoints.height * this._contentScaleFactor); 325 }, 326 327 /** 328 * getVisibleSize/getVisibleOrigin move to CCDirectorWebGL/CCDirectorCanvas 329 * getZEye move to CCDirectorWebGL 330 */ 331 332 /** 333 * Returns the visible size of the running scene 334 * @function 335 * @return {cc.Size} 336 */ 337 getVisibleSize: null, 338 339 /** 340 * Returns the visible origin of the running scene 341 * @function 342 * @return {cc.Point} 343 */ 344 getVisibleOrigin: null, 345 346 /** 347 * Returns the z eye, only available in WebGL mode 348 * @function 349 * @return {Number} 350 */ 351 getZEye: null, 352 353 /** 354 * Pause the director's ticker 355 */ 356 pause: function () { 357 if (this._paused) 358 return; 359 360 this._oldAnimationInterval = this._animationInterval; 361 // when paused, don't consume CPU 362 this.setAnimationInterval(1 / 4.0); 363 this._paused = true; 364 }, 365 366 /** 367 * Pops out a scene from the queue.<br/> 368 * This scene will replace the running one.<br/> 369 * The running scene will be deleted. If there are no more scenes in the stack the execution is terminated.<br/> 370 * ONLY call it if there is a running scene. 371 */ 372 popScene: function () { 373 374 cc.assert(this._runningScene, cc._LogInfos.Director_popScene); 375 376 this._scenesStack.pop(); 377 var c = this._scenesStack.length; 378 379 if (c === 0) 380 this.end(); 381 else { 382 this._sendCleanupToScene = true; 383 this._nextScene = this._scenesStack[c - 1]; 384 } 385 }, 386 387 /** 388 * Removes cached all cocos2d cached data. It will purge the cc.textureCache, cc.spriteFrameCache, cc.animationCache 389 */ 390 purgeCachedData: function () { 391 cc.animationCache._clear(); 392 cc.spriteFrameCache._clear(); 393 cc.textureCache._clear(); 394 }, 395 396 /** 397 * Purge the cc.director itself, including unschedule all schedule, remove all event listeners, clean up and exit the running scene, stops all animations, clear cached data. 398 */ 399 purgeDirector: function () { 400 //cleanup scheduler 401 this.getScheduler().unscheduleAll(); 402 403 // Disable event dispatching 404 if (cc.eventManager) 405 cc.eventManager.setEnabled(false); 406 407 // don't release the event handlers 408 // They are needed in case the director is run again 409 410 if (this._runningScene) { 411 this._runningScene.onExitTransitionDidStart(); 412 this._runningScene.onExit(); 413 this._runningScene.cleanup(); 414 } 415 416 this._runningScene = null; 417 this._nextScene = null; 418 419 // remove all objects, but don't release it. 420 // runScene might be executed after 'end'. 421 this._scenesStack.length = 0; 422 423 this.stopAnimation(); 424 425 // Clear all caches 426 this.purgeCachedData(); 427 428 cc.checkGLErrorDebug(); 429 }, 430 431 /** 432 * Suspends the execution of the running scene, pushing it on the stack of suspended scenes.<br/> 433 * The new scene will be executed.<br/> 434 * Try to avoid big stacks of pushed scenes to reduce memory allocation.<br/> 435 * ONLY call it if there is a running scene. 436 * @param {cc.Scene} scene 437 */ 438 pushScene: function (scene) { 439 440 cc.assert(scene, cc._LogInfos.Director_pushScene); 441 442 this._sendCleanupToScene = false; 443 444 this._scenesStack.push(scene); 445 this._nextScene = scene; 446 }, 447 448 /** 449 * Run a scene. Replaces the running scene with a new one or enter the first scene. 450 * @param {cc.Scene} scene 451 */ 452 runScene: function (scene) { 453 454 cc.assert(scene, cc._LogInfos.Director_pushScene); 455 456 if (!this._runningScene) { 457 //start scene 458 this.pushScene(scene); 459 this.startAnimation(); 460 } else { 461 //replace scene 462 var i = this._scenesStack.length; 463 if (i === 0) { 464 this._sendCleanupToScene = true; 465 this._scenesStack[i] = scene; 466 this._nextScene = scene; 467 } else { 468 this._sendCleanupToScene = true; 469 this._scenesStack[i - 1] = scene; 470 this._nextScene = scene; 471 } 472 } 473 }, 474 475 /** 476 * Resume director after pause, if the current scene is not paused, nothing will happen. 477 */ 478 resume: function () { 479 if (!this._paused) { 480 return; 481 } 482 483 this.setAnimationInterval(this._oldAnimationInterval); 484 this._lastUpdate = Date.now(); 485 if (!this._lastUpdate) { 486 cc.log(cc._LogInfos.Director_resume); 487 } 488 489 this._paused = false; 490 this._deltaTime = 0; 491 }, 492 493 /** 494 * The size in pixels of the surface. It could be different than the screen size.<br/> 495 * High-res devices might have a higher surface size than the screen size. 496 * @param {Number} scaleFactor 497 */ 498 setContentScaleFactor: function (scaleFactor) { 499 if (scaleFactor !== this._contentScaleFactor) { 500 this._contentScaleFactor = scaleFactor; 501 } 502 }, 503 504 /** 505 * Enables or disables WebGL depth test.<br/> 506 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js 507 * @function 508 * @param {Boolean} on 509 */ 510 setDepthTest: null, 511 512 /** 513 * set color for clear screen.<br/> 514 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js 515 * @function 516 * @param {cc.Color} clearColor 517 */ 518 setClearColor: null, 519 /** 520 * Sets the default values based on the CCConfiguration info 521 */ 522 setDefaultValues: function () { 523 524 }, 525 526 /** 527 * Sets whether next delta time equals to zero 528 * @param {Boolean} nextDeltaTimeZero 529 */ 530 setNextDeltaTimeZero: function (nextDeltaTimeZero) { 531 this._nextDeltaTimeZero = nextDeltaTimeZero; 532 }, 533 534 /** 535 * Starts the registered next scene 536 */ 537 setNextScene: function () { 538 var runningIsTransition = false, newIsTransition = false; 539 if (cc.TransitionScene) { 540 runningIsTransition = this._runningScene ? this._runningScene instanceof cc.TransitionScene : false; 541 newIsTransition = this._nextScene ? this._nextScene instanceof cc.TransitionScene : false; 542 } 543 544 // If it is not a transition, call onExit/cleanup 545 if (!newIsTransition) { 546 var locRunningScene = this._runningScene; 547 if (locRunningScene) { 548 locRunningScene.onExitTransitionDidStart(); 549 locRunningScene.onExit(); 550 } 551 552 // issue #709. the root node (scene) should receive the cleanup message too 553 // otherwise it might be leaked. 554 if (this._sendCleanupToScene && locRunningScene) 555 locRunningScene.cleanup(); 556 } 557 558 this._runningScene = this._nextScene; 559 cc.renderer.childrenOrderDirty = true; 560 561 this._nextScene = null; 562 if ((!runningIsTransition) && (this._runningScene !== null)) { 563 this._runningScene.onEnter(); 564 this._runningScene.onEnterTransitionDidFinish(); 565 } 566 }, 567 568 /** 569 * Sets Notification Node 570 * @param {cc.Node} node 571 */ 572 setNotificationNode: function (node) { 573 cc.renderer.childrenOrderDirty = true; 574 if(this._notificationNode){ 575 this._notificationNode.onExitTransitionDidStart(); 576 this._notificationNode.onExit(); 577 this._notificationNode.cleanup(); 578 } 579 this._notificationNode = node; 580 if(!node) 581 return; 582 this._notificationNode.onEnter(); 583 this._notificationNode.onEnterTransitionDidFinish(); 584 }, 585 586 /** 587 * Returns the cc.director delegate. 588 * @return {cc.DirectorDelegate} 589 */ 590 getDelegate: function () { 591 return this._projectionDelegate; 592 }, 593 594 /** 595 * Sets the cc.director delegate. It shall implement the CCDirectorDelegate protocol 596 * @return {cc.DirectorDelegate} 597 */ 598 setDelegate: function (delegate) { 599 this._projectionDelegate = delegate; 600 }, 601 602 /** 603 * Sets the view, where everything is rendered, do not call this function.<br/> 604 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 605 * @function 606 * @param {cc.view} openGLView 607 */ 608 setOpenGLView: null, 609 610 /** 611 * Sets an OpenGL projection.<br/> 612 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 613 * @function 614 * @param {Number} projection 615 */ 616 setProjection: null, 617 618 /** 619 * Update the view port.<br/> 620 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 621 * @function 622 */ 623 setViewport: null, 624 625 /** 626 * Get the CCEGLView, where everything is rendered.<br/> 627 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 628 * @function 629 * @return {cc.view} 630 */ 631 getOpenGLView: null, 632 633 /** 634 * Sets an OpenGL projection.<br/> 635 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 636 * @function 637 * @return {Number} 638 */ 639 getProjection: null, 640 641 /** 642 * Enables/disables OpenGL alpha blending.<br/> 643 * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. 644 * @function 645 * @param {Boolean} on 646 */ 647 setAlphaBlending: null, 648 649 /** 650 * Returns whether or not the replaced scene will receive the cleanup message.<br> 651 * If the new scene is pushed, then the old scene won't receive the "cleanup" message.<br/> 652 * If the new scene replaces the old one, the it will receive the "cleanup" message. 653 * @return {Boolean} 654 */ 655 isSendCleanupToScene: function () { 656 return this._sendCleanupToScene; 657 }, 658 659 /** 660 * Returns current running Scene. Director can only run one Scene at the time 661 * @return {cc.Scene} 662 */ 663 getRunningScene: function () { 664 return this._runningScene; 665 }, 666 667 /** 668 * Returns the FPS value 669 * @return {Number} 670 */ 671 getAnimationInterval: function () { 672 return this._animationInterval; 673 }, 674 675 /** 676 * Returns whether or not to display the FPS informations 677 * @return {Boolean} 678 */ 679 isDisplayStats: function () { 680 return cc.profiler ? cc.profiler.isShowingStats() : false; 681 }, 682 683 /** 684 * Sets whether display the FPS on the bottom-left corner 685 * @param {Boolean} displayStats 686 */ 687 setDisplayStats: function (displayStats) { 688 if (cc.profiler) { 689 displayStats ? cc.profiler.showStats() : cc.profiler.hideStats(); 690 } 691 }, 692 693 /** 694 * Returns seconds per frame 695 * @return {Number} 696 */ 697 getSecondsPerFrame: function () { 698 return this._secondsPerFrame; 699 }, 700 701 /** 702 * Returns whether next delta time equals to zero 703 * @return {Boolean} 704 */ 705 isNextDeltaTimeZero: function () { 706 return this._nextDeltaTimeZero; 707 }, 708 709 /** 710 * Returns whether or not the Director is paused 711 * @return {Boolean} 712 */ 713 isPaused: function () { 714 return this._paused; 715 }, 716 717 /** 718 * Returns how many frames were called since the director started 719 * @return {Number} 720 */ 721 getTotalFrames: function () { 722 return this._totalFrames; 723 }, 724 725 /** 726 * Pops out all scenes from the queue until the root scene in the queue. <br/> 727 * This scene will replace the running one. <br/> 728 * Internally it will call "popToSceneStackLevel(1)" 729 */ 730 popToRootScene: function () { 731 this.popToSceneStackLevel(1); 732 }, 733 734 /** 735 * Pops out all scenes from the queue until it reaches "level". <br/> 736 * If level is 0, it will end the director. <br/> 737 * If level is 1, it will pop all scenes until it reaches to root scene. <br/> 738 * If level is <= than the current stack level, it won't do anything. 739 * @param {Number} level 740 */ 741 popToSceneStackLevel: function (level) { 742 cc.assert(this._runningScene, cc._LogInfos.Director_popToSceneStackLevel_2); 743 744 var locScenesStack = this._scenesStack; 745 var c = locScenesStack.length; 746 747 if (level === 0) { 748 this.end(); 749 return; 750 } 751 // stack overflow 752 if (level >= c) 753 return; 754 755 // pop stack until reaching desired level 756 while (c > level) { 757 var current = locScenesStack.pop(); 758 if (current.running) { 759 current.onExitTransitionDidStart(); 760 current.onExit(); 761 } 762 current.cleanup(); 763 c--; 764 } 765 this._nextScene = locScenesStack[locScenesStack.length - 1]; 766 this._sendCleanupToScene = true; 767 }, 768 769 /** 770 * Returns the cc.Scheduler associated with this director 771 * @return {cc.Scheduler} 772 */ 773 getScheduler: function () { 774 return this._scheduler; 775 }, 776 777 /** 778 * Sets the cc.Scheduler associated with this director 779 * @param {cc.Scheduler} scheduler 780 */ 781 setScheduler: function (scheduler) { 782 if (this._scheduler !== scheduler) { 783 this._scheduler = scheduler; 784 } 785 }, 786 787 /** 788 * Returns the cc.ActionManager associated with this director 789 * @return {cc.ActionManager} 790 */ 791 getActionManager: function () { 792 return this._actionManager; 793 }, 794 /** 795 * Sets the cc.ActionManager associated with this director 796 * @param {cc.ActionManager} actionManager 797 */ 798 setActionManager: function (actionManager) { 799 if (this._actionManager !== actionManager) { 800 this._actionManager = actionManager; 801 } 802 }, 803 804 /** 805 * Returns the delta time since last frame 806 * @return {Number} 807 */ 808 getDeltaTime: function () { 809 return this._deltaTime; 810 }, 811 812 _calculateMPF: function () { 813 var now = Date.now(); 814 this._secondsPerFrame = (now - this._lastUpdate) / 1000; 815 } 816 }); 817 818 /** 819 * The event projection changed of cc.Director 820 * @constant 821 * @type {string} 822 * @example 823 * cc.eventManager.addCustomListener(cc.Director.EVENT_PROJECTION_CHANGED, function(event) { 824 * cc.log("Projection changed."); 825 * }); 826 */ 827 cc.Director.EVENT_PROJECTION_CHANGED = "director_projection_changed"; 828 829 /** 830 * The event after update of cc.Director 831 * @constant 832 * @type {string} 833 * @example 834 * cc.eventManager.addCustomListener(cc.Director.EVENT_AFTER_UPDATE, function(event) { 835 * cc.log("after update event."); 836 * }); 837 */ 838 cc.Director.EVENT_AFTER_UPDATE = "director_after_update"; 839 840 /** 841 * The event after visit of cc.Director 842 * @constant 843 * @type {string} 844 * @example 845 * cc.eventManager.addCustomListener(cc.Director.EVENT_AFTER_VISIT, function(event) { 846 * cc.log("after visit event."); 847 * }); 848 */ 849 cc.Director.EVENT_AFTER_VISIT = "director_after_visit"; 850 851 /** 852 * The event after draw of cc.Director 853 * @constant 854 * @type {string} 855 * @example 856 * cc.eventManager.addCustomListener(cc.Director.EVENT_AFTER_DRAW, function(event) { 857 * cc.log("after draw event."); 858 * }); 859 */ 860 cc.Director.EVENT_AFTER_DRAW = "director_after_draw"; 861 862 /*************************************************** 863 * implementation of DisplayLinkDirector 864 **************************************************/ 865 cc.DisplayLinkDirector = cc.Director.extend(/** @lends cc.Director# */{ 866 invalid: false, 867 868 /** 869 * Starts Animation 870 */ 871 startAnimation: function () { 872 this._nextDeltaTimeZero = true; 873 this.invalid = false; 874 }, 875 876 /** 877 * Run main loop of director 878 */ 879 mainLoop: function () { 880 if (this._purgeDirectorInNextLoop) { 881 this._purgeDirectorInNextLoop = false; 882 this.purgeDirector(); 883 } 884 else if (!this.invalid) { 885 this.drawScene(); 886 } 887 }, 888 889 /** 890 * Stops animation 891 */ 892 stopAnimation: function () { 893 this.invalid = true; 894 }, 895 896 /** 897 * Sets animation interval 898 * @param {Number} value the animation interval desired 899 */ 900 setAnimationInterval: function (value) { 901 this._animationInterval = value; 902 if (!this.invalid) { 903 this.stopAnimation(); 904 this.startAnimation(); 905 } 906 } 907 }); 908 909 cc.Director.sharedDirector = null; 910 cc.Director.firstUseDirector = true; 911 912 cc.Director._getInstance = function () { 913 if (cc.Director.firstUseDirector) { 914 cc.Director.firstUseDirector = false; 915 cc.Director.sharedDirector = new cc.DisplayLinkDirector(); 916 cc.Director.sharedDirector.init(); 917 } 918 return cc.Director.sharedDirector; 919 }; 920 921 /** 922 * Default fps is 60 923 * @type {Number} 924 */ 925 cc.defaultFPS = 60; 926 927 //Possible OpenGL projections used by director 928 /** 929 * Constant for 2D projection (orthogonal projection) 930 * @constant 931 * @type {Number} 932 */ 933 cc.Director.PROJECTION_2D = 0; 934 935 /** 936 * Constant for 3D projection with a fovy=60, znear=0.5f and zfar=1500. 937 * @constant 938 * @type {Number} 939 */ 940 cc.Director.PROJECTION_3D = 1; 941 942 /** 943 * Constant for custom projection, if cc.Director's projection set to it, it calls "updateProjection" on the projection delegate. 944 * @constant 945 * @type {Number} 946 */ 947 cc.Director.PROJECTION_CUSTOM = 3; 948 949 /** 950 * Constant for default projection of cc.Director, default projection is 3D projection 951 * @constant 952 * @type {Number} 953 */ 954 cc.Director.PROJECTION_DEFAULT = cc.Director.PROJECTION_2D; 955