Merge pull request from paulkaplan/fix-say-think-moving

Fix several say/think bugs
This commit is contained in:
Paul Kaplan 2017-10-24 08:40:29 -04:00 committed by GitHub
commit f07c70938a

View file

@ -6,9 +6,10 @@ const RenderedTarget = require('../sprites/rendered-target');
* @typedef {object} BubbleState - the bubble state associated with a particular target. * @typedef {object} BubbleState - the bubble state associated with a particular target.
* @property {Boolean} onSpriteRight - tracks whether the bubble is right or left of the sprite. * @property {Boolean} onSpriteRight - tracks whether the bubble is right or left of the sprite.
* @property {?int} drawableId - the ID of the associated bubble Drawable, null if none. * @property {?int} drawableId - the ID of the associated bubble Drawable, null if none.
* @property {Boolean} drawableVisible - false if drawable has been hidden by blank text.
* See _renderBubble for explanation of this optimization.
* @property {string} text - the text of the bubble. * @property {string} text - the text of the bubble.
* @property {string} type - the type of the bubble, "say" or "think" * @property {string} type - the type of the bubble, "say" or "think"
* @property {Boolean} visible - whether the bubble is hidden along with its sprite.
*/ */
class Scratch3LooksBlocks { class Scratch3LooksBlocks {
@ -35,11 +36,11 @@ class Scratch3LooksBlocks {
static get DEFAULT_BUBBLE_STATE () { static get DEFAULT_BUBBLE_STATE () {
return { return {
drawableId: null, drawableId: null,
drawableVisible: true,
onSpriteRight: true, onSpriteRight: true,
skinId: null, skinId: null,
text: '', text: '',
type: 'say', type: 'say'
visible: true
}; };
} }
@ -72,7 +73,7 @@ class Scratch3LooksBlocks {
*/ */
_onTargetMoved (target) { _onTargetMoved (target) {
const bubbleState = this._getBubbleState(target); const bubbleState = this._getBubbleState(target);
if (bubbleState.drawableId && bubbleState.visible) { if (bubbleState.drawableId) {
this._positionBubble(target); this._positionBubble(target);
} }
} }
@ -84,14 +85,15 @@ class Scratch3LooksBlocks {
*/ */
_onTargetWillExit (target) { _onTargetWillExit (target) {
const bubbleState = this._getBubbleState(target); const bubbleState = this._getBubbleState(target);
if (bubbleState.drawableId) { if (bubbleState.drawableId && bubbleState.skinId) {
this.runtime.renderer.destroyDrawable(bubbleState.drawableId); this.runtime.renderer.destroyDrawable(bubbleState.drawableId);
bubbleState.drawableId = null;
}
if (bubbleState.skinId) {
this.runtime.renderer.destroySkin(bubbleState.skinId); this.runtime.renderer.destroySkin(bubbleState.skinId);
bubbleState.drawableId = null;
bubbleState.skinId = null; bubbleState.skinId = null;
bubbleState.drawableVisible = true; // Reset back to default value
this.runtime.requestRedraw();
} }
target.removeListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved);
} }
/** /**
@ -102,6 +104,7 @@ class Scratch3LooksBlocks {
for (let n = 0; n < this.runtime.targets.length; n++) { for (let n = 0; n < this.runtime.targets.length; n++) {
this._onTargetWillExit(this.runtime.targets[n]); this._onTargetWillExit(this.runtime.targets[n]);
} }
clearTimeout(this._bubbleTimeout);
} }
/** /**
@ -147,19 +150,26 @@ class Scratch3LooksBlocks {
*/ */
_renderBubble (target) { _renderBubble (target) {
const bubbleState = this._getBubbleState(target); const bubbleState = this._getBubbleState(target);
const {type, text, onSpriteRight} = bubbleState; const {drawableVisible, type, text, onSpriteRight} = bubbleState;
if (text === '') {
return this._setBubbleVisibility(target, false); // Remove the bubble if target is not visible, or text is being set to blank
// without being initialized. See comment below about blank text optimization.
if (!target.visible || (text === '' && !bubbleState.skinId)) {
return this._onTargetWillExit(target);
} }
if (bubbleState.skinId) { if (bubbleState.skinId) {
if (!bubbleState.visible) { // Optimization: if text is set to blank, hide the drawable instead of
bubbleState.visible = true; // getting rid of it. This prevents flickering in "typewriter" projects
if ((text === '' && drawableVisible) || (text !== '' && !drawableVisible)) {
bubbleState.drawableVisible = text !== '';
this.runtime.renderer.updateDrawableProperties(bubbleState.drawableId, { this.runtime.renderer.updateDrawableProperties(bubbleState.drawableId, {
visible: bubbleState.visible visible: bubbleState.drawableVisible
}); });
} }
this.runtime.renderer.updateTextSkin(bubbleState.skinId, type, text, onSpriteRight, [0, 0]); if (bubbleState.drawableVisible) {
this.runtime.renderer.updateTextSkin(bubbleState.skinId, type, text, onSpriteRight, [0, 0]);
}
} else { } else {
target.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved); target.addListener(RenderedTarget.EVENT_TARGET_MOVED, this._onTargetMoved);
@ -197,23 +207,6 @@ class Scratch3LooksBlocks {
this._renderBubble(target); this._renderBubble(target);
} }
/**
* Hide the bubble for a given target.
* @param {!Target} target Target that say/think blocks are being called on.
* @param {!boolean} visibility Visible or not.
* @private
*/
_setBubbleVisibility (target, visibility) {
const bubbleState = this._getBubbleState(target);
bubbleState.visible = visibility;
if (bubbleState.drawableId) {
this.runtime.renderer.updateDrawableProperties(bubbleState.drawableId, {
visible: bubbleState.visible
});
}
this.runtime.requestRedraw();
}
/** /**
* Retrieve the block primitives implemented by this package. * Retrieve the block primitives implemented by this package.
* @return {object.<string, Function>} Mapping of opcode to Function. * @return {object.<string, Function>} Mapping of opcode to Function.
@ -253,7 +246,8 @@ class Scratch3LooksBlocks {
sayforsecs (args, util) { sayforsecs (args, util) {
this.say(args, util); this.say(args, util);
return new Promise(resolve => { return new Promise(resolve => {
setTimeout(() => { this._bubbleTimeout = setTimeout(() => {
this._bubbleTimeout = null;
// Clear say bubble and proceed. // Clear say bubble and proceed.
this._updateBubble(util.target, 'say', ''); this._updateBubble(util.target, 'say', '');
resolve(); resolve();
@ -268,7 +262,8 @@ class Scratch3LooksBlocks {
thinkforsecs (args, util) { thinkforsecs (args, util) {
this.think(args, util); this.think(args, util);
return new Promise(resolve => { return new Promise(resolve => {
setTimeout(() => { this._bubbleTimeout = setTimeout(() => {
this._bubbleTimeout = null;
// Clear say bubble and proceed. // Clear say bubble and proceed.
this._updateBubble(util.target, 'think', ''); this._updateBubble(util.target, 'think', '');
resolve(); resolve();
@ -283,7 +278,7 @@ class Scratch3LooksBlocks {
hide (args, util) { hide (args, util) {
util.target.setVisible(false); util.target.setVisible(false);
this._setBubbleVisibility(util.target, false); this._renderBubble(util.target);
} }
/** /**