Cats-vs-Mice/js/scenemanager.js
2025-05-01 16:27:01 +09:00

211 lines
6.0 KiB
JavaScript

//
// p5 SceneManager helps you create p5.js sketches with multiple states / scenes
// Each scene is a like a sketch within the main sketch. You focus on creating
// the scene like a regular sketch and SceneManager ensure scene switching
// routing the main setup(), draw(), mousePressed(), etc. events to the
// appropriate current scene.
//
// Author: Marian Veteanu
// http://github.com/mveteanu
//
function SceneManager(p)
{
this.scenes = [];
this.scene = null;
// Wire relevant p5.js events, except setup()
// If you don't call this method, you need to manually wire events
this.wire = function()
{
const P5Events = [ "mouseClicked",
"mousePressed",
"mouseReleased",
"mouseMoved",
"mouseDragged",
"doubleClicked",
"mouseWheel",
"keyPressed",
"keyReleased",
"keyTyped",
"touchStarted",
"touchMoved",
"touchEnded",
"deviceMoved",
"deviceTurned",
"deviceShaken" ];
var me = this;
var o = p != null ? p : window;
// Wire draw manually for speed reasons...
o.draw = function(){ me.draw(); };
// This loop will wire automatically all P5 events to each scene like this:
// o.mouseClicked = function() { me.handleEvent("mouseClicked"); }
for(var i = 0; i < P5Events.length; i++)
{
let sEvent = P5Events[i]; // let is necesary to set the scope at the level of for
o[sEvent] = function() { me.handleEvent(sEvent) };
}
return me;
}
// Add a scene to the collection
// You need to add all the scenes if intend to call .showNextScene()
this.addScene = function( fnScene )
{
var oScene = new fnScene(p);
// inject p as a property of the scene
this.p = p;
// inject sceneManager as a property of the scene
oScene.sceneManager = this;
var o = { fnScene: fnScene,
oScene: oScene,
hasSetup : "setup" in oScene,
hasEnter : "enter" in oScene,
hasDraw : "draw" in oScene,
hasExit : "exit" in oScene,
setupExecuted : false,
enterExecuted : false
};
this.scenes.push(o);
return o;
}
// Return the index of a scene in the internal collection
this.findSceneIndex = function( fnScene )
{
for(var i = 0; i < this.scenes.length; i++)
{
var o = this.scenes[i];
if ( o.fnScene == fnScene )
return i;
}
return -1;
}
// Return a scene object wrapper
this.findScene = function( fnScene )
{
var i = this.findSceneIndex( fnScene );
return i >= 0 ? this.scenes[i] : null;
}
// Returns true if the current displayed scene is fnScene
this.isCurrent = function ( fnScene )
{
if ( this.scene == null )
return false;
return this.scene.fnScene == fnScene;
}
// Show a scene based on the function name
// Optionally you can send arguments to the scene
// Arguments will be retrieved in the scene via .sceneArgs property
this.showScene = function( fnScene, sceneArgs )
{
var o = this.findScene( fnScene );
if ( o == null )
o = this.addScene( fnScene );
// Re-arm the enter function at each show of the scene
o.enterExecuted = false;
if (this.scene && this.scene.hasExit) {
this.scene.oScene.exit();
}
this.scene = o;
// inject sceneArgs as a property of the scene
o.oScene.sceneArgs = sceneArgs;
}
// Show the next scene in the collection
// Useful if implementing demo applications
// where you want to advance scenes automatically
this.showNextScene = function( sceneArgs )
{
if ( this.scenes.length == 0 )
return;
var nextSceneIndex = 0;
if ( this.scene != null )
{
// search current scene...
// can be optimized to avoid searching current scene...
var i = this.findSceneIndex( this.scene.fnScene );
nextSceneIndex = i < this.scenes.length - 1 ? i + 1 : 0;
}
var nextScene = this.scenes[nextSceneIndex];
this.showScene( nextScene.fnScene, sceneArgs );
}
// This is the SceneManager .draw() method
// This will dispatch the main draw() to the
// current scene draw() method
this.draw = function()
{
// take the current scene in a variable to protect it in case
// it gets changed by the user code in the events such as setup()...
var currScene = this.scene;
if ( currScene == null )
return;
if ( currScene.hasSetup && !currScene.setupExecuted )
{
currScene.oScene.setup();
currScene.setupExecuted = true;
}
if ( currScene.hasEnter && !currScene.enterExecuted )
{
currScene.oScene.enter();
currScene.enterExecuted = true;
}
if ( currScene.hasDraw )
{
currScene.oScene.draw();
}
}
// Handle a certain event for a scene...
// It is used by the anonymous functions from the wire() function
this.handleEvent = function(sEvent)
{
if ( this.scene == null || this.scene.oScene == null )
return;
var fnSceneEvent = this.scene.oScene[sEvent];
if (fnSceneEvent)
fnSceneEvent.call(this.scene.oScene);
}
// Legacy method... preserved for maintaining compatibility
this.mousePressed = function()
{
this.handleEvent("mousePressed");
}
// Legacy method... preserved for maintaining compatibility
this.keyPressed = function()
{
this.handleEvent("keyPressed");
}
}