【Scratch拡張機能をJavascriptで自作】svg画像からRPG風のマップを生成する拡張機能を作る〜拡張機能の実装③
※ 当ページには【広告/PR】を含む場合があります。
2021/02/05
スクラッチでRPGはどこまで作れるか?
タイルマップの描画操作
タイルパターンマップを生成・描画する拡張機能の作成
①scratch-gui
②scratch-vm
① scratch-gui側でやること:
1. 拡張機能のカードリスト用に600x372と80x80のpng画像を
用意して、
2. 拡張機能用のライブラリファイル(index.js)に登録する
② scratch-vm側でやること:
1. ブロックアイコン用の画像をBase64化して、
jsコード内に貼り付け
2. エクステンションのコード本体を実装
3. extension-manager.jsに拡張機能を登録
① 1. - 2.
② 1.
② 2. -3.
拡張機能の実装例
scratch-vm/src/extensions
scratch3_tilemap/index.js
index.js
$ tree
.
├── index.js
├── map1.csv
└── map1.dat
map1.svg
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');
const svgTileMap_ = require('raw-loader!./map1.dat');
const csvTileData_ = require('raw-loader!./map1.csv');
class Scratch3Tilemap {
constructor (runtime) {
this.runtime = runtime;
this._x = 0;
this._y = 0;
this._xOrigin = 0;
this._yOrigin = 0;
this._mapDrawableId = -1;
this._mapSkinId = -1;
this.svgElements = [];
this._initMaps();
}
_getMapLayerID () {
if (this._mapSkinId < 0 && this.runtime.renderer) {
this._mapSkinId = this.runtime.renderer.createSVGSkin('<svg xmlns="http://www.w3.org/2000/svg" version="1.1"></svg>');
this._mapDrawableId = this.runtime.renderer.createDrawable(StageLayering.SPRITE_LAYER);
this.runtime.renderer.updateDrawableProperties(this._mapDrawableId, {skinId: this._mapSkinId});
}
return this._mapSkinId;
}
_updateSvgDraw(svgXml) {
const mapSkinId = this._getMapLayerID();
if (mapSkinId >= 0) {
const skin = /** @type {SVGSkin} */ this.runtime.renderer._allSkins[mapSkinId];
skin.setSVG(svgXml);
this.runtime.renderer.updateDrawableProperties(this._mapDrawableId, {
skinId: mapSkinId,
position: [this._xOrigin, this._yOrigin], // Set origin for svg layer
scale: [100, 100],
direction: 90
});
this.runtime.requestRedraw(); // overlay image over sprites!
}
}
_initMaps() {
this.tilemaps = [];
const mapBody = svgTileMap_.default;
const mapLoc = this._cvs2Maparray(csvTileData_.default);
const sampleMap = {mapBody, mapLoc};
this.tilemaps.push(sampleMap);
}
_cvs2Maparray(raw_csvdata = '') {
const parsed_csv = [];
if (raw_csvdata) {
const rows_ = raw_csvdata.split(/\r?\n/);
for (const row_ of rows_) {
if (row_) {
parsed_csv.push(row_.split(/,/));
}
}
}
return parsed_csv;
}
getInfo () {
return {
id: 'tilemap',
name: formatMessage({
id: 'tilemap.categoryName',
default: 'Tilemap',
description: 'Label for the tilemap extension category'
}),
blockIconURI: '',
blocks: [
{
opcode: 'stamp',
blockType: BlockType.COMMAND,
text: formatMessage({
id: 'tilemap.stamp',
default: 'stamp [MAP_ID]',
description: 'Render svg on background'
}),
arguments: {
MAP_ID: {
type: ArgumentType.NUMBER,
defaultValue: 1
}
}
},
{
opcode: 'checkTileFromPosition',
text: 'Check Tile ? <= ([X_POS], [Y_POS])',
blockType: BlockType.REPORTER,
arguments: {
X_POS: {
type: ArgumentType.NUMBER,
defaultValue: 0
},
Y_POS: {
type: ArgumentType.NUMBER,
defaultValue: 0
}
}
}
],
menus: {
}
};
}
stamp (args, util) {
this._x = Cast.toNumber(args.X_POS);
this._y = Cast.toNumber(args.Y_POS);
this._updateSvgDraw(this.tilemaps[0].mapBody);
}
checkTileFromPosition(args, util) {
this._x = Cast.toNumber(args.X_POS);
this._y = Cast.toNumber(args.Y_POS);
const revX = Math.floor((this._x + 240) / 24);
const revY = Math.floor((180 - this._y) / 24);
if (0 <= revX && revX < 20 && 0 <= revY && revY < 15) {
return this.tilemaps[0].mapLoc[revY][revX];
} else {
return 0;
}
}
}
module.exports = Scratch3Tilemap;
scratch-vm/src/extensions/scratch3_pen/index.js
raw-loaderで生のテキストを読み込む
$ cd scratch-vm
$ yarn add raw-loader -D
webpack.config.js
//...
module.exports = {
module: {
rules: [
{
test: /\.txt$/i,
use: 'raw-loader',
},
],
},
};
//...
import txt from './file.txt';
//...
svg|png|wav|gif|jpg
//...
const svgTileMap_ = require('raw-loader!./map1.dat');
const csvTileData_ = require('raw-loader!./map1.csv');
//...
//👇ローダーからのファイルの中身はdefaultプロパティで取り出す
// console.log(svgTileMap_.default);
// console.log(csvTileData_.default);
//...
extension-manager.jsへ登録
scratch-vm/src/extension-support/extension-manager.js
builtinExtensions
///...
const builtinExtensions = {
// This is an example that isn't loaded with the other core blocks,
// but serves as a reference for loading core blocks as extensions.
coreExample: () => require('../blocks/scratch3_core_example'),
// These are the non-core built-in extensions.
pen: () => require('../extensions/scratch3_pen'),
wedo2: () => require('../extensions/scratch3_wedo2'),
music: () => require('../extensions/scratch3_music'),
microbit: () => require('../extensions/scratch3_microbit'),
text2speech: () => require('../extensions/scratch3_text2speech'),
translate: () => require('../extensions/scratch3_translate'),
videoSensing: () => require('../extensions/scratch3_video_sensing'),
ev3: () => require('../extensions/scratch3_ev3'),
makeymakey: () => require('../extensions/scratch3_makeymakey'),
boost: () => require('../extensions/scratch3_boost'),
gdxfor: () => require('../extensions/scratch3_gdx_for'),
//👇自作の拡張機能を定義・登録する
tilemap: () => require('../extensions/scratch3_tilemap'),
};
///...
///...
const builtinExtensions = {
//👇自作の拡張機能のみ使う場合
tilemap: () => require('../extensions/scratch3_tilemap'),
};
///...
まとめ
記事を書いた人
ナンデモ系エンジニア
これからの"地方格差"なきプログラミング教育とは何かを考えながら、 地方密着型プログラミング学習関連テーマの記事を不定期で独自にブログ発信しています。
カテゴリー