Sadržaj:

Scratch 3.0 proširenja: 8 koraka
Scratch 3.0 proširenja: 8 koraka

Video: Scratch 3.0 proširenja: 8 koraka

Video: Scratch 3.0 proširenja: 8 koraka
Video: Разбор лучших проектов Скретч хакатона VolBIT - Космос 2024, Novembar
Anonim
Scratch 3.0 proširenja
Scratch 3.0 proširenja

Scratch ekstenzije su komadi Javascript koda koji dodaju nove blokove u Scratch. Iako je Scratch u paketu s gomilom službenih proširenja, ne postoji službeni mehanizam za dodavanje ekstenzija koje su izradili korisnici.

Kad sam pravio svoju Minecraft kontrolnu ekstenziju za Scratch 3.0, bilo mi je teško započeti. Ovaj Instructable zajedno prikuplja informacije iz različitih izvora (posebno ovog), plus nekoliko stvari koje sam sam otkrio.

Morate znati kako programirati u Javascriptu i kako smjestiti svoj Javascript na web stranici. Za ovo drugo preporučujem GitHub stranice.

Glavni trik je korištenje SheepTester -ovog moda Scratch -a koji vam omogućuje učitavanje ekstenzija i dodataka.

Ovaj Instructable će vas voditi kroz izradu dva nastavka:

  • Dohvaćanje: učitavanje podataka s URL -a i izdvajanje JSON oznaka, na primjer za učitavanje vremenskih podataka
  • SimpleGamepad: upotreba kontrolera igre u Scratch -u (ovdje postoji sofisticiranija verzija).

Korak 1: Dvije vrste proširenja

Postoje dvije vrste ekstenzija koje ću nazvati "nesandboxed" i "sandboxed". Proširenja u testnom okruženju izvode se kao web radnici i kao rezultat toga imaju značajna ograničenja:

  • Web radnici ne mogu pristupiti globalima u prozoru objekta (umjesto toga, oni imaju globalni self objekt, koji je mnogo ograničeniji), pa ih ne možete koristiti za stvari poput pristupa gamepadu.
  • Proširenja u sandboxu nemaju pristup objektu Scratch runtime.
  • Proširenja u sandboxu su mnogo sporija.
  • Poruke o greškama konzole Javascript za proširenja u zaštićenom okruženju kriptovalan su u Chromeu.

S druge strane:

  • Korištenje tuđih proširenja u sigurnom okruženju je sigurnije.
  • Proširenja u sandboxu vjerojatnije će raditi s bilo kojom eventualnom službenom podrškom za učitavanje proširenja.
  • Sandbox ekstenzije se mogu testirati bez učitavanja na web server kodiranjem u data: // URL.

Službene ekstenzije (poput muzike, olovke itd.) Su bez sandučića. Konstruktor za proširenje preuzima runtime objekt iz Scratch -a, a prozor je potpuno dostupan.

Proširenje Fetch je zaštićeno, ali Gamepadu je potreban navigacijski objekt iz prozora.

Korak 2: Pisanje proširenja u zaštićenom okruženju: I dio

Da biste napravili proširenje, kreirate klasu koja kodira informacije o njemu, a zatim dodajte malo koda za registraciju proširenja.

Glavna stvar u klasi proširenja je metoda getInfo () koja vraća objekt sa obaveznim poljima:

  • id: interni naziv proširenja mora biti jedinstven za svako proširenje
  • name: prijateljski naziv ekstenzije koji se prikazuje na Scratch listi blokova
  • Blokovi: popis objekata koji opisuju novi prilagođeni blok.

Postoji i opciono polje menija koje se ne koristi u Fetch -u, ali će se koristiti u Gamepad -u.

Dakle, evo osnovnog predloška za Dohvaćanje:

klasa ScratchFetch {

constructor () {} getInfo () {return {"id": "Dohvati", "name": "Dohvati", "blokovi": [/* dodaj kasnije * /]}} / * dodaj metode za blokove * /} Scratch.extensions.register (novi ScratchFetch ())

Korak 3: Pisanje proširenja u zaštićenom okruženju: Dio II

Sada moramo stvoriti listu blokova u objektu getInfo (). Svaki blok treba najmanje ova četiri polja:

  • opcode: ovo je naziv metode koja se poziva za obavljanje posla bloka
  • blockType: ovo je tip bloka; najčešći za proširenja su:

    • "command": radi nešto, ali ne vraća vrijednost
    • "reporter": vraća niz ili broj
    • "Boolean": vraća boolean (obratite pažnju na velika slova)
    • "hat": blok za hvatanje događaja; ako vaš Scratch kôd koristi ovaj blok, vrijeme izvođenja Scratch -a redovno anketira pridruženu metodu koja vraća boolean da kaže je li se događaj dogodio
  • text: ovo je prijateljski opis bloka, sa argumentima u zagradama, npr. "dohvati podatke iz "
  • argumenti: ovo je objekt koji ima polje za svaki argument (npr. "url" u gornjem primjeru); ovaj objekt pak ima ova polja:

    • tip: "string" ili "number"
    • defaultValue: zadana vrijednost koja se mora prethodno popuniti.

Na primjer, evo polja blokova u mojoj ekstenziji Dohvaćanje:

"blokovi": [{"opcode": "fetchURL", "blockType": "reporter", "text": "dohvati podatke iz ", "argumenti": {"url": {"type": "string", "defaultValue ":" https://api.weather.gov/stations/KNYC/observations "},}}, {" opcode ":" jsonExtract "," blockType ":" reporter "," text ":" ekstrakt [ime] from [data] "," arguments ": {" name ": {" type ":" string "," defaultValue ":" temperature "}," data ": {" type ":" string "," defaultValue ": '{"temperatura": 12.3}'},}},]

Ovdje smo definirali dva bloka: fetchURL i jsonExtract. Obojica su reporteri. Prvi izvlači podatke iz URL -a i vraća ih, a drugi izdvaja polje iz JSON podataka.

Na kraju, morate uključiti metode za dva bloka. Svaka metoda uzima objekt kao argument, pri čemu objekt uključuje polja za sve argumente. Možete ih dekodirati pomoću vitičastih zagrada u argumentima. Na primjer, evo jednog sinhronog primjera:

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") vrati ako (t == "boolean") return t? 1: 0 vrati JSON.stringify (out)} else {return ""}}

Kod povlači polje za ime iz JSON podataka. Ako polje sadrži niz, broj ili logičku vrijednost, vraćamo to. U suprotnom ćemo ponovo JSONifikovati polje. Vraćamo prazan niz ako ime nedostaje u JSON -u.

Ponekad ćete, međutim, možda htjeti napraviti blok koji koristi asinhroni API. Metoda fetchURL () koristi asinkroni API za dohvaćanje. U takvom slučaju, trebali biste vratiti obećanje svoje metode koje će uspjeti. Na primjer:

fetchURL ({url}) {

return fetch (url).then (response => response.text ())}

To je to. Potpuno proširenje je ovdje.

Korak 4: Korištenje proširenja u sandboxu

Korištenje proširenja u sandboxu
Korištenje proširenja u sandboxu
Korištenje proširenja u sandboxu
Korištenje proširenja u sandboxu
Korištenje proširenja u sandboxu
Korištenje proširenja u sandboxu

Postoje dva načina korištenja proširenja u sandboxu. Prvo ga možete postaviti na web server, a zatim učitati u SheepTester -ov mod Scratch. Drugo, možete ga kodirati u URL podataka i učitati u mod Scratch. Zapravo prilično koristim drugu metodu za testiranje, jer izbjegava brige o tome da poslužitelj kešira starije verzije proširenja. Imajte na umu da, iako možete ugostiti javascript sa Github stranica, to ne možete učiniti izravno iz običnog github spremišta.

Moj fetch.js se nalazi na https://arpruss.github.io/fetch.js. Ili možete pretvoriti svoje proširenje u URL podataka tako što ćete ga postaviti ovdje, a zatim ga kopirati u međuspremnik. URL podataka je ogromni URL koji sadrži cijelu datoteku.

Idite na SheepTester's Scratch mod. Kliknite na dugme Dodaj proširenje u donjem lijevom kutu. Zatim kliknite na "Odaberi proširenje" i unesite svoj URL (ako želite, možete zalijepiti cijeli ogromni URL podataka).

Ako je sve prošlo u redu, imat ćete unos za proširenje s lijeve strane ekrana za grebanje. Ako stvari nisu krenule dobro, otvorite svoju Javascript konzolu (shift-ctrl-J u Chromeu) i pokušajte otkloniti problem.

Gore ćete pronaći neki primjer koda koji dohvaća i analizira JSON podatke sa stanice KNYC (u New Yorku) američke Nacionalne meteorološke službe i prikazuje ih, dok okreće sprajt na lice na isti način na koji vjetar puše. Način na koji sam to napravio bio je preuzimanjem podataka u web preglednik, a zatim otkrivanjem oznaka. Ako želite isprobati drugu meteorološku stanicu, unesite obližnji poštanski broj u okvir za pretraživanje na weather.gov, a vremenska stranica za vašu lokaciju trebala bi vam dati četveroslovni kôd postaje, koji možete koristiti umjesto KNYC -a u kod.

Takođe možete uključiti svoje proširenje u sandboxu direktno u URL za SheepTester -ov mod dodavanjem argumenta "? Url =". Na primjer:

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

Korak 5: Pisanje ekstenzije bez kutije: Uvod

Konstruktor ekstenzije bez sandučića dobiva proslijeđen Runtime objekt. Možete ga zanemariti ili koristiti. Jedna upotreba objekta Runtime je korištenje njegovog svojstva currentMSecs za sinkronizaciju događaja ("blokovi šešira"). Koliko ja mogu zaključiti, svi opkodovi bloka događaja se redovno anketiraju, a svaki krug ispitivanja ima jednu vrijednost currentMSecs. Ako vam je potreban Runtime objekt, vjerojatno ćete započeti proširenje sa:

klasa EXTENSIONCLASS {

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

Sve standardne stavke prozorskog objekta mogu se koristiti u ekstenziji bez sanduka. Konačno, vaša ekstenzija bez sanduka trebala bi završiti ovim dijelom čarobnog koda:

(funkcija () {

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

gdje biste trebali zamijeniti EXTENSIONCLASS klasom ekstenzije.

Korak 6: Pisanje ekstenzije bez kutije: Jednostavan gamepad

Napravimo sada jednostavno proširenje za gamepad koje pruža blok od jednog događaja ("šešir") za pritiskanje ili otpuštanje tipke.

Tokom svakog ciklusa ispitivanja bloka događaja, spremit ćemo vremensku oznaku iz objekta za vrijeme izvođenja, te prethodno i trenutno stanje gamepada. Vremenska oznaka se koristi za prepoznavanje imamo li novi ciklus glasanja. Dakle, počinjemo sa:

klasa ScratchSimpleGamepad {

constructor (runtime) {this.runtime = runtime this.currentMSecs = -1 this.previousButtons = this.currentButtons = }…} Imat ćemo jedan blok događaja, s dva ulaza-brojem gumba i izbornikom za odabir želimo li da se događaj pokrene pritiskom ili otpuštanjem. Dakle, evo naše metode

getInfo () {

return {"id": "SimpleGamepad", "name": "SimpleGamepad", "Blocks": [{"opcode": "buttonPressedReleased", "blockType": "hat", "text": "button [eventType] "," argumenti ": {" b ": {" type ":" number "," defaultValue ":" 0 "}," eventType ": {" type ":" number "," defaultValue ":" 1 "," menu ":" pressReleaseMenu "},},},]," menus ": {" pressReleaseMenu ": [{text:" press ", vrijednost: 1}, {text:" release ", vrijednost: 0}],}}; } Mislim da se vrijednosti u padajućem izborniku i dalje prosljeđuju opcode funkciji kao nizovi, unatoč tome što su deklarirane kao brojevi. Zato ih izričito uporedite sa vrijednostima navedenim u izborniku po potrebi. Sada pišemo metodu koja ažurira stanja dugmeta svaki put kada se dogodi novi ciklus ispitivanja događaja

update () {

if (this.runtime.currentMSecs == this.currentMSecs) return // nije novi ciklus ispitivanja this.currentMSecs = this.runtime.currentMSecs var gamepads = navigator.getGamepads () if (gamepads == null || gamepads.length = = 0 || gamepads [0] == null) {this.previousButtons = this.currentButtons = return} var gamepad = gamepads [0] if (gamepad.buttons.length! = This.previousButtons.length) { // različit broj gumba, pa je novi gamepad this.previousButtons = za (var i = 0; i <gamepad.buttons.length; i ++) this.previousButtons.push (false)} else {this.previousButtons = this. currentButtons} this.currentButtons = za (var i = 0; i <gamepad.buttons.length; i ++) this.currentButtons.push (gamepad.buttons .pressed)} Konačno, možemo implementirati naš blok događaja pozivanjem metode update (), a zatim provjerom da li je potrebno dugme samo pritisnuto ili otpušteno, usporedbom trenutnog i prethodnog stanja dugmeta

buttonPressedReleased ({b, eventType}) {

this.update () if (b <this.currentButtons.length) {if (eventType == 1) {// napomena: ovo će biti niz, pa je bolje uporediti ga sa 1 nego tretirati kao logičko polje if ((this.currentButtons &&! this.previousButtons ) {return true}} else {if (! this.currentButtons && this.previousButtons ) {return true}}} return false} I na kraju dodajemo naš čarobni registracijski kod proširenja nakon definiranja klase

(funkcija () {

var extensionInstance = novi ScratchSimpleGamepad (window.vm.extensionManager.runtime) var serviceName = window.vm.extensionManager._registerInternalExtension (extensionInstance) window.vm.extensionManager._loadedExtensions.set (extensionInstance.getInmea) (serviceInstance.getInmea))))

Potpuni kôd možete dobiti ovdje.

Korak 7: Upotreba ekstenzije bez kutije

Upotreba ekstenzije bez kutije
Upotreba ekstenzije bez kutije

Još jednom, smjestite svoju ekstenziju negdje i ovaj put je učitajte s load_plugin = umjesto url = argumentom u SheepTester -ov mod Scratch. Na primjer, za moj jednostavan Gamepad mod, idite na:

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

(Usput, ako želite sofisticiraniji gamepad, samo uklonite "simple" s gornjeg URL -a i imat ćete podršku za tutnjavu i analognu os.)

Opet, proširenje bi se trebalo pojaviti na lijevoj strani uređivača Scratch. Gore je vrlo jednostavan program za grebanje koji kaže "zdravo" kada pritisnete dugme 0 i "zbogom" kada ga otpustite.

Korak 8: Dvojna kompatibilnost i brzina

Primijetio sam da ekstenzioni blokovi trče za red veličine brže koristeći metodu učitavanja koju sam koristio za ekstenzije bez sanduka. Dakle, osim ako vam nije stalo do sigurnosnih prednosti izvođenja u Sandworku za rad na webu, vaš će kôd imati koristi od učitavanja sa? Load_plugin = URL argumentom u SheepTester -ovom modu.

Proširenje u sandboxu možete učiniti kompatibilnim s obje metode učitavanja pomoću sljedećeg koda nakon definiranja klase proširenja (promijenite CLASSNAME u naziv svoje klase proširenja):

(funkcija () {

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)}}) ()

Preporučuje se: