如果你和我一样,常年混迹于各种开源引擎的发布页和开发者论坛,大概率见过Superpowers这个名字。我第一次注意到它,是因为一条帖子下面的评论:某位老哥说“装上之后,我家初中生侄子用一晚上做出了一个能多人联机的小游戏”。当时第一反应是广告,后来发现创始人真把源码放出来了,而且项目定位就是“给创造者的超能力”——一个免费、开源、架在浏览器里的3D游戏开发与实时协作平台。它把传统引擎动辄几个G的安装包、漫长的编译流程、复杂的账号体系全部砍掉,换来的是一个你只需要打开浏览器就能开始做游戏的网页工作台。
这篇文章写给两类人:一是想找一个轻量方案带学生或新手入门3D开发的老师、团队负责人;二是自己捣鼓小游戏、想做多人联机原型但又嫌Unity太重、Three.js又要从零搭工程的朋友。下面我会从安装部署、编辑器玩法、协作开发、踩坑实录四个大方向展开,把我自己从第一次安装到长期使用的经验全部摊开讲。
1. Superpowers是什么:给独立开发者的开源游戏引擎
1.1 一个可以装在浏览器里的3D创意工作台
如果你之前完全没接触过Superpowers,可以先把它理解成一个“运行在你自己服务器上的网页版游戏编辑器”。引擎的核心分为两块:服务端是一个Node.js进程,负责项目存储、用户管理、资源同步;客户端则是浏览器里的Web应用,负责三维场景渲染、脚本编译、界面交互。你不需要在每台电脑上安装庞大的IDE,只要一台机器跑起了服务,团队里任何人的浏览器输入地址就能进入编辑器干活。
这样的架构带来的直接好处是跨平台极其顺畅。Windows、macOS、Linux都只要一个现代浏览器,哪怕是性能一般的轻薄本也能完成大部分编辑工作。渲染层面它基于WebGL,场景里看得见的效果就是最终发布在网页上的效果,所见即所得的感觉很强。对比传统引擎那种“编辑器里一套渲染,发布后另一套效果”的割裂感,Superpowers在原型验证阶段能省很多确认时间。
它的核心理念也不是“逼你写代码”,而是让创作方式更贴近人的直觉。编辑器里同时提供可视化脚本(拖拽节点、连线做逻辑)和TypeScript文本脚本两种模式,新手可以从完全没有代码基础起步,老手则可以直接写类写组件。这种双轨设计在同类开源工具里非常少见,也是我后来一直安利它的重要原因。
1.2 为什么我在一堆引擎里选了它
在Superpowers之前,我试过用Unity做教学项目,也试过直接用Three.js带着几个学员从零搭引擎壳子。Unity的问题在于安装包太大、版本升级频繁、许可证策略要考虑团队合规,而且多人协作通常得配一套版本控制流程;Three.js的问题则是“什么都要自己造”,场景管理、资源加载、编辑器界面,还没有开始做游戏就先花了两周写工具。
Superpowers恰好解决了这两个痛点。它自带完整编辑器,PostgreSQL级别的资源管理思路被简化成了文件树系统;它的多人协作不是“提交-合并”,而是像在线文档一样所有人实时编辑同一份项目。安装这个工具的过程基本就是把压缩包解压、跑一个脚本启动服务,对我这种“能少装一个软件就少装一个软件”的人来说,这种轻量感是致命的吸引力。
当然它也有明显短板。生态规模远不如商业引擎,能参考的教程和现成资源相对少;渲染特性上限不高,做不了电影级画质;项目维护活跃度也比不上Unity、Godot背后的商业公司。所以我心里对它一直有个清晰定位:Superpowers适合“快速验证创意、教学演示、小团队并行开发原型”,而不是一款用来做最终商业化大作的引擎。
1.3 适合谁用,能做什么
就我实际接触的使用者画像来看,Superpowers的用户大概可以分成三类:第一类是中小学和高校的编程老师,看中的是“浏览器即开即用、学生不用装环境、老师能随时查看每个学生的实时进度”;第二类是独立游戏开发者,尤其是做多人派对游戏、解谜游戏的小团队,看中的是“协作者不用拉分支,改完立刻生效”;第三类是创意编程爱好者,把Superpowers当成交互叙事、虚拟展厅、简单VR原型的快速搭建工具。
它能做的具体事情包括:第三人称探索游戏、俯视角射击、跑酷类玩法、答题闯关式的交互课件、带有简单对话系统的视觉叙事,以及通过浏览器里WebVR/WebXR接口实现的低成本虚拟现实原型。如果你需要的是一个“今天想到创意、今天就能在浏览器里跑起来”的试验场,那它非常合适;如果你一上来就想做开放世界、实时全局光照、大规模物理模拟,那还是选择商业引擎更现实。
2. 安装部署:从下载到跑起第一台服务器
2.1 准备工作:Node.js环境与版本选择
安装Superpowers之前,你需要确保机器上有Node.js运行环境。虽然不同版本的Superpowers对Node版本要求略有差异,但统一思路是:优先使用Node.js官方长期支持版本,避免追最新大版本造成原生模块编译失败。最初我用的是很旧的Superpowers版本,当时要求Node.js也比较老,后来切到新版本后就把本机Node升级到了LTS版,一路顺畅。
你可以先去 Node.js 官网下载对应的安装包,安装完成后在终端验证一下环境,输入node -v和npm -v,能看到版本号就说明环境没问题。如果你机器上已经装了其他基于Node的工具链,建议先用nvm(Node Version Manager)管理版本,这样Superpowers需要旧Node时可以随时切换,不至于和主业项目打架。我自己就在一台公用开发机上用nvm装了两个Node版本,平时切到LTS跑游戏服务,需要跑老脚本时再切回旧版,省心很多。
2.2 三步启动:解压、运行、连接
安装这个项目的门槛比我用过的任何引擎都低。整体流程基本只有三步:从GitHub官方仓库的Release页面下载对应操作系统的压缩包,解压到你自己习惯的目录,然后启动服务。Windows系统通常可以直接双击运行压缩包里的start.bat,macOS和Linux则是在终端里执行bash start.sh,或者手动执行node server/superpowers.js。
服务启动后,超级终端里会打印出监听的端口号,默认是4237。接着你用任意现代浏览器访问http://localhost:4237,第一次打开时页面会引导你创建一个管理员账号。这个管理员账号非常重要,后续审批新用户、管理服务器设置都靠它。一切顺利的话,你此时已经看到了一个可以创建项目的编辑界面,整个安装过程耗时一般不超过十分钟,全程不需要安装任何插件或额外运行时。
有一点提醒一下:不同时期下载的版本在启动脚本名称、默认端口上可能存在细微差别,执行脚本前先看一眼压缩包里的README文件,通常几分钟就能定位到对应命令,不要指望一个命令在老版本和新版本间完全通用。
2.3 局域网协作:让团队连进你的服务器
Superpowers最吸引我的一点就是多人协作是原生能力,而且用起来极其简单。只要主服务器所在电脑的防火墙允许4237端口的入站连接,同一局域网内的同事就能在浏览器地址栏输入http://服务器IP:4237直接进入编辑器。所谓“服务器IP”,就是在启动服务的那台机器上通过ipconfig(Windows)或ifconfig(Linux)查到的局域网地址。
如果你希望不同网络的伙伴也能连接进来,一般需要在你家或公司路由器的端口转发设置里把4237端口指向这台服务器的内网IP。这个步骤属于局域网设备和网络常识,照着路由器后台的“端口转发”或“虚拟服务器”条目填一下即可。需要注意,端口转发之后一定要确认服务器本身启用了系统防火墙的放行规则,否则外部访问依然会被拦在门外。数据安全方面,建议在正式团队协作前修改默认端口号,并把管理员密码设置得足够健壮,避免陌生设备扫描到你的服务后白嫖你的存储空间和带宽。
2.4 配置文件修改与自定义
Superpowers服务端的配置文件一般放在server目录下的config.json里。里面有几个字段是我每次搭建团队服务器时都会调整的:一是端口号,我把默认的4237改成了自己团队约定的端口,减少被扫描到的概率;二是身份密钥,这个字段相当于服务的“签名”,如果你不想覆盖之前的数据,就不要随意改动;三是实例显示名称,用于在编辑器的登录页面上展示“XX工作室游戏开发服务”之类的标识,团队成员一眼就能确认自己连对了服务器。
修改配置文件前记得先停掉服务,改完再重新启动,否则改动不会生效。还有一个容易被忽略的点:如果你有多台机器同时跑同一个Superpowers服务,一定要确认各机器上的身份密钥一致且项目数据做了同步,否则会出现两台机器各存一份数据、互相覆盖的混乱局面。我通常直接用Git来同步server端的storage目录,每次启动前先拉取最新数据,这样可以最大程度降低风险。
3. 编辑器与核心玩法实操
3.1 界面布局与基本操作
第一次打开Superpowers编辑器,界面其实挺清爽的。顶部是工具栏,包含播放/停止、保存、撤销重做、当前用户列表等功能;左侧是资源管理器,项目里的场景、贴图、模型、脚本、音频都按文件夹形式组织;中央大区域就是三维场景视图,所有的物体摆放和视角操作都在这里完成;右侧是属性面板,当你选中场景中的某个实体时,它的位置、旋转、缩放以及挂载的组件都会出现在这里,类似Unity的Inspector面板。
基础操作逻辑也和主流三维软件一致:按住鼠标右键拖动是旋转视角,按住鼠标中键或Shift+右键拖动是平移视角,滚动滚轮是缩放。想要在场景里创建一个立方体,就在左侧资源列表里找到基本几何体资源,往场景视图中拖拽即可。选中物体之后,顶部工具栏会出现移动、旋转、缩放三种变换工具,点击后视图里会出现对应的操控手柄,拖动手柄就能精确调整物体到想要的位置。
初次上手时最容易困惑的是“场景”和“实体”的关系。在Superpowers里,一个场景保存的是这个关卡的根节点和所有实体层级;实体则是场景内一个个具体的对象,可以是一个方块、一架摄影机、一盏灯,甚至是一个空节点,脚本就通过挂载到实体上来控制游戏行为。理解了这两个概念,后面的编辑工作基本都能顺下来。
3.2 可视化脚本:拖拖拉拉做游戏逻辑
Superpowers的可视化脚本是我带新手入坑时最常用到的功能,因为它真的能让一个没写过代码的人在一个下午内做出可交互的小游戏。在资源管理器里右键创建一个可视化脚本,然后双击打开,会看到一个类似节点图编辑器的界面。左侧有一个节点库,里面列出了各种事件节点、条件判断节点、数学运算节点和游戏控制节点,用鼠标把它们拖到画布上,再把端口之间连线,就构成了动静皆宜的逻辑链路。
举个最常见的例子:你想做一个“点击屏幕里的方块就让它消失”的效果。你只需要在可视化脚本里拖入一个“开始”事件节点,拖入一个“点击拾取”事件节点,再拖入一个“销毁实体”的操作节点,然后把“点击拾取”的输出端口连接到“销毁实体”的执行端口即可。整个过程不需要写一行代码,更多的是像拼积木一样思考“什么触发了什么、什么影响了什么”。
对于完全没有程序概念的初学者,我会这样解释可视化脚本的思维模式:把程序的运行想象成水流,事件节点就是水龙头,当你按下键盘或点击鼠标时,水龙头被拧开,水流顺着连线流到下一个节点,再触发那边的操作。只要把这种“事件-响应”的思维建立起来,再去看传统代码,很多基础概念其实就已经打通了。我自己带过几个零基础的学员,都是先玩一周可视化脚本,再去学TypeScript,接受速度明显比直接学代码快得多。
3.3 TypeScript脚本:从组件到完整的后端逻辑
当可视化脚本遇到复杂逻辑变得力不从心时,就该切换到文本脚本了。Superpowers的文本脚本基于TypeScript语言——简单说就是在JavaScript的基础上加了类型系统,写起来不仅有代码补全,还能在编译阶段就发现很多低级错误。创建方式同样是在资源管理器里右键新建脚本,选择文本脚本类型,然后编辑器会帮你生成一个类模板,你在这个类里写具体的游戏逻辑代码。
以“让物体自动旋转”这样一个最基础的操作为例,一个简单脚本的核心结构大致长这样(不同版本的API名称会略有差异,但思路是相通的):
class Spinner extends Sup.Class { update() { this.actor.localEulerAngles.y += 0.02; } }这里update方法会在每一帧被调用,this.actor指的就是脚本所挂载的那个实体。把这段脚本保存之后,拖拽到场景里的一个方块实体上,点击播放按钮,就能看到方块在场景里缓缓旋转。这背后其实隐藏了一个很重要的概念:脚本本身只是一段逻辑,它必须“挂在”某个实体上才有意义,这就好比演员的剧本必须由某个角色去演,剧情才会发生。
文本脚本里除了可以控制物体的变换,还能访问摄影机、灯光、声音、输入状态,甚至可以定义公共属性,让其他协作者在属性面板里直接调整参数而不需要改动代码。这一点在做玩法调节时特别有用:你可以把移动速度、跳跃高度、物理重量等数值都暴露成属性,团队成员在编辑器里边试边调,不用反复改代码重新编译。对于多人协作来说,这种“代码与参数分离”的设计能有效减少团队间的频繁打扰。
3.4 资源导入与场景搭建
一个空荡荡的编辑器是撑不起完整游戏的,所以资源导入必须熟练。Superpowers支持的常见资源的格式包括:贴图方面支持PNG、JPG、DDS等,模型方面经常用OBJ和DAE,音频则是MP3和OGG。导入操作很简单,在资源管理器里右键选择导入文件,或者直接把文件拖进编辑器窗口,服务端会自动把资源传输到项目存储里。
做场景搭建时,资源管理器里的文件夹结构就成了一种隐形的约束。我一般会建立Assets、Models、Textures、Scripts、Audio这几个一级目录,每个目录下面再按玩法模块划分二级目录。这样做的最大好处是多人协作者找东西的时候不需要问来问去,一眼就能看到资源在哪。还有一个很实用的小习惯:文件名不要使用中文和空格,一律使用英文加下划线。Superpowers对中文资源名的兼容性虽然比从前好,但遇到某些浏览器缓存或网络传输环节,中文文件名偶尔会出幺蛾子,为这点小事浪费半个小时的排查时间完全不值。
场景搭建有一个很关键的“层次结构”概念:物体之间可以存在父子关系。比如一个角色的身体是父节点,左右手是两个子节点,当你移动身体时左右手会跟着一起移动,而单独移动手不会影响身体。这种结构在制作角色动画、机甲组装、建筑模块化搭建时非常有用,相当于给你的场景建立了一棵有组织的关系树。撑握了这部分,后面的玩法设计和动画控制就会顺手很多。
4. 协作开发:像写在线文档一样做游戏
4.1 多人在线编辑的体验
Superpowers最打动我的功能绝对就是实时协作。我第一次带着两个朋友在同一台服务器上开启一个项目时,三台电脑的屏幕同时显示着同一个场景,各自的鼠标光标和选中高亮在场景里同步移动,那种感觉真的就像三五个人同时在一个Google文档里打字一样顺滑。每个人新建的资源、挪动的位置、写好的脚本,别人几乎在同一秒就能看到结果。
这种模式对开发节奏的帮助是巨大的。没有“你改完了吗?我拉一下你的分支”这类繁琐对话,也没有“我本地运行不起你的代码”这种环境差异问题,因为所有人的运行环境都是同一台服务器,资源更新是即时同步的。尤其是做游戏玩法调校的时候,负责场景的人在右边摆地形,负责逻辑的人在左边写脚本,负责资源的人在资源管理器里不断上传新贴图,三个人在同一个画面里并行推进,整个项目的推进速度会被拉得很高。
当然也有需要注意的地方。实时协作的本质是“谁都能改一切”,如果没有约定,很容易出现A挪了B精心摆放的道具、C把D正在调参的脚本拖到了别处这种“好心办坏事”的情况。我一般在项目启动时会和团队明确分工:场景布局以一个人为主,其他人需要新增道具时先放在单独的文件夹里;脚本文件按功能模块分组,每个人只认领自己负责的那几个文件。约定虽然简单,但能省下大量的沟通成本和返工时间。
4.2 权限管理与用户体系
Superpowers的服务器是支持用户注册和权限管理的。服务器管理员登录后台后,可以查看所有已注册的用户并执行批准操作。在默认配置下,新用户注册后不会直接获得全部权限,而是需要管理员手动激活,这样才能防止陌生用户进入项目乱搞。我在团队服务器上会把所有人的账号先批量创建好,然后把对应的权限组划分清楚:策划只给资源和场景编辑权限,程序只给脚本目录权限,资管只给上传目录权限。避免“一人改坏,全员返工”的最快办法,其实不是事后追责,而是事前就划分好边界。
但要注意一点:项目的协作者权限范围和服务器用户权限范围是两码事。你可以先让用户成为这台服务器的成员,再在具体项目设置里为他配置项目级权限。如果一个用户被加入了A项目但没有被加入B项目,那么他打开B项目时会被拒绝,看到的就是“无权限访问”之类的提示。这个颗粒度足够应付绝大多数小团队场景,不需要像大型公司那样做复杂的组织架构管理。
4.3 协作中的冲突处理与注意事项
既然所有人都能实时编辑,冲突怎么避免?Superpowers的做法是“改动即同步”,它是基于操作级别的实时同步,而不是基于文件级别的保存合并,所以一般不会出现“两个人同时保存产生冲突提示”的情况。但这不意味着完全没有风险。如果两个人同时对一个物体的位置属性做不同的修改,后一个操作会覆盖前一个操作,这在可视化上表现为物体连续跳动两下。所以,涉及高精度摆放操作的物体最好由一个人专管。
另一个常见的协作问题是“历史操作不可追溯”。Superpowers不像SVN或Git那样有完整的版本历史回溯,如果你误删了一个重要实体且没有及时发现,再想通过历史记录找回是比较麻烦的。我的习惯是每天结束前对项目storage目录做一次压缩备份,重要关卡做大幅度改动前也留一个备份包,这样即便出现灾难性误操作,也能快速恢复到一个可用的状态。
协作模式还需要注意网络质量和带宽。虽然实时同步的数据量不大,但如果团队成员数量多且频繁上传大体积素材,服务器的上行带宽会成为瓶颈。我实操下来的经验是,一个正常规模的网页游戏项目控制在五六个人同时在线编辑比较舒适,再多的话建议分出第二个项目或者错峰编辑,不必强求所有人都在同一个项目里挤着。
5. 常见问题与避坑实录
5.1 安装与启动篇
很多人第一次启动Superpowers时会卡在“访问localhost:4237白屏”这一步,排查时先不要怀疑服务本身,优先检查浏览器的WebGL支持。可以访问一些测试WebGL是否开启的页面,或者直接在浏览器地址栏输入chrome://gpu(Chromium内核)查看状态,如果GPU加速被禁用,Superpowers的渲染就会失败,表现为页面白屏或黑屏。解决办法是在浏览器设置里开启硬件加速,或者换一台显卡驱动正常、显存足够的机器。
还有一类问题出现在旧版本Node环境下:服务启动后终端直接报错,提示某个原生模块无法加载。这时候最快的处理方案是把Node版本切换到当年Superpowers版本对应的版本区间。不要试图用新版Node强行兼容,很多原生模块在Node大版本升级后就不再重新编译,最容易出现的坑就是这些模块报 “invalid ELF header” 或 “module version mismatch”。换Node版本用nvm操作非常快,一般五分钟内能搞定。
端口被占用也是个高频问题。如果你本地已经跑着其他Web服务,4237可能被某些应用悄悄占用。排查方法是先停掉Superpowers,再用netstat -ano | findstr 4237(Windows)或lsof -i :4237(Linux/macOS)查看是谁占用了端口,找到之后再决定是杀掉相应进程还是修改Superpowers配置文件换个端口。
5.2 渲染与性能篇
WebGL渲染天然受制于浏览器的内存和显卡能力,使用过程中性能问题需要提前预防。在编辑大场景时如果掉帧严重,首先检查场景里的实时光源数量。Superpowers的实时渲染对多光源支持有限,一个场景里放着四五个动态点光源,帧率会明显下滑。我的做法是用两到三个关键光源做主照明,其他装饰性光源全部去掉,或者在材质里用贴图来模拟光照效果,这样画面感受损失不大,性能却提升明显。
阴影质量也是性能杀手。默认设置下阴影分辨率可能开得比较高,在大场景里会让帧率断崖式下降。我通常会在场景并不复杂的原型阶段直接关闭阴影,等到需要展示效果时再按需打开。还有一个容易忽略的性能问题出在模型面数上:直接从外部导入的高精度模型可能带着上百万顶点,浏览器渲染起来非常吃力。建议在外部工具里先把模型减面到必要程度,再导入Superpowers使用,切忌“高模硬塞”。
粒子系统和高频脚本循环也需要留意。给粒子系统设置过多数量的粒子,或者在一个帧循环里执行高开销的逻辑,例如每帧遍历所有实体做碰撞检测,在Web端很容易把CPU打满。对于原型项目来说,优先保证流畅度比追求华丽效果重要得多,能简化就简化。
5.3 协作网络篇
团队协作时最常遇到的问题就是“我怎么访问不了服务器”。如果现场是在同一局域网内并确认地址没错,第一反应应该是查看启动服务那台机器的防火墙入站规则。我遇到过很多次局面:服务正常在跑,但防火墙没有放行对应端口,导致其他成员完全连不上。在Windows上手动添加一条“允许TCP端口连接”的规则,或者把问题端口加入白名单,通常就能立刻解决。
如果团队成员分散在不同的地点,就需要依赖路由器的端口转发功能。但要注意,有些家用路由器默认开启了“AP隔离”或“客户端隔离”功能,它会阻止设备之间的互访,这个设置偶尔会让端口转发失效。此外,在修改路由器配置后,最好用手机4G/5G网络从外网测一次连接(不连家里的Wi-Fi),避免误判为“已经生效”。
还有一种隐蔽的问题是本地缓存错乱。成员A在旧版本里打开了项目,此时开发者改了项目结构或资源名,A的浏览器缓存可能还停留在旧状态,导致出现“看不见别人新建的资源”或“打开项目报一堆错误”的现象。这种问题的常规解法是让A强制刷新页面(Ctrl+Shift+R)或者清一次浏览器缓存,一般都能恢复正常。
5.4 资源导入篇
OBJ模型导入后出现破面、缺贴图是新手经常碰到的。OBJ格式本身只是记录了顶点坐标和面索引,贴图是配套的MTL文件在描述,所以你导入模型时需要把OBJ文件、MTL文件和贴图文件放在同一个文件夹里,再一起导入,否则模型可能丢失材质贴图。这时候去检查资源管理器里是不是有灰色材质,基本就说明贴图映射缺失了。
音频资源方面,最常遇到的是格式不支持。Superpowers对音频格式的支持偏向OGG和MP3,如果你手头只有WAV或M4A,建议先用音频软件转换成支持的格式再导入。我自己的经验是,体积大、时长长的背景音乐尽量压缩成OGG或MP3,体积小、触发密集的音效则可以用稍高一点的码率,以保证响应速度。
最后是关于资源文件命名的忠告:不要使用中文、不要使用空格、不要以数字开头。这个问题虽然看起来老生常谈,但它确实是资源导入失败里最常见的原因之一。我早期把所有模型命名为“测试_01”之类的混合格式,结果每次导入都随机失败一部分,排查了半天才发现是文件名编码在服务端传输时出了问题。把文件名全部改成test_01.obj这样的规范格式之后,一次导入就全部成功了。
6. 我的长期使用体会与扩展玩法
用了很长时间之后,我对Superpowers的感情可以说是又爱又恨。爱的是它把“做游戏”的门槛压到了一个相当低的位置,恨的是它的生态和性能天花板摆在那里,不可能成为所有项目的终点。但我个人在实际使用中的体会是:它适合当一个“空间站”,让团队的创意先在低重力环境里快速成形,然后再决定要不要把成熟的项目降落到Unity或者Godot这些更重型的“行星”上。
如果让我给别人推荐使用路径,我会这样建议:先用Superpowers做完一整个可以玩的小原型,验证核心玩法的乐趣;然后把场景内容、资源清单、玩法逻辑写成文档,再进入商业引擎正式开发。这个流程里的Superpowers承担的是“创意筛选器”的角色,它的实时协作和低门槛让它非常适合这个职能。事实上,我见过好几个小团队靠着这种流程,在正式开工前就砍掉了一半不靠谱的玩法点子,省下了大量人力物力。
最后一个分享的小技巧是:如果你同时教多个学生或者管理多个项目,可以在一台配置稍好的服务器上运行多套Superpowers服务,每套服务用不同端口,再配合文件夹命名把项目隔离开来。这样一台机器就能支撑起一个班级的并行开发,学生各自访问自己的端口,互不干扰。我用这个方式带过一轮暑期课程,整个过程中没有出现一次学生项目被其他人误改的混乱,基本可以放心把这种模式复制给任何有类似需求的朋友。