We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Since this question crops up regularly I figured I'd write a separate post with a clear title so hopefully it will be easy to find...
To understand instance mode you have to understand what's happening inside p5 when you invoke it. The official example passes a callback function named 'sketch' to the p5 constructor:
var myp5 = new p5(sketch);
Here's a simplified representation of what p5 does with that callback:
// a pseudo class:
var iamP5 = function(callback) {
this.name = "P5 impostor";
this.someProperty = "foo";
// *** pass a reference to the newly created object into the callback ***
callback(this);
};
// pseudo-class method:
iamP5.prototype.sayName = function() {
console.info(this.name);
};
// instantiate the pseudo-class passing it our callback function
new iamP5 (sketch);
// the callback being passed to foo. Could equally be
// a directly passed anonymous function
function sketch(input) {
// Here 'input' is the 'this' being passed to callback() in iamP5's 'constructor'.
// It therefore acts as a reference to the instance of foo created above.
// Any property or method exposed by foo can be accessed via this variable.
// If you need to reference it a lot you might choose a shorter variable
// name such as 'p'; which is what is generally recommended with p5...
console.info(input.someProperty);
input.sayName();
// if they aren't protected you can override properties
// and methods of the instantiated object (see notes below)
input.sayName = function() {
console.log("I am a robot");
}
input.sayName();
}
It's obviously significantly more complex than that in reality but I think that's enough to explain the code structure... The ability to override or add properties and methods to the instance of p5 is important for two reasons:
It's worth mentioning that the ability to pass a function as a parameter to another function - as demonstrated above - is one of the features that makes JS such a powerful and flexible language. It's also a feature that, if not applied carefully, can lead to brittle, hard to maintain code ;)
This post is intended to be helpful to people unfamiliar with instance mode. Feedback is most welcome.
Answers
Example with two sketches
index.html
sketch.js
Note the comment on mousePressed in the second instance: the same will apply to other event listeners so you will need to do additional work to check if the mouse is over the current sketch and be careful with keyboard input as this will trigger events in all sketches (of course that might also be useful in some cases)...
Attaching to a dynamically created node
Notice that the sketch import has been moved to the body tag. It should appear after any node (i.e. content) that the sketch script might reference.
index.html
sketch.js
Global variables between sketches
Passing a single p5 reference to external objects
I'll start with an example of an anti-pattern mainly because I've advocated use of this when working with single sketches...
WARNING: the following should only be considered if you have a single sketch:
The obvious reason the above strategy would be problematic with multiple sketches is that any classes referencing the global variable could only realistically be used in that particular sketch instance. The 'advantage' of this pattern when working with a single sketch is that you don't have to explicitly pass a reference into object instances.
Passing a p5 reference to external objects
Storing a reference on the object
Here a reference to the p5 instance is stored in the object on instantiation. The advantage is you don't have to pass additional parameters to class methods; but referencing the p5 instance does require you to use
this.p
instead of simplyp
. You can of course store the reference in a function level variable calledp
...This pattern might be useful if you need to call methods on all instances of a pseudo-class independently from the individual sketches they reference; since you only have to pass a reference when first initialised... You may also want to take this approach if methods are called internally but need to reference the sketch instance; otherwise you may find yourself passing a reference to the sketch instance between internal methods.
Passing a reference to all object methods
In this pattern a reference to the p5 instance is passed in whenever it is needed:
This avoids the need for aliasing
this.p
but means you have to remember to pass a reference to all methods that require it; including those called internally... That means object methods dependent on the p5 instance can only be called from inside the sketch code or from methods themselves called from the sketch code.