当前位置 博文首页 > 为少:探索使用 Golang 和 Webassembly 构建一个多人游戏服务器

    为少:探索使用 Golang 和 Webassembly 构建一个多人游戏服务器

    作者:为少 时间:2021-05-04 18:17

    什么是 WebAssembly?由 GoogleMicrosoftMozillaApple 等发起的 WebAssembly 是一种新的字节码格式,主流浏览器都已经支持 WebAssembly。 和 JS 需要解释执行不同,WebAssembly 字节码和底层机器码很相似可快速装载运行,因此性能相对于 JS 解释执行大大提升。WebAssembly 并不是一门编程语言,而是一份字节码标准,需要用高级编程语言编译出字节码放到 WebAssembly 虚拟机中才能运行。

    Panzr.io 简介

    • 基于开源技术的游戏
    • 使用 Web 作为发行平台
    • 轻巧快速
    • 探索基本的多人游戏技术
    • 扩展 Go 技术知识

    Panzr.io 架构

    Panzr.io 部署架构

    Triebwerk 简介

    项目源码:

    • https://github.com/awdng/triebwerk

    项目 Status:

    • Triebwerk 是一个开源的多人游戏服务器
    • 使用 Go 语言编写
    • 目前仅是基础原型

    游戏是如何运行的?

    服务器权威架构

    • 仅通过服务器进行通讯
    • 客户端将所有输入发送到服务器
    • 服务器有权进行模拟
    • 防止作弊并引入延迟

    客户端预测和服务器协调

    • 最早由 QuakeWorld 推广
    • 本地模拟运动
    • 不断与服务器状态同步
    • 根据服务器状态更正本地状态

    客户端插值

    • 网络更新(Updates) < 每秒帧数(Frames)
    • 过去状态之间的插值
    • 保守算法
    • 没有推断

    定义边界

    限制:

    • 所有游戏逻辑仅在 2D 空间中
    • 均匀表面
    • 仅通过键盘进行输入控制
    • 限制地图尺寸
    • 缓慢移动的车辆
    • 没有物理引擎

    服务器实现

    玩家移动

    碰撞检测

    二进制数据传输

    • 最小化资源使用
    • 防止数据包分段
    • 最小化丢包的影响

    WebAssembly 模块

    游戏逻辑(Game logic)Server -> Client

    • 文件大小 > 2MB
    • 服务器和客户端根据相同的逻辑计算状态
    • 通过二进制类型进行数据传输

    编译:

    GOOS=js GOARCH=wasm go build -o tanks.wasm cmd/wasm/tanks.go
    

    Client:

    <script src="/game/wass_exec.js"></script>
    <script>
    const go = new Go();
    WebAssembly.instantiateStreaming(featch("/game/tanks.wass"), go.importObject).then(result => {
        go.run(result.instance);
    });
    </script>
    

    Server:

    js.Global().Set("updateNetworkPlayer", js.FuncOf(updateNetworkPlayer))
    

    在 Go 中编码 state

    posX := float32(30.457777)
    posY := float32(10.336666)
    buf := make([]byte, 8)
    
    binary.LittleEndian.PutUint32(buf[0:], math.Float32bits(posX))
    binary.LittleEndian.PutUint32(buf[4:], math.Float32bits(posY))
    
    var uint8Array = js.Global().Get("Uint8Array")
    dst := uint8Array.New(len(buf))
    js.CopyBytesToJS(dst, buf)
    

    在 Javascript 中解码 state

    let dv = new DataView(state.buffer)
    let posX = dv.getFloat32(0, true)
    let posY = dv.getFloat32(4, true)
    

    在线试玩

    http://panzr.io

    Refs

    • https://www.youtube.com/watch?v=ZyGw1yLNO9E
    • https://github.com/awdng/triebwerk
    • http://panzr.io
    我是为少
    微信:uuhells123
    公众号:黑客下午茶
    加我微信(互相学习交流),关注公众号(获取更多学习资料~)
    
    bk
    下一篇:没有了