summaryrefslogtreecommitdiff
path: root/objects.js
diff options
context:
space:
mode:
Diffstat (limited to 'objects.js')
-rw-r--r--objects.js217
1 files changed, 200 insertions, 17 deletions
diff --git a/objects.js b/objects.js
index cf4d0ea..14e68da 100644
--- a/objects.js
+++ b/objects.js
@@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.objects = '2015-January-21';
+modules.objects = '2015-February-28';
var SpriteMorph;
var StageMorph;
@@ -613,11 +613,22 @@ SpriteMorph.prototype.initBlocks = function () {
category: 'control',
spec: 'when %keyHat key pressed'
},
+
+ /* migrated to a newer block version:
+
receiveClick: {
type: 'hat',
category: 'control',
spec: 'when I am clicked'
},
+ */
+
+ receiveInteraction: {
+ type: 'hat',
+ category: 'control',
+ spec: 'when I am %interaction',
+ defaults: ['clicked']
+ },
receiveMessage: {
type: 'hat',
category: 'control',
@@ -1254,6 +1265,29 @@ SpriteMorph.prototype.initBlocks = function () {
defaults: [localize('each item')]
},
+ // peer to peer communication
+ receivePeerMessage: {
+ type: 'hat',
+ category: 'other',
+ spec: 'when I receive %upvar from %upvar',
+ defaults: [localize('message'), localize('peer')]
+ },
+ sendPeerMessage: {
+ type: 'command',
+ category: 'other',
+ spec: 'send %s to %s'
+ },
+ reportPeerId: {
+ type: 'reporter',
+ category: 'other',
+ spec: 'my peer id'
+ },
+ reportPeerList: {
+ type: 'reporter',
+ category: 'other',
+ spec: 'peers online'
+ },
+
// Code mapping - experimental
doMapCodeOrHeader: { // experimental
type: 'command',
@@ -1294,6 +1328,10 @@ SpriteMorph.prototype.initBlockMigrations = function () {
doStopBlock: {
selector: 'doStopThis',
inputs: [['this block']]
+ },
+ receiveClick: {
+ selector: 'receiveInteraction',
+ inputs: [['clicked']]
}
};
};
@@ -1342,8 +1380,6 @@ SpriteMorph.prototype.blockAlternatives = {
setSize: ['changeSize'],
// control:
- receiveGo: ['receiveClick'],
- receiveClick: ['receiveGo'],
doBroadcast: ['doBroadcastAndWait'],
doBroadcastAndWait: ['doBroadcast'],
doIf: ['doIfElse', 'doUntil'],
@@ -1514,15 +1550,13 @@ SpriteMorph.prototype.setName = function (string) {
SpriteMorph.prototype.drawNew = function () {
var myself = this,
- currentCenter = this.center(),
+ currentCenter,
facing, // actual costume heading based on my rotation style
isFlipped,
- isLoadingCostume = this.costume &&
- typeof this.costume.loaded === 'function',
+ isLoadingCostume,
cst,
pic, // (flipped copy of) actual costume based on my rotation style
- stageScale = this.parent instanceof StageMorph ?
- this.parent.scale : 1,
+ stageScale,
newX,
corners = [],
origin,
@@ -1536,6 +1570,11 @@ SpriteMorph.prototype.drawNew = function () {
this.wantsRedraw = true;
return;
}
+ currentCenter = this.center();
+ isLoadingCostume = this.costume &&
+ typeof this.costume.loaded === 'function';
+ stageScale = this.parent instanceof StageMorph ?
+ this.parent.scale : 1;
facing = this.rotationStyle ? this.heading : 90;
if (this.rotationStyle === 2) {
facing = 90;
@@ -1683,7 +1722,7 @@ SpriteMorph.prototype.blockForSelector = function (selector, setDefaults) {
: new ReporterBlockMorph(info.type === 'predicate');
block.color = this.blockColor[info.category];
block.category = info.category;
- block.selector = selector;
+ block.selector = migration ? migration.selector : selector;
if (contains(['reifyReporter', 'reifyPredicate'], block.selector)) {
block.isStatic = true;
}
@@ -1930,7 +1969,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('receiveGo'));
blocks.push(block('receiveKey'));
- blocks.push(block('receiveClick'));
+ blocks.push(block('receiveInteraction'));
blocks.push(block('receiveMessage'));
blocks.push('-');
blocks.push(block('doBroadcast'));
@@ -2204,6 +2243,13 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push('=');
+ blocks.push(block('receivePeerMessage'));
+ blocks.push(block('sendPeerMessage'));
+ blocks.push(block('reportPeerId'));
+ blocks.push(block('reportPeerList'));
+
+ blocks.push('=');
+
if (StageMorph.prototype.enableCodeMapping) {
blocks.push(block('doMapCodeOrHeader'));
blocks.push(block('doMapStringCode'));
@@ -2915,7 +2961,7 @@ SpriteMorph.prototype.setColor = function (aColor) {
var x = this.xPosition(),
y = this.yPosition();
if (!this.color.eq(aColor)) {
- this.color = aColor;
+ this.color = aColor.copy();
this.drawNew();
this.gotoXY(x, y);
}
@@ -3326,6 +3372,7 @@ SpriteMorph.prototype.prepareToBeGrabbed = function (hand) {
SpriteMorph.prototype.justDropped = function () {
this.restoreLayers();
this.positionTalkBubble();
+ this.receiveUserInteraction('dropped');
};
// SpriteMorph drawing:
@@ -3655,8 +3702,8 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) {
if (morph.selector === 'receiveOnClone') {
return message === '__clone__init__';
}
- if (morph.selector === 'receiveClick') {
- return message === '__click__';
+ if (morph.selector === 'receivePeerMessage') {
+ return message === '__peer__message__';
}
}
return false;
@@ -3686,13 +3733,37 @@ SpriteMorph.prototype.allHatBlocksForKey = function (key) {
});
};
+SpriteMorph.prototype.allHatBlocksForInteraction = function (interaction) {
+ return this.scripts.children.filter(function (morph) {
+ if (morph.selector) {
+ if (morph.selector === 'receiveInteraction') {
+ return morph.inputs()[0].evaluate()[0] === interaction;
+ }
+ }
+ return false;
+ });
+};
+
// SpriteMorph events
SpriteMorph.prototype.mouseClickLeft = function () {
- var stage = this.parentThatIsA(StageMorph),
- hats = this.allHatBlocksFor('__click__'),
- procs = [];
+ return this.receiveUserInteraction('clicked');
+};
+
+SpriteMorph.prototype.mouseEnter = function () {
+ return this.receiveUserInteraction('mouse-entered');
+};
+
+SpriteMorph.prototype.mouseDownLeft = function () {
+ return this.receiveUserInteraction('pressed');
+};
+SpriteMorph.prototype.receiveUserInteraction = function (interaction) {
+ var stage = this.parentThatIsA(StageMorph),
+ procs = [],
+ hats;
+ if (!stage) {return; } // currently dragged
+ hats = this.allHatBlocksForInteraction(interaction);
hats.forEach(function (block) {
procs.push(stage.threads.startProcess(block, stage.isThreadSafe));
});
@@ -4367,6 +4438,7 @@ SpriteMorph.prototype.mouseEnterDragging = function () {
};
SpriteMorph.prototype.mouseLeave = function () {
+ this.receiveUserInteraction('mouse-departed');
if (!this.enableNesting) {return; }
this.removeHighlight();
};
@@ -4531,6 +4603,95 @@ StageMorph.prototype.init = function (globals) {
this.acceptsDrops = false;
this.setColor(new Color(255, 255, 255));
this.fps = this.frameRate;
+
+ this.initPeering();
+};
+
+StageMorph.prototype.initPeering = function (id) {
+ var myself = this;
+
+ if (window.peers) {
+ // I don't know why, but it works.
+ window.peers.forEach(function (oldpeer) {
+ if (id != oldpeer.id) {
+ oldpeer.destroy()
+ }
+ });
+ }
+
+ this.peer = new Peer(id, {
+ host: 'snapmesh.herokuapp.com',
+ port: 443,
+ secure: true,
+ path: '/'
+ });
+
+ this.peer.on('open', function (id) {
+ myself.peerId = id;
+ });
+ this.peer.on('disconnected', function () {
+ // peer.reconnect does not work (?) because 'id' is undefined
+ if (!myself.peer.destroyed) {
+ myself.initPeering(myself.peerId);
+ }
+ });
+ this.peer.on('error', function (err) {
+ console.log(err); // DEBUG
+ });
+
+ this.peer.on('connection', function (connection) {
+ connection.on('open', function () {
+ connection.on('data', function (data) {
+ myself.newPeerMessage(data, connection.peer);
+ });
+ });
+ });
+
+ window.peers.push(this.peer);
+};
+
+StageMorph.prototype.newPeerMessage = function (data, peer) {
+ var ide = this.parentThatIsA(IDE_Morph);
+ var myself = this;
+ var hats = [], model, message;
+
+ try {
+ model = ide.serializer.parse(data);
+ message = ide.serializer.loadValue(model);
+
+ // TODO: If a Context is sent, a new Sprite appears.
+ // This below is just a workaround for one-level rings,
+ // objects should be cleaned recursively.
+ message.receiver = null;
+ message.outerContext = null;
+ } catch (err) {
+ console.log(err); // DEBUG
+ // Ok, it does not seem to be XML. It must be a string then.
+ message = data;
+ }
+
+ // call hat blocks
+ this.children.concat(myself).forEach(function (morph) {
+ if (morph instanceof SpriteMorph
+ || morph instanceof StageMorph) {
+ hats = hats.concat(
+ morph.allHatBlocksFor('__peer__message__'));
+ }
+ });
+ hats.forEach(function (block) {
+ var process = myself.threads.startProcess(block,
+ myself.isThreadSafe);
+ process.context.outerContext.variables.addVar(localize('message'));
+ process.context.outerContext.variables.setVar(
+ localize('message'),
+ message
+ );
+ process.context.outerContext.variables.addVar(localize('peer'));
+ process.context.outerContext.variables.setVar(
+ localize('peer'),
+ peer
+ );
+ });
};
// StageMorph scaling
@@ -5224,7 +5385,7 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('receiveGo'));
blocks.push(block('receiveKey'));
- blocks.push(block('receiveClick'));
+ blocks.push(block('receiveInteraction'));
blocks.push(block('receiveMessage'));
blocks.push('-');
blocks.push(block('doBroadcast'));
@@ -5484,6 +5645,12 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push('=');
+ blocks.push(block('receivePeerMessage'));
+ blocks.push(block('sendPeerMessage'));
+ blocks.push(block('reportPeerId'));
+ blocks.push(block('reportPeerList'));
+ blocks.push('=');
+
if (StageMorph.prototype.enableCodeMapping) {
blocks.push(block('doMapCodeOrHeader'));
blocks.push(block('doMapStringCode'));
@@ -5819,11 +5986,27 @@ StageMorph.prototype.allHatBlocksFor
StageMorph.prototype.allHatBlocksForKey
= SpriteMorph.prototype.allHatBlocksForKey;
+StageMorph.prototype.allHatBlocksForInteraction
+ = SpriteMorph.prototype.allHatBlocksForInteraction;
+
// StageMorph events
StageMorph.prototype.mouseClickLeft
= SpriteMorph.prototype.mouseClickLeft;
+StageMorph.prototype.mouseEnter
+ = SpriteMorph.prototype.mouseEnter;
+
+StageMorph.prototype.mouseLeave = function () {
+ this.receiveUserInteraction('mouse-departed');
+};
+
+StageMorph.prototype.mouseDownLeft
+ = SpriteMorph.prototype.mouseDownLeft;
+
+StageMorph.prototype.receiveUserInteraction
+ = SpriteMorph.prototype.receiveUserInteraction;
+
// StageMorph custom blocks
StageMorph.prototype.deleteAllBlockInstances