Clones

Clones are created in two phases: First, we create a new Python instance with the same properties as the existing one; this is done via standard Python deepcopy(). (We might hit some limitations of this in future, but so far it seems to be working.) Second, we register that instance with the Project; see next.

Registering a clone

When registering a clone, that counts as that instance ‘starting as a clone’ in the Scratch sense. A list of handlers for this event is stored in the PytchActor instance. We only want to run methods on the particular instance being registered, so handlers are not stored in the central event-handler map of the Actor, but in a dedicated list clone_handlers. Threads are created, gathered into one thread-group, and marked ‘running’, ready for the next time round one_frame().

A newly-registered clone is inserted in the drawing order just before the instance from which it was cloned. This makes it appear just behind its parent instance, from the viewer’s perspective.

‘Deleting’ a clone

This only de-registers the JavaScript-side PytchActorInstance. The actual Python object can continue to exist, although nothing (except perhaps threads: see below) within Pytch refers to it any more, so it will play no further part in the running of the Project.

We must handle races which arise if more than one thread does delete-this-clone “concurrently” (i.e., in the same frame).

A deleted clone might have live threads on it; those threads need to be killed. We note in the PytchActorInstance whether the Python-side object is registered with Pytch — starts off ‘true’, set to ‘false’ on de-registration. A thread is turned into a zombie if its target is dereg’d.

Red stop

When the red-stop event happens, we discard all clones (this does not include the instance-0 ‘original’ of each Sprite) by truncating the list of PytchActorInstances down to just its original instance. We also empty the list of thread groups, effectively killing all threads. There is no need for a ‘stop’ method on the Thread class, because a Thread will never be one_frame()’d again given that its thread-group is not part of the project’s ‘live thread groups’ list. And we stop all sounds (see own section).

The green-flag event does an implicit red-stop first.