目次
bas弹幕使用教程
开始前的亿些说明
什么是bas弹幕?
Bas弹幕全称bilibili animation script,也可称作m9或mode9,是新一代的bilibili 高级弹幕系统
难度如何?
bas弹幕虽然主要使用代码编写,但并不需要编程基础。只要愿意花时间去研究难度不会太大
代码排版格式方面的注意事项?
官方的文档(下面有)是一个很好的参考,最终如何编写还是看个人习惯,不过把代码给别人看时最好注意下注释和美观和可读性(
高级弹幕系统间的区别?
· “高级弹幕”是一个比较广泛的统称,主要指以下三种:
mode7-高级弹幕:在视频中看到的”高级弹幕”基本属于m7,在弹幕列表中显示为特殊弹幕。点击弹幕列表旁边的按钮即可进入编辑页面,支付2硬币并获取up授权后可拥有在该视频使用权限。功能相对简单,支持移动端,由于播放器改版bug严重
(av297197美丽之物,此为录屏版)
mode8-代码弹幕:基于flash播放器,功能极为强大的弹幕系统,可以实现复杂动画,特效,甚至制作弹幕游戏,支持插入矢量图。数年前常见的op转跳便由代码弹幕实现。但在16年左右因安全问题被禁止发送(有傻逼尝试用代码炸播放器)。仅支持PC端flash播放器
(av2775802 世界终结舞厅)
mode9-bas弹幕:基于html5播放器,算是m8的替代品,功能相对较弱但仍远强于m7,也可以制作复杂动画,支持矢量图,互动方面较为简易。无字幕君权限只能在自己的视频里发送,仅支持PC端 html5播放器。bas弹幕在浏览器适配上有点问题,接下来的教程均以Chrome为准
(av796642408 p2 カワキヲアメク)
一.最基本的工具/软件
- bas弹幕的官方文档,https://bilibili.github.io/bas/#/guide(无法加载可以使用本地版)。详细代码介绍与实验室都在这里,并且有大量实例,务必配合使用。
- 一个文本编辑器,如notepad++,笔记本也问题不大
- Chrome浏览器,不保证bas在所有浏览器上效果相同,以Chrome为准
- 一个自己的弹幕测试视频,视频页编辑器比实验室完善,编写测试更方便
二.¨C11C实验室与视频页编辑器
- 实验室,位于官方文档右上方,功能简陋,不显示错误信息,个人不推荐使用
- 视频页编辑器,在自己的视频中点击弹幕列表旁按钮,选择bas弹幕,点击代码模式打开代码编辑器(普通编辑器基本是m7+,就不介绍了)
- 视频/弹幕显示区
- 帮助,点击转跳至官方文档
- 清屏,清空屏幕(点击进度条会重载常驻弹幕和已发送弹幕)
- 测试弹幕,测试当前分页的代码
- ¨C12C测试弹幕常驻,启用后测试效果更接近实际发送效果,但测试的弹幕只能通过刷新页面清除,容易导致卡顿
- 以当前时间作为弹幕出现时间
- 弹幕出现时间,单位为ms,启用测试弹幕常驻后才能在弹幕测试中生效
- 分页,每个分页可编写不同弹幕代码,由于bug切换分p时可能会吞弹幕
- 颜色拾取,可选取颜色
- 坐标拾取,可在视频界面中显示网格,点击获取坐标
- 发送弹幕,单条上限512k,发送后仍可修改,以发送顺序叠加(大概)
- 代码编辑区,有代码补全功能
(比较玄学)
2021.4.24补充
目前单条上限只有10kb,不知道什么时候修。。。
三.text-文本弹幕
- “定义”一条弹幕
Bas弹幕的格式为:
def text/path/button 名称{属性}
def用于定义一条新弹幕,注意这与弹幕列表中的”一条弹幕”不同,”一条”bas弹幕可包含多个def
text即为文本,path与button会在后面介绍
弹幕名称只能含有字母和数字且必须以字母开头,弹幕名称重复只执行最后一个,区分大小写
各种符号均为英文字符
在任意字符前添加”\”可使后续同行文字变成注释
属性格式为{xxx=x xxx=x xxx=x},属性重复只执行最后一个
属性包含了弹幕的内容和样式,下表为官方文档中文本类型弹幕所有可用属性,官方文档有大量代码实例可以测试
属性名 | 值类型 | 必要 | 默认值 | 可变 | 渐变 | 补充说明 >(属性名注意大小写) |
x | number | 否 | 0 | 是 | 是 | x 坐标,可以为百分比值 |
y | number | 否 | 0 | 是 | 是 | y 坐标,可以为百分比值 |
zIndex | number | 否 | 0 | 否 | 否 | 层次权重,值高的对象在上层 |
scale | number | 否 | 1 | 是 | 是 | 缩放 |
duration | time | 否 | – | 否 | 否 | 元素生命周期,有动画时默认为动画总时间,无动画时默认4s |
content | string | 是 | ‘请输入内容’ | 是 | 否 | 文本内容 |
alpha | number | 否 | 1 | 是 | 是 | 透明度,取值范围 [0, 1],0 完全透明, 1 完全不透明 |
color | number | 否 | 0xffffff | 是 | 是 | 文本颜色 |
anchorX | number | 否 | 0 | 否 | 否 | 锚点,位置为长度的百分比 |
anchorY | number | 否 | 0 | 否 | 否 | 锚点,位置为宽度的百分比 |
fontSize | number | 否 | 25 | 是 | 否 | 文本字体大小,可以为百分比,百分比字体大小为当前屏幕宽度字体百分比px(务必在文本弹幕中写入该属性并设为百分比,否则弹幕会受播放器分辨率影响,导致全屏错位) |
fontFamily | string | 否 | – | 否 | 否 | 文本字体,默认值为平台默认字体。字体不存在时,使用浏览器默认字体(所以不要乱用字体,别人大概率无法显示) |
bold | number | 否 | 1 | 否 | 否 | 加粗 |
textShadow | number | 否 | 1 | 否 | 否 | 字体阴影 |
strokeWidth | number | 否 | 0 | 否 | 否 | 描边宽度 |
strokeColor | number | 否 | 0xffffff | 否 | 否 | 描边颜色 |
rotateX | number | 否 | 0 | 是 | 是 | X轴旋转 |
rotateY | number | 否 | 0 | 是 | 是 | Y轴旋转 |
rotateZ | number | 否 | 0 | 是 | 是 | Z轴旋转 |
parent | text | 否 | – | 否 | 否 | 所属层 |
- 文本内容-content
{
content=“文本”
}
不能含有”\”字符,但可用”\n”进行换行,不支持enter换行
¨C13C {
content=”a\naa\naaa\naaaa”
}
- 坐标-x,y
{
x=a/a%
y=b/b%
}
a,b可为负数,以视频左上角为坐标轴原点,坐标轴受视频比例影响。强烈建议使用百分比值
- 锚点-anchorX/Y
{
anchorX=a
anchorY=b
}
锚点是xy坐标的定位点,适当调整锚点可以减少弹幕定位难度。同时弹幕旋转,缩放等功能也以锚点为中心
bas实际范围是一个矩形¨C14C,通常比可见字符大一圈,(0,0)时锚点位于矩形左上角,(0.5,0.5)位于矩形中心,(1,0)时位于矩形右上角,以此类推。a,b可为任意值
(0,0)
(1,0)紫色
(-1,0)绿色
(0,1)蓝色
(0,-1)青色
xy坐标均相同
- 缩放-scale
{
scale=a
}
以锚点为中心对整条弹幕进行缩放,a为负数时弹幕以锚点为中心翻转,为0时弹幕消失
scale值过大会导致弹幕模糊,对于文本类型弹幕如果不需要动画渐变效果建议使用fontSize而不是scale
¨C15C {
scale=1/-1/0.5/-0.5
}
对应颜色(紫色/红色/灰色/绿色)
- 旋转-rotateX/Y/Z
{
rotateX=α
rotateY=β
rotateZ=γ
}
¨C16C以锚点为中心绕X/Y/Z轴旋转对应角度。
(α,β,γ)
(60,0,0)红色
(0,60,0)紫色
(0,0,60)灰色
(30,45,20)绿色
特性:
rx和ry透视效果受xy坐标和弹幕大小影响
弹幕作为子级时rx,ry透视效果消失(parent部分说明)
- 字体大小-fontSize
{
fontSize=a/a%
}
效果与scale类似,但fontSize不可渐变,a可为负数,使用百分比时固定弹幕与播放器的比例,可以避免因分辨率造成的错位,非常重要
- 生命周期-duration
{
duration=xhxmxs/xxs/xxms
}
用于规定弹幕的生存时间,单位可以为h/m/s/ms。除duration外也有其他方法可以调整弹幕生存时间,将在动画部分介绍
- 字体-fontFamily
{
fontFamily=“字体名称”
}
指定文本字体,可输入中文名称,若没有安装指定字体将显示默认字体
- 层次-zIndex
{
zIndex=a
}
设置弹幕的层级,默认为0,可为负数,层级高的弹幕会覆盖层级低的弹幕,层级相同按照在代码文本中的”def”顺序,先”def”的弹幕会被后”def”的弹幕覆盖,仅在”同一条”弹幕内生效
¨C17C {
zIndex=0/1(红色/绿色)
}
- 其他文本效果
颜色-color 格式为 color=0x 后接16进制颜色值
粗体-bold 格式为 bold=0/1 ,0为关闭,1为启用,默认启用
描边宽度-strokeWidth为0时不显示描边
描边颜色-strokeColor 格式与color相同,默认为0xffffff白色
字体阴影-textShadow 格式与bold相同,默认启用,需要纯色弹幕可设为0
- 所属层-parent
主要用于动画,稍后说明
四.简单弹幕动画
对弹幕属性进行变动可做出丰富的动画效果,这时需要用到set语句
- 基本格式
set 名称{
…
}动画时间
set可以改变弹幕的属性,制作渐变动画
def text a{
content=”AAA”
x=20%
y=20%
fontSize=8%
}set a{
alpha=0.5
x=40%
color=0xaa0000
fontSize=12%
}2s
以上代码使用2s将弹幕透明度变为0.5,x坐标变为40%,颜色变为aa0000,字体大小变为12%。
注意如fontSize,content等属性是不可渐变的,这些属性的变化会在瞬间完成(与0s动画时间效果相同),anchorX/Y,fontFamily,zIndex等属性完全不可变
set语句不必须紧跟原弹幕,可以放在原弹幕下方的任意位置
- 并联动画
set a{…}2s
set a{…}1s
set a{…}3s
…
连续出现的set语句可以并联多个动画,每个语句的动画时间可以独立设置。但x y rotateX rotateY rotateZ scale会被视为相同属性,只能任取其一
- 串联动画
}
set a{…}1s
then set a{…}1s
then set a{…}1s
…
set语句可以被then连接,依次进行动画,与并联动画相比没有属性限制,但想实现类似并联的效果需要准确计算动画时间和属性值,较为麻烦
与set不同,then set必须紧跟上一个set语句
- 动画时间与duration
duration属性优先度高于动画时间,到达duration所定时间弹幕会直接消失,无论弹幕动画是否结束。若动画在duration所定时间前结束,弹幕保持不变直至指定时间。
不写入duration属性时系统会取默认值4s,并降低优先度,弹幕生存时间由动画时间决定
- 维持弹幕
set语句后的大括号可以为空
利用这个特性可以更灵活地制作动画或设定生存时间,如
set a{}10s或then set a{}10s
效果为保持弹幕十秒不变,没有后续set语句弹幕消失
- 隐藏弹幕
Bas没有规定弹幕出现时间的属性,但可以使用set{}和alpha=0隐藏弹幕,如
def text a{
alpha=0
…
}set a{}10s
then set a{
alpha=1
}0s then set a{}10s
以上代码使弹幕保持透明10s后再出现,并维持10s
五.path-图形弹幕
def path a{
d=“”
…
}
path类型弹幕可以发送svg格式的矢量图,可用属性列表如下
属性名 | 值类型 | 必要 | 默认值 | 可变 | 渐变 | 说明 |
x | number | 否 | 0 | 是 | 是 | x 坐标,可以为百分比值 |
y | number | 否 | 0 | 是 | 是 | y 坐标,可以为百分比值 |
zIndex | number | 否 | 0 | 否 | 否 | 层次权重,值高的对象在上层 |
scale | number | 否 | 1 | 否 | 否 | 缩放 |
duration | time | 否 | – | 否 | 否 | 元素生命周期,有动画时默认为动画总时间,无动画时默认4s |
d | string | 是 | “” | 否 | 否 | svg 路径 |
borderWidth | number | 否 | 0 | 否 | 否 | 描边宽度 |
borderColor | number | 否 | 0 | 否 | 否 | 描边颜色 |
borderAlpha | number | 否 | 1 | 否 | 否 | 描边透明度 |
fillColor | number | 否 | 0xffffff | 否 | 否 | 填充颜色 |
fillAlpha | number | 否 | 1 | 否 | 否 | 填充透明度 |
viewBox | string | 否 | – | 否 | 否 | svg 画布大小,默认完整显示 |
width | number | 否 | – | 否 | 否 | 宽度,可以为百分比值,需要设置 viewBox 才可生效 |
height | number | 否 | – | 否 | 否 | 高度,可以为百分比值,需要设置 viewBox 才可生效 |
parent | text | 否 | – | 否 | 否 | 所属层 |
- 获取svg
path弹幕格式为svg,普通图片需经转换才能使用,这个过程通常会对图片造成很大的损伤
放两个转换网站↓
pngtosvg.com 功能简单,免费,颜色识别精度低,适用于转换一些比较简单的图形
¨C18Cwww.vectorizer.io 功能强大,半免费(每小时有操作上限,图片上传限制1m)下方补充,精度非常高,但也导致图片体积巨大,适当调整设置可以在保证质量的同时缩小体积。
(pid 79936421)转换后大小1.3m,远超单条弹幕上限,只能分为多条弹幕发送,且容易造成卡顿
若需要特殊图形(如齿轮,曲线,多边形)或字体,path可以降低弹幕编写难度,请勿滥用path,bas是弹幕,不是图片发送器
看查或手动绘制svg可以使用Inkscape
- 属性差异
x, y, zIndex, duration没有变动
描边替换为borderWidth, borderColor, borderAlpha
color替换为fillColor, alpha换为fillAlpha,且不可变
scale可用但不可变
大部分文本弹幕属性在path弹幕不可用
- Svg路径-d
用文本编辑器打开svg文件,下图中d=” “便是svg路径,决定了svg的图形,可作为属性写入弹幕。简单图形的路径长度一般只有几k或更少,一些复杂图形路径长度可达数百k,使用path时注意不要超过512k的弹幕大小限制
fill对应当前路径的颜色,颜色值可以直接使用
每条路径只对应一种颜色,一种颜色能有多条路径,多色svg的路径数一般较多
- 画布大小-viewBox
viewBox=“x1 y1 x2 y2“
viewBox决定svg的画布大小和偏移,设置viewBox后只有画布范围内的图形会被显示,画布的左上角也是path弹幕的锚点
x1 y1对应x,y轴偏移量;x2,y2对应画布宽高。Svg文件中一般带有viewBox值,可以直接使用
viewBox也可用于分割svg
- 弹幕宽高-width/height
作用类似text中的fontSize,设置viewBox后生效。为百分比时固定画布与弹幕显示区的比例,一般使用其一足够,可以避免全屏错位
- 弹幕叠加
Svg文件中可能有多条路径,保证xy,viewBox,width等属性相同即可正常叠加
- 附赠-Inkscape的一些功能
由于技术力不足+懒,这只是一些比较实用的功能,详细教程建议百度
查看viewBox
svg自带的viewBox会以一个黑框的形式显示
合并路径
用vectorizer转换的svg虽然按颜色区分了图层,但路径基本是分割过的。可以用“路径”选项中的“合并”将同色路径并为一条
优化格式
可以优化svg文件的代码结构,将文件另存为一次即可
文字转svg
左侧工具栏中有输入文字的选项,并且可以转化成路径。使用“分离”可以拆分路径(需要断开连接),用“互斥”能在其他图形上扣洞
临摹位图轮廓
Inkscape可以将图片以各种形式转换成svg,但不建议把精度调太高,体积会非常巨大 (原图↓)
2021.4.24补充
vectorizer网站改版了,撤掉了操作数限制,但免费下载次数被彻底限制(10欧100次),有条件可以支持网站(毕竟确实好用),也可以f12
把蓝色部分整体复制到一个txt里,后缀改svg,丢inkscape里重写格式
简单图形推荐自己画,难度不高
Inkscape的群组问题,文字转换成路径后会是一个群组,虽然群组在当前选择的图层,但其中的路径实际上被转移到了一个子图层,导致无法直接与其他路径进行互斥,并集等操作。双击群组进入路径所在图层,才可选择路径本体进行操作,双击空白处回到初始图层。为了方便可以把路径转移到需要的图层。另外建议使用“并集”而不是“合并”,合并也会造成上述问题
¨C23C¨C24C
合并vectorizer转换的路径时,节点量往往非常巨大,并集会重新计算节点位置,产生大量小数点导致路径长度激增,这时候还是建议使用合并,需要编辑可以先用图层功能将各色路径重新分层
推荐一个软件,svgo-gui,可以压缩路径大小,但会干掉inkscape加入的数据(如新加入的图层,注释),而且会直接覆盖源文件,注意备份
六.弹幕模板
制作大量弹幕时可以简化代码
- let
def text a{…}
let b=a{…}
弹幕b将继承弹幕a的属性,可以在大括号中添加或修改属性
- 模板
除了直接使用弹幕,也可以定义模板,如:
def text a(content=“a“ alpha=1 color=0x000000 x=20%){
content=content
color=color
x=x
alpha=alpha
fontSize=5%
}
let b=a(“ccc“ ,0.5,0xaaaaaa,30%)
其他格式在官方文档里有说明
- 匿名实例
可以用于set语句简化代码
def text a{
content=“aaa“
fontSize=5%
}
set (a{content=“bbb“ fontSize=8%}){
x=50%
alpha=0.5
}1s
set (a{content=“ccc“ fontSize=3%}){
y=50%
scale=2
}1s
(似乎做不了串联动画?
七.复杂弹幕动画
其实并不算复杂,主要包含了官方文档中没提到或介绍不详细的功能和特性
- parent-所属层
def text a{…}
def text b{
parent=“a“
…
}
使弹幕b以弹幕a为父级进行绘制,弹幕a的缩放,旋转,透明度都会影响到弹幕b,大大降低整体动画的制作难度。parent可以多层嵌套,子级和父级可以同时设定不同动画
父级属性会影响所有子级,属性也能多层叠加(如父级alpha为0.5,子级为0.3,那么子级实际透明度为0.50.3=0.15),但如color等针对文本的属性对子级无影响
1-1. 隐藏父级
使用文本类型弹幕作父级,在content输入空格可以隐藏父级同时正常对子级进行变换
1-2. path动画
path类型弹幕的大部分属性不可变,但可以将其作为文本弹幕的子级,这样就能通过调整父级做出缩放,透明度,旋转等属性的渐变效果。
1-3. 子级旋转
一个可能的bug,弹幕作为子级使用rX和rY时会失去旋转透视,可以用于压缩或拉伸弹幕
1-4. 子级定位
子级所处坐标系与普通弹幕不同,原点为父级锚点,xy值0-100%为父级弹幕的矩形范围
- timing-function
def text a{
…
}set a{
…
}2s,“timing-function“
一个用css数据类型表示的函数,可以改变弹幕动画的渐变曲线,对所有可渐变属性生效,有以下几种类型
2-1. linear
弹幕动画的默认值,从开始到结束速度恒定不变
(0.0, 0.0, 1.0, 1.0)
2-2. ease
先加速,后减速
填入timing-function但无效时默认使用ease
(0.25, 0.1, 0.25, 1.0)
2-3. ease-in
逐渐加速
(0.42, 0.0, 1.0, 1.0)
2-4. ease-out
逐渐减速
(0.0, 0.0, 0.58, 1.0)
2-5. ease-in-out
类似ease,但加速较缓
(0.42, 0.0, 0.58, 1.0)
2-6. cubic-bezier(x1, y1, x2, y2)
演示图中的曲线实际上是一条三次贝塞尔曲线,由四个点定义,其中两点已固定(开始和结束),(x1, y1, x2, y2)即是剩余两点的坐标,其中x1,x2必须在[0,1]之间才能生效
(0.14,0.65,0.78,0.36) (0.34,1.07,0.71,-0.23) (0.12,3.56,0.86,-2.67)
调整两点坐标,可以使曲线递减甚至超出边界。
曲线递减动画逆向进行,造成弹跳效果。曲线超出边界时弹跳范围超出原属性或目标属性范围,但如color等属性到达上限/下限(ffffff或000000)时不会继续增大/减小。
2-7. step-start
动画开始后立刻转跳到结束状态,并保持到动画时间结束
2-8. step-end
动画开始后保持不变,直到动画时间结束立刻转跳到结束状态
2-9. steps(n, step-position)
使动画分步进行,n为正整数
step-position可以为jump-start / jump-end / jump-none / jump-both / start / end
start / jump-start,初始状态不包含在分步
end / jump-end,结束状态不包含在分步内
jump-none,n大于1生效,初始和结束状态均包含在分步内
jump-both,初始和结束状态均不包含在分步内
八.button-互动按钮
def button a{
text=“”
…
target=av/seek/bangumi{
…
}
}
提供比较简单的互动按钮,可以点击转跳视频或时间
属性名 | 值类型 | 必要 | 默认值 | 可变 | 渐变 | 说明 |
x | number | 否 | 0 | 是 | 是 | x 坐标,可以为百分比值 |
y | number | 否 | 0 | 是 | 是 | y 坐标,可以为百分比值 |
zIndex | number | 否 | 0 | 否 | 否 | 层次权重,值高的对象在上层 |
scale | number | 否 | 1 | 否 | 否 | 缩放 |
duration | time | 否 | – | 否 | 否 | 元素生命周期,有动画时默认为动画总时间,无动画时默认4s |
text | string | 是 | ‘请输入内容’ | 是 | 否 | 按钮显示文字 |
fontSize | number | 否 | 25 | 是 | 否 | 按钮字体大小,可以为百分比(百分比字体大小为当前屏幕宽度*字体百分比px) |
textColor | number | 否 | 0x000000 | 否 | 否 | 按钮文字颜色 |
textAlpha | number | 否 | 1 | 否 | 否 | 按钮字体透明度 |
fillColor | number | 否 | 0xffffff | 否 | 否 | 按钮填充颜色 |
fillAlpha | number | 否 | 1 | 否 | 否 | 按钮填充透明度 |
target | 是 | – | 否 | 否 | 按钮功能 | |
fontFamliy | string | 否 | – | 否 | 否 | 按钮文字字体 |
- 属性差异
与path类似,大部分文本弹幕属性不可用。作为子级时按钮功能依然生效,被旋转或缩放后按钮点击范围相应变动
- 按钮功能-target
指定按钮功能,格式稍微特殊,在上方有提到。分为三类
1-1. av
用于转跳视频,支持bv和av
属性名 | 值类型 | 必要 | 默认值 | 可变 | 渐变 | 说明 |
bvid | 二选一 | – | 否 | 否 | 视频bv号,需带BV前缀 | |
av | number | 二选一 | – | 否 | 否 | 视频av号 |
page | number | 否 | 1 | 否 | 否 | 视频分P号 |
time | time | 否 | 0s | 否 | 否 | 视频开始播放点 |
1-2. bangumi
用于转跳番剧
seasonId为番剧id,对应番剧网页链接的ssxxxxx部分
episodeId为剧集id,点开任意一集后链接出现epxxxxx
部分页面不显示ssid,可以打开网页源码寻找www.bilibili.com/bangumi/play/ssxxxx/链接
属性名 | 值类型 | 必要 | 默认值 | 可变 | 渐变 | 说明 |
seasonId | number | 是 | 否 | 否 | 否 | 番剧id |
episodeId | number | 是 | 否 | 否 | 否 | 番剧分集id |
time | time | 否 | 0s | 否 | 否 | 视频开始播放点 |
1-3. seek
转跳视频时间
属性名 | 值类型 | 必要 | 默认值 | 可变 | 渐变 | 说明 |
time | time | 是 | – | 否 | 否 | seek目标时间 |
九.关于弹幕PV(大坑)
0.先来个提醒
能找到这个教程的应该都看过蓝白四期和以前的一些弹幕祭,基本是些比较神仙的弹幕pv,但个人不建议刚入坑就去肝pv,费时费力而且容易碰壁(深有体会)
弹幕pv需要设计画面,然后在bas弹幕的各种功能中找到实现方案,对没有实践经验的新人实在过于困难,也可能写着写着突然出现我tm写了坨屎的想法(也是深有体会)
先做些不太复杂的小动画或尝试还原一些片段是更好的选择
1-1. ???
(这个坑不一定会填,不知道怎么写
(直接问人肯定比等我填坑靠谱
十.广告时间
想到的已经写完了,代码实例和演示用docx太麻烦就不做了
以后可能会继续更新(咕
更新了,好耶!
我的b站uid:52454723 S-Haya
社团uid:8324 弹幕Art研究社
已经复活蓝白官号:65413 弹幕娘
弹幕群:1006093326