Talaan ng mga Nilalaman:

Mga Extension ng Scratch 3.0: 8 Mga Hakbang
Mga Extension ng Scratch 3.0: 8 Mga Hakbang

Video: Mga Extension ng Scratch 3.0: 8 Mga Hakbang

Video: Mga Extension ng Scratch 3.0: 8 Mga Hakbang
Video: LTO MOTORCYCLE REGISTRATION 2023| PAANO MAG REHISTRO NG MOTOR|LTO|SHEEPVLOGS 2024, Hulyo
Anonim
Mga Extension ng Scratch 3.0
Mga Extension ng Scratch 3.0

Ang mga extension ng gasgas ay mga piraso ng Javascript code na nagdaragdag ng mga bagong bloke sa Scratch. Habang ang Scratch ay na-bundle ng isang grupo ng mga opisyal na extension, walang isang opisyal na mekanismo para sa pagdaragdag ng mga ginawa ng gumagamit.

Kapag ginagawa ko ang aking Minecraft na pagkontrol ng extension para sa Scratch 3.0, nahirapan akong magsimula. Nangongolekta ang Instructable na ito ng impormasyon mula sa iba't ibang mga mapagkukunan (lalo na ito), kasama ang ilang mga bagay na natuklasan ko mismo.

Kailangan mong malaman kung paano magprogram sa Javascript at kung paano i-host ang iyong Javascript sa isang website. Para sa huli, inirerekumenda ko ang Mga GitHub na Pahina.

Ang pangunahing trick ay ang paggamit ng mod ng Scratch ng SheepTester na nagbibigay-daan sa iyong mag-load ng mga extension at plugin.

Gagabayan ka ng Instructable na ito sa pamamagitan ng paggawa ng dalawang mga extension:

  • Kunin: paglo-load ng data mula sa isang URL at pagkuha ng mga tag ng JSON, halimbawa para sa paglo-load ng data ng panahon
  • SimpleGamepad: paggamit ng isang game controller sa Scratch (narito ang isang mas sopistikadong bersyon).

Hakbang 1: Dalawang Uri ng Mga Extension

Mayroong dalawang uri ng mga extension na tatawagin kong "unsandboxed" at "sandboxed". Ang mga sandboxed extension ay tumatakbo bilang mga Web Worker, at bilang isang resulta ay may makabuluhang mga limitasyon:

  • Ang mga manggagawa sa web ay hindi ma-access ang mga global sa window object (sa halip, mayroon silang isang pandaigdigang object sa sarili, na higit na limitado), kaya hindi mo magagamit ang mga ito para sa mga bagay tulad ng pag-access ng gamepad.
  • Ang mga sandboxed extension ay walang access sa Scratch runtime object.
  • Ang mga sandboxed extension ay mas mabagal.
  • Ang mga mensahe ng error sa Javascript console para sa mga sandboxed extension ay mas cryptic sa Chrome.

Sa kabilang kamay:

  • Mas ligtas ang paggamit ng mga sandboxed extension ng ibang tao.
  • Ang mga sandbox na extension ay mas malamang na gumana sa anumang paglaon na suporta sa opisyal na paglo-load ng extension.
  • Maaaring masubukan ang mga sandboxed extension nang hindi ina-upload sa isang web server sa pamamagitan ng pag-encode sa isang data: // URL.

Ang mga opisyal na extension (tulad ng Musika, Panulat, atbp.) Lahat ay hindi naka -bobock. Ang tagabuo para sa extension ay nakakakuha ng runtime object mula sa Scratch, at ang window ay ganap na naa-access.

Ang extension na Fetch ay sandboxed, ngunit kailangan ng Gamepad ang isang bagay ng navigator mula sa window.

Hakbang 2: Pagsulat ng isang Sandboxed Extension: Bahagi I

Upang makagawa ng isang extension, lumikha ka ng isang klase kung saan naka-encode ang impormasyon tungkol dito, at pagkatapos ay magdagdag ng isang piraso ng code upang irehistro ang extension.

Ang pangunahing bagay sa klase ng extension ay isang paraan ng getInfo () na nagbabalik ng isang bagay na may kinakailangang mga patlang:

  • id: ang panloob na pangalan ng extension, dapat na natatangi para sa bawat extension
  • pangalan: ang magiliw na pangalan ng extension, lumalabas sa listahan ng mga bloke ng Scratch
  • mga bloke: isang listahan ng mga bagay na naglalarawan sa bagong pasadyang bloke.

At mayroong isang opsyonal na menu ng mga menu na hindi ginagamit sa Fetch ngunit gagamitin sa Gamepad.

Kaya, narito ang pangunahing template para sa Fetch:

klase ng ScratchFetch {

konstruktor () {} getInfo () {return {"id": "Fetch", "name": "Fetch", "blocks": [/* add later * /]}} / * magdagdag ng mga pamamaraan para sa mga blocks * /} Scratch.extensions.register (bagong ScratchFetch ())

Hakbang 3: Pagsulat ng isang Sandboxed Extension: Bahagi II

Ngayon, kailangan naming lumikha ng listahan ng mga bloke sa object ng getInfo (). Ang bawat bloke ay nangangailangan ng hindi bababa sa apat na patlang na ito:

  • opcode: ito ang pangalan ng pamamaraan na tinawag upang gawin ang gawain ng block
  • blockType: ito ang uri ng block; ang pinaka-karaniwang mga para sa mga extension ay:

    • "utos": gumagawa ng isang bagay ngunit hindi nagbabalik ng isang halaga
    • "reporter": nagbabalik ng isang string o numero
    • "Boolean": nagbabalik ng isang boolean (tandaan ang malaking titik)
    • "sumbrero": nakahahalina sa kaganapan; kung ginagamit ng iyong Scratch code ang bloke na ito, regular na binobola ng runtime ng Scratch ang nauugnay na pamamaraan na nagbabalik ng isang boolean upang sabihin kung nangyari ang kaganapan
  • teksto: ito ay isang magiliw na paglalarawan ng bloke, na may mga argumento sa mga braket, hal., "kunin ang data mula sa "
  • mga argumento: ito ay isang bagay na mayroong isang patlang para sa bawat pagtatalo (hal., "url" sa halimbawa sa itaas); ang bagay na ito naman ay mayroong mga patlang na ito:

    • uri: alinman sa "string" o "numero"
    • defaultValue: ang default na halaga na dapat paunang punan.

Halimbawa, narito ang patlang ng mga bloke sa aking Fetch extension:

"blocks": [{"opcode": "fetchURL", "blockType": "reporter", "text": "kumuha ng data mula sa ", "arguments": {"url": {"type": "string", "defaultValue ":" https://api.weather.gov/stations/KNYC/observations "},}}, {" opcode ":" jsonExtract "," blockType ":" reporter "," text ":" extract [name] mula sa [data] "," arguments ": {" name ": {" type ":" string "," defaultValue ":" temperatura "}," data ": {" type ":" string "," defaultValue ": '{"temperatura": 12.3}'},}},]

Dito, tinukoy namin ang dalawang mga bloke: fetchURL at jsonExtract. Parehong mga reporter. Ang una ay kumukuha ng data mula sa isang URL at ibinalik ito, at ang pangalawa ay kumukuha ng isang patlang mula sa data ng JSON.

Panghuli, kailangan mong isama ang mga pamamaraan para sa dalawang mga bloke. Ang bawat pamamaraan ay tumatagal ng isang bagay bilang isang argument, kasama ang object kasama ang mga patlang para sa lahat ng mga argumento. Maaari mong decode ang mga ito gamit ang mga kulot na brace sa mga argumento. Halimbawa, narito ang isang magkasabay na halimbawa:

jsonExtract ({pangalan, data}) {

var parsed = JSON.parse (data) kung (pangalan sa parsed) {var out = parsed [name] var t = typeof (out) kung (t == "string" || t == "number") bumalik kung (t == "boolean") ibalik t? 1: 0 ibalik ang JSON.stringify (palabas)} iba pa {bumalik ""}}

Kinukuha ng code ang patlang ng pangalan mula sa data ng JSON. Kung ang patlang ay naglalaman ng isang string, numero o boolean, ibabalik namin iyon. Kung hindi man, muling na-JSONify namin ang patlang. At ibabalik namin ang isang walang laman na string kung ang pangalan ay nawawala mula sa JSON.

Gayunpaman, minsan, baka gusto mong gumawa ng isang bloke na gumagamit ng isang asynchronous API. Ang fetchURL () na pamamaraan ay gumagamit ng fetch API na hindi kasabay. Sa ganitong kaso, dapat mong ibalik ang isang pangako mula sa iyong pamamaraan na gumagawa ng trabaho. Halimbawa:

fetchURL ({url}) {

ibalik ang pagkuha (url). pagkatapos (tugon => tugon.text ())}

Ayan yun. Narito na ang buong extension.

Hakbang 4: Paggamit ng isang Sandboxed Extension

Paggamit ng isang Sandboxed Extension
Paggamit ng isang Sandboxed Extension
Paggamit ng isang Sandboxed Extension
Paggamit ng isang Sandboxed Extension
Paggamit ng isang Sandboxed Extension
Paggamit ng isang Sandboxed Extension

Mayroong dalawang paraan ng paggamit ng sandboxed extension. Una, maaari mo itong i-upload sa isang web server, at pagkatapos ay i-load ito sa Scratch mod ng SheepTester. Pangalawa, maaari mo itong i-encode sa isang data URL, at i-load iyon sa Scratch mod. Talagang ginagamit ko ang pangalawang pamamaraan nang kaunti para sa pagsubok, dahil iniiwasan nito ang mga pag-aalala tungkol sa mga mas lumang bersyon ng extension na nai-cache ng server. Tandaan na habang maaari kang mag-host ng javascript mula sa Mga Pahina ng Github, hindi mo ito magagawa nang direkta mula sa isang ordinaryong repository ng github.

Ang aking fetch.js ay naka-host sa https://arpruss.github.io/fetch.js. O maaari mong mai-convert ang iyong extension sa isang data URL sa pamamagitan ng pag-upload dito at pagkatapos ay kopyahin ito sa clipboard. Ang isang data URL ay isang higanteng URL na mayroong isang buong file dito.

Pumunta sa mod ng Scratch ng SheepTester. Mag-click sa pindutang Magdagdag ng Extension sa ibabang kaliwang sulok. Pagkatapos mag-click sa "Pumili ng isang extension", at ipasok ang iyong URL (maaari mong i-paste sa buong higanteng URL ng data kung nais mo).

Kung naging maayos ang lahat, magkakaroon ka ng isang entry para sa iyong extension sa kaliwang bahagi ng iyong Scratch screen. Kung hindi naging maayos ang mga bagay, dapat mong buksan ang iyong Javascript console (shift-ctrl-J sa Chrome) at subukang i-debug ang isyu.

Sa itaas ay mahahanap mo ang ilang halimbawang code na kumukuha at na-parse ang data ng JSON mula sa istasyon ng KNYC (sa New York) ng US National Weather Service, at ipinapakita ito, habang binabaling ang sprite upang harapin ang parehong paraan ng pag-ihip ng hangin. Ang paraan ng paggawa ko nito ay sa pamamagitan ng pagkuha ng data sa isang web browser, at pagkatapos ay alamin ang mga tag. Kung nais mong subukan ang ibang istasyon ng panahon, maglagay ng isang malapit na zip code sa box para sa paghahanap sa weather.gov, at ang pahina ng panahon para sa iyong lokasyon ay dapat magbigay sa iyo ng isang apat na code ng istasyon ng liham, na maaari mong gamitin bilang kapalit ng KNYC sa code

Maaari mo ring isama ang iyong sandboxed extension mismo sa URL para sa mod ng SheepTester sa pamamagitan ng pagdaragdag ng isang "? Url =" argument. Halimbawa:

sheeptester.github.io/scratch-gui/?url=https://arpruss.github.io/fetch.js

Hakbang 5: Pagsulat ng isang Hindi napasarangbo na Extension: Panimula

Ang tagabuo ng isang hindi nakaayos na extension ay nakakakuha ng isang Runtime object. Maaari mo itong balewalain o gamitin ito. Ang isang paggamit ng Runtime object ay ang paggamit nito kasalukuyang pag-aari ng MSCs upang i-synchronize ang mga kaganapan ("mga bloke ng sumbrero"). Hangga't maaari kong sabihin, ang lahat ng mga opcode ng block ng kaganapan ay regular na nai-poll, at ang bawat pag-ikot ng botohan ay may isang solong kasalukuyang halaga ng mgaMSec. Kung kailangan mo ng Runtime object, malamang na sisimulan mo ang iyong extension sa:

klase EXTENSIONCLASS {

konstruktor (runtime) {this.runtime = runtime…}…}

Ang lahat ng mga karaniwang bagay sa window object ay maaaring magamit sa unsandboxed extension. Sa wakas, ang iyong unsandboxed extension ay dapat magtapos sa kaunting magic code na ito:

(pagpapaandar () {

var extensionInstance = bagong EXTENSIONCLASS (window.vm.extensionManager.runtime) var serviceName = window.vm.extensionManager._registerInternalExtension (extensionInstance) window.vm.extensionManager._loadedExtensions.set (extensionInstance.getInfo (). id, serviceName)}))

kung saan mo dapat palitan ang EXTENSIONCLASS ng klase ng iyong extension.

Hakbang 6: Pagsulat ng isang Hindi napasarangbo na Extension: Simpleng Gamepad

Gumawa tayo ngayon ng isang simpleng extension ng gamepad na nagbibigay ng isang solong kaganapan ("sumbrero") na bloke para sa kapag ang isang pindutan ay pinindot o inilabas.

Sa bawat pag-ikot ng ikot ng botohan ng kaganapan, magse-save kami ng isang timestamp mula sa runtime object, at ang dati at kasalukuyang estado ng gamepad. Ginagamit ang timestamp upang makilala kung mayroon kaming isang bagong siklo ng botohan. Kaya, nagsisimula kami sa:

klase ng ScratchSimpleGamepad {

konstruktor (runtime) {this.runtime = runtime this.currentMSecs = -1 this.previous Buttons = this.currentButtons = }…} Magkakaroon kami ng isang bloke ng kaganapan, na may dalawang mga input - isang numero ng pindutan at isang menu upang mapili kung nais naming mag-trigger sa kaganapan sa pagpindot o paglabas. Kaya, narito ang aming pamamaraan

getInfo () {

ibalik ang "" id ":" SimpleGamepad "," name ":" SimpleGamepad "," blocks ": [{" opcode ":" buttonPressedReleased "," blockType ":" hat "," text ":" button [eventType] "," arguments ": {" b ": {" type ":" number "," defaultValue ":" 0 "}," eventType ": {" type ":" number "," defaultValue ":" 1 "," menu ":" pressReleaseMenu "},},},]," menus ": {" pressReleaseMenu ": [{text:" press ", value: 1}, {text:" release ", value: 0}],}}; } Sa palagay ko ang mga halaga sa drop-down na menu ay naipasa pa rin sa pagpapaandar ng opcode bilang mga string, sa kabila ng pagdeklara bilang mga numero. Kaya malinaw na ihambing ang mga ito laban sa mga halagang tinukoy sa menu kung kinakailangan. Nagsusulat kami ngayon ng isang pamamaraan na nag-a-update ng mga estado ng pindutan tuwing may isang bagong ikot ng botohan ng kaganapan

i-update () {

kung (this.runtime.currentMSecs == this.currentMSecs) bumalik // hindi isang bagong cycle ng botohan na ito.currentMSecs = this.runtime.currentMSecs var gamepads = navigator.getGamepads () kung (gamepads == null || gamepads.length = = 0 || gamepads [0] == null) {this.previous Buttons = this.currentButtons = return} var gamepad = gamepads [0] if (gamepad.buttons.length! = This.previous Buttons.length) { // magkakaibang bilang ng mga pindutan, kaya't bagong gamepad this.previousButtons = para sa (var i = 0; i <gamepad.buttons.length; i ++) this.previousbuttons.push (false)} iba pa {this.previousbuttons = ito. currentButtons} this.currentButtons = para sa (var i = 0; i <gamepad.buttons.length; i ++) this.currentButtons.push (gamepad.buttons .pressed)} Panghuli, maaari naming ipatupad ang aming bloke ng kaganapan, sa pamamagitan ng pagtawag sa pag-update () na pamamaraan at pagkatapos ay suriin kung ang kinakailangang pindutan ay na-press o pinakawalan lamang, sa pamamagitan ng paghahambing ng kasalukuyan at nakaraang mga estado ng pindutan

buttonPressedReleased ({b, eventType}) {

this.update () kung (b <this.currentButtons.length) {if (eventType == 1) {// note: ito ay magiging isang string, kaya mas mahusay na ihambing ito sa 1 kaysa sa tratuhin ito bilang isang Boolean kung (this.currentButtons &&! this.previousButtons ) {return true}} iba pa {kung (! this.currentButtons && this.previousbuttons ) {return true}}} return false} At sa wakas ay idinagdag namin ang aming code ng pagpaparehistro ng magic extension pagkatapos ng pagtukoy sa klase

(pagpapaandar () {

var extensionInstance = bagong ScratchSimpleGamepad (window.vm.extensionManager.runtime) var serviceName = window.vm.extensionManager._registerInternalExtension (extensionInstance) window.vm.extensionManager._loadedExtensions.set (extensionInstance.getInfo (). id, serviceName)

Maaari mong makuha ang buong code dito.

Hakbang 7: Paggamit ng isang Hindi na-sandboxed Extension

Paggamit ng isang Hindi naka-sandbox na Extension
Paggamit ng isang Hindi naka-sandbox na Extension

Muli, i-host ang iyong extension sa isang lugar, at sa oras na ito i-load ito sa load_plugin = kaysa url = argument sa SheepTester's Scratch mod. Halimbawa, para sa aking simpleng mod ng Gamepad, pumunta sa:

sheeptester.github.io/scratch-gui/?load_plugin=https://arpruss.github.io/simplegamepad.js

(Sa pamamagitan ng paraan, kung nais mo ang isang mas sopistikadong gamepad, alisin lamang ang "simple" mula sa itaas na URL, at magkakaroon ka ng rumb at suporta sa analog axis.)

Muli, dapat lumitaw ang extension sa kaliwang bahagi ng iyong Scratch editor. Sa itaas ay isang napaka-simpleng programa ng Scratch na nagsasabing "hello" kapag pinindot mo ang pindutan 0 at "paalam" kapag pinakawalan mo ito.

Hakbang 8: Dalawang-pagiging tugma at Bilis

Napansin kong ang mga bloke ng extension ay nagpapatakbo ng isang order ng magnitude nang mas mabilis gamit ang paraan ng paglo-load na ginamit ko para sa mga hindi naka -bock na extension. Kaya maliban kung pinahahalagahan mo ang mga benepisyo sa seguridad ng pagtakbo sa isang sandbox ng Web Worker, makikinabang ang iyong code mula sa paglo-load ng? Load_plugin = URL na argument sa mod ng SheepTester.

Maaari kang gumawa ng isang sandboxed extension na katugma sa parehong mga paraan ng paglo-load sa pamamagitan ng paggamit ng sumusunod na code pagkatapos ng pagtukoy sa klase ng extension (baguhin ang CLASSNAME sa pangalan ng iyong klase ng extension):

(pagpapaandar () {

var extensionClass = CLASSNAME kung (typeof window === "undefined" ||! window.vm) {Scratch.extensions.register (bagong extensionClass ())} iba pa {var extensionInstance = bagong extensionClass (window.vm.extensionManager.runtime) var serviceName = window.vm.extensionManager._registerInternalExtension (extensionInstance) window.vm.extensionManager._loadedExtensions.set (extensionInstance.getInfo (). id, serviceName)}}) ()

Inirerekumendang: