kopia lustrzana https://github.com/backface/turtlestitch
updated Morpic documentation
rodzic
ad7ce96abb
commit
dd4399ba23
211
src/morphic.js
211
src/morphic.js
|
@ -26,55 +26,6 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
*** UNDER CONSTRUCTIOM ***
|
|
||||||
|
|
||||||
Morphic changes to v1:
|
|
||||||
|
|
||||||
* noticesTransparentClick => !isFreeForm (reversed default)
|
|
||||||
* drawOn() / fullDrawOn() takes context instead of Canvas as first arg
|
|
||||||
* drawNew() is deprecated => render(), also takes context as arg
|
|
||||||
* rerender() to earmark for rerendering
|
|
||||||
* image has a getter method: getImage()
|
|
||||||
* image has been renamed to cachedImage
|
|
||||||
* isCachingImage flag (default: false)
|
|
||||||
* shouldRerender flag (default: false)
|
|
||||||
* fixLayout() determines extent and arranges submorphs, if any, gets called
|
|
||||||
from setExtent()
|
|
||||||
* fixHolesLayout
|
|
||||||
|
|
||||||
"silent" - functions are no longer needed:
|
|
||||||
|
|
||||||
* silentSetExtent => bounds.setExtent()
|
|
||||||
* silentMoveBy
|
|
||||||
* silentSetPosition
|
|
||||||
* silentSetWidth => bounds.setWidth()
|
|
||||||
* silentSetHeight = bounds.setHeight()
|
|
||||||
|
|
||||||
likewise "silent" parameters are no longer needed and supported
|
|
||||||
|
|
||||||
* cachedFullImage
|
|
||||||
* cachedFullBounds
|
|
||||||
|
|
||||||
are deprecated
|
|
||||||
|
|
||||||
"trackChanges" and other damage-list housekeeping tweaks are no longer
|
|
||||||
needed and no longer supported, except for the Pen constructor's isWarped
|
|
||||||
property and its methods, such as startWarp and endWarp.
|
|
||||||
|
|
||||||
Pen >> wantsRedraw is no longer needed and deprecated
|
|
||||||
|
|
||||||
holes:
|
|
||||||
Morphs have a list of rectangles representing "untouchable" areas
|
|
||||||
|
|
||||||
* virtualKeyboard property and Morphic preference has been deprecated
|
|
||||||
* fullImageClassic() => is always just fullImage()
|
|
||||||
* keyboardReceiver => keyboardFocus
|
|
||||||
|
|
||||||
* keyboard navigation can be activated for any visible menu by pressing an arbitrary key
|
|
||||||
|
|
||||||
* new "noDropShadow" property for Morphs that already have built-in shadows (Menus, SpeechBubbles)
|
|
||||||
* new "fullShadowSource" flag for Morphs, default is true, turn off (false) to only use the simple image instead of fullImage()
|
|
||||||
|
|
||||||
documentation contents
|
documentation contents
|
||||||
----------------------
|
----------------------
|
||||||
I. inheritance hierarchy
|
I. inheritance hierarchy
|
||||||
|
@ -100,6 +51,13 @@
|
||||||
(h) text editing events
|
(h) text editing events
|
||||||
(4) stepping
|
(4) stepping
|
||||||
(5) creating new kinds of morphs
|
(5) creating new kinds of morphs
|
||||||
|
(a) drawing the shape
|
||||||
|
(b) determining extent and arranging submorphs
|
||||||
|
(c) pixel-perfect pointing events
|
||||||
|
(d) caching the shape
|
||||||
|
(e) holes
|
||||||
|
(f) updating
|
||||||
|
(g) duplicating
|
||||||
(6) development and user modes
|
(6) development and user modes
|
||||||
(7) turtle graphics
|
(7) turtle graphics
|
||||||
(8) supporting high-resolution "retina" screens
|
(8) supporting high-resolution "retina" screens
|
||||||
|
@ -897,25 +855,156 @@
|
||||||
--------------------------------
|
--------------------------------
|
||||||
The real fun begins when you start to create new kinds of morphs
|
The real fun begins when you start to create new kinds of morphs
|
||||||
with customized shapes. Imagine, e.g. jigsaw puzzle pieces or
|
with customized shapes. Imagine, e.g. jigsaw puzzle pieces or
|
||||||
musical notes. For this you have to override the default
|
musical notes.
|
||||||
|
|
||||||
|
When you create your own morphs, you'll want to think about how to
|
||||||
|
graphically render it, how to determine its size and whether it needs
|
||||||
|
to arrange any other parts ("submorphs). There are also ways to specify
|
||||||
|
its collision detection behavior and define "untouchable" regions
|
||||||
|
("holes").
|
||||||
|
|
||||||
|
|
||||||
|
(a) drawing the shape
|
||||||
|
---------------------
|
||||||
|
For this you have to override the default
|
||||||
|
|
||||||
render(ctx)
|
render(ctx)
|
||||||
|
|
||||||
method.
|
method.
|
||||||
|
|
||||||
This method draws the morph's shape with a 2d graphics context.
|
This method draws the morph's shape using a given 2d graphics context.
|
||||||
|
Note that any coordinates used in the render() method must be relative
|
||||||
|
to the morph's own position, i.e. you don't need to worry about
|
||||||
|
translating the shape yourself.
|
||||||
|
|
||||||
explain
|
You can use the following template for a start:
|
||||||
|
|
||||||
* isCachingImage
|
|
||||||
* isFreeForm = bool
|
|
||||||
|
|
||||||
Use the following template for a start:
|
|
||||||
|
|
||||||
MyMorph.prototype.render = function(ctx) {
|
MyMorph.prototype.render = function(ctx) {
|
||||||
// use ctx to paint stuff here
|
ctx.fillStyle = this.color.toString();
|
||||||
|
ctx.fillRect(0, 0, this.width(), this.height());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
it renders the morph as a solid rectangle completely filling its
|
||||||
|
area with its current color.
|
||||||
|
|
||||||
|
Notice how the coordinates for the fillRect() call are relative
|
||||||
|
to the morph's own position: The rendered rectangle's origin is always
|
||||||
|
located at (0, 0) regardless of the morph's actual position in the World.
|
||||||
|
|
||||||
|
|
||||||
|
(b) determining extent and arranging submorphs
|
||||||
|
----------------------------------------------
|
||||||
|
If your new morph also needs to determine its extent and, e.g. to
|
||||||
|
encompass one or several other morphs, or arrange the layout of its
|
||||||
|
submorphs, make sure to also override the default
|
||||||
|
|
||||||
|
fixLayout()
|
||||||
|
|
||||||
|
method.
|
||||||
|
|
||||||
|
NOTE: If you need to set the morph's extent inside, in order to avoid
|
||||||
|
infinite recursion instead of calling morph.setExtent() - which will
|
||||||
|
in turn call morph.fixLayout() again - directly modify the morph's
|
||||||
|
|
||||||
|
bounds
|
||||||
|
|
||||||
|
property. Bounds is a rectable on which you can also use the same
|
||||||
|
size-setters, e.g. by calling:
|
||||||
|
|
||||||
|
this.bounds.setExtent()
|
||||||
|
|
||||||
|
|
||||||
|
(c) pixel-perfect pointing events
|
||||||
|
---------------------------------
|
||||||
|
In case your new morph needs to support pixel-perfect collision detection
|
||||||
|
with other morphs or pointing devices such as the mouse or a stylus you
|
||||||
|
can set the inherited attribute
|
||||||
|
|
||||||
|
isFreeForm = bool
|
||||||
|
|
||||||
|
to "true" (default is "false"). This makes sense the more your morph's
|
||||||
|
visual shape diverges from a rectangle. For example, if you create a
|
||||||
|
circular filled morph the default setting will register mouse-events
|
||||||
|
anywhere within its bounding box, e.g. also in the transparent parts
|
||||||
|
between the bounding box's corners outside of the circle's bounds.
|
||||||
|
Instead you can specify your irregulary shaped morph to only register
|
||||||
|
pointing events (mouse and touch) on solid, non-transparent parts.
|
||||||
|
|
||||||
|
Notice, however, that such pixel-perfect collision detection might
|
||||||
|
strain processing resources, especially if applied liberally.
|
||||||
|
|
||||||
|
In order to mitigate unfavorable processor loads for pixel-perfect
|
||||||
|
collision deteciton of irregularly shaped morphs there are two strategies
|
||||||
|
to consider: Caching the shape and specifying "untouchable" regions.
|
||||||
|
|
||||||
|
|
||||||
|
(d) caching the shape
|
||||||
|
---------------------
|
||||||
|
In case of pixel-perfect free-form collision detection it makes sense to
|
||||||
|
cache your morph's current shape, so it doesn't have to be re-drawn onto a
|
||||||
|
new Canvas element every time the mouse moves over its bounding box.
|
||||||
|
For this you can set then inherited
|
||||||
|
|
||||||
|
isCachingImage = bool
|
||||||
|
|
||||||
|
attribute to "true" instead of the default "false" value. This will
|
||||||
|
significantly speed up collision detection and smoothen animations that
|
||||||
|
continuously perform collision detection. However, it will also consume
|
||||||
|
more memory. Therefore it's best to use this setting with caution.
|
||||||
|
|
||||||
|
Snap! caches the shapes of sprites but not those of blocks. Instead it
|
||||||
|
manages the insides of C- and E-shaped blocks through the morphic "holes"
|
||||||
|
mechanism.
|
||||||
|
|
||||||
|
|
||||||
|
(e) holes
|
||||||
|
---------
|
||||||
|
An alternative albeit not as precise and general way for handling
|
||||||
|
irregularly shaped morphs with "untouchable" regions is to specify a set
|
||||||
|
of rectangular areas in which pointing events (mouse or touch) are not
|
||||||
|
registered.
|
||||||
|
|
||||||
|
By default the inherited
|
||||||
|
|
||||||
|
holes = []
|
||||||
|
|
||||||
|
property is an empty array. You can add one or more morphic Rectangle
|
||||||
|
objects to this list, representing regions, in which occurring events will
|
||||||
|
instead be passed on to the morph underneath.
|
||||||
|
|
||||||
|
Note that, same with the render() method, the coordinates of these
|
||||||
|
rectangular holes must be specified relative to your morph's position.
|
||||||
|
|
||||||
|
If you specify holes you might find the need to adjust their layout
|
||||||
|
depending on the layout of your morph. To accomplish this you can override
|
||||||
|
the inherited
|
||||||
|
|
||||||
|
fixHolesLayout()
|
||||||
|
|
||||||
|
method.
|
||||||
|
|
||||||
|
|
||||||
|
(f) updating
|
||||||
|
------------
|
||||||
|
One way for morphs to become alive is form them to literally "morph" their
|
||||||
|
shape depending on whicher contest you wish them to react to. For example,
|
||||||
|
you might want the user to interactively draw a shape using their fingers
|
||||||
|
on a touch screen device, or you want the user to be able to "pinch" or
|
||||||
|
otherwise distort a shape interactively. In all of these situations you'll
|
||||||
|
want your morph to frequently rerender its shape.
|
||||||
|
|
||||||
|
You can accomplish this, by calling
|
||||||
|
|
||||||
|
rerender()
|
||||||
|
|
||||||
|
after every change to your morph's appearance that requires rerendering.
|
||||||
|
|
||||||
|
Such changes are usually only happening when the morph's dimensions or
|
||||||
|
other visual properties - such as its color - changes.
|
||||||
|
|
||||||
|
|
||||||
|
(g) duplicating
|
||||||
|
---------------
|
||||||
If your new morph stores or references to other morphs outside of
|
If your new morph stores or references to other morphs outside of
|
||||||
the submorph tree in other properties, be sure to also override the
|
the submorph tree in other properties, be sure to also override the
|
||||||
default
|
default
|
||||||
|
@ -3378,12 +3467,16 @@ Morph.prototype.fixLayout = function () {
|
||||||
// implemented by my heirs
|
// implemented by my heirs
|
||||||
// determine my extent and arrange my submorphs, if any
|
// determine my extent and arrange my submorphs, if any
|
||||||
// default is to do nothing
|
// default is to do nothing
|
||||||
|
// NOTE: If you need to set the extent, in order to avoid
|
||||||
|
// infinite recursion instead of calling setExtent() (which will
|
||||||
|
// in turn call fixLayout() again) directly modify the bounds
|
||||||
|
// property, e.g. like this: this.bounds.setExtent()
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
Morph.prototype.fixHolesLayout = function () {
|
Morph.prototype.fixHolesLayout = function () {
|
||||||
// implemented by my heirs
|
// implemented by my heirs
|
||||||
// determine my extent and arrange my submorphs, if any
|
// arrange my untouchable areas, if any
|
||||||
// default is to do nothing
|
// default is to do nothing
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
Ładowanie…
Reference in New Issue