Sadržaj:

Proširenja Scratch 3.0: 8 koraka
Proširenja Scratch 3.0: 8 koraka

Video: Proširenja Scratch 3.0: 8 koraka

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

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

Kad sam izrađivao Minecraft kontrolno proširenje 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 programirati u Javascriptu i kako smjestiti svoj Javascript na web mjestu. Za potonje preporučujem GitHub stranice.

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

Ovaj Instructable će vas voditi kroz izradu dva proširenja:

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

Korak 1: Dvije vrste proširenja

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

  • Web radnici ne mogu pristupiti globalima u prozoru (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 zaštićenom okruženju nemaju pristup objektu vremena izvođenja Scratch.
  • Proširenja u sandboxu mnogo su sporija.
  • Poruke o pogreškama konzole Javascript za proširenja u sigurnom okruženju kriptova su u Chromeu.

S druge strane:

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

Službena proširenja (kao što su Glazba, Olovka itd.) Nisu zaštićena. Konstruktor za proširenje dobiva runtime objekt iz Scratcha, a prozor je potpuno dostupan.

Proširenje Dohvaćanje 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, stvorite klasu koja kodira podatke 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: unutarnji naziv proširenja mora biti jedinstven za svako proširenje
  • name: prijateljski naziv proširenja koji se prikazuje na Scratch popisu blokova
  • Blokovi: popis objekata koji opisuju novi prilagođeni blok.

Postoji i izborno polje izbornika koje se ne koristi u Dohvaćanju, ali će se koristiti u Gamepadu.

Dakle, ovdje je osnovni predložak 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 popis blokova u objektu getInfo (). Svaki blok treba barem 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:

    • "naredba": radi nešto, ali ne vraća vrijednost
    • "reporter": vraća niz ili broj
    • "Boolean": vraća boolean (obratite pozornost na velika slova)
    • "šešir": blok za hvatanje događaja; ako vaš Scratch kôd koristi ovaj blok, vrijeme izvođenja Scratch -a redovito ispituje povezanu metodu koja vraća boolean da kaže je li se događaj dogodio
  • text: ovo je prijateljski opis bloka s 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:

    • vrsta: "string" ili "number"
    • defaultValue: zadana vrijednost koja se mora prethodno ispuniti.

Na primjer, evo polja blokova u mom proširenju Dohvati:

"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 ":" extract [name] 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, a objekt uključuje polja za sve argumente. Možete ih dekodirati pomoću vitkih zagrada u argumentima. Na primjer, evo jednog sinkronog 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") vratiti t? 1: 0 return JSON.stringify (out)} else {return ""}}

Kôd povlači polje naziva iz JSON podataka. Ako polje sadrži niz, broj ili logičku vrijednost, vraćamo to. U suprotnom slučaju ponovno JSONificiramo polje. Vraćamo prazan niz ako naziv nedostaje u JSON -u.

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

fetchURL ({url}) {

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

To je to. Cijelo proširenje je ovdje.

Korak 4: Korištenje proširenja u izoliranom okruženju

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 pješčaniku. Prvo ga možete učitati na web poslužitelj, a zatim učitati u SheepTester -ov mod Scratch. Drugo, možete ga kodirati u podatkovni URL i učitati u mod Scratch. Zapravo prilično koristim drugu metodu za testiranje jer izbjegavam brige oko toga da poslužitelj kešira starije verzije proširenja. Imajte na umu da, iako možete ugostiti javascript sa stranica Github, to ne možete učiniti izravno iz običnog spremišta github.

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

Idite na SheepTester's Scratch mod. Kliknite gumb 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 zaslona Scratch. Ako stvari nisu išle dobro, otvorite Javascript konzolu (shift-ctrl-J u Chromeu) i pokušajte otkloniti problem.

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

Također možete uključiti svoje pješčano proširenje izravno 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 proširenja bez omota: Uvod

Konstruktor proširenja bez sandučića dobiva proslijeđen objekt Runtime. Možete ga zanemariti ili koristiti. Jedna od 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 redovito se 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 proširenju bez sanduka. Konačno, vaše proširenje bez okvira mora završiti ovim djelićem č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 servisa)

gdje biste trebali zamijeniti EXTENSIONCLASS klasom vašeg proširenja.

Korak 6: Pisanje ekstenzije bez kutije: Jednostavan gamepad

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

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

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

dobiti informacije() {

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. Stoga ih prema potrebi izričito usporedite sa vrijednostima navedenim u izborniku. Sada pišemo metodu koja ažurira stanja gumba kad god se dogodi novi ciklus ispitivanja događaja

ažuriranje() {

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 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 .pritisnuto)} Konačno, možemo implementirati naš blok događaja pozivanjem metode update (), a zatim provjerom je li potreban gumb upravo pritisnut ili otpušten, usporedbom trenutnog i prethodnog stanja gumba

buttonPressedReleased ({b, eventType}) {

this.update () if (b <this.currentButtons.length) {if (eventType == 1) {// napomena: ovo će biti niz, pa ga je bolje usporediti s 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 kôd za proširenje 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)))

Cijeli kôd možete dobiti ovdje.

Korak 7: Upotreba proširenja bez okvira

Korištenje proširenja bez spremnika
Korištenje proširenja bez spremnika

Još jednom smjestite svoje proširenje negdje i ovaj put učitajte ga s load_plugin = umjesto url = argumentom u SheepTester -ov mod Scratch. Na primjer, za moj jednostavan mod Gamepada, 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 s lijeve strane uređivača Scratch. Gore je vrlo jednostavan program za grebanje koji kaže "zdravo" kada pritisnete gumb 0 i "zbogom" kada ga otpustite.

Korak 8: Dvojna kompatibilnost i brzina

Primijetio sam da blokovi za proširenje trče za red veličine brže koristeći metodu učitavanja koju sam koristio za proširenja bez sanduka. Dakle, osim ako vas nije briga za sigurnosne prednosti izvođenja u pješčaniku Web Worker, vaš će kôd imati koristi od učitavanja s argumentom? Load_plugin = URL u SheepTester -ovom modu.

Proširenje u izoliranom okruženju 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čeni: