kopia lustrzana https://github.com/backface/turtlestitch
new feature/block: sense colors and sprites anywhere
use sprites to read/write data encoded in colorspull/89/head
rodzic
9ea9c8c3f5
commit
b2b3aea8d2
|
@ -2,6 +2,9 @@
|
|||
|
||||
## in development
|
||||
|
||||
### 2019-01-04
|
||||
* Objects, Blocks, Threads: new feature/block: sense colors and sprites anywhere
|
||||
|
||||
### 2019-01-02
|
||||
* Objects, Blocks, Threads, GUI, Store: added third color dimension and transparency to pen
|
||||
* renamed help screens for "setHue" to "setPenHSVA" and "changeHue" to "changePenHSVA"
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
<link rel="shortcut icon" href="src/favicon.ico">
|
||||
<script type="text/javascript" src="src/morphic.js?version=2019-01-01"></script>
|
||||
<script type="text/javascript" src="src/widgets.js?version=2018-10-02"></script>
|
||||
<script type="text/javascript" src="src/blocks.js?version=2019-01-02"></script>
|
||||
<script type="text/javascript" src="src/threads.js?version=2019-01-02"></script>
|
||||
<script type="text/javascript" src="src/objects.js?version=2019-01-02"></script>
|
||||
<script type="text/javascript" src="src/blocks.js?version=2019-01-04"></script>
|
||||
<script type="text/javascript" src="src/threads.js?version=2019-01-04"></script>
|
||||
<script type="text/javascript" src="src/objects.js?version=2019-01-04"></script>
|
||||
<script type="text/javascript" src="src/gui.js?version=2019-01-02"></script>
|
||||
<script type="text/javascript" src="src/paint.js?version=2018-10-02"></script>
|
||||
<script type="text/javascript" src="src/lists.js?version=2018-10-02"></script>
|
||||
|
|
|
@ -148,7 +148,7 @@ CustomCommandBlockMorph, SymbolMorph, ToggleButtonMorph, DialMorph*/
|
|||
|
||||
// Global stuff ////////////////////////////////////////////////////////
|
||||
|
||||
modules.blocks = '2019-January-02';
|
||||
modules.blocks = '2019-January-04';
|
||||
|
||||
var SyntaxElementMorph;
|
||||
var BlockMorph;
|
||||
|
@ -1091,6 +1091,14 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
|
|||
true // read-only
|
||||
);
|
||||
break;
|
||||
case '%loc': // location
|
||||
part = new InputSlotMorph(
|
||||
null,
|
||||
false,
|
||||
'locationMenu',
|
||||
true
|
||||
);
|
||||
break;
|
||||
case '%spr':
|
||||
part = new InputSlotMorph(
|
||||
null,
|
||||
|
@ -1302,6 +1310,22 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
|
|||
);
|
||||
part.setContents(['front']);
|
||||
break;
|
||||
case '%asp': // aspect
|
||||
part = new InputSlotMorph(
|
||||
null,
|
||||
false,
|
||||
{
|
||||
color : ['color'],
|
||||
saturation : ['saturation'],
|
||||
brightness : ['brightness'],
|
||||
transparency : ['transparency'],
|
||||
'~' : null,
|
||||
sprites : ['sprites'],
|
||||
},
|
||||
true
|
||||
);
|
||||
part.setContents(['color']);
|
||||
break;
|
||||
case '%txtfun':
|
||||
part = new InputSlotMorph(
|
||||
null,
|
||||
|
@ -8493,6 +8517,31 @@ InputSlotMorph.prototype.collidablesMenu = function () {
|
|||
return dict;
|
||||
};
|
||||
|
||||
InputSlotMorph.prototype.locationMenu = function () {
|
||||
var dict = {
|
||||
'mouse-pointer' : ['mouse-pointer'],
|
||||
'myself' : ['myself']
|
||||
},
|
||||
rcvr = this.parentThatIsA(BlockMorph).scriptTarget(),
|
||||
stage = rcvr.parentThatIsA(StageMorph),
|
||||
allNames = [];
|
||||
|
||||
stage.children.forEach(function (morph) {
|
||||
if (morph instanceof SpriteMorph && !morph.isTemporary) {
|
||||
if (morph.name !== rcvr.name) {
|
||||
allNames = allNames.concat(morph.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (allNames.length > 0) {
|
||||
dict['~'] = null;
|
||||
allNames.forEach(function (name) {
|
||||
dict[name] = name;
|
||||
});
|
||||
}
|
||||
return dict;
|
||||
};
|
||||
|
||||
InputSlotMorph.prototype.distancesMenu = function () {
|
||||
var block = this.parentThatIsA(BlockMorph),
|
||||
dict = {},
|
||||
|
|
|
@ -83,7 +83,7 @@ BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
|
|||
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph,
|
||||
AlignmentMorph, Process, XML_Element, VectorPaintEditorMorph*/
|
||||
|
||||
modules.objects = '2019-January-02';
|
||||
modules.objects = '2019-January-04';
|
||||
|
||||
var SpriteMorph;
|
||||
var StageMorph;
|
||||
|
@ -737,6 +737,12 @@ SpriteMorph.prototype.initBlocks = function () {
|
|||
category: 'sensing',
|
||||
spec: 'filtered for %clr'
|
||||
},
|
||||
reportAspect: {
|
||||
type: 'reporter',
|
||||
category: 'sensing',
|
||||
spec: '%asp at %loc',
|
||||
defaults: [['color']]
|
||||
},
|
||||
reportStackSize: {
|
||||
dev: true,
|
||||
type: 'reporter',
|
||||
|
@ -1986,6 +1992,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
|
|||
blocks.push(block('reportKeyPressed'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('reportRelationTo'));
|
||||
blocks.push(block('reportAspect'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doResetTimer'));
|
||||
blocks.push(watcherToggle('getTimer'));
|
||||
|
@ -7183,6 +7190,8 @@ StageMorph.prototype.blockTemplates = function (category) {
|
|||
blocks.push('-');
|
||||
blocks.push(block('reportKeyPressed'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('reportAspect'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doResetTimer'));
|
||||
blocks.push(watcherToggle('getTimer'));
|
||||
blocks.push(block('getTimer'));
|
||||
|
|
153
src/threads.js
153
src/threads.js
|
@ -59,10 +59,10 @@ MultiArgMorph, Point, ReporterBlockMorph, SyntaxElementMorph, contains, Costume,
|
|||
degrees, detect, nop, radians, ReporterSlotMorph, CSlotMorph, RingMorph, Sound,
|
||||
IDE_Morph, ArgLabelMorph, localize, XML_Element, hex_sha512, TableDialogMorph,
|
||||
StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
|
||||
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph,
|
||||
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph, Color,
|
||||
TableFrameMorph, ColorSlotMorph, isSnapObject, Map*/
|
||||
|
||||
modules.threads = '2019-January-02';
|
||||
modules.threads = '2019-January-04';
|
||||
|
||||
var ThreadManager;
|
||||
var Process;
|
||||
|
@ -3260,6 +3260,155 @@ Process.prototype.reportColorIsTouchingColor = function (color1, color2) {
|
|||
return false;
|
||||
};
|
||||
|
||||
Process.prototype.reportAspect = function (aspect, location) {
|
||||
// sense colors and sprites anywhere,
|
||||
// use sprites to read/write data encoded in colors.
|
||||
//
|
||||
// usage:
|
||||
// ------
|
||||
// left input selects color/saturation/brightness/transparency or "sprites".
|
||||
// right input selects "mouse-pointer", "myself" or name of another sprite.
|
||||
// you can also embed a a reporter with a reference to a sprite itself
|
||||
// or a list of two items representing x- and y- coordinates.
|
||||
//
|
||||
// what you'll get:
|
||||
// ----------------
|
||||
// left input (aspect):
|
||||
//
|
||||
// 'color' - hsv HUE on a scale of 0 - 100
|
||||
// 'saturation' - hsv SATURATION on a scale of 0 - 100
|
||||
// 'brightness' - hsv VALUE on a scale of 0 - 100
|
||||
// 'transparency' - rgba ALPHA on a reversed (!) scale of 0 - 100
|
||||
// 'sprites' - a list of sprites at the location, empty if none
|
||||
//
|
||||
// right input (location):
|
||||
//
|
||||
// 'mouse-pointer' - color/sprites at mouse-pointer anywhere in Snap
|
||||
// 'myself' - sprites at or color UNDERNEATH the rotation center
|
||||
// sprite-name - sprites at or color UNDERNEATH sprites's rot-ctr.
|
||||
// two-item-list - color/sprites at x-/y- coordinates on the Stage
|
||||
//
|
||||
// what does "underneath" mean?
|
||||
// ----------------------------
|
||||
// the not-fully-transparent color of the top-layered sprite at the given
|
||||
// location excluding the receiver sprite's own layer and all layers above
|
||||
// it gets reported.
|
||||
//
|
||||
// color-aspect "underneath" a sprite means that the sprite's layer is
|
||||
// relevant for what gets reported. Sprites can only sense colors in layers
|
||||
// below themselves, not their own color and not colors in sprites above
|
||||
// their own layer.
|
||||
|
||||
var choice = this.inputOption(aspect),
|
||||
target = this.inputOption(location),
|
||||
options = ['color', 'saturation', 'brightness', 'transparency'],
|
||||
idx = options.indexOf(choice),
|
||||
thisObj = this.blockReceiver(),
|
||||
thatObj,
|
||||
stage = thisObj.parentThatIsA(StageMorph),
|
||||
world = thisObj.world(),
|
||||
point,
|
||||
clr;
|
||||
|
||||
if (target === 'myself') {
|
||||
if (choice === 'sprites') {
|
||||
if (thisObj instanceof StageMorph) {
|
||||
point = thisObj.center();
|
||||
} else {
|
||||
point = thisObj.rotationCenter();
|
||||
}
|
||||
return this.spritesAtPoint(point, stage);
|
||||
} else {
|
||||
clr = this.colorAtSprite(thisObj);
|
||||
}
|
||||
} else if (target === 'mouse-pointer') {
|
||||
if (choice === 'sprites') {
|
||||
return this.spritesAtPoint(world.hand.position(), stage);
|
||||
} else {
|
||||
clr = world.getGlobalPixelColor(world.hand.position());
|
||||
}
|
||||
} else if (target instanceof List) {
|
||||
point = new Point(
|
||||
target.at(1) * stage.scale + stage.center().x,
|
||||
stage.center().y - (target.at(2) * stage.scale)
|
||||
);
|
||||
if (choice === 'sprites') {
|
||||
return this.spritesAtPoint(point, stage);
|
||||
} else {
|
||||
clr = world.getGlobalPixelColor(point);
|
||||
}
|
||||
} else {
|
||||
if (!target) {return; }
|
||||
thatObj = this.getOtherObject(target, thisObj, stage);
|
||||
if (thatObj) {
|
||||
if (choice === 'sprites') {
|
||||
point = thatObj instanceof SpriteMorph ?
|
||||
thatObj.rotationCenter() : thatObj.center();
|
||||
return this.spritesAtPoint(point, stage);
|
||||
} else {
|
||||
clr = this.colorAtSprite(thatObj);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > 3) {
|
||||
return;
|
||||
}
|
||||
if (idx === 3) {
|
||||
return (1 - clr.a) * 100;
|
||||
}
|
||||
return clr.hsv()[idx] * 100;
|
||||
};
|
||||
|
||||
Process.prototype.colorAtSprite = function (sprite) {
|
||||
// private - helper function for aspect of location
|
||||
// answer the color underneath the layer of the sprite's rotation center
|
||||
var point = sprite instanceof SpriteMorph ? sprite.rotationCenter()
|
||||
: sprite.center(),
|
||||
stage = sprite.parentThatIsA(StageMorph),
|
||||
below = stage,
|
||||
found = false,
|
||||
child,
|
||||
i;
|
||||
|
||||
if (!stage) {return new Color(); }
|
||||
for (i = 0; i < stage.children.length; i += 1) {
|
||||
if (!found) {
|
||||
child = stage.children[i];
|
||||
if (child === sprite) {
|
||||
found = true;
|
||||
} else if (child.isVisible &&
|
||||
child.bounds.containsPoint(point) &&
|
||||
!child.isTransparentAt(point)
|
||||
) {
|
||||
below = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (below.bounds.containsPoint(point)) {
|
||||
return below.getPixelColor(point);
|
||||
}
|
||||
return new Color();
|
||||
};
|
||||
|
||||
Process.prototype.spritesAtPoint = function (point, stage) {
|
||||
// private - helper function for aspect of location
|
||||
// point argument is an absolute (Morphic) point
|
||||
// answer a list of sprites, if any, at the given point
|
||||
// ordered by their layer, i.e. top-layer is last in the list
|
||||
return new List(
|
||||
stage.children.filter(function (morph) {
|
||||
return morph instanceof SpriteMorph &&
|
||||
morph.isVisible &&
|
||||
morph.bounds.containsPoint(point) &&
|
||||
!morph.isTransparentAt(point);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
Process.prototype.reportRelationTo = function (relation, name) {
|
||||
var rel = this.inputOption(relation);
|
||||
if (rel === 'distance') {
|
||||
|
|
Ładowanie…
Reference in New Issue