泡饭工坊项目流程
泡饭工坊介绍
泡饭工坊是什么?
泡饭是一套网页虚拟环境下的代码编辑工具,内嵌了多种预设和模板,集成了vscode来编辑代码,自动编译,可以方便的预览和分享给小伙伴体验。
泡饭链接
[链接](https://webdev.popx.com)
泡饭账号注册登录
没账号的需要在泡饭注册账号
点击左上角个人信息
点击注册
注册页面
请记住您的账号密码,这关系到后续我们管理您的使用权限
和我们内部人员沟通,申请后台权限
如需开通后台使用权限,将您的账号告知我们内部人员帮操作,等待通知完成后,重新刷新网页即可
第一次需要创建一个工程
有了工程后,打开工程
打开泡饭体验项目
参考视频泡饭下载模板[1]
参考视频泡饭运行模板[2]
如何用泡饭开发自己的项目
点击跳转后台
就第一次需要创建打开一个工程,才能出现地图编辑器的跳转页面
后台创建游戏,绑定地图
- 需要泡饭跳转到后台,去新建游戏,生成独属于你的gameid和secret,这在后续的开发和上传时至关重要,请点击下方超链接,去参考其中新建gameid的部分
- 请看该链接中,新建游戏玩法的部分
修改package.json进入自己的游戏和地图
- 点击左侧修改配置按钮
- gameid 开发者后台中指定的游戏玩法
- secretkey 游戏玩法对应的密钥
- defaultMap 游戏玩法中,指定的地图,请在后台至少指定一张,默认填写"地图_0"
- sdkVersion sdk版本号,点击修改可以弹出下拉框,一般选用release标签的稳定版本,修改后,会去修改对应的bridge依赖,并且下载
- resVersion 美术资源版本号,会影响游戏内地图和模型的显示,一般选用最新的版本即可
首次运行需要先发布
当前的gameid是最新的,
目前后台服务器还没有一个初始版本的记录,所以需要在package.json中,修改完gameid之后。
首次运行要发布游戏(后续不需要每次发布,直接保存就可以编译调试)。
等待右上脚提示发布完成,即可启动进入游戏
启动项目
一般选用启动游戏(服务器模式)
登录界面
- 运行后,浏览器将显示登陆界面。
- 账号密码随便输入,会创建新账号
- 输入账号密码后,选择指定地图(可选),即可看到战斗服务器世界中有自己的人物。
- 默认的demo工程中,如果没有修改gameid和secretKey,地图请填写"地图_0"
泡饭模板的多人合作
发布模板
设置团队成员权限和名称
发布后管理项目
发布后可以在商店模板里去修改自己发布的项目。
其他成员就可以在模板商店拉取模板了
比如上图中的playername1的账号,就可以拉取模板了
打开项目
点击编辑按钮,切换到vscode运行环境。
团队成员修改提交
我们尝试写第一行代码提交下
具体在vscode中,怎么使用git来提交和拉取,可以参考如下文档
[vscode使用git插件](https://blog.csdn.net/khhmd/article/details/144131405)
多人合作冲突的解决(遇到冲突再看,可以先跳过)
选择远端的master分支来merge
根据需求去修改冲突文件
冲突文件修改完成,resolve
同步到远端
前端基础逻辑
根据以下步骤,一步步进入泡泡的游戏世界,即使你是新手也无需担心。
前端游戏入口
- /src/client/index.ts 文件中的 `XPopManager.onGameStart` 是前端的主要入口点。
创建第一个人物
在 `simpleGame` 类中,我们将创建并初始化第一个游戏人物。
export class simpleGame { private firstModel: XModelHero; constructor() { // 创建第一个人物 this.firstModel = new XModelHero(); let path = 'role/model_avatar_body_default'; // 加载人物模型并播放动画 this.firstModel.loadModel(path, null, this, (success) => { // 播放跑步动画 let actName = "act_avatar_base_run"; this.firstModel.playAniUp(`${actName}_up`); this.firstModel.playAniDown(`${actName}_down`); // 摄像机跟随 let camera = XPopManager.instance.xScene.camera; camera.focus = this.firstModel; // 定时更新人物位置 XTimer.loop(100, this, this.updateModelPos.bind(this)); }); } updateModelPos(delta: number, frame?: string) { // 更新人物位置 this.firstModel.position.x += 0.1; } } // 设置游戏启动时执行 XPopManager.onGameStart = () => { new simpleGame(); }
- 注意:请将原代码中的 new Main() 替换为 new simpleGame();
上述的代码我们以最简单的方式,去掉一切服务器交互,添加一个基础模型到游戏中跑动
再提醒一次,每次有代码修改后,运行前需调用命令进行编译 #编译
播放人物的动作
我们的人物有上下半身,在知道动画名字的情况下,需要分上下半身来播放动画
以'act_avatar_plant_collect'为例
let animbaseStr = 'act_avatar_plant_collect'; role.model.playAniUp(`${animbaseStr}_up`); role.model.playAniDown(`${animbaseStr}_down`);
那么如何快速查看已有哪些动画呢?
添加按键控制
看demo中的代码,提供了一个MoveComponent类 摇杆的显示资源放在res-extra目录中
以下是示例中添加摇杆控制的代码
//摇杆背景 let rocker = new XImage('res-extra/imgs/stick_bg.png'); rocker.width = rocker.height = 164; rocker.pivotX = rocker.pivotY = 82; rocker.pos(178, -198); leftbottom.addChild(rocker); //摇杆方向 let imgdir = new XImage('res-extra/imgs/stick_dir.png'); imgdir.centerX = imgdir.centerY = 0; imgdir.anchorX = imgdir.anchorY = 0.5; imgdir.name = "dir"; rocker.addChild(imgdir); //摇杆中心点 let node = new XImage('res-extra/imgs/stick_rocker.png'); node.centerX = node.centerY = 0; node.anchorX = node.anchorY = 0.5; node.name = "node"; rocker.addChild(node); //移动 let hero = this.heros.get(this.roleIndex); if (hero) { let movecomponent = rocker.addComponent(MoveComponent) as MoveComponent; movecomponent.init(hero, ctrlayer, rocker); }
示例中,添加了一个触摸区域挂载在根节点的左下角,触摸反馈会根据XEvent来传递给节点 代码中根据摇杆方向变化来控制人物移动 其中涉及了部分修改玩家状态的服务器代码,可以先忽略
摄像机的跟随
代码中,摄像机跟随人物移动,只需要简单的一行
let hero = new Xmodel(); //这是全局的摄像机 XPopManager.instance.xScene.camera.focus = hero;
摄像机的旋转视角,demo中也提供了一个类CameraComponent 和摇杆的节点类似,通过XEvent来传递点击事件, 根据点击事件的拖动,来修改摄像机的旋转视角 xcamera.rotate
private onCtrlMouseMove(e: XEvent): void { if(this._touchId != e.touchId) return; let xcamera = XPopManager.instance.xScene.camera as XCamera; if(!xcamera)return; if(this._mouseX == 0) this._mouseX = e.stageX; if(this._mouseY == 0) this._mouseY = e.stageY; let offx = e.stageX-this._mouseX; let offy = e.stageY-this._mouseY; this._mouseX = e.stageX; this._mouseY = e.stageY; xcamera.rotate(offx, offy); }
砖块说明
如图所示,我们的世界地图由若干个方形大地块组成,
每个地块里,可以划分成32*32的平面坐标,一层层叠高,可以有64层高,
转化为三维坐标系就是32*64*32,对应xyz轴,
地块上,可以添加以坐标为单位的砖块。
其中,cubeId表示砖块的类型,比如草地就是id为1的砖块,该砖块具有可以踩踏行走的特性。
某些其他的砖块具有别的特性,都通过cubeid来区分,当开发者接触地图编辑器时,就会有所了解。
我们以Demo中,MoveComponent中的一段代码来参考
// 游戏世界地图 let scene = XPopManager.instance.xScene; // 判断水平方向是否有砖块 // 根据坐标位置,找到世界中,其坐标对应的砖块id let cubeid = scene.getCube(dir.x ,position.y, dir.z) if(cubeid){ // 根据砖块id,找到砖块的类型,判断其是否和人物碰撞阻挡 scene.getCubeInfo(cubeid, this.cubeInfo); if(this.cubeInfo.collisionPlayer){ dir.x = position.x; dir.z = position.z; } } //如果没有砖块或者有无阻挡砖块,给一个向下的位移 cubeid = scene.getCube(dir.x ,position.y-0.1, dir.z) if(cubeid){ scene.getCubeInfo(cubeid, this.cubeInfo); if(!this.cubeInfo.collisionPlayer){ dir.y = position.y-0.1; } }else{ dir.y = position.y-0.1; }
- 再以图中为例,v3的坐标代表了地图上的位置,(24,3,26)
- 如果需要设置模型在地图上的位置,用如下代码
let pos = new XVector3(x,y,z); xModel.position = pos;
资源加载说明
演示加载图片
// 测试加载图片 // 创建一个全屏的挂载UI层 let mainui = new XImage(); mainui.left = mainui.right = mainui.top = mainui.bottom = 0; XPopManager.rootNode.addChild(mainui); // 图片路径,如果是本地的额外资源,就加上"res-extra/"前缀,否则就是远端资源 let path = 'avatarstart/ball_btn2.png'; // 创建图片 let img = new XImage(path); // 添加到父节点显示 mainui.addChild(img); // 设置位置 img.left = img.top = 100;
编译,运行后,可以看到,添加了指定的图片
公共资源
PGT为开发者提供了很多基础的图片,模型,音频等等的资源。
怎么查看有哪些公共资源呢?
- 打开项目目录下的package.json文件
学会查看远端json文件地址
查看pacakge.json
- 查看当前的远端资源版本,比如"resVersion": "1.0.15",
- 具体有哪些资源版本可用如下命令
查看资源版本列表:npm run reslist (只包含正式发布的版本)
查看所有资源版本列表:npm run reslistall
- 如果用的泡饭工坊,直接在配制节目选择下拉框即可查看
- 把下面链接里的v1.0.15替换成和你目前版本一致的数字,就可以查看远端资源列表
resVersion
如下是1.0.5版本的资源列表,可以修改数字查找不同版本
[远端文件列表json](https://h5ppreview.jumpw.com/popion/popx-res/version-1.0.5.json)
确认好resVersion和远程链接
在上述json文件中,可以搜索文件名,来判断资源在不在美术包里
查看json文件
- json文件左侧是游戏内加载的路径,右侧是实际的打过md5值的网络路径
这就是我们刚刚演示的加载图片
avatarstart/ball_btn2.png": "avatarstart/ball_btn2-2c717f83a3.png
- 游戏内我们通过加载接口去加载左侧路径
- 游戏外,直接在刚刚的cdnUrl后拼接带md5值的完整路径即可查看
[查看网络资源](https://h5ppreview.jumpw.com/popion/sdk/v1.0.17/avatarstart/ball_btn2-2c717f83a3.png)
- 音频文件同理,模型文件直接游戏内调用接口显示
额外资源
最基础的demo中,会看到用于演示的摇杆资源是放在res-extra目录下的。
一般来说,开发者的一些特制UI,图形,可以放在这里。
加载时在路径前加上"res-extra/"即可。
- 注意,我们目前不支持第三方模型文件,模型必须提交审核,不放在res-extra中
模型查看器
- 除了图片资源外,为了方便开发者使用,我们额外做了一个模型查看器
UI界面开发
git拉取ui工程到本地
泡饭的项目发布后获取到了git地址
查看git密钥
使用accesstoken来拉取项目到本地
常见的git工具中
git clone 地址
输入泡饭账号和accesstoken即可拉取,注意不是泡饭的密码,是token
没有工具时用命令拉取说明
安装本地ui的编辑环境
laya 版本 v2.13.1
- [laya官方ide](https://ldc2.layabox.com/layadownload/?type=layaairide-LayaAir%20IDE%202.13.1)
安装项目自定义封装的cmd命令库
- 推荐安装方式:
npm i popxcmd -g --registry https://registry.popx.com
node 版本 v10.24.1
- 必须使用指定的nodejs版本 ,推荐安装nvm以自由转换node版本。
- [nvm下载及安装方式](https://blog.csdn.net/ppz8823/article/details/130862191)
- 记得nvm需要换源,否则后续安装可能会出错,按照下述操作
- 最下面两行修改node和npm的镜像地址
node_mirror: https://npmmirror.com/mirrors/node/ npm_mirror: https://npmmirror.com/mirrors/npm/
- 安装nvm后,命令行运行如下命令切换到node版本v10.24.1,一步步来:
// 安装 nvm install 10.24.1 // 等待安装完成后,切换 nvm use 10.24.1
- nodejs也需要用下面的命令来换源,修改镜像地址
npm config set registry https://registry.popx.com/
修改host文件
- 找到host文件,一般在`C:\WINDOWS\system32\drivers\etc`目录下。 - 在文件末尾添加:
199.232.68.133 raw.githubusercontent.com
npm i
项目工程中,npm i,安装依赖
在编辑器中创建UI
如果开发者有额外的ui交互需求,希望在IDE中自己拼接UI
可以在指定目录下,去添加资源,一般来说,拼接scene即可,scene用到的资源要放在如下的指定目录中
- ui_laya/laya/ - 开发者可以自由扩展的ui资源目录
* ui_laya/laya/pages - 开发者创建的.scene文件目录 * ui_laya/laya/assets/uiextra - secne文件中引用到的各种美术资源,包括音频和动画
打开Laya工程
使用指定版本的Laya编辑器打开 `demo/ui_laya/ui_laya.laya` 项目。
添加.scene界面
在编辑器中,可以添加一个新的scene界面,并在其上放置UI元素。
界面添加UI组件
例如,添加一个名为 `btnFirst` 的按钮,并确保其 `var` 属性有值,以便后续导出。
添加后,记得保存,ctrl+S
额外资源的添加
注意,所有上述scene中用到的美术资源,必须放在Assets/uiextra/ 目录下
否则导出ui时会失败
运行生成UI命令
在命令行中运行以下命令来生成UI代码:
npm run ui
-运行后,会在client目录代码中,生成对应的XUIComponent类,
-运行后,会更新res-extra文件夹下的fileconfig.json,该文件会把额外的资源列表记录下来
运行成功后,生成的UI类将位于 `src/ui/popxMaxUI.ts` 文件中。
其中,添加了一个和scene名相同的UI类, 并且,var有值的组件也一起生成了对应属性。
每次在调用命令,npm run ui时,会更新上述的fileconfig.json文件。
- 注意,UI资源使用前,要调用如下固定代码开启合图资源的配置,建议参考demo,在游戏入口就初始化调用一次
XResManager.instance.enableAtlas("res-extra/fileconfig.json",()=>{ // 可以调用额外资源了 });
修改后的资源,git上传到远端
注意:提交的文件里,最终要检查下如下内容,才能保证正常泡饭中正常使用。
1.修改后的ui内容,比如修改了mainUI.scene,对应的,在res-extra/ui文件夹下,mainUI.json就会有修改
2.res-extra目录里,有刚刚通过npm run ui 命令,拷贝过来的laya工程中的文件。
3.fileconfig.json里,有那些新增和改动的文件的配置。
上传后,泡饭即可使用
先git commit提交 注意推送时要用如下命令
git push --force
如果弹出输入框,账号输入泡饭账号名,密码输入accesstoken
代码控制XUIComponent
注册UI类的控制文件
使用 `PopxBridge.regUIClass()` 方法在相应的类中注册UI类,并处理UI相关的按键逻辑。
//注册自定义的ui类 PopxBridge.regUIClass(DemoUI.getClassName(), DemoUI);
以下是我们新加UI的最基础代码,在界面显示的时候,注册点击事件,点击后打印日志
export class DemoUI extends uiextra.demoUIUI{ constructor(){ super(); } onAwake(): void { } onEnable(): void { // 设置在顶层可以被点击 this.zOrder = 1; this.first_btn.on(XEvent.CLICK, this, this.onClickFirstBtn); } private onClickFirstBtn(e:XEvent){ console.log("click first btn"); } }
代码调用显示UI
通过 `xUiManager.instance.openUI()` 方法来调用并显示UI界面。
// 加载对应的json文件路径,并挂载在指定父节点上 XUiManager.instance.openUI('res-extra/ui/demoUI', XPopManager.rootNode);
-编译,运行
代码调用加载组件
- 某些界面上的元素,比如卡牌,也可以类似做成一个scene,运行npm run ui 自动生成类
- 比如类名为CardView
- 注册和UI注册类似
PopxBridge.regUIClass(CardView.getClassName(), CardView);
- 创建时,调用`XUiManager.instance.createView`
XUiManager.instance.createView(path,parent,this.onLoadCardView,showData); onLoadCardView(view:XUIComponent) { }
前后端数据交互
该篇会讲述服务器和前端的数据同步,如果想要先了解项目目录和工作流,建议先参考如下篇幅 #主要工程目录
进入房间(游戏世界)
如下是最基本的开发登录流程说明
步骤 | 描述 | 流向 |
---|---|---|
开始 | 流程的开始 | -> 登录页面 |
登录页面 | 账号密码,选定地图,输入房间号(可不填) | -> 远端服务器(官方) |
远端服务器(官方) | 获取玩家账户信息,分配到房间,房间就是我们的host代码 | -> Client 和 -> Host |
Client | 监听XPopManager.onGameStart | -> 前端逻辑开始 |
Host | 监听XPopManager.onHostStart | -> 房间战斗逻辑开始 |
远端服务器(官方)会处理最基本的登录,分配房间,创建游戏世界的逻辑,并且同步该世界中的游戏数据。
通过XpopManager管理类,来向Client和Host抛出事件,开发者可以监听这些事件做处理。
开发者需要关心的逻辑,就是Clint和Server(上图中Host)目录下的代码。
前后端协议交互
项目采用proto来做相互通信
前后端共用配置
前端src/client目录和后端src/server目录中,都可以调用如下代码来加载所有的表格配置
CsvManager.ins.loadCsvs(this, () => { // Do some thing after load });
表格的加载逻辑和解析逻辑,可以参考CsvManager中的代码 src/shared/csv/CsvManager.ts
如何新增配置?
以demo中的item.csv为例.
- 1.配置csv文件资源的根目录为res-extra/csv/ ,在里面添加item.csv
- 2.CsvManager.ts文件中,添加读取表格和解析表格的逻辑
// loadCsvs代码中,添加你需要解析的csv名称 public loadCsvs(caller: any = null, listener: Function = null) { let assets = [ this._prefix + "item.csv", ]; // XResManager加载本地资源 XResManager.instance.loadText(assets, () => { // 在加载完成的回调中,处理表格数据结构,生成CItemData,不再赘述 this.onCompleted(caller, listener); }); }
- 3.解析表格得到的CItemData结构,定义在src/shared/dataMgr/中,可以被前后端一起调用
- 4.如果是加载json文件,用XResManager.instance.loadText
玩家战斗数据快照
游戏战斗服务器中,每个玩家的实时信息,通过快照来更新
XVF_SnapData
以demo中的Snap_UserData.ts为例
- 该玩家数据中类中,包含的各种public变量,都是XVF_SnapData接口类型
export class Snap_UserData { //坐标旋转 public position: XVF_SnapData<SyncPos>; //状态 public state: XVF_SnapData<SyncState>; //hp public hp: XVF_SnapData<number>; }
快照类型数据,前端负责注册和监听,服务器负责修改
- 每次该接口类型的数据发生变化时,会调用OnSet方法,这类数据的修改逻辑是:服务器修改,前端监听变化
- 前端登录成功后,服务器注册对应玩家数据
- 前端对数据中的某个XVF_SnapData做监听,注册OnSet方法
- 服务器战斗逻辑修改了该数据时,前端根据OnSet的逻辑做表现处理
服务器先注册全局的快照
let userData = new Snap_UserData(); XPopManager.instance.xHost.RegisterSnapshot(`UserData${i}`, userData);
前端绑定同一个地址的快照
this._userData = new Snap_UserData(); XPopManager.instance.xRemote.RegisterSnapshot(`UserData${index}`, this._userData);
- XVF_SnapData数据,如果是复杂类型,需要调用UpdateData()方法,前端才能触发OnSet
如下的SyncState就是复杂类型
public state: XVF_SnapData<SyncState>; public setState(key:string, obj:string):void{ this.state.value.key = key; this.state.value.obj = obj; this.state.UpdateData(); }
- XVF_SnapData如果是基础类型,不需要调用UpdateData()
public hp: XVF_SnapData<number>; public setHP(hp:number):void { this.hp.value = hp; }
代码如何调试
前端调试
直接在网页上调试
f12打开控制台,
点击源代码,
可以根据代码目录结构找到想要断点的文件,
也可以快捷键"ctrl + p"输入文件名查找 (mac上是cmd + p),
找到后,点击具体左侧代码行数标签即可。
可以很方便的观察堆栈和变量信息
服务器调试
- 启动运行时,会弹出一个host弹窗服务器在调用命令npm run server后,会启动一个Host网页
- 只要是网页,那就能调试js代码
- 打开网页的开发者工具(一般浏览器是f12),找到index.js文件
- 该文件是由服务器代码入口index.ts编译生成的js文件,注意,不止是index.ts,里面相关的引用代码都会编进去
- 虽然代码经过编译,但是没有混淆,可以通过函数名,找到js代码中的行号,打断点
调试注意事项
- 每次npm run build后,如果修改了服务器代码,可以在本地host的浏览器里,立刻刷新,F5或者shift+f5
- 如果修改了编译脚本来调试服务器,记得最后打包上传前,把rollup的代码改回来
地图的制作和选取
地图制作导出
教学视频已经上传到网页链接
[新建地图](https://formalhead.popx.com/popxVedio/mapeditor/新建地图.mp4)
[地块操作](https://formalhead.popx.com/popxVedio/mapeditor/地块操作.mp4)
[地块(水)](https://formalhead.popx.com/popxVedio/mapeditor/地块(水).mp4)
[地形设置(增加)](https://formalhead.popx.com/popxVedio/mapeditor/地形设置(增加).mp4)
[新地编添加预制件和编辑](https://formalhead.popx.com/popxVedio/mapeditor/新地编添加预制件和编辑.mp4)
[预制件操作](https://formalhead.popx.com/popxVedio/mapeditor/预制件操作.mp4)
[授权给他人使用](https://formalhead.popx.com/popxVedio/mapeditor/授权.mp4)
[如何游戏内绑定后台玩法和地图](https://formalhead.popx.com/popxVedio/mapeditor/如何游戏内绑定后台玩法和地图.mp4)
开发环境选择地图
我们在登录界面,可以通过填写你gameid中的地图名字,来进入指定地图。
所以必须要先创建gameid,并且选择至少一张地图,该地图才能在调试时进入。
举例:
- 上传地图到某个游戏gameid时,会从你自己的可用地图中选择。
- 可用地图指的是你自己制作上传了地图。或者其他人共享给了你地图。
- 比如你的可用地图名字是"推箱子"。
- 右边会有可填写的自定义地图名字,比如"第一关"
那么登录的时候就是填写 "第一关"
- 也就是说,地图做完后,必须要在审核平台上,添加到玩法里,生成自定义的名字,才可以在测试时填写进去生效
上传|测试|提审|上线
点击发布后,会把构建生成的压缩包上传到远端,就可以去试玩了。
玩法测试
网页试玩链接
固定试玩链接为
[试玩链接](https://subgame.popx.com/popion/opendev.html)
随意输入账号密码登录,在游戏列表中找到游戏试玩。
真机测试
点击泡泡管理后台->地图编辑
游戏中选择版本管理->点击提审
过审后,就可以在 快手提审服 进行测试,测试资格可以和各自项目负责人对齐。
注意:如果是竖屏游戏,需要用APP版本,进入 提审服 进行真机测试。
游戏上线发布
项目目录
主要工程目录
对于开发者,需要关心和操作的目录如下:
- node_modules/ - 通过npm安装的PGC库文件,对外暴露的方法,可以通过bridge.d.ts来外部引用
- res-extra/ - 开发者除了PGC的远程资源外,需要额外使用到的资源目录,比如UI,图片,音频,表格,最后会打包上传到PGC远端资源服务器
- ui/ - 开发者自己在laya编辑器中,拼接的界面json文件,运行命令后,会转化为PGT指定的XUIComponent存放于此
- src/ - 开发者所有的战斗逻辑代码修改都在此进行
* src/client/ - 前端代码,入口文件index.ts,监听XPopManager.onGameStart,前端游戏逻辑 * src/server/ - 后端代码,入口文件index.ts,监听XPopManager.onHostStart,后端游戏逻辑 * src/shared/ - 前后端共用的数据结构,包括表格,协议,玩家数据
- dist/ - 编译后,生成的运行文件,包含前后端代码
* dist/client/ - 编译后生成的混淆的前端代码 * dist/host/ - 编译后服务端的代码文件,里面也包括表格数据的缓存
前后端协议通信生成
协议通信
该命令会用到tsrpc的proto协议, 把src/shared/protocols下的指定格式文件, 转换到src/shared/protocols/generated/serviceProto文件中,
- 文件名为:Ptl{接口名}.ts (Ptl 是 Protocol 的缩写,l是小写的L)
- 请求类型名为: Req{接口名},通过 interface 或 type 定义,需 export
- 响应类型名为:Res{接口名},通过 interface 或 type 定义,需 export
例如,添加PtlPosition.ts文件 文件代码如下
// 该接口用于向服务器同步自身的坐标 export interface ReqPosition { i: number; x: number; y: number; z: number; ry: number; } export interface ResPosition { ret: string; diy: string; }
serviceProto.ts中会增加可外部调用的api类型
export interface ServiceType { api: { "Position": { req: ReqPosition, res: ResPosition }, }, msg: { } }
前端代码调用请求
// 前端可以用promise语法来调用同步位置的Request,异步处理服务器的返回值 let remote = XPopManager.instance.xRemote; let ret = await remote.Request('Position', {i: 1, x:2, y:3, z:4, ry:5}); if(ret && ret.isSucc){ console.log(ret.res.diy) }
后端代码监听请求处理返回
// 服务器收到前端请求的处理返回RegisterRpc let host = XPopManager.instance.xHost; //当收到坐标变化请求 host.RegisterRpc("Position", async (call: ApiCall<ReqPosition, ResPosition>) => { let index = call.req.i; let userData = this.usersData.get(index); userData.setPosition(call.req.x, call.req.y, call.req.z, call.req.ry); return call.succ({ ret: "Success", diy: "自定义参数" }); });
如果想更多了解proto的结构和数据类型说明,可以参考官方链接 [tsrpc-proto格式说明](https://tsrpc.cn/docs/server/service-proto.html)
核心类目说明
XPopManager
Bridge.d.ts中的核心类
对游戏逻辑进行了结构化的拆封和管理,
可以理解为,
库文件内处理了各种玩家的逻辑,比如登录,加载地图,分配房间,快照数据同步等等,然后关键的几个节点,暴露给外部去执行游戏逻辑。
开发者只需要去编写独立游戏模块的代码,其中,Xremote暴露给前端处理,Xhost暴露给后端处理
下面是最重要的几个生命周期函数
- onGameStart
- 玩家已经完成了登录步骤,已经分配好了房间,通知前端游戏开始
- onHostStart
- 玩家已经完成了登录步骤,已经分配好了房间,通知后端游戏开始
- onGameOver
- 游戏结束(一般是玩家都离开了战斗房间)
- onUpdate
- 每一帧会调用更新
我们在demo中,index.ts里,可以给这几个方法监听绑定函数,输出日志就可以查看
XPopManager.onGameStart = ()=>{ new Main(); console.log("qc,XPopManager.onGameStart"); } XPopManager.onGameOver = () => { console.log("qc,XPopManager.onGameOver"); } XPopManager.onHostStart = () => { console.log("qc,XPopManager.onHostStart"); } XPopManager.onUpdate = () => { console.log("XPopManager.onUpdate"); }
XRemote(前端)
- 以下是最关键的生命周期和方法调用,调用逻辑可以自定义设计,后端代码同理
- UserID
- 玩家进入游戏的唯一id
- onUserEnter
- 每当房间内玩家进入时会调用,前端可以在此根据返回的userId来同步XHost玩家的快照数据,创建角色等等
- onUserLeave
- 每当房间内玩家离开时会调用,前端根据userId来处理模型的销毁
- RegisterSnapshot
- 用于注册绑定快照,快照类型开发者自定义,需要和XHost代码中绑定的地址一致,才可以收到OnSet回调
- Request
- 发送RPC请求,请求和回调的代码由protocol生成
XHost(后端)
- onUserEnter
- 每当房间内玩家进入时会调用,初始化玩家身上的快照数据,可以根据人数来判断游戏阶段,比如准备阶段
- onUserLeave
- 每当房间内玩家离开时会调用,清理玩家数据,可以根据玩家人数来判断是否进入结算或者游戏结束
- RegisterSnapshot
- 用于注册绑定快照,快照类型开发者自定义,需要和XRemote代码中绑定的地址一致
- RegisterRpc
- 注册RPC回调
XUIComponent(UI组件)
UI组件通过XUiManager.instance.OpenUI或者XUiManager.instance.CreateView加载显示
- showUI
- 调用后会设置active为true,当调用创建的方法,加载成功显示时也会调用一次,可以在创建时传参,每次主动调用也可以传参。
- hideUI
- 把该组件的active设置成false
- closeUI
- 把该组件从父节点移除,可以传参处理移除成功时的回调
XEventDispatcher(事件)
我们可以根据已有的XEventDispatcher来封装一个单例,这样就能外部夸文件调用事件了。 如下为演示封装的单例
export class EventManager extends XEventDispatcher{ constructor () { super(); } private static _instance: EventManager public static get instance(): EventManager { if (!this._instance) { this._instance = new EventManager(); } return this._instance; } }
事件的派发
EventManager.instance.dispatch("new_event_name", ...args);
事件的监听
EventManager.instance.add("new_event_name", this, this.ParseNewEvent); private ParseNewEvent(...args) { console.log("parse new event") }
泡饭实用工具
泡饭内置了实用的工具,方便外部使用,提高开发者效率
模型查看器
模型查看器会拉取最新的资源版本号,显示在左上角,
可以比较方便的查看模型,特效,动作等等的资源
AI对话
接入了deepseek-r1
泡饭账号可以直接登录,可以体验对话
AI语音生成
可以生成长的,短的音频文件
AI图转3d模型
可以上传2d图片,去生成glb格式和高斯格式的3d模型。
下载后,glb能通过blender去导入,转化成可用的fbx文件。
常见工作流问题
如何把本地的项目上传到泡饭
建议先上传项目到自己的git仓库
从git拉取
点击图中创建模板按钮,从git创建工程
注意切换分支
注意,如果是从已有git创建的分支,泡饭默认会用main分支
请在编辑模式里,vscode,手动切换分支
如何分享泡饭链接
左侧页签我的工程->
点击打开工程->
左侧页签分享游戏->
服务器模式
官方论坛
- [论坛地址](https://bbs.popx.com/)
- 可以由我们内部人员给出的邀请链接申请加入论坛。
- 申请后,等待审核人员核实,批准后,即可浏览论坛内容,发表疑问贴。
- 强烈建议多去论坛搜索关键字,发帖会有对应的专业人员回答问题,大家一起维护论坛生态。
- 常见问题faq帖子会持续维护
[论坛FAQ](https://bbs.popx.com/t/topic/53)