-
Notifications
You must be signed in to change notification settings - Fork 0
Copycat object
TODO: Fill this in!
(This is basically revisiting the idea here in light of some ideas hashed out in the other page mentioned next.)
Other possibilities for the name: follower, mimic, shadow. The last one already has graphical connotations, though (in fact, this would be a handy use for it). The names are never quite right, since the ability to make individual properties independent (not just via the parent) would be quite helpful.
There are some opportunities here that present themselves, for instance re-introducing objects into the rendering stream as suggested here. This is probably the more natural and general way to do so, for that matter.
In reviewing a bit, probably graphics or display object methods would provide a means to do this, where supported (it's genuinely difficult for some cases, e.g. groups, lines, meshes), or else the objects in question could expose such a method, if it was felt that the result could measure up to the challenge!
Once instantiated, the relevant properties could probably be enumerated, on first use, by what the object in question provides, otherwise providing nil. (TODO: Off-hand, three different means of instantiation.) Before submission, would query a dirty flag and synchronize propertties.
In practice we might want to be explicit that we're using a copycat? So, e.g. stuff like xCopy
or setFrameCopy()
, although that looks a little annoying. Not sure here.
Sub-properties, such as the different fields of a fill, would also be useful to configure, if not too difficult. In any case, swapping out the texture or shader would offer benefits as well.
In looking through the code, it seems like a matter of deciding which RenderData
to draw from, probably suggesting how to handle some of the memory concerns.
Some things, given their current list of behaviors, would be "easy" to do, e.g. circles, rects, polygons, probably images and sprites, maybe emitters.
Meshes seem feasible although we'd need to resync the lists if allowed to only modify individual vertices, uvs, etc.
Lines present a complication, since adding vertices is cumulative and there's no "correct" way to proceed once the two diverge. Text is like this as well. Then again, copycats of these would be useful even were these features blacklisted.
The various group-ish things (vanilla groups, containers, snapshots) also seem like major headaches, and probably worth just omitting. In particular, allowing the copycat to appear in the original's tree sounds like a disaster waiting to happen. (For convenience, though, maybe a method to make a shallow "copy" of a stock group would be useful, where a follower is emitted for each feasible object? Then again, it would probably be better to just offer enough to do this reliably from Lua.)
After some review of the source, some of the important details seem to go like this:
The proxy vtable stuff is the main area of focus. Objects will mostly be rerouting property accesses.
The "true" objects that are able to be followed would expose some method, say follow
, in their respective getters. The followers would have a similar-looking getter, but omitting this method and possibly a few other problem ones, e.g. append
for lines as described above.
The bulk of several getters and setters could be hoisted into auxiliary functions to allow us to change the object being queried / assigned. This would allow reusing the bulk of the logic in a follower, apart from those blacklisted as just mentioned or that need additional bookkeeping, or the type property. It would also handle the logic for nil assignments.
Ideally the follower objects will be essentially the same type as the original aside from the different proxy table. A virtual clone
method would be supplied to copy over the representation intact. After a call to follow
, a flag will be set in the prototype object indicating that it has (or once had, if it's not worth cleaning it up after going unreferenced) followers. It would contain a list of pointers to any followers. A follower, on the other hand, will contain a link back to the prototype, and be unable to have its own followers.
More than likely, we will usually want to clean up any followers when the prototype goes away, though there could be a flag to make them decay to a vanilla object. By the looks of it, the onRemovedFromParent
method could be used to do cleanup in both directions.
On any "did write"-type property assignment to a prototype-style object, the property will be broadcast to its followers. For each object, we do a lookup to see if it has its own value, calling its setter otherwise. If we drop a property, on the other hand, we call the prototype's getter and then call the follower's setter. (For some properties like colors and such, maybe we need to provide our own variants with a "memory" of the most recent values?)
There are table-style properties like fill
as well. These might require some kind of proxy object, since we'd like to reuse the prototype's, but would then need to do a copy-on-write if we assigned anything via the follower. Would this be all or nothing, or then have a sub-property list?
This is medium- to high-priority, if it does ultimately seem the way to go.