สารบัญ:

ส่วนขยาย Scratch 3.0: 8 ขั้นตอน
ส่วนขยาย Scratch 3.0: 8 ขั้นตอน

วีดีโอ: ส่วนขยาย Scratch 3.0: 8 ขั้นตอน

วีดีโอ: ส่วนขยาย Scratch 3.0: 8 ขั้นตอน
วีดีโอ: สอนโปรแกรม Scratch ตอนที่ 2 : ส่วนประกอบของโปรแกรม Scratch 3.0 2024, กรกฎาคม
Anonim
ส่วนขยาย Scratch 3.0
ส่วนขยาย Scratch 3.0

ส่วนขยาย Scratch เป็นโค้ด Javascript ที่เพิ่มบล็อกใหม่ให้กับ Scratch แม้ว่า Scratch จะมาพร้อมกับส่วนขยายอย่างเป็นทางการจำนวนมาก แต่ก็ไม่มีกลไกอย่างเป็นทางการในการเพิ่มส่วนขยายที่ผู้ใช้สร้างขึ้น

เมื่อฉันสร้างส่วนขยายการควบคุม Minecraft สำหรับ Scratch 3.0 ฉันพบว่ามันยากที่จะเริ่มต้น คำแนะนำนี้รวบรวมข้อมูลจากแหล่งต่าง ๆ (โดยเฉพาะสิ่งนี้) รวมถึงบางสิ่งที่ฉันค้นพบตัวเอง

คุณจำเป็นต้องรู้วิธีเขียนโปรแกรมใน Javascript และวิธีโฮสต์ Javascript ของคุณบนเว็บไซต์ อย่างหลัง ฉันขอแนะนำ GitHub Pages

เคล็ดลับหลักคือการใช้ตัวดัดแปลง Scratch ของ SheepTester ซึ่งช่วยให้คุณโหลดส่วนขยายและปลั๊กอินได้

คำแนะนำนี้จะแนะนำคุณเกี่ยวกับการสร้างส่วนขยายสองแบบ:

  • ดึงข้อมูล: โหลดข้อมูลจาก URL และแยกแท็ก JSON เช่น สำหรับการโหลดข้อมูลสภาพอากาศ
  • SimpleGamepad: การใช้ตัวควบคุมเกมใน Scratch (เวอร์ชันที่ซับซ้อนกว่าอยู่ที่นี่)

ขั้นตอนที่ 1: ส่วนขยายสองประเภท

ส่วนขยายมีสองประเภทที่ฉันจะเรียกว่า "ไม่แซนด์บ็อกซ์" และ "แซนด์บ็อกซ์" ส่วนขยายแซนด์บ็อกซ์ทำงานเป็น Web Workers และด้วยเหตุนี้จึงมีข้อจำกัดที่สำคัญ:

  • Web Workers ไม่สามารถเข้าถึง globals ในวัตถุหน้าต่างได้ (แต่พวกเขามีวัตถุ global self ซึ่งมีข้อ จำกัด มากกว่า) ดังนั้นคุณจึงไม่สามารถใช้งานได้สำหรับสิ่งต่าง ๆ เช่นการเข้าถึง gamepad
  • ส่วนขยายแซนด์บ็อกซ์ไม่มีสิทธิ์เข้าถึงวัตถุรันไทม์ Scratch
  • ส่วนขยายแซนด์บ็อกซ์นั้นช้ากว่ามาก
  • ข้อความแสดงข้อผิดพลาดของคอนโซล Javascript สำหรับส่วนขยายแบบแซนด์บ็อกซ์นั้นมีความคลุมเครือมากกว่าใน Chrome

ในทางกลับกัน:

  • การใช้ส่วนขยายแซนด์บ็อกซ์ของผู้อื่นนั้นปลอดภัยกว่า
  • ส่วนขยายแซนด์บ็อกซ์มีแนวโน้มที่จะทำงานร่วมกับการสนับสนุนการโหลดส่วนขยายอย่างเป็นทางการในที่สุด
  • ส่วนขยายแซนด์บ็อกซ์สามารถทดสอบได้โดยไม่ต้องอัปโหลดไปยังเว็บเซิร์ฟเวอร์โดยการเข้ารหัสลงใน data:// URL

ส่วนขยายที่เป็นทางการ (เช่น เพลง ปากกา ฯลฯ) ทั้งหมดไม่มีแซนด์บ็อกซ์ ตัวสร้างสำหรับส่วนขยายรับวัตถุรันไทม์จาก Scratch และสามารถเข้าถึงหน้าต่างได้อย่างเต็มที่

ส่วนขยายการดึงข้อมูลอยู่ในแซนด์บ็อกซ์ แต่เกมแพดต้องการวัตถุเนวิเกเตอร์จากหน้าต่าง

ขั้นตอนที่ 2: การเขียนส่วนขยายแซนด์บ็อกซ์: ตอนที่ I

ในการสร้างส่วนขยาย คุณต้องสร้างคลาสที่เข้ารหัสข้อมูลเกี่ยวกับส่วนขยาย จากนั้นเพิ่มโค้ดเล็กน้อยเพื่อลงทะเบียนส่วนขยาย

สิ่งสำคัญในคลาสส่วนขยายคือเมธอด getInfo() ซึ่งส่งคืนอ็อบเจ็กต์ที่มีฟิลด์ที่จำเป็น:

  • id: ชื่อภายในของนามสกุล ต้องไม่ซ้ำกันสำหรับแต่ละนามสกุล
  • ชื่อ: ชื่อที่เป็นมิตรของส่วนขยายที่แสดงในรายการบล็อกของ Scratch
  • บล็อก: รายการของวัตถุที่อธิบายบล็อกที่กำหนดเองใหม่

และมีช่องเมนูเสริมซึ่งไม่ได้ใช้ในการดึงข้อมูล แต่จะใช้ใน Gamepad

นี่คือเทมเพลตพื้นฐานสำหรับการดึงข้อมูล:

คลาส ScratchFetch {

ตัวสร้าง () { } getInfo () { กลับ { "id": "ดึงข้อมูล", "ชื่อ": "ดึงข้อมูล", "บล็อก": [/* เพิ่มภายหลัง */] } } /* เพิ่มวิธีการสำหรับบล็อก */ } Scratch.extensions.register(ใหม่ ScratchFetch())

ขั้นตอนที่ 3: การเขียนส่วนขยายแซนด์บ็อกซ์: ตอนที่ II

ตอนนี้ เราต้องสร้างรายการบล็อกในวัตถุของ getInfo() แต่ละบล็อกต้องการอย่างน้อยสี่ฟิลด์เหล่านี้:

  • opcode: นี่คือชื่อของเมธอดที่เรียกใช้เพื่อทำงานของบล็อก
  • blockType: นี่คือประเภทบล็อก ส่วนขยายที่พบบ่อยที่สุดคือ:

    • "command": ทำบางสิ่งแต่ไม่คืนค่ากลับมา
    • "reporter": ส่งกลับสตริงหรือตัวเลข
    • "บูลีน": ส่งกลับบูลีน (สังเกตอักษรตัวพิมพ์ใหญ่)
    • "หมวก": บล็อกจับเหตุการณ์; หากรหัส Scratch ของคุณใช้บล็อกนี้ Scratch runtime จะสำรวจวิธีการที่เกี่ยวข้องซึ่งส่งคืนบูลีนเพื่อบอกว่าเหตุการณ์นั้นเกิดขึ้นหรือไม่
  • ข้อความ: นี่คือคำอธิบายที่เป็นมิตรของบล็อก โดยมีอาร์กิวเมนต์อยู่ในวงเล็บ เช่น "ดึงข้อมูลจาก "
  • อาร์กิวเมนต์: นี่คือวัตถุที่มีฟิลด์สำหรับทุกอาร์กิวเมนต์ (เช่น "url" ในตัวอย่างด้านบน); ออบเจ็กต์นี้มีฟิลด์เหล่านี้:

    • ประเภท: "สตริง" หรือ "หมายเลข"
    • defaultValue: ค่าเริ่มต้นที่จะเติมล่วงหน้า

ตัวอย่างเช่น นี่คือฟิลด์บล็อกในส่วนขยายการดึงข้อมูลของฉัน:

"บล็อก": [{ "opcode": "fetchURL", "blockType": "reporter", "text": "ดึงข้อมูลจาก ", "arguments": { "url": { "type": "string", "defaultValue ": "https://api.weather.gov/stations/KNYC/observations" }, } }, { "opcode": "jsonExtract", "blockType": "reporter", "text": "extract [ชื่อ] จาก [data]", "arguments": { "name": { "type": "string", "defaultValue": "temperature" }, "data": { "type": "string", "defaultValue": '{"อุณหภูมิ": 12.3}' }, } },]

ที่นี่ เรากำหนดสองช่วงตึก: fetchURL และ jsonExtract ทั้งคู่เป็นนักข่าว อันแรกดึงข้อมูลจาก URL แล้วส่งคืน และอันที่สองแยกฟิลด์จากข้อมูล JSON

สุดท้าย คุณต้องรวมวิธีการสำหรับสองช่วงตึก แต่ละเมธอดรับอ็อบเจ็กต์เป็นอาร์กิวเมนต์ โดยมีอ็อบเจ็กต์รวมถึงฟิลด์สำหรับอาร์กิวเมนต์ทั้งหมด คุณสามารถถอดรหัสสิ่งเหล่านี้โดยใช้วงเล็บปีกกาในอาร์กิวเมนต์ ตัวอย่างเช่น นี่คือตัวอย่างแบบซิงโครนัสหนึ่งตัวอย่าง:

jsonExtract ({ชื่อ, ข้อมูล}) {

var parsed = JSON.parse(data) if (name in parsed) { var out = parsed[name] var t = typeof(out) if (t == "string" || t == "number") ส่งคืนหาก (t == "บูลีน") ส่งกลับ t ? 1: 0 ส่งคืน JSON.stringify (ออก) } อื่น ๆ { return "" } }

รหัสดึงฟิลด์ชื่อจากข้อมูล JSON หากฟิลด์มีสตริง ตัวเลข หรือบูลีน เราจะคืนค่านั้น มิฉะนั้น เราจะ JSONify ฟิลด์อีกครั้ง และเราส่งคืนสตริงว่างหากชื่อหายไปจาก JSON

อย่างไรก็ตาม บางครั้งคุณอาจต้องการสร้างบล็อกที่ใช้ API แบบอะซิงโครนัส เมธอด fetchURL() ใช้การดึงข้อมูล API ซึ่งเป็นแบบอะซิงโครนัส ในกรณีเช่นนี้ คุณควรคืนคำสัญญาจากวิธีการของคุณที่ได้ผล ตัวอย่างเช่น:

fetchURL ({url}) {

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

แค่นั้นแหละ. ส่วนขยายแบบเต็มอยู่ที่นี่

ขั้นตอนที่ 4: การใช้ส่วนขยายแซนด์บ็อกซ์

การใช้ส่วนขยายแซนด์บ็อกซ์
การใช้ส่วนขยายแซนด์บ็อกซ์
การใช้ส่วนขยายแซนด์บ็อกซ์
การใช้ส่วนขยายแซนด์บ็อกซ์
การใช้ส่วนขยายแซนด์บ็อกซ์
การใช้ส่วนขยายแซนด์บ็อกซ์

มีสองวิธีในการใช้ส่วนขยายแบบแซนด์บ็อกซ์ ขั้นแรก คุณสามารถอัปโหลดไปยังเว็บเซิร์ฟเวอร์ แล้วโหลดลงในม็อด Scratch ของ SheepTester ประการที่สอง คุณสามารถเข้ารหัสลงใน URL ข้อมูล และโหลดลงใน Scratch mod ที่จริงฉันใช้วิธีที่สองค่อนข้างน้อยในการทดสอบ เนื่องจากหลีกเลี่ยงความกังวลว่าส่วนขยายรุ่นเก่ากว่าจะถูกแคชโดยเซิร์ฟเวอร์ โปรดทราบว่าในขณะที่คุณสามารถโฮสต์จาวาสคริปต์จาก Github Pages ได้ คุณไม่สามารถดำเนินการดังกล่าวได้โดยตรงจากที่เก็บ github ทั่วไป

fetch.js ของฉันโฮสต์อยู่ที่ https://arpruss.github.io/fetch.js หรือคุณสามารถแปลงส่วนขยายของคุณเป็น URL ข้อมูลโดยอัปโหลดที่นี่ แล้วคัดลอกไปยังคลิปบอร์ด URL ข้อมูลคือ URL ขนาดใหญ่ที่มีไฟล์ทั้งหมดอยู่ในนั้น

ไปที่ม็อด Scratch ของ SheepTester คลิกที่ปุ่มเพิ่มส่วนขยายที่มุมล่างซ้าย จากนั้นคลิกที่ "เลือกส่วนขยาย" และป้อน URL ของคุณ (คุณสามารถวาง URL ข้อมูลขนาดยักษ์ทั้งหมดได้หากต้องการ)

หากทุกอย่างเป็นไปด้วยดี คุณจะมีรายการส่วนขยายทางด้านซ้ายของหน้าจอ Scratch หากทุกอย่างเป็นไปด้วยดี คุณควรเปิดคอนโซล Javascript (shift-ctrl-J ใน Chrome) แล้วลองแก้ปัญหา

ด้านบนคุณจะพบโค้ดตัวอย่างที่ดึงและแยกวิเคราะห์ข้อมูล JSON จากสถานี KNYC (ในนิวยอร์ก) ของ US National Weather Service และแสดงข้อมูลดังกล่าว ขณะที่หมุนสไปรต์ให้หันไปทางเดียวกับที่ลมพัด วิธีที่ฉันสร้างคือดึงข้อมูลลงในเว็บเบราว์เซอร์แล้วค้นหาแท็ก หากคุณต้องการลองใช้สถานีตรวจอากาศอื่น ให้ป้อนรหัสไปรษณีย์ใกล้เคียงลงในช่องค้นหาที่ weather.gov และหน้าสภาพอากาศสำหรับตำแหน่งของคุณควรมีรหัสสถานีสี่ตัวอักษร ซึ่งคุณสามารถใช้แทน KNYC ใน รหัส.

คุณยังสามารถรวมส่วนขยายแซนด์บ็อกซ์ของคุณไว้ใน URL สำหรับม็อดของ SheepTester โดยเพิ่มอาร์กิวเมนต์ "?url=" ตัวอย่างเช่น:

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

ขั้นตอนที่ 5: การเขียนส่วนขยายที่ไม่ได้แซนด์บ็อกซ์: บทนำ

คอนสตรัคเตอร์ของส่วนขยายที่ไม่ได้แซนด์บ็อกซ์ส่งผ่านอ็อบเจ็กต์รันไทม์ คุณสามารถเพิกเฉยหรือใช้งานได้ การใช้อ็อบเจ็กต์ Runtime อย่างหนึ่งคือการใช้คุณสมบัติ currentMSecs เพื่อซิงโครไนซ์เหตุการณ์ ("hat blocks") เท่าที่ฉันสามารถบอกได้ opcodes บล็อกเหตุการณ์ทั้งหมดจะถูกสำรวจอย่างสม่ำเสมอ และแต่ละรอบของการหยั่งเสียงมีค่า currentMSecs เดียว หากคุณต้องการวัตถุรันไทม์ คุณอาจเริ่มส่วนขยายด้วย:

คลาส EXTENSIONCLASS {

ตัวสร้าง (รันไทม์) { this.runtime = รันไทม์ … } … }

วัตถุหน้าต่างมาตรฐานทั้งหมดสามารถใช้ในส่วนขยายที่ไม่อยู่ในแซนด์บ็อกซ์ สุดท้าย ส่วนขยายที่ไม่ได้แซนด์บ็อกซ์ของคุณควรลงท้ายด้วยโค้ดวิเศษนี้:

(การทำงาน() {

var extensionInstance = EXTENSIONCLASS ใหม่ (window.vm.extensionManager.runtime) var serviceName = window.vm.extensionManager._registerInternalExtension(extensionInstance) window.vm.extensionManager._loadedExtensions.set(extensionInstance.getInfo().id, serviceName) })()

โดยที่คุณควรแทนที่ EXTENSIONCLASS ด้วยคลาสของส่วนขยายของคุณ

ขั้นตอนที่ 6: การเขียนส่วนขยาย Unsandboxed: Simple Gamepad

ตอนนี้เรามาสร้างส่วนขยายแป้นเกมอย่างง่ายที่มีบล็อกเหตุการณ์เดียว ("หมวก") เมื่อมีการกดหรือปล่อยปุ่ม

ในแต่ละรอบการโพลบล็อคเหตุการณ์ เราจะบันทึกการประทับเวลาจากอ็อบเจ็กต์รันไทม์ และสถานะ gamepad ก่อนหน้าและปัจจุบัน การประทับเวลาใช้เพื่อรับรู้ว่าเรามีรอบการเลือกตั้งใหม่หรือไม่ ดังนั้นเราจึงเริ่มต้นด้วย:

คลาส ScratchSimpleGamepad {

ตัวสร้าง (รันไทม์) { this.runtime = รันไทม์ this.currentMSecs = -1 this.previousButtons = this.currentButtons = } … } เราจะมีบล็อกเหตุการณ์หนึ่งบล็อก โดยมีอินพุตสองช่อง ได้แก่ หมายเลขปุ่มและเมนูเพื่อเลือกว่าเราต้องการให้เหตุการณ์ทริกเกอร์เมื่อมีการกดหรือปล่อย นี่คือวิธีการของเรา

รับข้อมูล() {

ส่งคืน { "id": "SimpleGamepad", "name": "SimpleGamepad", "blocks": [{ "opcode": "buttonPressedReleased", "blockType": "hat", "text": "button [eventType]", "อาร์กิวเมนต์": { "b": { "type": "number", "defaultValue": "0" }, "eventType": { "type": "number", "defaultValue": "1 ", "menu": "pressReleaseMenu" }, }, },], "menus": { "pressReleaseMenu": [{text:"press", value:1}, {text:"release", value:0}], } }; } ฉันคิดว่าค่าในเมนูแบบเลื่อนลงยังคงถูกส่งผ่านไปยังฟังก์ชัน opcode เป็นสตริง แม้ว่าจะประกาศเป็นตัวเลขก็ตาม ดังนั้นเปรียบเทียบให้ชัดเจนกับค่าที่ระบุในเมนูตามต้องการ ตอนนี้เราเขียนวิธีการที่อัปเดตสถานะปุ่มทุกครั้งที่มีรอบการโพลเหตุการณ์ใหม่เกิดขึ้น

อัปเดต() {

if (this.runtime.currentMSecs == this.currentMSecs) ส่งคืน // ไม่ใช่รอบการเลือกตั้งใหม่ 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] ถ้า (gamepad.buttons.length != this.previousButtons.length) { // จำนวนปุ่มที่แตกต่างกัน ดังนั้น gamepad ใหม่ this.previousButtons = สำหรับ (var i = 0; i < gamepad.buttons.length; i++) this.previousButtons.push(false) } else { this.previousButtons = นี่ currentButtons } this.currentButtons = สำหรับ (var i = 0; i < gamepad.buttons.length; i++) this.currentButtons.push(gamepad.buttons.pressed) } สุดท้าย เราสามารถใช้บล็อกเหตุการณ์ของเราได้ โดยเรียกใช้เมธอด update() แล้วตรวจสอบว่าเพิ่งกดหรือปล่อยปุ่มที่จำเป็น โดยเปรียบเทียบสถานะปุ่มปัจจุบันและก่อนหน้า

buttonPressedReleased ({b, eventType}) {

this.update() if (b < this.currentButtons.length) { if (eventType == 1) { // หมายเหตุ: นี่จะเป็นสตริง ดังนั้นควรเปรียบเทียบกับ 1 ดีกว่าถือว่าเป็นบูลีน if (this.currentButtons && ! this.previousButtons) { return true } } else { if (!this.currentButtons && this.previousButtons) { return true } } } คืนค่าเท็จ } และสุดท้ายเราก็เพิ่มรหัสลงทะเบียนส่วนขยายเวทย์มนตร์หลังจากกำหนดคลาส

(การทำงาน() {

var extensionInstance = ใหม่ ScratchSimpleGamepad(window.vm.extensionManager.runtime) var serviceName = window.vm.extensionManager._registerInternalExtension(extensionInstance) window.vm.extensionManager._loadedExtensions.set(extensionInstance.getInfo()id, serviceName) })

คุณสามารถรับรหัสเต็มได้ที่นี่

ขั้นตอนที่ 7: การใช้ส่วนขยายที่ไม่ได้แซนด์บ็อกซ์

การใช้ส่วนขยายที่ไม่ได้แซนด์บ็อกซ์
การใช้ส่วนขยายที่ไม่ได้แซนด์บ็อกซ์

อีกครั้ง ให้โฮสต์ส่วนขยายของคุณไว้ที่ใดที่หนึ่ง และคราวนี้โหลดด้วยอาร์กิวเมนต์ load_plugin= แทน url= ไปยังตัวดัดแปลง Scratch ของ SheepTester ตัวอย่างเช่น สำหรับม็อด Gamepad แบบง่ายของฉัน ให้ไปที่:

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

(อย่างไรก็ตาม หากคุณต้องการ gamepad ที่มีความซับซ้อนมากขึ้น เพียงแค่ลบ "simple" ออกจาก URL ด้านบน แล้วคุณจะได้รับการสนับสนุน rumble และ analog axis)

อีกครั้ง ส่วนขยายควรปรากฏที่ด้านซ้ายของโปรแกรมแก้ไข Scratch ด้านบนเป็นโปรแกรม Scratch ที่เขียนว่า "สวัสดี" เมื่อคุณกดปุ่ม 0 และ "ลาก่อน" เมื่อคุณปล่อย

ขั้นตอนที่ 8: ความเข้ากันได้แบบคู่และความเร็ว

ฉันสังเกตเห็นว่าส่วนขยายบล็อกทำงานเร็วขึ้นโดยใช้วิธีการโหลดที่ฉันใช้สำหรับส่วนขยายที่ไม่ได้แซนด์บ็อกซ์ ดังนั้น เว้นแต่ว่าคุณสนใจเกี่ยวกับประโยชน์ด้านความปลอดภัยของการทำงานในแซนด์บ็อกซ์ Web Worker โค้ดของคุณจะได้รับประโยชน์จากการโหลดอาร์กิวเมนต์ ?load_plugin=URL สำหรับม็อดของ SheepTester

คุณสามารถสร้างส่วนขยายแซนด์บ็อกซ์ที่เข้ากันได้กับวิธีการโหลดทั้งสองวิธีโดยใช้รหัสต่อไปนี้หลังจากกำหนดคลาสส่วนขยาย (เปลี่ยน CLASSNAME เป็นชื่อของคลาสส่วนขยายของคุณ):

(การทำงาน() {

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) } })() วาร์ serviceName = window.vm.extensionManager._registerInternalExtension(extensionInstance) window.vm.extensionManager._loadedExtensions.set

แนะนำ: