【Scratch拡張機能をJavascriptで自作】SVG画像からスプライトをアニメーション的に動かす拡張機能の作成方法


※ 当ページには【広告/PR】を含む場合があります。
2021/02/17
【Scratch拡張機能をJavascriptで自作】RPG風の吹き出しを表示する拡張機能
【SvelteでRPGゲーム開発】マップ背景を表示する〜基本編

Scratchプログラミングにおいてスプライトを歩かせるように見せるには、コスチュームを一定時間ごとに切り替えてたり、位置が変わる度に進行方向に合わせたりするようにします。

このような基本的なスプライトのアニメーションの付け方は以前の記事でも取り上げていました。

合同会社タコスキングダム|タコキンのPスクール
【Scratch入門】はじめてのScratchアプリ作成〜スプライトを自由に歩かせてみよう

Scratchで画面内を自由に動き回るスプライトを作成します。

合同会社タコスキングダム|タコキンのPスクール
【Scratch入門】コスチュームを変えてスプライトのアニメーション効果を付ける

Scratchでスプライトを移動させる時にコスチューム番号をずらしてアニメーションで動かす方法を解説します。

今回は開発者向けの話題になってしまいますが、より実用性の高いSVGの使い方として
clipPathuseを用いたアニメーションをScratchアプリに組み込める拡張機能の自作方法を紹介します。


合同会社タコスキングダム|タコキンのPスクール【Html&Cssアプリ】Html/JavascriptとSassを使った四択クイズゲームの作り方

すぐに作れる ずっと使える Inkscapeのすべてが身に付く本

無償で試せる素材を提供されているサイト

RPGで使える動きをひとまとめにしたアニメーション画像セットを自作するのは中々骨の折れる作業です。

今回のように動きをプログラミングしたいだけであれば、わざわざアニメーション画像を用意しなくても無償で公開されているサイトがあります。

以降ではまず参考までに優良な無料で利用できるサイトを紹介させていただきます。

ぴぽや倉庫

ぴぽや倉庫さんは、Scratchのビギナーにはとても有り難い良質な素材を公開されている国内では有名な老舗サイトです。

なお特定のライセンスのない無償の素材とはいえ個人で使う分には問題はありませんが、もしそれらを組み込んだスクラッチアプリを公開または商用目的で利用したい場合などは、利用規約に従ってください。

Superpowers Asset Packs

Superpowers Asset Packs

Github上におかれたフリーの素材集で、もうあまりメンテナンスや更新などはされていないようですが、Scratchゲームを試したいだけであれば十分使える画像がたくさん集められています。

またライセンスも縛りの最も緩い(というか無いに等しい)CC0ですので、画像にどのような操作を加えても著作権利などを深くは考えなくてもよいのが使う側としては有り難いことでもあります。

もちろんどのような権利も持たない(=公共の財産)ので、期限切れで消滅しても一切の責任なども生じないですので誰にも不満は言えないのがこのCC0の唯一のライセンス条件と言えます。

利用される場合には、
公共の財産ですのできちんとルールを守って大切に使っていきましょう。


合同会社タコスキングダム|タコキンのPスクール【Html&Cssアプリ】Html/JavascriptとSassを使った四択クイズゲームの作り方

すぐに作れる ずっと使える Inkscapeのすべてが身に付く本

テクニックのキモ ~ SVG画像を分割する

こちらのサイトが参考になります。

use要素とclipPath要素とを組み合わせることで単一の画像を複数のパーツに分割することができます。

これを使い、一つの画像から効率的にパラパラアニメーションのようなエフェクトをSVGのみで作り出すことが可能になります。

テスト画像としては
Superpowers Asset PacksのNinja Adventure2の17.pngを特に理由はありませんが利用させていただくとします。

では
svgお試しサイトで以下のsvgインラインコードを表示してみてください。

            
            <svg xmlns="http://www.w3.org/2000/svg" width="200" height="300" version="1.1" viewBox="0 0 100 150">
    <defs>
        <g id="baseImage">
            <image width="64" height="112" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABwCAYAAACuE3ZzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAADHhJREFUeNrsXd9rG9kV/u6MElHy0BJIIG9OwWDXqSsWbBUKG9ysYZ9KoMbCxrvtuiSxvUSwD5uH/AH74H0IJFnFSRqlSYuCjQNLnwIuFQkUVjEsxmvjgGGdt4AWluQhD97sMH3QnKszd+6dGY0ky050QSBr5tx7z7m/zvedM2Phui7e5ZIyXbBtO2AZx3FE3IqblU9aR6MyKVMlzx8MaH+Po0Sz8knrSCIj+BIg6z1/MIAfvv5J27GhxW2EdaAV8nHqACAcxyE5AHBXc73a+4+dPYyeiU3tjEjprNczsYnBpQpO3agAADZms1gfz8qOkUVt2wbrRMvko+owFc8wWjleN58RwnVd49QJK55FheM4eyKvzgY+k2zbDoz+sbOHI9t3HEekohrSTad2FLVdtZ1jZw9H9i2sjyZZS73p0JHR0E9YJ/i1ON/5XjS0uO1rh6/ZZkvPxKavbtpDAqfAoSOjyBQL2F0Y01aUnlnG2vQcgMe0mSQyAtuM6Ktba7OK9MwyANT68Ap48cutWDNT7QPNghOv+rG70I/0TEHWuzs8hvTMsgvAvwT6h6t0sd4JT/H631W8aKNjojP+y5XTOHQEePN6JVYdh46M4uUK8KvRx6H1+o5B27Zd0026maAeZbqNKGy35vK2bbv//f2vAQB/+Ot7vnu3nh6X38kAQ4vbWM31ivdKzwAA3072YWhxW7Z/6Miob1B5+d8/vgUA/PGb74Ob4NbT4z4Bupl3indIZ/moUap1bjvwu6q4rq26YtshdQfr4DrJdr75PugJzu/04RL7++hvPvQq8d9jKvM7fbh0Mnz0DfIiPbPs1vYXf/n4w78AgDzXqdDoy++Ltq/ujdmaz3D/0b2AITPFgtwEpR8wuFSRDX12/JqcapMjV33CVPH6eNZ3DnN5XkrlPGhqXqleNMljd6G2Ma3mevG3P/9L1nPp5DOf4UrlfKgnSf1V5TZms7jzcApDi9vYXRgT3jKGZdu2uzY9h/uP7slGr1Qv4tjZw3j+YAClcl52mhS8/+ge1qbnYNu2q5M3Ka+Tp9OANlp+hpfKefQPV9E/XEWpnI+9kZrkqG5SPuAH8Jsv37ogXdf18aw0QlhH+DWd8mHyjuPAcRzRM7HpM2R6ZlkaJ2z0ycen+rkcGZ68P358i3bxAUnhsG3boOW0Pp71HV9cIdUH8QBR4MhLzyz76lPlUu1Svhk4TDNgXVE6blFleH2hcLhVZERSOHygCZFm4fCBJkSahcMHlhBp575xIAgR7gjRiNFZG/X9rSVEEsLhjhEiKR0hEq7gSjtYITG0uO3DAj0TBTQ6K8NGm9fNsUBThAjfVBqBw3z5vFWESBw4rHpv6jG414RIisDMyxXghIeb1ZvVvzUjGBsOZ4oFDoREGPdAyut2+9Vcr5RdzfUKTohw2RMGQiSwB2SKBaxhrilC5G7uCQDgk8X3jYCoBlefBTbBThEiwrIsAHCpc4SjdSNH9+hQGafUaMmEocG16Tnx29vXfI5MHELEkxcGMCT5AE6IGHQRjuPUZ8DgUgUbAOZvIECIlMp5uQyGjmaBcnD90kZIu7on76qECr+uLDORnikEjDipMEhef1zbtgOeIG+LDJYpFwL7GREiAGARDl8fzxoJEV44k6MZAaEoJ1SOgK5nigUJYTkhohqqESLEwE8IA6nr3wOCSn1a+31ccV7OwRgTUJ0cMkqpnMfkyFVJr/3zP5/68DurT/x8O6eOeFyXO3AfzV5+LTYf0Cis1KxJVx0NLh9lQPIP1BkQZZBSOe/GMU4oH2DyzU3HX6vlk9aRRKabH0C7ebNw+MDmB5Af0Ao4nJQQ6eYHoJsf0Ln8AHZeJ4bDLSBEuvkBnYLD3fyAMOjYzQ/o5gd08wO6+QHd/IAmQl2NwOlOlX2ZH7CXZd/lBxAj5E1fV8PyyGmuwGHJF+r0JB8ndW6xPYRII3CY6kmSH7AvCZFufkAb9o1ufsBBJUS6+QEJT6NufsC7QohwOLwv8gP4CO4u9GtvVv9+uXIaa9OnOb3trk3Pydh/Ajjc+fyARggRk6KTI1cxv1P7roPUd3NPcHe4ilI5uAnGIUTqoEoPqOg6D/FH5gdwSowFE40jOb/TxxGdcBwH3527iEyxIHMMqHAjqEsqSX4AKcbj+zr5+Z2+xvIDyJfemM1iN0edLGA11xsgRTZmsxicreicEqH67leqF33RWW/jgeM44rtzF9VlJtIzNSNyR4YnRlw6ORebD5hErc/z6As4Ujw/gBwhGR7jo8Q9Q24EFZcroW7Jypji8zpfgEbx+YMB/Mku+jgBVo8vAUMFQ8p1Vx24fzvTARc8Nh/w0QdfAajF9sPcWZqGlFLz1vABYYrr1lgr+ICOpcs3w+iQ8jrHZTXX29Z3ECSR6ejzAmFGjzKiCQ7rZKhN3UB2lA9Qo0MNwuGAAehCFBzmbfv8gEYZnVYZoONwWO3A8wcDgDMNnKc5cxNQruumcSN8QJSCHYHDe80H7Ds43EE+YH/A4Q7yAZ2Fw63iAxp9XoCfPJ2Aw7Ztuy3hAzhSjPO8ACdD6knYn+PUjQr+7sUt7uaetDQ/gFL48Yv3a6Dvxy+DcHhteq4hPiBTLPim8kcffBVIjw0JkArHcfDz7ZzLDRAH6SFGunxY2ZjNYlVngKR8gAqYyCkhPsAQHZaUuEqq8Ht1eQeqEXTK8zwEtU5erAAfsDCG3YUxZIoFvHm9gkyxgPmdPvmhiiP8eeEdbT7l5S5cm/Ycugqd8pMjVwU5YDxHwbvP5TA4RHlfyj27T+wujAmLV6CSHLpnBk7dqGBy5Gpg5GzbRqmch9KY7nmBUKPRh7LCB5cqWiOETW9SfnCpQoYVav20uRuDo2EdjZPq3iooG7cPKh6IIGGE9hjkYCjEB3ejWJ5WQFmOR744f1P1I7SPzKhtXr51IV5sUNcBTksRncQ7ZxiFtqBJrkgjaFA1nM4ZCwRHVb/ZxPSoRmgWTUahuWbRoEneZwDCAuSsqJ7g2vQc3rxeSRTdjYDDAVpcR6txJcIMoCpvAkO+x+bIkyJ3WO8JVrH1dBRhydKtBEMvsNWSyms5iHowZKlYQPWb1VCSek+jUDgK1TE/ASde9ceWM/WD6uD1xmaFdeEqHaffAj7ACIZahQZ1YEh6grROwhKhTfG6pIVnipLiJuVjosFYsmo7KR4N+mTRnyytIjhyJUsTBfUZwIb4AJ1joyZLU5v8tyRokG/gOkZIWJbFDFCDjJ8dv+aLCXIXlI4z3VlOp0RUodGiACk/xweXKr43SA0d/dznhsdBg7y/hProjVLMlxCO48DyrO/Lqz129jBWc73Sdz91oyI/fPoSGKGpPL/TF/nMEZuqQg2fcd9BLfS7BggF0GBYHYQuZScsy5KBUd6BL87fxA9f/xSIDpfKeckFeNMoMIPi8gF8I+Wp7ipw0mF8PhNU2ag6eHA3xaaSWB/Puqe8Gy/fuiArUFEcX0NhjcZV3oQWvTB2U9ncVIcJiXIsEMDW3ggKmgUUIFWf/OZ+OKXA6nB62JPctm0HRpp12jVcM84A3pbummzbdV24rgvLsvjHZR808XGnzlx3p85cdy3LctV2qG1N+77P1Jnrap9k3zzZwDVPxvihdrvPC7RL+XfyeQGuvMon3Hk4xX2ASFZpr/7BQ0vyA3Rx/TuYAshrfujPFqNzvJWJDknlU40wOmqGBzkgnDcIiy+u5kCPrWk71Gj7poFoRL7lzwvUFPydIba4HWvU9uoFDnIPaOaJDwAuf2sr8xK1jFKmWFDf8ipamWARN7xvfF4gSVHf2mqKLdIjuGFveW00P4HvP0nC+00ZgL97oO5xPQslOcJid0kUqMPcx4nC+63IEBGlcl4LRsIYJV0WabMvcEgS3m8qQ0SDCQJPoKvXwkpcBdIey+s7fkcHFBJ0md4bpg3vA5s+A4ieiU2Xb2C6DtCU8/J3hLeRwLZt3ywgUkQNjOqADGeU4uYnKHEL4fXJXZs+7SNtyRAGOZ8Bajv5o3va6cd/23paIy56xrORITIKb8eJ+xPfGDc/gRilTLEg/6Z3IqrGopT7+TqjJJdfnRP88Uuki8u+lyqqHaDGd4erwEKdW6cXoZmICQ0UFaYlUmIzkEbM8AIH4SVoyOU4uFTBxxpGSDMAgjNCrm6qR3H3dD8/i7nyFJdTnRKdEUh2YzaL+4/uyQGQ7xRUYv8qNxiHEZKErkLIWI7jcE5QeGtKF0+Xv7MNxrgETO8f0HmA1Pn18Wwg8MLfCWDgBsOUl4SIaWb+fwCcPl4MsJm3rQAAAABJRU5ErkJggg=="/>
        </g>
        <clipPath id="anim1">
            <rect width="16" height="16"/>
        </clipPath>
        <clipPath id="anim2">
            <rect y="17" width="16" height="16"/>
        </clipPath>
        <clipPath id="anim3">
            <rect y="33" width="16" height="16"/>
        </clipPath>
        <clipPath id="anim4">
            <rect y="49" width="16" height="16"/>
        </clipPath>
    </defs>
    <use xlink:href="#baseImage" clip-path="url(#anim1)" x="0" y="0"></use>
    <use xlink:href="#baseImage" clip-path="url(#anim2)" x="24" y="24"></use>
    <use xlink:href="#baseImage" clip-path="url(#anim3)" x="48" y="48"></use>
    <use xlink:href="#baseImage" clip-path="url(#anim4)" x="72" y="72"></use>
</svg>
        
このsvgコードは以下のようになります。

合同会社タコスキングダム|タコキンのPスクール

今回は意図的に一つの画像から4つの画像を意図的に抽出し、少しずらして表示しているだけですが、
clipPathで画像の一部を新しい画像として登録して、useでどの画像を表示させるかを一定のタイミングで決定させるだけでアニメーションとして仕上げるように出来ます。

なお、分割後の画像のサイズ調整などはSVGの別のテクニックが必要になります。

前回以下の記事にてSVG基本的な使いこなしをまとめていたので、画像の調整方法が気になる方はそちらの内容でチェックしてください。

合同会社タコスキングダム|タコキンのPスクール
【Scratch入門】SVG画像のviewportの意味とviewBox属性の使い方

ScratchにおけるSVG画像で重要なビューポート(Viewport)の概念と使い方の基本を説明します。

ではこの仕組みを踏まえて早速今回の拡張機能を実装してみます。

拡張機能の実装

今回も拡張機能のJavascriptの実装部分だけを紹介させていただきます。

もし詳しくScratch3の拡張機能の作成手順を知りたい方は、何度か具体的な実装を当ブログで解説していますので例えば以下のリンクの内容で確認してください。

合同会社タコスキングダム|タコキンのPスクール
【Scratch拡張機能・自作】文字からユニコード番号に変換するちょっとしたエクステンションを作る

Scratch-guiから、文字もしくは文字列からユニコード(16進数)に変換するための拡張機能を自作します。

以下に拡張用の
index.jsの実装を示します。

            
            const ArgumentType = require('../../extension-support/argument-type');
const BlockType = require('../../extension-support/block-type');
const Cast = require('../../util/cast');
const formatMessage = require('format-message');
const log = require('../../util/log');
const StageLayering = require('../../engine/stage-layering');

class Scratch3PartialImageWriter {
    constructor (runtime) {
        this._extVersion = '0.0.1';
        this.runtime = runtime;
        this._x = 0;
        this._y = 0;
        this._xOrigin = 24;
        this._yOrigin = -48;
        this._imageDrawableId = -1;
        this._imageSkinId = -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>';
    }

    _spawnSprite(partId_) {
        const xoffsets_ = [0, 0, 0, 0, -16, -16, -16, -16, -32, -32, -32, -32, -48, -48, -48, -48];
        const yoffsets_ = [0, -17, -33, -49, 0, -17, -33, -49, 0, -17, -33, -49, 0, -17, -33, -49];
        if (partId_ < 0 || partId_ > 16) { return this.emptyImg; }

        const characterSeed = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="96" height="168" viewBox="0 0 64 112">
            <defs>
                <g id="baseImage">
                    <image width="64" height="112" xlink:href="data:image/png;base64,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"/>
                </g>
                <clipPath id="anim1"><rect width="16" height="16"/></clipPath>
                <clipPath id="anim2"><rect y="17" width="16" height="16"/></clipPath>
                <clipPath id="anim3"><rect y="33" width="16" height="16"/></clipPath>
                <clipPath id="anim4"><rect y="49" width="16" height="16"/></clipPath>
                <clipPath id="anim5"><rect x="17" y="0" width="16" height="16"/></clipPath>
                <clipPath id="anim6"><rect x="17" y="17" width="16" height="16"/></clipPath>
                <clipPath id="anim7"><rect x="17" y="33" width="16" height="16"/></clipPath>
                <clipPath id="anim8"><rect x="17" y="49" width="16" height="16"/></clipPath>
                <clipPath id="anim9"><rect x="33" y="0" width="16" height="16"/></clipPath>
                <clipPath id="anim10"><rect x="33" y="17" width="16" height="16"/></clipPath>
                <clipPath id="anim11"><rect x="33" y="33" width="16" height="16"/></clipPath>
                <clipPath id="anim12"><rect x="33" y="49" width="16" height="16"/></clipPath>
                <clipPath id="anim13"><rect x="49" y="0" width="16" height="16"/></clipPath>
                <clipPath id="anim14"><rect x="49" y="17" width="16" height="16"/></clipPath>
                <clipPath id="anim15"><rect x="49" y="33" width="16" height="16"/></clipPath>
                <clipPath id="anim16"><rect x="49" y="49" width="16" height="16"/></clipPath>
            </defs>
            <use xlink:href="#baseImage" clip-path="url(#anim${partId_})" x="${xoffsets_[partId_ - 1]}" y="${yoffsets_[partId_ - 1]}"></use>
        </svg>`;
        return characterSeed;
    }

    getInfo () {
        return {
            id: 'partialimagewriter',
            name: formatMessage({
                id: 'partialimagewriter.categoryName',
                default: 'PartialImageWriter',
                description: 'Label for the partialimagewriter extension category'
            }),
            blocks: [
                {
                    opcode: 'initSprite',
                    blockType: BlockType.COMMAND
                },
                {
                    opcode: 'stamp',
                    blockType: BlockType.COMMAND,
                    text: formatMessage({
                        id: 'partialimagewriter.stamp',
                        default: 'stamp [PART_ID]',
                        description: 'Render a current skin onto a drawble'
                    }),
                    arguments: {
                        PART_ID: {
                            type: ArgumentType.NUMBER,
                            defaultValue: 1
                        }
                    }
                },
                {
                    opcode: 'moveTo',
                    blockType: BlockType.COMMAND,
                    text: formatMessage({
                        id: 'partialimagewriter.moveto',
                        default: 'move to ( [X_POS], [Y_POS] )',
                        description: 'move current sprite to'
                    }),
                    arguments: {
                        X_POS: {
                            type: ArgumentType.NUMBER,
                            defaultValue: 0
                        },
                        Y_POS: {
                            type: ArgumentType.NUMBER,
                            defaultValue: 0
                        }
                    }
                },
                {
                    opcode: 'setXYOffset',
                    blockType: BlockType.COMMAND,
                    text: formatMessage({
                        id: 'partialimagewriter.setxyoffset',
                        default: 'Origin set to ( [X_ORIGIN], [Y_ORIGIN] )',
                        description: 'set new origin'
                    }),
                    arguments: {
                        X_ORIGIN: {
                            type: ArgumentType.NUMBER,
                            defaultValue: 0
                        },
                        Y_ORIGIN: {
                            type: ArgumentType.NUMBER,
                            defaultValue: 0
                        }
                    }
                },
                {
                    opcode: 'clearImage',
                    blockType: BlockType.COMMAND
                },
                {
                    opcode: 'goImageToBack',
                    blockType: BlockType.COMMAND
                },
                {
                    opcode: 'goImageToFront',
                    blockType: BlockType.COMMAND
                },
                {
                    opcode: 'getVersion',
                    text: 'Version Info',
                    blockType: BlockType.REPORTER
                }
            ],
            menus: {}
        };
    }

    stamp (args, util) {
        if (this._imageSkinId >= 0) {
            this._pi = Cast.toNumber(args.PART_ID);
            const chara1 = this._spawnSprite(this._pi);
            this.runtime.renderer.updateSVGSkin(this._imageSkinId, chara1);
        }
    }

    moveTo (args, util) {
        this._x = Cast.toNumber(args.X_POS);
        this._y = Cast.toNumber(args.Y_POS);
        if (this._imageDrawableId >= 0 && this._imageSkinId >= 0) {
            this.runtime.renderer.updateDrawableProperties(this._imageDrawableId, {
                skinId: this._imageSkinId,
                position: [this._x + this._xOrigin, this._y + this._yOrigin],
                scale: [100, 100],
                direction: 90
            });
            this.runtime.requestRedraw();
        }
    }

    setXYOffset(args, util) {
        this._xOrigin = Cast.toNumber(args.X_ORIGIN);
        this._yOrigin = Cast.toNumber(args.Y_ORIGIN);
    }

    initSprite() {
        if (this._imageSkinId < 0 && this.runtime.renderer) {
            const skinId = this.runtime.renderer.createSVGSkin(this.emptyImg);
            this._imageSkinId = skinId;
            this._imageDrawableId = this.runtime.renderer.createDrawable(StageLayering.SPRITE_LAYER);
            this.runtime.renderer.updateDrawableProperties(this._imageDrawableId, {skinId: this._imageSkinId});
        }
    }

    clearImage () {
        if (this._imageSkinId >= 0) {
            this.runtime.renderer.updateSVGSkin(this._imageSkinId, this.emptyImg);
        }
    }

    goImageToBack() {
        if (this._imageDrawableId >= 0 && this._imageSkinId >= 0) {
            this.runtime.renderer.setDrawableOrder(this._imageDrawableId, 1, StageLayering.SPRITE_LAYER);
        }
    }

    goImageToFront() {
        if (this._imageDrawableId >= 0 && this._imageSkinId >= 0) {
            this.runtime.renderer.setDrawableOrder(this._imageDrawableId, Infinity, StageLayering.SPRITE_LAYER);
        }
    }

    getVersion(args) {
        return this._extVersion;
    }
}

module.exports = Scratch3PartialImageWriter;
        
現状動かれせる画像が1つのスプライトのみしかありませんが、この拡張機能をインポートし、適当なプロジェクトを作って以下のように簡単なブロックプログラミングをしてみます。

合同会社タコスキングダム|タコキンのPスクール

テストとして動きを確認してみると、こんな感じに動いていればOKです。

合同会社タコスキングダム|タコキンのPスクール

ゲームとして遊ぶレベルになるにはまだまだ実装しなけれならない動きや操作が山積みですが、そこら辺はScratchでのプログラミングで作り込みしていくことになるので、1枚の画像から動くSVGアニメーションを作り出す拡張機能としてはだいたいこんな感じではなかろうかと思います。


合同会社タコスキングダム|タコキンのPスクール【Html&Cssアプリ】Html/JavascriptとSassを使った四択クイズゲームの作り方

すぐに作れる ずっと使える Inkscapeのすべてが身に付く本

まとめ

今回はRPGを作る上でマップを動き回る際のキャラクターチップのアニメーションを行うためだけの拡張機能を作成して動作させてみました。

この程度であれば拡張機能を使うまでも無いかも知れませんが、ゲームの作り込みが進んで、沢山のキャラクターを登場させてその一つ一つにアニメーションを付けて回るようなところまで来ると今回のような拡張機能が役に立つものと思います。

参考サイト

ぴぽや倉庫

Superpowers Asset Packs