-
-
Notifications
You must be signed in to change notification settings - Fork 183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for p5 instance mode #22
Conversation
Conflicts: lib/p5.play.js
Conflicts: lib/p5.play.js
Hey @islemaster, would you be interested in code reviewing this at all? It'd be really great to have a second pair of eyes on this, but no worries if not. |
I'll be happy to. I can take a look later today.
|
Awesome, thanks!!! I just updated the description of this PR to reflect some API design considerations too. |
// The above will create functions createVector and loadImage, which can be | ||
// used similar to p5 global mode--however, they're bound to specific p5 | ||
// instances, and can thus be used outside of global mode. | ||
function createPInstBinder(pInst) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how I feel about this createPInstBinder
thing--I admit that I did it partly out of laziness, but also because I didn't want to hamper readability by having a million things be prefixed with pInst.
or this.
.
A couple of initial thoughts, more on the way.
Thanks for tackling this big change! |
Great ideas! I've just filed those PRs, and will implement your suggestion for the curried constructors. |
Oh, do you have time to take a look at the new PRs? It's ok if not, just let me know. |
I do ; sorry, I'm on Pacific time and can review more in about 90 minutes.
|
Awesome, thanks! So in 768b414 I added the currying you suggested. Now I think all that's left is to decide whether we also want to expose the non-documented constructors |
// This returns a factory function, suitable for passing to | ||
// defineLazyP5Property, that returns a subclass of the given | ||
// constructor that is always bound to a particular p5 instance. | ||
function boundConstructorFactory(constructor) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ug, it's a factory for creating constructors... Not a huge fan of the multiple levels of indirection but it's all I could think of for now.
Conflicts: test/unit/keycodes.js
|
||
defineLazyP5Property('allSprites', function() { return new Group(); }); | ||
|
||
p5.prototype.spriteUpdate = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a problem - the whole reason you wrote defineLazyP5Property
? I assume the value of spriteUpdate
isn't shared across all p5 instances. If this is working, why can't you just
p5.prototype.allSprites = new Group():
since Group
has no dependencies on p5 either? (Probably because you interact with allSprites
by modifying it, never overwriting the reference, right?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be easiest to answer these questions by writing some tests that verify these properties are not shared when you make multiple instances.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh good idea about the tests! I'll do that.
So the main reason I wrote defineLazyP5Property
was actually so that mutable properties, like allSprites
, would be per-instance, rather than global. e.g. so that calling sketch1.allSprites.add(mySprite)
wouldn't also add the sprite to sketch2.allSprites
. Since booleans like spriteUpdate
are immutable, and since assigning to the property will actually set it on a particular p5 instance rather than the prototype, I thought it would be OK to put the "starting" value on the prototype. Does that make sense?
In any case, I totally agree that tests would serve both as good executable documentation and as protection against regressions, so I'll do that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that make sense now. Thanks for clarifying!
Recommendation: Also break the following commit out into its own PR: |
After all that, I don't think I have anything else to add. Thanks for your patience with my gradual understanding of the initialization challenges around p5 instance properties! |
As suggeseted by @islemaster in: https://github.com/molleindustria/p5.play/pull/22#discussion_r53377780 Coincidentally, this also gets rid of a nasty bug surfaced by the last merge. Yay!
Awesome, thanks @islemaster! And no worries, I'm actually learning how this code works myself too, hehe. It's been very helpful to have a second set of eyes reading over this. |
Add support for p5 instance mode
Added a global !mouseIsPressed in addition to !this.mouseIsPressed because when you attempt to drag a sprite you are likely to roll out of its collider setting this.mouseIsPressed to false and triggering the release function. I hope it doesn't break anything.
This adds support for p5 instance mode in p5.play, which fixes #12.
Global Sketch Properties
A number of variables, like
allSprites
, were formerly global, but now need to be bound to the lifetime of a particular sketch instance. I found doing this a bit tricky because there seems to be no easy way to initialize such properties upon sketch initialization; I've documented this limitation and my workaround for it at processing/p5.js#1263.Constructor Changes
One particular challenge of this feature is the fact that almost all of the p5.play classes, with the notable exception of
Group
, now need to be bound to ap5
instance; I've changed their constructors to take this instance as their first argument. However, this makes it a bit tricky to support legacy code.Ideally, we should simply expose the instantiation of these classes via factory functions onp5.prototype
, which is already being done withcreateSprite
,loadAnimation
, andloadSpriteSheet
--however, the constructors of all these classes are also publicly documented, which means that it's entirely possible for legacy code to be instantiating them directly--for example, theexamples/sprites_with_sheet.js
example directly callsnew SpriteSheet()
at one point instead of usingloadSpriteSheet()
.An alternative here is to simply not support legacy code when it's problematic, and increment the major version number in the next release as per semantic versioning to indicate backwards-incompatible API changes.As per @islemaster's suggestion, we're exposing curried versions of the constructors on all created p5 instances, so legacy code still works!
Formerly Global Variables
In order for this to work properly, I had to enclose the entire library in an IIFE. Previously, only about half of the library was enclosed in one, which meant that some of its private implementation functions, like
construct
, were actually in global scope (see below for a full list). While all the examples in theexamples/
directory still work fine, I hope that third-party code still works. Might be a good idea to QA this somehow.The following were formerly globals but are now enclosed in an IIFE:
Sprite
(now exposed viap5.prototype.Sprite
)Camera
(now exposed viap5.prototype.Camera
)cameraPush
cameraPop
Group
(now exposed viap5.prototype.Group
)CircleCollider
AABB
Animation
(now exposed viap5.prototype.Animation
)SpriteSheet
(now exposed viap5.prototype.SpriteSheet
)Quadtree
updateTree
construct
Note that even for the items that are now exposed via
p5.prototype
, they won't become globals until and unless p5 enters global mode on page load.Examples Changes
Nothing was changed in the examples, because I wanted to make sure p5.play still works with legacy code.
However, I did get rid of the extra copy ofThis is still true, but has been spun out into #36.p5.play.js
in f1363d1 so that we don't need to pollute the repository's commit history by constantly updating two separate copies of the library.Other Notes
Of great help here was:
This logs any undefined globals, which was useful in finding p5 global methods/properties that needed to be bound to p5 instances.
To Do
Animation
, at least in a deprecated way, as its constructor is currently publicly documented.Camera
, at least in a deprecated way, as its constructor is currently publicly documented.Sprite
, at least in a deprecated way, as its constructor is currently publicly documented.(deprecated methods,.pInst
as first argument for constructors, etc)