译介丨把《请出示证件》塞到手机上


3楼猫 发布时间:2022-09-01 08:24:18 作者:Zuxin Language

原作者:Lucas Pope
原文链接: Cramming 'Papers, Please' Onto Phones | Development Logs by Lucas Pope (dukope.com)
翻译:Zuxin
本文可能有剧透成分,建议您通关后再看。这篇文章讲了很多把游戏迁移到手机上会做的UI和其他方面的调整,让译者想起当年的暴雪在《炉石传说》PC版大火以后也没有急于发售移动版而是花了很长时间调整适合手机和平板的表现方式,手机平台应该被考虑如何在它自己的空间上表现良好,而不是粗暴地把主机/PC画面加上一些劣质的虚拟操控UI来显示。

正文

我在2013年制作了《请出示证件》,专门针对用鼠标控制的台式电脑。现在已经2022年了,台式电脑已经不存在了,所有的计算都通过手持移动电话完成。是时候更新这只恐龙了。
这些数以千计的文字和数以兆记的字节的图像将涵盖将游戏从大桌面移植到小手机的一些片段。作为对过去日子的一种回顾,这是一大堆文字和内联的图片标签,而不是令人兴奋的快剪视频。九年后,我会把这个游戏移植到VR平台。
除了使界面正常工作所需的最低限度的内容外,这次移植没有任何内容上的变化或增加。没有疯狂的故事转折,没有新的角色,没有语音对话,没有立体的光线跟踪图像,最令人失望的是,没有皮肤解锁。
同样的饭菜,不同的盘子(Same meal, different plate)。

第一步,迁移到Unity

《请出示证件》最初是用Haxe/OpenFL编写的,这是一种结合了现代ECMA类语言、类Flash的API和多平台的构建系统。这对于在2013年快速完成游戏来说是一个很好的环境,但多年来Haxe已经远离了它的以Flash为目标的根源,而且要跟上OpenFL的变化来进行游戏更新需要付出巨大的努力。
当我最终决定制作这个移植时,我的第一个决定是用C#/Unity重写游戏。在《奥伯拉丁号的回归》之后,我是Unity的忠实粉丝——编辑器、实体/组件设计、构建系统、普遍性,几乎所有的东西(the editor, the entity/component design, the build system, the ubiquity, just about everything)。
我在重写了几天后发现,虽然我喜欢C#,但我更喜欢Haxe。在制作游戏的过程中,我利用了很多Haxe的核心功能,比如超级枚举和隐式类型(super enums and implicit typing),而这一切在C#中手工实现起来越来越困难了。
一种选择是保留Haxe部分不过从OpenFL切换到Heaps——另一个基于Haxe的引擎和构建系统。《死亡细胞》、《北境之地》和其他一些游戏都是用Haxe/Heaps构建的,所以它是一个完全有能力的系统。但是,对于像我这样的人来说,Unity是多么的合适:一个针对多个平台的独立开发者,渴望得到一个流行的、经过验证的、得到良好支持的引擎和构建系统。
幸运的是,Haxe是一种转译语言,这意味着你用一种语言(Haxe)编写的代码会被转换为另一种语言(Javascript、PHP、Python、C++、C#、Lua等),然后被编译/解释为你的目标。因此,在Haxe中写代码并将其转换为可以在Unity中加载和编译的C#是可能的。这就是我决定使用这个的原因。
Haxe 代码

Haxe 代码

同样的代码转译成C#

同样的代码转译成C#

首先,我剥离了OpenFL所提供的类似Flash的API的所有用法。显示树、输入事件、位图操作、资源管理、声音播放——基本上所有不属于核心游戏逻辑的东西(The display tree, input events, bitmap manipulation, resource management, sound playback – basically everything that wasn’t core game logic)。然后我用自定义代码重建了这一切,目标是创建一个类似于《请出示证件》的黑箱,它可以接受用户的输入并吐出一个要绘制的四边形列表(a list of quads to draw)和每帧要执行的音频命令(audio commands to execute every frame)。
这可能是这个项目中最有趣的部分。对于《请出示证件》来说,完整的Flash API是多余的,为我需要的东西专门建立一个新的引擎是一种宣泄(cathartic)。
我在这里稍微担心了一下性能,因为OpenFL的大部分API是用C++写的,而我要用更高级别的Haxe代码来取代它。不过游戏的要求很低,而且Haxe的性能很好,所以我只需要稍微小心一点就能得到好的帧率。
最终的结果需要一个最小的host shell(minimal host shell)来向黑箱发送输入,并渲染它每一帧输出的四边形和音频命令。这种极简主义意味着我可以创建两个host:一个在Heaps中,一个在Unity中。
一切都一清二楚

一切都一清二楚

Haxe本身几乎可以立即编译,并且在Visual Studio Code中支持得很好,所以用Haxe/Heaps编写和调试是快速而简单的。对于发布版本,我把它转译成C#,然后在Unity上做标签(tab over to Unity),并在那里建立项目。

第二步,手机界面

撇开维护不谈,阻碍我将这款游戏引入手机的主要因素是它的用户界面。《请出示证件》总是在大型设备上玩的。实际分辨率低得令人发笑(570x320),但这些像素需要很大。
屏幕被划分为三个始终可见的区域:
检查站、展台和办公桌

检查站、展台和办公桌

早在2014年,我从核心逻辑中分离出一大块界面布局代码,以创建游戏的iPad版本。通过一些调整,我能够保留 "三个区域 "的布局和拖放的游戏方式。最大的变化是,这些区域是垂直堆叠的,具有轻微的动态尺寸能力,而且检查点区域显示的是一个可水平滚动的窗口,而不是一次性显示全部内容。
iPad布局,检查站需要能滚动

iPad布局,检查站需要能滚动

詹姆斯·格雷(James Gray)在此基础上创造了PSV版本,它需要更多的布局变化,但保持了所有相同的游玩过程(gameplay)。
PSV布局,重叠的展台/检查站和全屏垂直滚动

PSV布局,重叠的展台/检查站和全屏垂直滚动

对于手机来说,我想要一些对于这个设备来说自然的感觉,这意味着一些主观的东西。
  1. 在纵向模式下游玩。
  2. 所有三个区域在任何时候都可见。
  3. 在阅读/操纵证件时不需要眯眼、缩放或精确。
从iPad的布局开始,用最新的iPhone屏幕方面来做一个快速的模拟图。
拧成一个极端的10:22的长宽比

拧成一个极端的10:22的长宽比

我尝试了几种不同的方式,都是一样的,将16:9的内容转换为10:22 涉及一种特殊的绝望。我不讨厌的一个变化是把脸变大了一点。
大脸

大脸

在制作了一堆模拟图之后,得出了一些结论:
  1. 在顶部的边境检查站的视图将不得不比iPad版本更多地向左/右滚动。值得庆幸的是,重要的东西还是可以不用滚动的。
  2. 证件区太小,办公桌区域太拥挤。可读性和有足够的空间安排东西之间存在着根本的冲突。
  3. 我喜欢那张大脸。
巨型脸的感觉如此之好,以至于我断定证件也应该是大的,这就揭开了定义这个界面的序幕:不再有桌面,不再有拖放。我把目光投向了可读性,完全消除了可排列性(arrangeability)的要求。
再见了,拖,拜拜了,拽

再见了,拖,拜拜了,拽

操作证件的办公桌已经被两个独立的元素所取代:一个用于特写工作的转盘和一个用于快速导航的架子。

转盘(Carousel)和架子(Rack)

转盘在屏幕外的两边延伸

转盘在屏幕外的两边延伸

通过转盘,证件在一个长的、水平的、快速滚动的列表中被全尺寸显示。底部的架子则以较小的形式显示所有的证件。导航可以通过直接滑动证件,或轻击/拖动架子上的任何地方来完成。
"导航"

"导航"

在思考这个界面时,我首先担心的是,它对游戏性的改变太大。你不再是在一个二维表面上组织证件,而是刷刷刷,在近乎孤立的情况下查看每个证件。桌面游戏中的横幅任务现在完全没有了。
这是一个很好线索来回头看,但我知道这个做出这个移植需要出一些血(付出一些代价)。在测试了我的第一个基本的圆盘的实现后,我所期望的失去文档管理的“动脉喷血”,结果来看更像是一种轻微的擦伤。
最后,我对这种权衡感到满意。在手机上滑动感觉很自然,处理证件检查有它自己的节奏——与桌面版本不同,但仍然很有趣。你不再安排证件,而是把你的眼睛四处瞟来瞟去来关联信息,你把证件作为一个组来操作,眼睛瞟得少一点。
这个转盘+架子代表了对手机界面的大变革适应,它对游戏主界面的每一个其他元素都产生了连锁反应。我将在下面用动画-gif补充的方式详细介绍这些变化中比较有趣的部分。
但首先要说明的是像素网格。

像素网格

在制作像素风格游戏的过程中,每个开发者都必须做出一个决定,那就是他们对自己的像素网格有多诚实。通常没有实际的限制,你的所有像素都需要相同的尺寸,甚至像任天堂的《超级马力欧创作家》系列直接每个画风的像素尺寸的一致性。
从分辨率上看,手机界面根据游戏的现有证件如何在现代非Max的iPhone上可读地适应,确定为208x405。坦率地说,像素并不多,而且顶部的检查站区域很臃肿。
臃肿的检查站

臃肿的检查站

我肯定更喜欢保持单一的一致的像素网格,但我们都要牺牲一些东西。在这种情况下,伪装到两个像素网格解决了很多问题。有了3倍的基本比例,展台和证件区域可以以3倍的比例运行,而检查站则是更容易管理的2倍。
检查站用2倍其他用3倍

检查站用2倍其他用3倍

在代码中,这是用2倍的小数2/3像素缩放来处理的,在最后的3倍缓冲区中乘以整数坐标。
随着像素网格的整理,仍然存在着将整个图像缩放到手机屏幕上的问题。值得庆幸的是,游戏的有效分辨率基本上只有208x450,而手机屏幕——尤其是视网膜屏幕却被像素弄得晕头转向。整数缩放和双线性过滤的组合(integer scaling and bilinear filtering)在这里并没有什么坏处。手机版本在一定范围内处理长宽调整,然后将结果缩放以填充设备的屏幕。
最终图像:整数+双线性缩放以填满屏幕

最终图像:整数+双线性缩放以填满屏幕

接下来是核心界面变化的一些具体细节。

太窄了,不合适

游戏中的几个单一视觉元素不适合在基本的208像素宽度内。与其重新绘制它们,额外的2/3比例选项使一些修复工作变得容易,如标题屏幕。
在大鹰的部分使用选择性的2/3比例

在大鹰的部分使用选择性的2/3比例

夜晚部分的屏幕布局就比较复杂了。它有太多的任务,在桌面的570x320的海洋中轻松滑行,但需要一个全新的布局和有条件的2/3缩放来适应208x450。
夜晚部分宽敞的桌面布局

夜晚部分宽敞的桌面布局

调整了手机布局,有2/3的比例,以适应状态图标、代币等

调整了手机布局,有2/3的比例,以适应状态图标、代币等

当天的报纸是另一个大问题,需要2/3的比例和更窄的3栏布局来取代原来的4栏布局。
改变了布局和比例以适应报纸

改变了布局和比例以适应报纸

这个“需要新的背景图片”的报纸要求与一个为移植而实现的核心引擎功能相衔接:加载时的图片转换(load-time image transmogrification)。

图片转换

《请出示证件》有大量包含文本的证件和图像。其中很大一部分是在游戏之外生成的,必须为每种支持的语言进行本地化。有一些工具可以帮助实现这一目标,但我这次移植的目标之一是尽可能少做本地化工作。
游戏在加载图像资产时有一个“mogrification”步骤,而不是仅仅为手机布局生成新的图像,该步骤根据运行的平台进行程序性编辑。这是在一个相当低的层级上处理的,所以高层的游戏逻辑不需要担心这个问题。
一个例子是报纸的背景,它有一个本地化的名称被烘烤在图像中。mogrification过程同时加载桌面格式的本地化图片和手机格式的非本地化图片,然后从其中的一个部分复制到另一个部分,得到一个手机格式的本地化图片。
在加载时对报纸横幅进行本地化

在加载时对报纸横幅进行本地化

另一种情况是带有检查相关说明的公告页。在这里,mogrifier将这个针对桌面的公告页的本地化下半部分与未本地化的针对手机的上半部分相结合,得到一个本地化的针对手机的公告。
这里加上那里

这里加上那里

这些加载时间的调整超出了图像的范围,也包括一些文档的布局。例如,规则手册是游戏中最宽的文档,但可怕的是,它并不适合208像素。它接近但不完全是,而且边缘有重要的标签和翻页链接,需要舒适地放在屏幕上。
原版规则手册,为桌面上的横向布局而设计

原版规则手册,为桌面上的横向布局而设计

我想把整个展位/证件区保持在一个像素的网格中,所以2/3的缩放在这里不是一个好的选择。
加载时间的mogrification 在此基础上工作,裁剪每个页面,移动所有活动链接,并旋转/重新定位标签以适应208像素的宽度。
Mogrified后的手机纵向布局的规则手册,RIP螺旋

Mogrified后的手机纵向布局的规则手册,RIP螺旋

交出你的证件

在桌面版本中,每个旅行者在进入展台后将他们的文件丢在台面上。简单明了。
台面文件

台面文件

由于缺乏空间,手机布局没有一个合适的台面。一个明显的替代方案是让文件一路下降到底部的架子上,并自动出现在转盘上。
但这对我来说似乎有点被动,失去了原始桌面版本中当你把文件从柜台拖到桌子上阅读时,最初的“好吧,我就拿这些”的活动。我想出的解决方案是先将文件浮动起来,需要轻敲以将它们放到架子上并放入转盘中。它们被点击的顺序决定了它们在列表中的顺序。
漂浮的文件

漂浮的文件

这个设计突出了整个手机版本中使用的东西:重叠元素。主转盘的目的是让人感觉你在举着文件细看,通过重叠的旅行者和展位控制台来加强一点。为了保持实用性,可以将转盘拉下来以获得更好的视野。
展台的原始设计总是很有空间感,但有一些明显的活动模式。对于这个界面,一般来说,可以通过掩盖/重叠(masking/overlapping)在一个活动中不需要的东西和现在需要的其他东西来优化空间的使用。

好吧,自定义界面API

我自己编写UI系统的一个明显的好处是,我可以用触摸和指针输入做一些非常特别的事情。《请出示证件》看起来是一个相当简单的2D游戏,但是在原来的Haxe/OpenFL中通过标准的输入事件回调来表示所有的文档和界面交互,这需要很多不舒服的hack技巧。新的输入系统不使用回调,而且现在更干净,这让我以一种更容易管理的方式实现所有的重叠和穿透输入逻辑。
旧的事件系统,输入处理逻辑被分散在各种回调函数中

旧的事件系统,输入处理逻辑被分散在各种回调函数中

新的react()事件系统,更加集中和灵活

新的react()事件系统,更加集中和灵活

盖章

桌面版有一个从右侧滑出的盖章杆,挂在桌面上。要在护照上盖章,你只需将其对准印章下方并点击。
原本桌面版的盖章栏

原本桌面版的盖章栏

我在为手机布局重新设计时遇到了一些麻烦,因为(A)你不能随便拖动护照来对准印章;(B)我不想放弃按压/触摸时盖章的满足感。如果没有这第二个要求,就可以简单地使印章本身可以拖动,放在护照上自动盖章。但这样一来,你就会在释放/未触及时盖章,这对我来说从来都不合适。这里是我想出的一些概念设计图:
天花板附件,分割杆,激光传感器

天花板附件,分割杆,激光传感器

这些都感觉很奇怪,令人困惑,或者只是完全不能用。桌面上的印章栏有一些隐含的合理性,但我没有想通。
经过更多的实验,我决定重新引入原来的设置,在一个模式的开关后面。在转盘上,护照可以被隔离到一个临时的盖章台,被随意拖动并盖章。
开设一个专门用于盖章的临时办公桌

开设一个专门用于盖章的临时办公桌

这个临时的盖章台是用拉链打开的,这让我可以节省一些屏幕空间,并且只有在一个可盖章的文件被关注时,才会帮助我显示它的可用性。另外,玩这个链子也有一点乐趣。
摇晃的链子

摇晃的链子

钥匙台也是,当然,为什么不呢?

这种临时办公桌的机制也被用于步枪和麻醉枪的序列中。当边界攻击正在进行时,它会迅速翻转到一个孤立的桌子上的钥匙。拖动钥匙和解锁枪支在这里的作用与桌面版相同。
用于解锁枪支的临时钥匙台

用于解锁枪支的临时钥匙台

夹子(Pincher)

对标准化模态印章/钥匙台的需求是在失败的实验中逐渐意识到的。相比之下,我从这个移植的一开始就知道,我需要一种方法来让玩家把某些文件放在彼此的上面。
"谜题"

"谜题"

为了在新的转盘移动设计中复制这一功能,我添加了一个鳄鱼夹式(alligator-clip)的夹子。就像邮票桌的拉环一样,这个夹子只在某些文件在转盘中被集中时出现。
鳄鱼夹夹子出现在可夹取的文件附近,用于夹取。

鳄鱼夹夹子出现在可夹取的文件附近,用于夹取。

点击夹子会抓住文件,并将其固定在转盘的上方和外面,在那里可以单独拖动。转盘在下面仍然可以滚动,所以东西可以排成一排。
夹子的动作

夹子的动作

这一切在游戏中都没有解释,所以让我们假设这个概念和机制是不言而喻的。

通缉:罪犯海报

桌面版中出现的一个游戏行为是如何处理每天的犯罪公告。
拘留这些人

拘留这些人

任何与这里的照片相匹配的旅行者都需要被审问,在工作时牢记这一点的最好方法是把它塞到桌子边上,一整天都放在那里。
你看着很眼熟

你看着很眼熟

由于在这个新的手机布局中,自由形式的办公桌没有了,所以很容易从公告上移开,而完全忘记了嫌疑犯的照片。这是一个我没有发现的问题,直到玩了大部分完成的界面,我怀念有一种方法可以随时看到这三张脸。
墙上贴着帮助用的的照片

墙上贴着帮助用的的照片

为了保留桌面版的一些意图,这并不是自动的。玩家需要在每天开始的时候,点击公告中的一个针,将它们贴在墙上。
从公告中钉到墙上

从公告中钉到墙上

动作按钮不合适

这本来可以放在 "不合适 "下面的。桌面版的指纹(FINGERPRINT)、搜查(SEARCH)和扣留(DETAIN)按钮不适合。
太宽了,无法在208px内水平排列这些东西

太宽了,无法在208px内水平排列这些东西

这是很痛苦的。这些按钮在审讯后会拿下来,它们的出现是一个嘈杂醒目的信号,表明玩家有一些新的行动可用。这三个按钮同时可用的情况很少,但也有可能。
这里有足够的空间

这里有足够的空间

由于基本上没有地方放它们,而且不想缩小它们的规模,我决定它们不能放在主展台的界面上。现在有一个额外的滑出式面板来容纳它们。
按钮的面板。这是一个较早的版本 —— 我在最后删除了图标,并将所有东西都右对齐。

按钮的面板。这是一个较早的版本 —— 我在最后删除了图标,并将所有东西都右对齐。

当一个新的动作可用时,面板会自动弹出,当点击外面任何地方时就会关闭,隐藏时显示一个闪烁的杠杆。
用闪动的杠杆打开面板

用闪动的杠杆打开面板

这些按钮都是完全本地化的图片,所以重复使用相同的按钮,只是把它们放在一个弹出式窗口中,就可以节省一堆本地化过程的麻烦。

增强的检查模式

原来的游戏将其差异突出检查模式视为一个快速的旁白。 首先,玩家排列文件以获得清晰的视野,然后发现差异,启用检查模式,突出问题,最后进行审问。当检查模式处于激活状态时,文件不能被移动,页面不能被翻动——在检查之前,事情必须按顺序进行。
桌面版中差异的审问

桌面版中差异的审问

如果你不能一次看到所有的文件,这个过程是不可能的,就像在手机界面。这个修复方法在概念上相当简单,但在技术上却是一个相当大的麻烦:在检查模式下,转盘和翻页按钮仍然是活动的,当他们的文件滚开时,突出显示的元素仍然部分地在屏幕上。
手机版的检查模式

手机版的检查模式

打磨调整(Polishing Tweaks)

在游戏的所有互动中,有很多小挫折的地方。每当我发现这些问题时,我都会尽力去解决。没有什么是关键的,但战斗的一半是认识到有一些可以使用平滑的摩擦,所以我喜欢这些类型的调整。
自动排序
最重要的三个文件是全天的:公告、音频记录和规则手册。因为现在所有的东西都在一个平面列表中,所以让这三个文件靠近每个入场者的新文件出现在右边的位置很重要。为了做到这一点,游戏在调用入场者时进行了即时的重新排序,而不影响重点视图。
即时自动排序,将重要文件放在右侧

即时自动排序,将重要文件放在右侧

给出文件后的智能转移
一旦护照被盖章,唯一要做的事情就是把所有的文件还给入境者。归还文件会将其从转盘列表中移除,从而将下一个文件移到视野中。我的第一个实现是天真的:如果文件n消失了,就转移到n-1。对于一连串的给予,这意味着它可能会转移到一个不应该被给出的文件上,需要玩家手动扫视。这不是什么大问题,但当转盘智能地转移到下一个可给的文件时,就不那么令人讨厌了。
转移到下一个可给出的文件

转移到下一个可给出的文件

偷看
在寻找相关性和差异性的时候,有很多来回翻动的动作。用刷子刷是很简单的,但如果你把手指放在屏幕上,只是左右滑动,那么角落就不足以真正看到两边的整个文件。这不是很明显,但在玩的时候却让人很沮丧。我的解决方法是实现一个“偷看”功能,当只滑动一点点时,相邻的文件就会完全进入视野。
偷看相邻的文件

偷看相邻的文件

自动玩家测试

最初的桌面游戏有一个调试“浸泡”测试模式,用于强调内存和游戏逻辑。基本上,一个进程通过调用内部调试函数来加载一天的游戏,在文件上盖章,射击攻击者,等等。这对于确保没有错误的内存泄漏或严重的逻辑错误是很有用的,但由于它直接调用了高级函数,对于测试整个游戏和引擎环境并没有什么用。
对这一移植的整个软件堆栈的完全控制使我能够大大加强这一系统。现在,它不再是一个内存浸泡测试,而是一个完全自动的玩家,使用与真实玩家相同的输入信息来控制游戏。
自动玩家在运行,显示路线、日期、旅行者、时间、记忆等。

自动玩家在运行,显示路线、日期、旅行者、时间、记忆等。

自动玩家是可编写脚本的,并遵循 "路线 "来。
  1. 从标题屏幕开始,玩到所有20个结局。
  2. 赚取所有代币。
  3. 在每个无尽模式和课程中玩几分钟。
  4. 在每次游戏中使用不同的随机种子。
确定路线计划

确定路线计划

由于整个重写的游戏+引擎是模块化的,所以无论是否有视觉效果,都可以尽可能快地运行这个自动玩家。在一个现代的iPhone上,每1000帧渲染一次,完整地扫过所有~30条路线大约需要15分钟。
创建这个系统至少需要一个月的初始工作和大量的维护工作。说实话,这是一个相当长的时间,但开发和使用它帮助我发现和修复了游戏中无数的错误。由于我在Mac上使用Haxe/Heaps开发,并在Haxe/Unity中部署,这也是验证Heaps和Unity的结果是否相同,以及Mac/iOS/Android的行为是否正确的宝贵方法。较小的单元测试可以验证其中的一些内容,但没有什么能胜过完整的演练。

平台,复数

现在游戏有三种核心界面模式:桌面、平板和手机。这个界面只处理移动界面,在同一个应用程序/二进制文件中支持手机和平板电脑的布局。
都是手机布局

都是手机布局

由于所有东西都在一个二进制文件中,游戏需要知道它在哪里运行,以便在启动时选择正确的界面。在iOS上,这很容易,因为有一个明确的检查,你可以选择iPhone或iPad。在安卓系统上,令人惊讶的是,手机和平板电脑之间没有明确的界限,游戏必须根据分辨率和DPI来决定。
在它猜错的情况下,有一个额外的设置可以明确选择你想要的模式。
一些设备可以选择

一些设备可以选择

最后的分类看起来是这样的。
  • iPhone:只有手机布局。
  • iPad:默认的平板电脑布局,可选的手机布局。
  • 安卓设备。可选的手机和平板电脑布局,默认是最佳的猜测。

终于

适和手机版本的《请出示证件》已经存在了很长时间。从9年前的桌面版开始,我就否定了这个游戏可以在手机上运行的想法,但我想去年我的脑子里一定有一个开关被打开了。
从开始到结束,这个移植花了大约8个月的时间。这听起来像是一个永恒的过程,但我很喜欢它的大部分内容,所以不会太大声抱怨。最伤的(sharpest cut)是,它让我远离了其他的工作
在发布之后,不管是什么火,我都会休息一阵子,然后再回去做新的东西。到时见。


© 2022 3楼猫 下载APP 站点地图 广告合作:asmrly666@gmail.com