【Scratch拡張機能をJavascriptで自作】RPG風の吹き出しを表示する拡張機能
※ 当ページには【広告/PR】を含む場合があります。
2021/02/10
RPG風のセリフウインドウとは?
意外と面倒な文字を含む画像の表示
ズバッといきなりソースコード
const ArgumentType = require('../../extension-support/argument-type');
const BlockType = require('../../extension-support/block-type');
const TargetType = require('../../extension-support/target-type');
const Cast = require('../../util/cast');
const formatMessage = require('format-message');
const MathUtil = require('../../util/math-util');
const log = require('../../util/log');
const StageLayering = require('../../engine/stage-layering');
class Scratch3MessageWindow {
constructor (runtime) {
this._extVersion = '0.0.1';
this.runtime = runtime;
this._fontDrawableId = -1;
this._fontSkinId = -1;
this.emptyImg = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="0" height="0" viewBox="0 0 0 0"></svg>';
}
getInfo () {
return {
id: 'messagewindow',
name: formatMessage({
id: 'messagewindow.categoryName',
default: 'MessageWindow',
description: 'Label for messagewindow extension category'
}),
blocks: [
{
opcode: 'initSkin',
blockType: BlockType.COMMAND
},
{
opcode: 'updateMessage',
blockType: BlockType.COMMAND,
text: formatMessage({
id: 'messagewindow.updateMessage',
default: 'stamp ( [STR] ) x [SCALE]',
description: 'render current costume on the background'
}),
arguments: {
STR: {
type: ArgumentType.STRING,
defaultValue: ''
},
SCALE: {
type: ArgumentType.NUMBER,
defaultValue: 100
}
}
},
{
opcode: 'goMapToBack',
blockType: BlockType.COMMAND
},
{
opcode: 'goMapToFront',
blockType: BlockType.COMMAND
},
{
opcode: 'clearSkin',
blockType: BlockType.COMMAND
},
{
opcode: 'getVersion',
text: 'Version Info',
blockType: BlockType.REPORTER
}
],
menus: {}
};
}
initSkin() {
if (this._fontSkinId < 0 && this.runtime.renderer) {
const skinId = this.runtime.renderer.createSVGSkin(this.emptyImg);
this._fontSkinId = skinId;
this._fontDrawableId = this.runtime.renderer.createDrawable(StageLayering.SPRITE_LAYER);
this.runtime.renderer.updateDrawableProperties(this._fontDrawableId, {skinId: this._fontSkinId});
}
}
updateMessage(args) {
const text_ = Cast.toString(args.STR);
const scale_ = Cast.toString(args.SCALE);
if (this._fontSkinId >= 0) {
const tArr = this._textSlice(text_);
const windowOrigin = [2, 258];
const fontSize_ = 14;
const fontSvg = `<svg width="480px" height="360px" version="1.1" viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg">
<g stroke-width="4">
<rect transform="translate(2,3)" x="${windowOrigin[0]}" y="${windowOrigin[1]}" width="476" height="100" rx="15" ry="15" opacity=".25" stroke="#000"/>
<rect x="${windowOrigin[0]}" y="${windowOrigin[1]}" width="476" height="100" rx="15" ry="15" fill="#fff" stroke="#000080"/>
<text fill="#0000ff" font-family="sans-serif" font-size="${fontSize_}px" letter-spacing="0px" word-spacing="0px" xml:space="preserve">
<tspan x="${windowOrigin[0] + 12}" y="${windowOrigin[1] + 25}">${tArr[0]}</tspan>
</text>
<text fill="#0000ff" font-family="sans-serif" font-size="${fontSize_}px" letter-spacing="0px" word-spacing="0px" xml:space="preserve">
<tspan x="${windowOrigin[0] + 12}" y="${windowOrigin[1] + 55}">${tArr[1]}</tspan>
</text>
<text fill="#0000ff" font-family="sans-serif" font-size="${fontSize_}px" letter-spacing="0px" word-spacing="0px" xml:space="preserve">
<tspan x="${windowOrigin[0] + 12}" y="${windowOrigin[1] + 85}">${tArr[2]}</tspan>
</text>
</g>
</svg>`;
this.runtime.renderer.updateSVGSkin(this._fontSkinId, fontSvg);
}
}
clearSkin() {
if (this._fontSkinId >= 0) {
this.runtime.renderer.updateSVGSkin(this._fontSkinId, this.emptyImg);
}
}
goMapToBack() {
if (this._fontDrawableId >= 0 && this._fontSkinId >= 0) {
this.runtime.renderer.setDrawableOrder(this._fontDrawableId, 1, StageLayering.SPRITE_LAYER);
}
}
goMapToFront() {
if (this._fontDrawableId >= 0 && this._fontSkinId >= 0) {
this.runtime.renderer.setDrawableOrder(this._fontDrawableId, Infinity, StageLayering.SPRITE_LAYER);
}
}
getVersion(args) {
return this._extVersion;
}
_textSlice(text = '') {
const splitText = [];
const onelineLimit = 32;
const sanitizedText = text.replace(/\s/g,'');
const textLen = sanitizedText.length;
if (sanitizedText) {
const firstRow = sanitizedText.slice(0, onelineLimit);
if (firstRow) {
splitText.push(firstRow);
} else {
splitText.push('');
}
if (textLen > onelineLimit) {
const secondRow = sanitizedText.slice(onelineLimit, onelineLimit * 2);
splitText.push(secondRow);
} else {
splitText.push('');
}
if (textLen > 2 * onelineLimit) {
const thirdRow = sanitizedText.slice(onelineLimit * 2, onelineLimit * 3);
splitText.push(thirdRow);
} else {
splitText.push('');
}
return splitText;
} else {
return ['', '', ''];
}
}
}
module.exports = Scratch3MessageWindow;
まとめ
記事を書いた人
ナンデモ系エンジニア
これからの"地方格差"なきプログラミング教育とは何かを考えながら、 地方密着型プログラミング学習関連テーマの記事を不定期で独自にブログ発信しています。
カテゴリー