唠唠闲话

2020 年底,Adobe Flash Player 正式停止更新和支持,那些曾经陪伴我们成长的经典 Flash 游戏和动画似乎注定要被时代遗忘。从 4399 小游戏到 QQ 宠物,这些曾经的网络文化标志物,都因为 Flash 的消逝而逐渐淡出人们的视野。

像 Q 宠这样在 2018 年就已经停服的游戏,许多人对它们的怀念之情愈加浓厚。而随着人工智能的发展,虚拟现实的兴起,相信未来会有更多的人希望重温这些经典。但现在,借助 Ruffle 开源项目,我们有机会让这些经典的 Flash 作品再次闪耀。

Ruffle 教程

Ruffle 是什么?

Ruffle 是一个基于 Rust 开发的开源项目,旨在无缝地在所有现代操作系统和浏览器上运行 Flash 内容,无需任何额外操作。通过 Ruffle,无论是经典游戏还是动画,都可以在现代环境中运行。

Ruffle 是一个非常活跃的开源项目,当前已有 11473 个 commit,162 个贡献者,且每天都在更新,对 Flash 的支持也越来越完善。

插件客户端

无论是 Windows、macOS(支持 M1/M2 芯片)还是 Linux,都可以在 Ruffle 官网 找到并下载相应的客户端。不过对于 Windows 用户,如果是在本地运行 Flash,更推荐直接下载 Flash Player。

20240303115425

对于希望在浏览器中直接体验 Flash 内容的用户,Ruffle 也提供了 Chrome、Firefox、Edge 和 Safari 的浏览器扩展插件。安装后,当访问包含 SWF 文件的网站时,Ruffle 会自动介入,使这些内容得以在现代浏览器上运行。

Ruffle 浏览器插件示意图

嵌入网页

如果希望让用户能直接访问带 flash 游戏的网页,且无需安装插件,可以将 Ruffle 添加到网站中。作为示例,我们先写一个简单的 HTML 页面,并引入 Ruffle:

下图 html 文件定义了一个全屏的容器,其中 container 放置游戏页面。

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>游戏名称</title>
    <link rel="stylesheet" href="style.css">
    <style>
        /* 确保html和body元素占满整个屏幕 */
        html, body {
            height: 100%;
            margin: 0;
            overflow: hidden; /* 隐藏滚动条 */
        }
        /* 使容器和Ruffle播放器全屏和自适应 */
        #container {
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        #container ruffle-player {
            flex-shrink: 0; /* 防止播放器被压缩 */
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <div id="container"></div>
    <script src="//unpkg.com/@ruffle-rs/ruffle"></script>
    <script>
      window.addEventListener('load', async () => {
          const ruffle = window.RufflePlayer.newest();
          const player = ruffle.createPlayer();
          const container = document.getElementById('container');
          container.appendChild(player);
          player.load('game.swf');
      });
    </script>
</body>
</html>

代码中的这段 JavaScript 代码,用于引入 ruffle 脚本并加载游戏。

<script src="//unpkg.com/@ruffle-rs/ruffle"></script>
<script>
  window.addEventListener('load', async () => {
      const ruffle = window.RufflePlayer.newest();
      const player = ruffle.createPlayer();
      const container = document.getElementById('container');
      container.appendChild(player);
      player.load('game.swf');
  });
</script>

第一行通过 https://unpkg.com/@ruffle-rs/ruffle 引入脚本,第二段 js 代码创建一个 Ruffle 播放器,并加载游戏,游戏文件为 game.swf

如果网络访问 unpkg.com 慢,可以在下载页 选择 Web Package,下载到网站目录,然后用相对路径加载:

<script src="path/to/ruffle.js"></script>

当然,也可以使用自定义的 CDN 资源,比如写个 Nginx 脚本分享 /var/www/cdn 目录下的内容

server{
    listen 80;
    server_name cdn.example.com;
    index index.html index.htm;
    add_header 'Access-Control-Allow-Origin' *;
    location / {
        root /var/www/cdn;
        try_files $uri $uri/ =404;
    }
}

这里加上一行 add_header 'Access-Control-Allow-Origin' *; 以避免跨域问题。

跨域问题

通常,为了加速网站的访问,我们会将游戏文件和 Ruffle 插件托管在如七牛云这样的流量分发平台上,但这可能会触发跨域资源共享(CORS)问题。跨域问题的发生是因为出于安全考虑,浏览器限制了一个源(如你的网站)如何访问另一个源(如 CDN)的资源。如果不正确配置 CORS,浏览器将阻止你的网页请求这些资源,导致游戏或动画无法加载。

例如,将 swf 游戏文件托管七牛云加速访问,如果没有适当设置 CORS,就会看到类似下图的错误:

CORS 错误示例图

为了解决这个问题,需在托管资源的服务器上设置适当的 CORS 策略,比如前边 Nginx 的配置。而对于七牛云,可以参考跨域资源共享设置指南

播放器配置

接下来,我们详细介绍 Ruffle 播放器的一些配置选项,这些选项可以帮助你更好地控制 Flash 内容的加载和显示。

多文件游戏

如果你的 Flash 游戏由多个 swf 文件组成,并且这些文件之间有相互调用关系,你需要在 Ruffle 的配置中设置 base 参数。

例如,如果你的游戏主文件是 game.swf,而它依赖于同一目录下的其他 swf 文件,你可以这样配置 Ruffle:

<script>
    window.addEventListener('load', async () => {
        window.RufflePlayer.config = {
            base: "your/path" // 指定 swf 文件的基础路径
        };
        const ruffle = window.RufflePlayer.newest();
        const player = ruffle.createPlayer();
        const container = document.getElementById('container');
        container.appendChild(player);
        player.load('your/path/game.swf');
    });
</script>

这样,Ruffle 会从指定的 your/path 路径加载 game.swf 和它依赖的其他 swf 文件,而不是从当前目录下查找。类似地,如果游戏文件以链接形式获取,前边 base 也需要相应修改。

修改内嵌字体

内嵌字体乱码是 Ruffle 被吐槽较多的一个问题,但去年年底 Ruffle 更新了一个特性:Add defaultFonts and fontSources config options,支持修改字体。

按官方文档的说法,支持对 Flash 默认三类字体的替换:

There are 3 default fonts in Flash, _sans _serif and _typewriter - in Ruffle they are normally all set to Noto Sans, but you can replace it such as:

window.RufflePlayer.config = {
    fontSources: ["fonts.swf"], // load up fonts here
    defaultFonts: {
        sans: ["Caveat"], // then replace them here.
        // serif: ["Font Name 1", "Font Name 2"], // Multiple fonts can be provided
        // typewriter: ["Noto Sans"], // typewriter is normally a monospace font
    }
}

具体地,先按照官网的图文教程,将字体转换为 swf 文件,然后在 Ruffle 配置中指定它们。

目前,第一步需单独用 Animate 软件进行操作转化。这里我按教程将“站酷快乐体”转化成了 swf 文件,支持中文字符。可通过如下配置引用,亲测有效:

window.RufflePlayer.config = {
    fontSources: ["https://cdn.wzhecnu.cn/adventure/myfont.swf"], // load up fonts here
    defaultFonts: {
        sans: ["站酷快乐体2016修订版"], // then replace them here.
    },
}

效果对比图:

20240303191024

Ruffle 后续会考虑对字体文件的直接支持,比如使用 .ttf 文件。

For now we only support SWFs containing fonts, but in the future we’ll allow actual font files too (such as ttf).

页面放缩

和 flash Player 不同,Ruffle 的右键没有控制缩放的选项,这些需在代码中设置。

举个例子,设置“显示全部”,以及强制缩放:

window.RufflePlayer.config = {
    scale: "showAll",
    forceScale: true
}

这样可以避免主画面太小,以及出现画面外辅助用的素材。

更多设置

以上的播放器设置可以整合到一块:

<script src="//unpkg.com/@ruffle-rs/ruffle"></script>
<script>
    window.addEventListener('load', async () => {
        window.RufflePlayer.config = {
            fontSources: ["https://cdn.wzhecnu.cn/adventure/myfont.swf"], // load up fonts here
            defaultFonts: {
                sans: ["站酷快乐体2016修订版"], // then replace them here.
            },
            scale: "showAll",
            forceScale: true,
            base: "your/path" // 设置CDN基路径
        }
        const ruffle = window.RufflePlayer.newest();
        const player = ruffle.createPlayer();
        const container = document.getElementById('container');
        container.appendChild(player);
        player.load('your/path/xmxd.swf');
    });
</script>

更多选项请参考 Ruffle 使用教程:Using Ruffle。实际上,可以先下载 Ruffle 的客户端,在本地调试后,将客户端里修改的参数填写到配置里。

相关链接

Ruffle 官网:Ruffle
常见问题:FAQ

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐