Scratch3.0 二次开发——舞台区域支持多尺寸模式

2,062 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

概述

Scratch3.0 二次开发系列,系列说明、Demo源码等请查看:《Scratch3.0 二次开发——开篇》

这次核心介绍如何实现舞台区域支持多尺寸模式的效果

最终效果如图:

需求分析

官方 Scratch 的舞台仅支持一种舞台尺寸(480*3604:3 的尺寸),如果想做一些竖屏的游戏就有点麻烦。所以,原始需求是希望舞台除了支持 4:3 的尺寸外,还需要支持 16:9 以及竖屏(大概是 3:5 的比例,具体比例可以根据各自的需要进行调整)。

ok,原始需求确定了,但对于心思缜密的程序员来说,确定原始需求只是第一步。除了原始需求之外,我们还要挖掘基于这个原始需求的边界情况:

  1. 舞台尺寸切换后,要把当前尺寸记录到工程文件(.sb3 文件中的 json 文件)中,并且再次打开工程文件时能读取到其值,而且自动将舞台尺寸切换到读取到的值
    • 比如,舞台尺寸默认是 4:3,我们现在改成 16:9,并且保存当前作品。那么当我们再次打开这份作品的时候,肯定希望舞台尺寸是修改后的 16:9。嗯嗯,没毛病 ( ̄▽ ̄)~*
    • 对应下文 “保存当前尺寸信息” 一节
  2. 当舞台尺寸切换后,原本在舞台上显示的内容不能乱,比如:
    • 说话气泡
    • 询问交互
    • 取色交互
    • 变量和列表
    • 内容在下文 “原始需求,先实现多尺寸模式” 一节中
  3. 当舞台尺寸切换后,背景编辑区域的尺寸也要跟着变化,比如:
      • 竖屏的尺寸
      • 4:3 的尺寸
      • 16:9 的尺寸
    • 对应下文 “背景编辑区域跟随当前尺寸” 一节
  4. 当舞台尺寸切换后,背景要适配对应尺寸,比如:
      • 竖屏的尺寸
      • 4:3 的尺寸
      • 16:9 的尺寸
    • 三种尺寸下,背景都能全屏填充不留白
    • 对应下文 “背景图片适配当前尺寸” 一节

ok,基本上边界情况也理清楚了,接下来干就完了

前置准备

接下来的修改会涉及到demo-scratch-renderdemo-scratch-svg-rendererdemo-scratch-vmdemo-scratch-guidemo-scratch-paint 五个库

详细的准备工作,请参考这篇:Scratch3.0 二次开发——开篇

思路 && 实现细节

这次内容比较多,具体思路和实现细节就放在一起写了。

原始需求,先实现多尺寸模式

如上图,右侧红框里面的内容就是整个舞台区域,里面分成两部分:

  • stage,相当于一个容器,用来框定舞台区域的宽高
  • canvas,相当于画布,是真正渲染的区域

这样一来我们就好办了,把 stage 的宽高固定起来,需要修改尺寸的仅有 canvas 部分,看一下下图 dom 结构的内容就更加清晰了:

ok,接下里的内容就是围绕如何实现上述思路了。

demo-scratch-gui 项目

修改到的内容比较多,具体修改的内容对比可以参考这个:commit,建议直接 clone 项目下来查看:demo-scratch-gui

上图红框中的文件都跟这一 part 有关

挑一下相对比较重要的地方讲解一下,详情请查看源码:

  1. src/components/stage/stage.jsx,这个组件以及对应的 css 文件调整幅度比较大,把 DOM 结构调整了一下,核心实现上述的两点需求:
    • 区分上面提到的 stagecanvas
  2. src/containers/stage-header.jsxsrc/components/stage-header/stage-header.jsx,用来增加多尺寸切换的按钮交互以及逻辑
  3. src/containers/stage.jsxPS:基本上多尺寸切换的核心逻辑都在这里,其中最关键的是 resizeCanvasonStageNativeSizeChange 两个函数
    • resizeCanvas 函数的作用是调节上述 canvas 的 css 尺寸,使其与选择的尺寸等比例
    • onStageNativeSizeChange 函数的作用是响应舞台尺寸改变时需要同步处理的操作

保存当前尺寸信息

看着这个需求好像很多的样子,实际上只需要在保存作品时记录当前的尺寸信息,打开作品读取并设置就 ok

demo-scratch-vm 项目

一共修改了以下文件:(红框中的文件)

其中:

  1. src/engine/runtime.js,在运行时中记录当前舞台的尺寸信息,供其它地方使用
    • 增加静态变量:stageNativeSize
    • 修改或增加 getter/setter 方法:STAGE_WIDTHSTAGE_HEIGHTSTAGE_WIDTHSTAGE_HEIGHTOFFICIAL_STAGE_WIDTHOFFICIAL_STAGE_HEIGHT
  2. src/serialization/sb3.js,用来存储或解析作品文件(工程文件,.sb3 文件中的 json 文件)中的舞台尺寸信息
    • serializeTarget 函数中的 stageNativeSize 相关内容,用来将舞台尺寸信息保存到作品文件中
    • parseScratchObject 函数中的 stageNativeSize 相关内容,用来解析作品文件中的舞台尺寸信息
  3. src/sprites/rendered-target.js,中 toJSON 函数,导出当前舞台的尺寸信息

demo-scratch-gui 项目

src/lib/sb-file-uploader-hoc.jsx,增加 initStageNativeSize 函数,通过本地工程文件加载工程后,用工程文件中的 stageNativeSize (舞台尺寸信息) 设置当前舞台的 stageNativeSize

背景编辑区域跟随当前尺寸

这个需求也不麻烦,只要在切换舞台尺寸时,更换背景编辑区域的尺寸就 ok

demo-scratch-paint 项目

主要修改内容如下:

核心就是提供一个接口函数,用于在切换舞台尺寸时,更换背景编辑区域的尺寸

  1. src/containers/paint-editor.jsx,修改原本的 handleZoomInhandleZoomOut 两个函数,优化放大、缩小时的交互效果
  2. src/helper/view.js,提供 setSvgArtBoardWidthHeight 接口函数,用于在切换舞台尺寸时,更换背景编辑区域的尺寸

demo-scratch-gui 项目

src/containers/stage-header.jsxonStageNativeSizeChange 函数中,调用上面 demo-scratch-paint 项目提供的 setSvgArtBoardWidthHeight 函数

背景图片适配当前尺寸

这个需求就比较复杂了,还是先理一理思路先。这个需求,明显上来说,就是当舞台尺寸切换时,背景图片要填满当前尺寸

竖屏的尺寸

4:3 的尺寸

16:9 的尺寸

再回顾一下这三个效果

来,接下来理解一下具体是什么含义,再来看三张图:

ok,到这里估计大家应该都已经猜到了,所谓“背景图片适配当前尺寸”,实际上就是先拿一张大图,然后再根据尺寸需要,“裁剪”出自己需要的大小

另外,如果每次切换都“裁剪”并保存一遍图片的话会很麻烦,我们可以在用户上传背景图的时候,一下子把四张图(原图、另外三种尺寸的图)都上传到图床中,文件名是文件内容的 md5 值,这样,下次切换的时候,只需要通过原图计算出各个尺寸的图,然后再做 md5 就可以直接确定图片的 url 链接,然后直接交给引擎自己加载就OK

PS:源码中因为没有加入上传图床的代码,所以这部分的内容只是保留了逻辑代码,不能完全跑通,各位可以自行实现上图图床的代码,把这部分流程衔接起来

demo-scratch-svg-renderer 项目

src/bitmap-adapter.js 文件中的 setStageNativeSizegetBackdropResizedWidthHeightimportBackdropBitmapchangeBackdropBitmapdataUrlToFileadaptiveMoreStageNativeSizeBackdropBitmap 函数都是新增的,用于实现上述说的通过原图计算所有尺寸的图片

demo-scratch-gui 项目

src/containers/costume-tab.jsx 文件中的 handleCostumeUpload 函数,在用户上传背景图时,将四张图(原图、另外三种尺寸的图)都上传到图床中

src/containers/stage.jsx 中的 onStageNativeSizeChange 函数,以下内容实现的是:通过原图计算出各个尺寸的图,然后再做 md5 就可以直接确定图片的 url 链接,然后直接交给引擎自己加载

至此,就完成了这一次的需求实现

不知不觉快 3 个月过去了,这个《Scratch3.0 二次开发》专栏系列也迎来了阶段性收尾 ✿✿ヽ(°▽°)ノ✿ ,希望专栏中记录的内容对大家进行 Scratch 的二次开发有一点点的帮助,如有疑问,欢迎在评论区或者 github 项目中留言 (づ ̄3 ̄)づ╭❤~