Table des matières:
- Étape 1: Deux types d'extensions
- Étape 2: Écriture d'une extension en bac à sable: Partie I
- Étape 3: Écriture d'une extension en bac à sable: Partie II
- Étape 4: Utilisation d'une extension en bac à sable
- Étape 5: Écriture d'une extension sans sandbox: Introduction
- Étape 6: Écriture d'une extension sans bac à sable: Manette de jeu simple
- Étape 7: Utilisation d'une extension sans sandbox
- Étape 8: Double compatibilité et vitesse
Vidéo: Extensions Scratch 3.0 : 8 étapes
2024 Auteur: John Day | [email protected]. Dernière modifié: 2024-01-30 09:05
Les extensions Scratch sont des morceaux de code Javascript qui ajoutent de nouveaux blocs à Scratch. Bien que Scratch soit fourni avec un tas d'extensions officielles, il n'y a pas de mécanisme officiel pour ajouter des extensions créées par l'utilisateur.
Lorsque je créais mon extension de contrôle Minecraft pour Scratch 3.0, j'ai eu du mal à démarrer. Ce Instructable rassemble des informations provenant de diverses sources (en particulier cela), ainsi que quelques choses que j'ai découvertes moi-même.
Il faut savoir programmer en Javascript et héberger son Javascript sur un site internet. Pour ce dernier, je recommande GitHub Pages.
L'astuce principale est d'utiliser le mod de Scratch de SheepTester qui vous permet de charger des extensions et des plugins.
Ce Instructable vous guidera à travers la fabrication de deux extensions:
- Fetch: chargement de données depuis une URL et extraction de balises JSON, par exemple pour charger des données météo
- SimpleGamepad: utilisation d'un contrôleur de jeu dans Scratch (une version plus sophistiquée est ici).
Étape 1: Deux types d'extensions
Il existe deux types d'extensions que j'appellerai "sans bac à sable" et "avec bac à sable". Les extensions en bac à sable s'exécutent en tant que Web Workers et présentent par conséquent des limitations importantes:
- Les Web Workers ne peuvent pas accéder aux globals dans l'objet window (au lieu de cela, ils ont un objet self global, qui est beaucoup plus limité), vous ne pouvez donc pas les utiliser pour des choses comme l'accès à la manette de jeu.
- Les extensions en bac à sable n'ont pas accès à l'objet d'exécution Scratch.
- Les extensions en bac à sable sont beaucoup plus lentes.
- Les messages d'erreur de la console Javascript pour les extensions en bac à sable sont plus cryptiques dans Chrome.
D'autre part:
- L'utilisation des extensions sandbox d'autres personnes est plus sûre.
- Les extensions en bac à sable sont plus susceptibles de fonctionner avec toute prise en charge officielle du chargement d'extensions.
- Les extensions en bac à sable peuvent être testées sans téléchargement sur un serveur Web en les encodant dans une URL data://.
Les extensions officielles (telles que Music, Pen, etc.) sont toutes non sandbox. Le constructeur de l'extension obtient l'objet d'exécution à partir de Scratch et la fenêtre est entièrement accessible.
L'extension Fetch est en bac à sable, mais la manette de jeu a besoin de l'objet navigateur de la fenêtre.
Étape 2: Écriture d'une extension en bac à sable: Partie I
Pour créer une extension, vous créez une classe qui encode les informations à son sujet, puis ajoutez un peu de code pour enregistrer l'extension.
La chose principale dans la classe d'extension est une méthode getInfo() qui renvoie un objet avec les champs requis:
- id: le nom interne de l'extension, doit être unique pour chaque extension
- name: le nom convivial de l'extension, apparaissant dans la liste des blocs de Scratch
- blocs: une liste d'objets décrivant le nouveau bloc personnalisé.
Et il y a un champ de menus facultatif qui n'est pas utilisé dans Fetch mais sera utilisé dans Gamepad.
Voici donc le modèle de base pour Fetch:
classe ScratchFetch {
constructor() { } getInfo() { return { "id": "Fetch", "name": "Fetch", "blocks": [/* ajouter plus tard */] } } /* ajouter des méthodes pour les blocs */ } Scratch.extensions.register (nouveau ScratchFetch())
Étape 3: Écriture d'une extension en bac à sable: Partie II
Maintenant, nous devons créer la liste des blocs dans l'objet de getInfo(). Chaque bloc a besoin d'au moins ces quatre champs:
- opcode: c'est le nom de la méthode qui est appelée pour faire le travail du bloc
-
blockType: c'est le type de bloc; les plus courantes pour les extensions sont:
- "commande": fait quelque chose mais ne renvoie pas de valeur
- "reporter": renvoie une chaîne ou un nombre
- "Boolean": renvoie un booléen (notez la majuscule)
- "hat": bloc de capture d'événement; si votre code Scratch utilise ce bloc, le runtime Scratch interroge régulièrement la méthode associée qui renvoie un booléen pour dire si l'événement s'est produit
- text: il s'agit d'une description conviviale du bloc, avec les arguments entre parenthèses, par exemple "récupérer les données de "
-
arguments: il s'agit d'un objet ayant un champ pour chaque argument (par exemple, "url" dans l'exemple ci-dessus); cet objet à son tour a ces champs:
- type: soit « chaîne » ou « nombre »
- defaultValue: la valeur par défaut à pré-remplir.
Par exemple, voici le champ des blocs dans mon extension Fetch:
"blocs": [{ "opcode": "fetchURL", "blockType": "reporter", "text": "récupérer les données de ", "arguments": { "url": { "type": "string", "defaultValue ": "https://api.weather.gov/stations/KNYC/observations" }, } }, { "opcode": "jsonExtract", "blockType": "reporter", "text": "extract [nom] from [data]", "arguments": { "name": { "type": "string", "defaultValue": "temperature" }, "data": { "type": "string", "defaultValue": '{"température": 12.3}' }, } },]
Ici, nous avons défini deux blocs: fetchURL et jsonExtract. Tous deux sont reporters. Le premier extrait les données d'une URL et les renvoie, et le second extrait un champ des données JSON.
Enfin, vous devez inclure les méthodes pour deux blocs. Chaque méthode prend un objet comme argument, l'objet incluant des champs pour tous les arguments. Vous pouvez les décoder en utilisant des accolades dans les arguments. Par exemple, voici un exemple synchrone:
jsonExtract({nom, données}) {
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 == "booléen") renvoie t ? 1: 0 return JSON.stringify(out) } else { return "" } }
Le code extrait le champ de nom des données JSON. Si le champ contient une chaîne, un nombre ou un booléen, nous le renvoyons. Sinon, nous re-JSONifierons le champ. Et nous retournons une chaîne vide si le nom est manquant dans le JSON.
Parfois, cependant, vous souhaiterez peut-être créer un bloc qui utilise une API asynchrone. La méthode fetchURL() utilise l'API fetch qui est asynchrone. Dans un tel cas, vous devez retourner une promesse de votre méthode qui fait le travail. Par exemple:
fetchURL({url}) {
return fetch(url).then(response => response.text()) }
C'est ça. L'extension complète est ici.
Étape 4: Utilisation d'une extension en bac à sable
Il existe deux façons d'utiliser l'extension en bac à sable. Tout d'abord, vous pouvez le télécharger sur un serveur Web, puis le charger dans le mod Scratch de SheepTester. Deuxièmement, vous pouvez l'encoder dans une URL de données et la charger dans le mod Scratch. En fait, j'utilise beaucoup la deuxième méthode pour les tests, car elle évite les soucis concernant les anciennes versions de l'extension mises en cache par le serveur. Notez que même si vous pouvez héberger du javascript à partir des pages Github, vous ne pouvez pas le faire directement à partir d'un référentiel github ordinaire.
Mon fetch.js est hébergé sur https://arpruss.github.io/fetch.js. Ou vous pouvez convertir votre extension en URL de données en la téléchargeant ici, puis en la copiant dans le presse-papiers. Une URL de données est une URL géante qui contient un fichier entier.
Accédez au module Scratch de SheepTester. Cliquez sur le bouton Ajouter une extension dans le coin inférieur gauche. Cliquez ensuite sur "Choisir une extension", et entrez votre URL (vous pouvez coller l'intégralité de l'URL des données géantes si vous le souhaitez).
Si tout s'est bien passé, vous aurez une entrée pour votre extension sur le côté gauche de votre écran Scratch. Si les choses ne se sont pas bien passées, vous devez ouvrir votre console Javascript (shift-ctrl-J dans Chrome) et essayer de déboguer le problème.
Ci-dessus, vous trouverez un exemple de code qui récupère et analyse les données JSON de la station KNYC (à New York) du US National Weather Service, et les affiche, tout en tournant le sprite pour faire face à la même direction que le vent souffle. La façon dont je l'ai fait était de récupérer les données dans un navigateur Web, puis de déterminer les balises. Si vous souhaitez essayer une autre station météo, entrez un code postal à proximité dans le champ de recherche de weather.gov, et la page météo de votre emplacement devrait vous donner un code de station à quatre lettres, que vous pouvez utiliser à la place de KNYC dans le code.
Vous pouvez également inclure votre extension sandbox directement dans l'URL du mod de SheepTester en ajoutant un argument "?url=". Par exemple:
sheeptester.github.io/scratch-gui/?url=https://arpruss.github.io/fetch.js
Étape 5: Écriture d'une extension sans sandbox: Introduction
Le constructeur d'une extension non sandbox reçoit un objet Runtime. Vous pouvez l'ignorer ou l'utiliser. L'une des utilisations de l'objet Runtime consiste à utiliser sa propriété currentMSecs pour synchroniser les événements (« blocs de chapeau »). Pour autant que je sache, tous les opcodes des blocs d'événements sont interrogés régulièrement et chaque tour d'interrogation a une seule valeur currentMSecs. Si vous avez besoin de l'objet Runtime, vous démarrerez probablement votre extension avec:
classe EXTENSIONCLASS {
constructeur(runtime) { this.runtime = runtime … } … }
Toutes les choses d'objet fenêtre standard peuvent être utilisées dans l'extension unsandbox. Enfin, votre extension non sandbox devrait se terminer par ce bout de code magique:
(fonction() {
var extensionInstance = new EXTENSIONCLASS(window.vm.extensionManager.runtime) var serviceName = window.vm.extensionManager._registerInternalExtension(extensionInstance) window.vm.extensionManager._loadedExtensions.set(extensionInstance.getInfo().id, serviceName) })()
où vous devez remplacer EXTENSIONCLASS par la classe de votre extension.
Étape 6: Écriture d'une extension sans bac à sable: Manette de jeu simple
Créons maintenant une simple extension de manette de jeu qui fournit un seul bloc d'événement ("chapeau") lorsqu'un bouton est enfoncé ou relâché.
Au cours de chaque cycle d'interrogation de bloc d'événement, nous enregistrerons un horodatage de l'objet d'exécution et les états de la manette de jeu précédent et actuel. L'horodatage est utilisé pour reconnaître si nous avons un nouveau cycle d'interrogation. Alors, on commence par:
class ScratchSimpleGamepad {
constructeur(runtime) { this.runtime = runtime this.currentMSecs = -1 this.previousButtons = this.currentButtons = } … } Nous aurons un bloc d'événement, avec deux entrées - un numéro de bouton et un menu pour sélectionner si nous voulons que l'événement se déclenche à la pression ou au relâchement. Alors voici notre méthode
obtenirInfo() {
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" }, }, },], "menus": { "pressReleaseMenu": [{text:"press", value:1}, {text:"release", value:0}], } }; } Je pense que les valeurs du menu déroulant sont toujours transmises à la fonction opcode sous forme de chaînes, bien qu'elles soient déclarées sous forme de nombres. Comparez-les donc explicitement aux valeurs spécifiées dans le menu si nécessaire. Nous écrivons maintenant une méthode qui met à jour les états des boutons chaque fois qu'un nouveau cycle d'interrogation d'événement se produit
mettre à jour() {
if (this.runtime.currentMSecs == this.currentMSecs) return // pas un nouveau cycle d'interrogation 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) { // nombre différent de boutons, donc nouvelle manette this.previousButtons = pour (var i = 0; i < gamepad.buttons.length; i++) this.previousButtons.push(false) } else { this.previousButtons = this. currentButtons } this.currentButtons = pour (var i = 0; i < gamepad.buttons.length; i++) this.currentButtons.push(gamepad.buttons.pressed) } Enfin, nous pouvons implémenter notre bloc d'événements, en appelant la méthode update(), puis en vérifiant si le bouton requis vient d'être enfoncé ou relâché, en comparant les états du bouton actuel et précédent
boutonAppuyéLibéré({b, eventType}) {
this.update() if (b < this.currentButtons.length) { if (eventType == 1) { // note: ce sera une chaîne, donc mieux vaut la comparer à 1 que de la traiter comme un booléen if (this.currentButtons && ! this.previousButtons) { return true } } else { if (!this.currentButtons && this.previousButtons) { return true } } } return false } Et enfin, nous ajoutons notre code d'enregistrement d'extension magique après avoir défini la classe
(fonction() {
var extensionInstance = new ScratchSimpleGamepad(window.vm.extensionManager.runtime) var serviceName = window.vm.extensionManager._registerInternalExtension(extensionInstance) window.vm.extensionManager._loadedExtensions.set(extensionInstance.getInfo().id, serviceName) })()
Vous pouvez obtenir le code complet ici.
Étape 7: Utilisation d'une extension sans sandbox
Encore une fois, hébergez votre extension quelque part, et cette fois chargez-la avec l'argument load_plugin= plutôt que url= dans le mod Scratch de SheepTester. Par exemple, pour mon mod Gamepad simple, allez sur:
sheeptester.github.io/scratch-gui/?load_plugin=https://arpruss.github.io/simplegamepad.js
(Au fait, si vous voulez une manette de jeu plus sophistiquée, supprimez simplement "simple" de l'URL ci-dessus, et vous aurez la prise en charge du grondement et de l'axe analogique.)
Encore une fois, l'extension devrait apparaître sur le côté gauche de votre éditeur Scratch. Ci-dessus se trouve un programme Scratch très simple qui dit "bonjour" lorsque vous appuyez sur le bouton 0 et "au revoir" lorsque vous le relâchez.
Étape 8: Double compatibilité et vitesse
J'ai remarqué que les blocs d'extension s'exécutent un ordre de grandeur plus rapidement en utilisant la méthode de chargement que j'ai utilisée pour les extensions sans sandbox. Donc, à moins que vous ne vous souciez des avantages de sécurité de l'exécution dans un bac à sable Web Worker, votre code bénéficiera du chargement avec l'argument ?load_plugin=URL du mod de SheepTester.
Vous pouvez rendre une extension en bac à sable compatible avec les deux méthodes de chargement en utilisant le code suivant après avoir défini la classe d'extension (remplacez CLASSNAME par le nom de votre classe d'extension):
(fonction() {
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) } })()
Conseillé:
BBC Micro:bit and Scratch - Volant interactif et jeu de conduite : 5 étapes (avec photos)
BBC Micro:bit et Scratch - Volant interactif et jeu de conduite : L'un de mes devoirs de classe cette semaine est d'utiliser le BBC Micro:bit pour s'interfacer avec un programme Scratch que nous avons écrit. J'ai pensé que c'était l'occasion parfaite d'utiliser mon ThreadBoard pour créer un système embarqué ! Mon inspiration pour le scratch p
State Machine et multitâche sur Arduino avec les extensions SPI : 3 étapes
State Machine et multitâche sur Arduino avec SPI Expanders : La semaine dernière, je demandais de créer un système pour piloter des feux d'artifice avec un arduino. Il fallait environ 64 sorties pour contrôler les incendies. Une façon de le faire est d'utiliser des expanseurs IC. Donc 2 solutions s'offrent à vous :- un expandeur I2C mais il a besoin d'un onduleur quand vous po
Comment installer des extensions dans Google Chrome : 3 étapes
Comment installer des extensions dans Google Chrome : Les extensions sont un outil très pratique à utiliser dans Google Chrome. Ils peuvent varier des dictionnaires, des raccourcis de courrier électronique ou même des enregistreurs d'écran. Des extensions extrêmement simples et super pratiques peuvent améliorer votre expérience Chrome
Extensions de servos DIY : 4 étapes
DIY Servo Extensions : travaillez-vous sur un projet Arduino ou robotique utilisant des servomoteurs où les fils ne sont pas assez longs ? Ensuite, vous avez besoin d'extensions de servo. Vous pouvez acheter des extensions de servo dans de nombreux magasins de loisirs et en ligne. Ils sont conçus pour une marque particulière de servo
Enregistrer des extensions avec une application portable : 5 étapes
Enregistrez des extensions avec une application portable : Si vous êtes comme moi, vous emportez une clé USB avec vous avec vos programmes préférés. Certains programmes ont des profils (firefox) et certains sont tout simplement parfaits pour les urgences. Quelle que soit la raison pour laquelle vous pouvez trouver utile de lier le programme et