Obsah:

Rozšíření Scratch 3.0: 8 kroků
Rozšíření Scratch 3.0: 8 kroků

Video: Rozšíření Scratch 3.0: 8 kroků

Video: Rozšíření Scratch 3.0: 8 kroků
Video: Scratch - jak na to (rekurze) 2024, Listopad
Anonim
Rozšíření Scratch 3.0
Rozšíření Scratch 3.0

Rozšíření Scratch jsou kousky kódu Javascript, které do Scratch přidávají nové bloky. Zatímco Scratch je dodáván se spoustou oficiálních rozšíření, neexistuje oficiální mechanismus pro přidávání uživatelsky vytvořených rozšíření.

Když jsem vyráběl rozšíření pro ovládání Minecraftu pro Scratch 3.0, bylo pro mě těžké začít. Tento Instructable shromažďuje informace z různých zdrojů (zejména z tohoto), plus pár věcí, které jsem sám objevil.

Musíte vědět, jak programovat v Javascriptu a jak hostovat Javascript na webové stránce. Pro ty druhé doporučuji stránky GitHub.

Hlavním trikem je použít SheepTester mod Scratch, který vám umožní načíst rozšíření a pluginy.

Tento Instructable vás provede dvěma rozšířeními:

  • Načíst: načítání dat z adresy URL a extrahování značek JSON, například pro načítání dat o počasí
  • SimpleGamepad: použití herního ovladače v programu Scratch (sofistikovanější verze je zde).

Krok 1: Dva typy rozšíření

Existují dva typy rozšíření, které budu nazývat „bez sandboxu“a „sandboxed“. Rozšíření v karanténě běží jako Web Workers a v důsledku toho mají významná omezení:

  • Web Workers nemůže přistupovat ke globálům v objektu okna (místo toho mají globální vlastní objekt, který je mnohem omezenější), takže je nemůžete použít pro věci, jako je přístup k gamepadu.
  • Rozšíření v izolovaném prostoru nemají přístup k běhovému objektu Scratch.
  • Rozšíření v izolovaném prostoru jsou mnohem pomalejší.
  • Chybové zprávy konzoly Javascript pro rozšíření v karanténě jsou v prohlížeči Chrome tajemnější.

Na druhou stranu:

  • Používání rozšíření jiných uživatelů v izolovaném prostoru je bezpečnější.
  • Rozšíření v izolovaném prostoru pravděpodobně fungují s případnou oficiální podporou načítání rozšíření.
  • Rozšíření v karanténě lze testovat bez nahrání na webový server kódováním do adresy URL data: //.

Oficiální rozšíření (například Hudba, Pero atd.) Jsou všechna bez sandboxu. Konstruktor pro rozšíření získá runtime objekt ze Scratch a okno je plně přístupné.

Rozšíření Fetch je v karanténě, ale Gamepad potřebuje objekt navigátoru z okna.

Krok 2: Psaní rozšíření v izolovaném prostoru: část I

Chcete -li vytvořit rozšíření, vytvoříte třídu, která kóduje informace o něm, a poté přidáte trochu kódu pro registraci rozšíření.

Hlavní věcí ve třídě rozšíření je metoda getInfo (), která vrací objekt s požadovanými poli:

  • id: interní název rozšíření, musí být pro každé rozšíření jedinečný
  • name: popisný název rozšíření, který se zobrazí v seznamu bloků Scratch
  • bloky: seznam objektů popisujících nový vlastní blok.

A existuje volitelné pole nabídek, které se ve Fetch nezvykne, ale bude použito v Gamepadu.

Zde je základní šablona pro Fetch:

třída ScratchFetch {

konstruktor () {} getInfo () {return {"id": "Načíst", "název": "Načíst", "bloky": [/* přidat později * /]}} / * přidat metody pro bloky * /} Scratch.extensions.register (nový ScratchFetch ())

Krok 3: Psaní rozšíření v karanténě: Část II

Nyní musíme vytvořit seznam bloků v objektu getInfo (). Každý blok potřebuje alespoň tato čtyři pole:

  • opcode: toto je název metody, která je volána k práci bloku
  • blockType: toto je typ bloku; Nejběžnější pro rozšíření jsou:

    • "příkaz": udělá něco, ale nevrátí hodnotu
    • "reportér": vrátí řetězec nebo číslo
    • "Boolean": vrátí logickou hodnotu (všimněte si velkých písmen)
    • "klobouk": blok zachycující událost; pokud váš Scratch kód používá tento blok, Scratch runtime pravidelně dotazuje přidruženou metodu, která vrací logickou hodnotu, aby řekla, zda k události došlo
  • text: toto je popis bloku s argumenty v závorkách, např. „načíst data z “
  • argumenty: toto je objekt, který má pole pro každý argument (např. „url“ve výše uvedeném příkladu); tento objekt má zase tato pole:

    • zadejte: buď „řetězec“nebo „číslo“
    • defaultValue: výchozí hodnota, která má být předvyplněna.

Zde je například pole bloků v mém rozšíření Fetch:

"bloky": [{"opcode": "fetchURL", "blockType": "reporter", "text": "fetch data from ", "arguments": {"url": {"type": "string", "defaultValue ":" https://api.weather.gov/stations/KNYC/observations "},}}, {" opcode ":" jsonExtract "," blockType ":" reportér "," text ":" extrahovat [jméno] from [data] "," arguments ": {" name ": {" type ":" string "," defaultValue ":" temperature "}," data ": {" type ":" string "," defaultValue ": '{"teplota": 12.3}'},}},]

Zde jsme definovali dva bloky: fetchURL a jsonExtract. Oba jsou reportéři. První načte data z adresy URL a vrátí je a druhá extrahuje pole z dat JSON.

Nakonec musíte zahrnout metody pro dva bloky. Každá metoda bere objekt jako argument, přičemž objekt obsahuje pole pro všechny argumenty. Můžete je dekódovat pomocí složených závorek v argumentech. Například zde je jeden synchronní příklad:

jsonExtract ({name, data}) {

var parsed = JSON.parse (data) if (name in parsed) {var out = parsed [name] var t = typeof (out) if (t == "string" || t == "number") return out if (t == "boolean") vrátit t? 1: 0 vrátit JSON.stringify (out)} else {return ""}}

Kód stáhne pole názvu z dat JSON. Pokud pole obsahuje řetězec, číslo nebo logickou hodnotu, vrátíme to. Jinak pole znovu JSONify. A pokud název v JSONu chybí, vrátíme prázdný řetězec.

Někdy však můžete chtít vytvořit blok, který používá asynchronní API. Metoda fetchURL () používá API pro načítání, které je asynchronní. V takovém případě byste měli vrátit příslib vaší metody, která funguje. Například:

fetchURL ({url}) {

vrátit načtení (URL). pak (odpověď => response.text ())}

A je to. Úplné rozšíření je zde.

Krok 4: Použití rozšíření v karanténě

Použití rozšíření v karanténě
Použití rozšíření v karanténě
Použití rozšíření v karanténě
Použití rozšíření v karanténě
Použití rozšíření v karanténě
Použití rozšíření v karanténě

Existují dva způsoby použití rozšíření v izolovaném prostoru. Nejprve jej můžete nahrát na webový server a poté načíst do Scratch mod SheepTesteru. Za druhé, můžete jej zakódovat do datové adresy URL a načíst do režimu Scratch. Ve skutečnosti používám druhou metodu docela dost pro testování, protože to eliminuje starosti se staršími verzemi rozšíření, které by server ukládal do mezipaměti. Všimněte si toho, že i když můžete hostovat javascript ze stránek Github, nemůžete to dělat přímo z běžného úložiště github.

Můj soubor fetch.js je umístěn na adrese https://arpruss.github.io/fetch.js. Nebo můžete své rozšíření převést na datovou adresu URL tak, že jej nahrajete sem a poté zkopírujete do schránky. Datová adresa URL je obrovská adresa URL, která obsahuje celý soubor.

Přejděte na Scratch mod SheepTester. Klikněte na tlačítko Přidat rozšíření v levém dolním rohu. Poté klikněte na „Vyberte rozšíření“a zadejte svou adresu URL (pokud chcete, můžete vložit celou obrovskou datovou adresu URL).

Pokud vše proběhlo dobře, budete mít na levé straně obrazovky Scratch položku pro své rozšíření. Pokud věci nešly dobře, měli byste otevřít konzolu Javascript (shift-ctrl-J v Chromu) a zkusit problém odladit.

Nahoře najdete nějaký ukázkový kód, který načítá a analyzuje data JSON ze stanice KNYC (v New Yorku) americké národní meteorologické služby a zobrazuje ji, zatímco otáčí skřítka čelem stejným způsobem, jakým fouká vítr. Způsob, jakým jsem to udělal, bylo načtení dat do webového prohlížeče a poté zjištění značek. Pokud chcete vyzkoušet jinou meteorologickou stanici, zadejte blízké PSČ do vyhledávacího pole na weather.gov a stránka s počasím pro vaši polohu by vám měla poskytnout čtyřpísmenný kód stanice, který můžete použít místo KNYC v kód.

Můžete také zahrnout rozšíření v izolovaném prostoru přímo do adresy URL pro režim SheepTester přidáním argumentu "? Url =". Například:

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

Krok 5: Psaní rozšíření bez pískoviště: Úvod

Konstruktor rozšíření bez sandboxu dostane předán objekt Runtime. Můžete jej ignorovat nebo použít. Jedno použití objektu Runtime je použití jeho vlastnosti currentMSecs k synchronizaci událostí ("bloků klobouků"). Pokud mohu říci, všechny operační kódy bloků událostí jsou pravidelně dotazovány a každé kolo hlasování má jedinou hodnotu currentMSecs. Pokud potřebujete objekt Runtime, pravděpodobně zahájíte rozšíření pomocí:

třída ROZŠÍŘENÍ TŘÍDA {

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

Všechny standardní věci pro okenní objekty lze použít v rozšíření, které není v karanténě. Konečně by vaše rozšíření bez schránky mělo končit tímto kouskem kouzelného kódu:

(funkce () {

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

kde byste měli nahradit EXTENSIONCLASS třídou vašeho rozšíření.

Krok 6: Psaní rozšíření bez pískoviště: Jednoduchý gamepad

Pojďme nyní vytvořit jednoduché rozšíření gamepadu, které poskytuje blok jedné události („klobouk“) při stisknutí nebo uvolnění tlačítka.

Během každého cyklu dotazování bloku událostí uložíme časové razítko z runtime objektu a předchozí a aktuální stavy gamepadu. Časové razítko se používá k rozpoznání, zda máme nový cyklus dotazování. Začínáme tedy s:

třída ScratchSimpleGamepad {

konstruktor (runtime) {this.runtime = runtime this.currentMSecs = -1 this.previousButtons = this.currentButtons = }…} Budeme mít jeden blok událostí se dvěma vstupy-číslem tlačítka a nabídkou pro výběr, zda chceme, aby se událost spustila stisknutím nebo uvolněním. Zde je tedy naše metoda

získat informace() {

return {"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 "},},},]," menu ": {" pressReleaseMenu ": [{text:" press ", hodnota: 1}, {text:" release ", hodnota: 0}],}}; } Myslím, že hodnoty v rozbalovací nabídce jsou stále předávány funkci opcode jako řetězce, přestože jsou deklarovány jako čísla. Podle potřeby je tedy výslovně porovnejte s hodnotami uvedenými v nabídce. Nyní napíšeme metodu, která aktualizuje stavy tlačítek, kdykoli dojde k novému cyklu dotazování událostí

Aktualizace() {

if (this.runtime.currentMSecs == this.currentMSecs) return // not a new polling cycle this.currentMSecs = this.runtime.currentMSecs var gamepads = navigator.getGamepads () if (gamepads == null || gamepads.length = = 0 || gamepady [0] == null) {this.previousButtons = this.currentButtons = return} var gamepad = gamepads [0] if (gamepad.buttons.length! = This.previousButtons.length) { // různý počet tlačítek, takže nový gamepad this.previousButtons = pro (var i = 0; i <gamepad.buttons.length; i ++) this.previousButtons.push (false)} else {this.previousButtons = this. currentButtons} this.currentButtons = pro (var i = 0; i <gamepad.buttons.length; i ++) this.currentButtons.push (gamepad.buttons .pressed)} Nakonec můžeme implementovat náš blok událostí voláním metody update () a poté kontrolou, zda bylo požadované tlačítko právě stisknuto nebo uvolněno, porovnáním aktuálního a předchozího stavu tlačítka

buttonPressedReleased ({b, eventType}) {

this.update () if (b <this.currentButtons.length) {if (eventType == 1) {// poznámka: toto bude řetězec, takže je lepší jej porovnat s 1, než s ním zacházet jako s booleovským if (this.currentButtons &&! this.previousButtons ) {return true}} else {if (! this.currentButtons && this.previousButtons ) {return true}}} return false} A nakonec po definování třídy přidáme náš registrační kód magického rozšíření

(funkce () {

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

Úplný kód můžete získat zde.

Krok 7: Použití rozšíření, které není v karanténě

Používání rozšíření Unsandboxed
Používání rozšíření Unsandboxed

Ještě jednou někde hostujte své rozšíření a tentokrát jej načtěte argumentem load_plugin = spíše než url = do Scratch mod SheepTesteru. Například pro můj jednoduchý režim Gamepad přejděte na:

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

(Mimochodem, pokud chcete propracovanější gamepad, stačí z výše uvedené adresy URL odstranit „simple“a budete mít podporu rachotů a analogových os.)

Rozšíření by se opět mělo objevit na levé straně vašeho Scratch editoru. Nahoře je velmi jednoduchý program Scratch, který říká „ahoj“, když stisknete tlačítko 0, a „sbohem“, když jej uvolníte.

Krok 8: Duální kompatibilita a rychlost

Všiml jsem si, že rozšiřující bloky běží řádově rychleji pomocí metody načítání, kterou jsem použil pro rozšíření bez sandboxu. Pokud vám tedy nezáleží na bezpečnostních výhodách běhu v karanténě Web Worker, bude váš kód těžit z načtení argumentu? Load_plugin = URL do režimu SheepTester.

Rozšíření v izolovaném prostoru můžete zajistit kompatibilitu s oběma způsoby načítání pomocí následujícího kódu po definování třídy rozšíření (změňte CLASSNAME na název vaší třídy rozšíření):

(funkce () {

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

Doporučuje: