惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
U
Unit 42
H
Help Net Security
博客园_首页
雷峰网
雷峰网
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园 - 【当耐特】
Recent Announcements
Recent Announcements
Recorded Future
Recorded Future
aimingoo的专栏
aimingoo的专栏
爱范儿
爱范儿
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Cloudflare Blog
S
Security @ Cisco Blogs
M
MIT News - Artificial intelligence
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
The GitHub Blog
The GitHub Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
K
Kaspersky official blog
MyScale Blog
MyScale Blog
阮一峰的网络日志
阮一峰的网络日志
C
CERT Recently Published Vulnerability Notes
V
Vulnerabilities – Threatpost
WordPress大学
WordPress大学
C
Cisco Blogs
G
Google Developers Blog
N
News and Events Feed by Topic
P
Palo Alto Networks Blog
Apple Machine Learning Research
Apple Machine Learning Research
Schneier on Security
Schneier on Security
博客园 - 聂微东
Security Latest
Security Latest
Security Archives - TechRepublic
Security Archives - TechRepublic
O
OpenAI News
云风的 BLOG
云风的 BLOG
IT之家
IT之家
PCI Perspectives
PCI Perspectives
Microsoft Security Blog
Microsoft Security Blog
NISL@THU
NISL@THU
小众软件
小众软件
Scott Helme
Scott Helme
大猫的无限游戏
大猫的无限游戏
L
LINUX DO - 最新话题
Microsoft Azure Blog
Microsoft Azure Blog
Simon Willison's Weblog
Simon Willison's Weblog
N
News and Events Feed by Topic
F
Fortinet All Blogs
The Last Watchdog
The Last Watchdog

夜行人

回家路上 第一期的直播演示项目 震动检测器 正能量 在线参观CodeLab Neverland 发布 CodeLab Adapter 3.3.1 DynamicTable 之 纸糊方向盘 CodeLab DynamicTable: 一个可实施的技术方案 CodeLab Insight 发布 Alpha 版 情人节 Home Assistant 周报 && IoT 周报 (02) Joplin: 关注隐私的 Evernote 开源替代软件 浏览器的未来与 Web 传感器 Home Assistant 周报 && IoT 周报 (01) 百宝箱(01) 论自由 介绍 WebThings Home Assistant 周报 && iot 周报 (00) 百宝箱(00) 毛姆读书心得 传世之作 周末徒步 CodeLab Adapter ❤️ Jupyter/Python 航班 躲雨 夏令营途中 [译]思想--作为一种技术 The future of coding 美国之行 三门问题的程序模拟 从Python转向Pharo https://blog.just4fun.site/post/iot/iot-open-source-projects/ Python异步编程笔记 https://blog.just4fun.site/post/iot/iot-open-source-hardware-community/ 万物积木化开发者社区 CodeLab ❤️ Blender Scratch3技术分析之云变量 API(第7篇) [译]对管道(Pipes)的偏爱 [译]提出正确的问题比得到正确答案更重要 蓝牙设备与Scratch3.0 创建你的第一个Scratch3.0 Extension Scratch3技术分析之项目内部数据(第6篇) Scratch3技术分析之社区 API(第5篇) Scratch3技术分析之User API(第4篇) Scratch3技术分析之项目主页API(第3篇) Scratch3技术分析之静态资源API(第2篇) Scratch3.0、micro:bit与Windows7 https://blog.just4fun.site/post/iot/zerynth-vs-micropython/ 核聚变、方所与半宅空间 可视化编程为何是个糟糕的主意 codelab.club周末聚会 关于codelab.club '下一件大事'是一个房间 Hungry Robot - Eat everything 编程作为一种思考方式 今日简史 史蒂夫·乔布斯传 罗素自选文集 https://blog.just4fun.site/post/edx/tianjin-scratch-ai/ https://blog.just4fun.site/post/edx/richie-cms-openedx/ 徒步武功山 WebUSB与micro:bit 积木化编程与3D场景 夜宿武功山顶 scratch3-adapter接入优必选Alpha系列机器人 https://blog.just4fun.site/post/edx/video-migration-note/ scratch3-adapter重构笔记 https://blog.just4fun.site/post/edx/edx-community-members/ 两种硬件编程风格的比较 使用micro:bit自制PPT翻页笔 柏拉图对话集 scratch3.0 + micro:bit 七月电影放映计划 非营利组织的管理 Screenly--用树莓派让任何屏幕变为可编程的数字标牌 以最佳实践开始你的Django项目 micro:bit与事件驱动 为Scratch3.0设计的插件系统(上篇) OCR应用一例 近两年读过的一些好书 blockly开发之使用python驱动浏览器中的turtle(2) 牛顿新传 文学理论入门 逻辑的引擎 人生的意义 blockly开发之生成并运行js代码(1) blockly开发之hello world(0) micro:bit使用笔记 神器之Termux https://blog.just4fun.site/post/iot/micropython-notes/ Cozmo what is this Scratch的前世今生 下段旅程 我行在远方 爆裂 途中杂记 https://blog.just4fun.site/post/edx/open-edx-startup/ cozmo系列之入门 - 有性格且可编程的机器人 PaperWeekly开发笔记 创业二三事
Godot 学习笔记
种瓜 · 2024-07-20 · via 夜行人

前言

It’s so cool that a loose community of “The People” have created things like Godot, OBS, and Blender. – seanw444(Hacker News)

之前做 游戏中的 AI Agent 的时候, 最初的选型过程, 调研过 Godot, 对它充满好感.

最近重新对 Godot 感兴趣, 是因为 John 在邮件里提到说, MicroBlocks 下一个版本的 IDE 将基于 Godot 构建.

为何要使用 Godot 构建 MicroBlocks IDE? 又要怎么做呢?

目前 John 还没有给出进一步的消息, 以下记录我的一些想法.

为何要使用 Godot 构建 MicroBlocks IDE?

目前, MicroBlocks 用户呼声最好的需求是支持移动端编程

MicroBlocks 当前的 IDE 基于 GP Blocks, 若要 MicroBlocks IDE 支持移动端, 需要在 GP Blocks 上进行许多工作, 可是 GP Blocks 已经不再维护.

因此, 更好的方向是使用一个成熟的 GUI 构建工具来重新制作 MicroBlocks IDE.

Godot 是一个非常强大的开源解决方案.

如何使用 Godot 构建 MicroBlocks IDE?

值得提醒的是, 并不是要使用 Godot 重新构建 MicroBlocks 而是使用 Godot 构建 MicroBlocks IDE

MicroBlocks 主要包含两大部分:

  • MicroBlocks VM
  • MicroBlocks IDE

MicroBlocks IDE 是 MicroBlocks VM 的图形化客户端, 它们之间通过消息进行通信(基于 MicroBlocks 协议). 要理解它们之间的关系可以参考 @邵悦 上周末的分享: MicroBlocks 能力图谱(视频)

使用 Godot 构建 MicroBlocks IDE 的含义是我们要制作一个图形化客户端, 它是一个 GUI 项目.

所以我们要做的事情是使用 Godot 制作一个 GUI 项目, 它能够支持移动端

Godot 非常擅长制作 GUI 项目:

兴趣点: GUI

Godot 主要是一个游戏引擎, 能做的事情非常多, 生态巨大, 文档极多. 这带来的一个问题是, 很难"学会"它.

好在, 我们并不需要"学会"它. 记住我们要做的事情是:

使用 Godot 制作一个 GUI 项目, 它能够支持移动端

我们并不需要学习如何使用 Godot 制作 2D 或 3D 游戏(这需要很多时间), 只需学习如何使用它制作 GUI 即可!

弄清楚目标, 需要学习的内容就变得很少且聚焦了, 我们只需要学习如何使用 Control 节点

以下是我喜欢的一些教学资源, 对于 Godot 这样**丰富(rich)**的计算环境, 强烈推荐通过观看视频来学习(尤其是入门阶段), 操作中的许多知识是隐性的, 很难通过文字描述学会:

关键概念

Godot 非常适合快速制作原型。一旦你理解了核心概念,编辑器就非常快速且直观 – Hacker New 用户

Godot 关键概念概述

任何游戏引擎都是围绕着构建程序所用的抽象的。在 Godot 中,游戏就是一棵由节点构成的,树又可以结合起来构成场景。然后你还可以将这些节点连起来,让它们通过信号进行通信。

GDScript

GDScript 与 Python 高度相似.

有 Python 经验的用户快速过一下 GDScript 参考 即可.

如果你想从头开始学习, Learn to Code From Zero with Godot 或许是不错的选择

值得注的是, 使用 GDScript 编程通常具有事件驱动风格(UI/游戏领域通常采用的编程风格), 你经常使用 callback, 有 JavaScript 经验的用户可能对此熟悉.

REPL/Playground

学习一门新语言时, 我喜欢使用 REPL 进行支持交互式的实验和探索, 对于新手非常有帮助

Godot 没有提供 GDScript REPL. 有社区用户提供了类似的东西 GDScript Playground

开发

导出 Web 项目

MicroBlocks 用户最喜欢使用 Web 版本的 MicroBlocks IDE, 因其支持无线编程(BLE).

如果我们使用 Godot 制作 MicroBlocks IDE, 会将其导出为 Web 项目 并部署到线上.

在 Web 中环境测试

如果你使用的本机版本的 Godot, 点击远程调试按钮, 即可在浏览器上运行:

此外, 你可以将项目导出, 然后导入到Godot Web 开发环境里, 这样就可以实时调试它. Godot 的 Web 开发环境甚至支持数据持久化, 关闭浏览器再次打开, 之前所做的工作都还在.

与 JavaScript 互操作

我们可以在 Godot 中与 JavaScript 互操作

从 Godot 调用 JavaScript

以下是一个简单例子:

1
2
3
4
5
6
7
func _on_button_pressed():
    if OS.has_feature('web'):
        JavaScriptBridge.eval('''
            console.log('The JavaScriptBridge singleton is available')
        ''')
    else:
        print("The JavaScriptBridge singleton is NOT available")

扫描蓝牙设备:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func _on_button_pressed():
    # var console = JavaScriptBridge.get_interface("console")
    # var window = JavaScriptBridge.get_interface("window")
    if OS.has_feature('web'):
        var code = '''
        console.log("test");
        navigator.bluetooth.requestDevice({
            acceptAllDevices: true,
            optionalServices: []
        });
        '''
        JavaScriptBridge.eval(code)
    else:
        print("The JavaScriptBridge singleton is NOT available")

使用 Godot 制作 MicroBlocks 客户端

相关代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
extends Control


# Called when the node enters the scene tree for the first time.
func _ready():
    print("ready")
    if OS.has_feature('web'):
        var code = '''
class MicroBlocksClient {
    constructor(height, width) {
        this.MICROBLOCKS_SERVICE_UUID = "bb37a001-b922-4018-8e74-e14824b3a638"
        this.MICROBLOCKS_RX_CHAR_UUID = "bb37a002-b922-4018-8e74-e14824b3a638" // board receive characteristic
        this.MICROBLOCKS_TX_CHAR_UUID = "bb37a003-b922-4018-8e74-e14824b3a638" // board transmit characteristic
        this.bleDevice = null;
    }

    connect() {
        navigator.bluetooth.requestDevice({
            filters: [
                { services: [this.MICROBLOCKS_SERVICE_UUID] }
            ]
        }).then((device) => { this.bleDevice = device; return device.gatt.connect(); })
    }

    send(aString) {
        // console.log(aString);
        const data = new TextEncoder().encode(aString);
        let length = data.length + 1;
        let bytes = new Uint8Array([...(new Uint8Array([251, 27, 0, length % 256, parseInt((length / 256))])), ...data, ...(new Uint8Array([254]))])
        if (this.bleDevice) {
            this.bleDevice.gatt
                .getPrimaryService(this.MICROBLOCKS_SERVICE_UUID)
                .then((service) => service.getCharacteristic(this.MICROBLOCKS_RX_CHAR_UUID))
                .then((characteristic) => characteristic.writeValue(bytes))
                .catch((error) => {
                    console.log("error:" + error);
                });
        }
    }
}

window.MicroBlocksClient = MicroBlocksClient;
        '''

        JavaScriptBridge.eval(code)



# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
    pass


func _on_send_pressed():
    if OS.has_feature('web'):
        var aString = $LineEdit.text;
        var code = 'window.microblocks_client.send("%s")' % aString
        print(code)
        JavaScriptBridge.eval(code)

func _on_connect_pressed():
    if OS.has_feature('web'):
        var code = '''
window.microblocks_client = new window.MicroBlocksClient();
window.microblocks_client.connect();
        '''
        JavaScriptBridge.eval(code)
    else:
        print("The JavaScriptBridge is NOT available")

从这个例子很开始, 很容易使用 Godot 为 MicroBlocks 设备设计手机控制界面.

从 JavaScript 调用 Godot

使用 Callbacks, 可以从 JavaScript 调用 Godot.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
extends Node

# Here we create a reference to the `_my_callback` function (below).
# This reference will be kept until the node is freed.
var _callback_ref = JavaScriptBridge.create_callback(_my_callback)

func _ready():
    # Get the JavaScript `window` object.
    var window = JavaScriptBridge.get_interface("window")
    # Set the `window.onbeforeunload` DOM event listener.
    window.sendToGodot = _callback_ref

func _my_callback(arg):
    print(arg)

以上代码将为导出的 web 项目注册 window.sendToGodot 函数, 你可以在浏览器环境调用它.

Dynatalk

即然我们可以在 JavaScript 和 Godot 环境中进行双向通信, 我们便可以构建出 Dynatalk, 进而实现 Snap! 中的 Spline 库 的所有功能: 使用 Snap! 驱动任何 Godot 制作的游戏!

由于我们之前已经把 Python 解释器带入了 Snap! , 所以我们也可以让 Python 驱动任何 Godot 制作的游戏!

这带来许多有趣的可能性, 诸如我们通过 Snap! 把 GPT-4o 或者 mediapipe 的 AI 能力带到游戏里, 或者通过 Python 把 OpenCV 带入游戏里

传递 json

如果你想在 GDScript 和 JavaScript 中传递复杂的数据结构, 可以考虑传递 json 字符串(list 也有有效的 json 数据)

GDScript 有JSON 模块.

FAQ

Web 导出能否运行在移动设备上?

Web Export in 4.3 里提到

Apple 设备(macOS 和 iOS)在播放 Godot Web 导出时会出现问题。好吧,当你以单线程方式导出游戏时,这些问题幸运地消失了。

使用 4.3(目前是 beta 版) 导出的 web 项目能够运行在 iOS 设备上. 而 4.2 不行.

为了在设计上测试, 我在本地运行了服务器:

1
npx local-web-server --https --cors.embedder-policy "require-corp" --cors.opener-policy "same-origin" --directory "."

并使用 ngrok 将其暴露到公网:

1
ngrok http https://127.0.0.1:8000

在 Bluefy 浏览器中打开:

扫描 BLE 设备:

横屏显示:

支持虚拟键盘输入, 目前还是实验性的功能, 光标的位置有些问题, 但基本可用:

PWA

4.3 的 PWA 功能也能够正常工作:

如何将外部 JavaScript 库引入 Godot web 项目

将外部 JavaScript 库(如test.js)放入导出的 web 项目目录

在 GDScript 中引入 JavaScript 库

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func _ready():
    print("ready")
    if OS.has_feature('web'):
        var code = '''
        let url = "test.js";
        let scriptElement = document.createElement("script");
        document.head.appendChild(scriptElement);
        scriptElement.src = url;
        // scriptElement.crossorigin="anonymous";
        '''
        JavaScriptBridge.eval(code)

测试:

在 web 项目目录启动服务器:

1
npx local-web-server --https --cors.embedder-policy "require-corp" --cors.opener-policy "same-origin" --directory "."

参考