new feature/block: sense colors and sprites anywhere

use sprites to read/write data encoded in colors
pull/89/head
jmoenig 2019-01-04 11:20:50 +01:00
rodzic 9ea9c8c3f5
commit b2b3aea8d2
5 zmienionych plików z 217 dodań i 7 usunięć

Wyświetl plik

@ -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"

Wyświetl plik

@ -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>

Wyświetl plik

@ -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 = {},

Wyświetl plik

@ -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'));

Wyświetl plik

@ -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') {