如果你想了解 WebAssembly ,又不想学习 C++ 或者 Rust ,刚好又对 Go 感兴趣,那你可以继续看下去。
目标: 使用 Go + WebAssembly 技术编写一个简单的小游戏,在固定画板上随机生成若干条横线,点击画板重新生成
环境: Go 1.11 及以上环境
代码演示
准备一个 html 和一个 js 文件
首先拿到 Go 为我们准备的 Go 和 JS 的“桥接器”
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
在 html 引入之后你便可以在全局访问到 Go 这个类
// ./index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Go + WebAssembly</title>
<script src="wasm_exec.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script>
// 加载 wasm
const go = new Go()
WebAssembly.instantiateStreaming(fetch('lib.wasm'), go.importObject).then(
(result) => {
go.run(result.instance)
}
)
</script>
</html>
编写我们的 Go 入口文件
// ./main.go
package main
func main() {
println("wasm app works")
}
编译成 .wasm 文件
GOARCH=wasm GOOS=js go build -o lib.wasm main.go
使用 http 访问我们的 index.html 文件,可以看到
编写我们的基础绘图逻辑
// ./main.go
package main
// 需要导入 syscall/js 包以调用 js API
import (
"math/rand"
"syscall/js"
"time"
)
const (
width = 400
height = 400
)
// 生成 0 - 1 的随机数
func getRandomNum() float32 {
rand.New(rand.NewSource(time.Now().UnixNano()))
n := float32(rand.Intn(10000))
return n / 10000.0
}
// 使用 canvas 绘制随机图
func draw() {
var canvas js.Value = js.
Global().
Get("document").
Call("getElementById", "canvas")
var context js.Value = canvas.Call("getContext", "2d")
// reset
canvas.Set("height", height)
canvas.Set("width", width)
context.Call("clearRect", 0, 0, width, height)
// 随机绘制 50 条直线
for i := 0; i < 50; i ++ {
context.Call("beginPath")
context.Call("moveTo", getRandomNum() * width, getRandomNum() * height)
context.Call("lineTo", getRandomNum() * width, getRandomNum() * height)
context.Call("stroke")
}
}
// 主程序入口
func main() {
println("wasm app works")
// bootstrap app
draw()
}
重新按照第二步流程编译一次,查看浏览器效果
绑定点击事件,实现点击重新随机画图
// ./main.go
package main
// 绘制随机图形
func draw() {
// ...
}
// 绑定点击事件
func addEventListener() {
// 回调中的操作将阻塞事件循环,需要明确地启动一个新的 goroutine
done := make(chan struct{})
var cb js.Callback = js.NewCallback(func(args []js.Value) {
go func() {
println("click")
draw()
}()
})
js.
Global().
Get("document").
Call("getElementById", "canvas").
Call("addEventListener", "click", cb)
<-done
}
// 启动应用
func bootstrapApp() {
draw()
addEventListener()
}
func main() {
println("wasm app works")
// bootstrap app
bootstrapApp()
}
重新编译,重新访问浏览器,Done!