scenemanager.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. //
  2. // p5 SceneManager helps you create p5.js sketches with multiple states / scenes
  3. // Each scene is a like a sketch within the main sketch. You focus on creating
  4. // the scene like a regular sketch and SceneManager ensure scene switching
  5. // routing the main setup(), draw(), mousePressed(), etc. events to the
  6. // appropriate current scene.
  7. //
  8. // Author: Marian Veteanu
  9. // http://github.com/mveteanu
  10. //
  11. function SceneManager(p)
  12. {
  13. this.scenes = [];
  14. this.scene = null;
  15. // Wire relevant p5.js events, except setup()
  16. // If you don't call this method, you need to manually wire events
  17. this.wire = function()
  18. {
  19. const P5Events = [ "mouseClicked",
  20. "mousePressed",
  21. "mouseReleased",
  22. "mouseMoved",
  23. "mouseDragged",
  24. "doubleClicked",
  25. "mouseWheel",
  26. "keyPressed",
  27. "keyReleased",
  28. "keyTyped",
  29. "touchStarted",
  30. "touchMoved",
  31. "touchEnded",
  32. "deviceMoved",
  33. "deviceTurned",
  34. "deviceShaken" ];
  35. var me = this;
  36. var o = p != null ? p : window;
  37. // Wire draw manually for speed reasons...
  38. o.draw = function(){ me.draw(); };
  39. // This loop will wire automatically all P5 events to each scene like this:
  40. // o.mouseClicked = function() { me.handleEvent("mouseClicked"); }
  41. for(var i = 0; i < P5Events.length; i++)
  42. {
  43. let sEvent = P5Events[i]; // let is necesary to set the scope at the level of for
  44. o[sEvent] = function() { me.handleEvent(sEvent) };
  45. }
  46. return me;
  47. }
  48. // Add a scene to the collection
  49. // You need to add all the scenes if intend to call .showNextScene()
  50. this.addScene = function( fnScene )
  51. {
  52. var oScene = new fnScene(p);
  53. // inject p as a property of the scene
  54. this.p = p;
  55. // inject sceneManager as a property of the scene
  56. oScene.sceneManager = this;
  57. var o = { fnScene: fnScene,
  58. oScene: oScene,
  59. hasSetup : "setup" in oScene,
  60. hasEnter : "enter" in oScene,
  61. hasDraw : "draw" in oScene,
  62. setupExecuted : false,
  63. enterExecuted : false };
  64. this.scenes.push(o);
  65. return o;
  66. }
  67. // Return the index of a scene in the internal collection
  68. this.findSceneIndex = function( fnScene )
  69. {
  70. for(var i = 0; i < this.scenes.length; i++)
  71. {
  72. var o = this.scenes[i];
  73. if ( o.fnScene == fnScene )
  74. return i;
  75. }
  76. return -1;
  77. }
  78. // Return a scene object wrapper
  79. this.findScene = function( fnScene )
  80. {
  81. var i = this.findSceneIndex( fnScene );
  82. return i >= 0 ? this.scenes[i] : null;
  83. }
  84. // Returns true if the current displayed scene is fnScene
  85. this.isCurrent = function ( fnScene )
  86. {
  87. if ( this.scene == null )
  88. return false;
  89. return this.scene.fnScene == fnScene;
  90. }
  91. // Show a scene based on the function name
  92. // Optionally you can send arguments to the scene
  93. // Arguments will be retrieved in the scene via .sceneArgs property
  94. this.showScene = function( fnScene, sceneArgs )
  95. {
  96. var o = this.findScene( fnScene );
  97. if ( o == null )
  98. o = this.addScene( fnScene );
  99. // Re-arm the enter function at each show of the scene
  100. o.enterExecuted = false;
  101. this.scene = o;
  102. // inject sceneArgs as a property of the scene
  103. o.oScene.sceneArgs = sceneArgs;
  104. }
  105. // Show the next scene in the collection
  106. // Useful if implementing demo applications
  107. // where you want to advance scenes automatically
  108. this.showNextScene = function( sceneArgs )
  109. {
  110. if ( this.scenes.length == 0 )
  111. return;
  112. var nextSceneIndex = 0;
  113. if ( this.scene != null )
  114. {
  115. // search current scene...
  116. // can be optimized to avoid searching current scene...
  117. var i = this.findSceneIndex( this.scene.fnScene );
  118. nextSceneIndex = i < this.scenes.length - 1 ? i + 1 : 0;
  119. }
  120. var nextScene = this.scenes[nextSceneIndex];
  121. this.showScene( nextScene.fnScene, sceneArgs );
  122. }
  123. // This is the SceneManager .draw() method
  124. // This will dispatch the main draw() to the
  125. // current scene draw() method
  126. this.draw = function()
  127. {
  128. // take the current scene in a variable to protect it in case
  129. // it gets changed by the user code in the events such as setup()...
  130. var currScene = this.scene;
  131. if ( currScene == null )
  132. return;
  133. if ( currScene.hasSetup && !currScene.setupExecuted )
  134. {
  135. currScene.oScene.setup();
  136. currScene.setupExecuted = true;
  137. }
  138. if ( currScene.hasEnter && !currScene.enterExecuted )
  139. {
  140. currScene.oScene.enter();
  141. currScene.enterExecuted = true;
  142. }
  143. if ( currScene.hasDraw )
  144. {
  145. currScene.oScene.draw();
  146. }
  147. }
  148. // Handle a certain even for a scene...
  149. // It is used by the anonymous functions from the wire() function
  150. this.handleEvent = function(sEvent)
  151. {
  152. if ( this.scene == null || this.scene.oScene == null )
  153. return;
  154. var fnSceneEvent = this.scene.oScene[sEvent];
  155. if (fnSceneEvent)
  156. fnSceneEvent.call(this.scene.oScene);
  157. }
  158. // Legacy method... preserved for maintaining compatibility
  159. this.mousePressed = function()
  160. {
  161. this.handleEvent("mousePressed");
  162. }
  163. // Legacy method... preserved for maintaining compatibility
  164. this.keyPressed = function()
  165. {
  166. this.handleEvent("keyPressed");
  167. }
  168. }