World
World
代表一个 3D 世界,这个世界由一个或多个 Room 组成。
初始化
import { World, IWorldOptions } from '@xverse/core'
const worldOptions: IWorldOptions = {
canvas: 'canvas',
appId: 'appId',
worldId: 'world',
releaseId: 'releaseId',
userId: 'userId'
token: 'token',
}
const world = new World(worldOptions)
await world.checkSupport()
await world.preInit()
await world.init()
在上述代码中我们从 SDK 中引入了 World 类和 World 初始化必要的一些参数定义 IWorldOptions。
注意:World 只允许构建一次,如果重复构建则会报错
排队系统
在当前服务器人数过多时,可以选择进入排队系统,而不是直接进入 B 面或者刷新页面,从而提供更好的体验. 使用方式如下
// 检测当前app是否接入排队系统和是否需要排队
const shouldAppEnqueue = world.shouldAppEnqueue()
if(shouldAppEnqueue){
// 进入排队系统, enqueue方法返回一个promise,这个promise会在排队完成后决议.
await world.enqueue()
}
// 监听当前排队进度
// 事件参数说明
// rank = 当前排队排名
// done = 是否完成排队
// waitTime = 后台返回的预估排队时间,不准
world.on('enqueuing', async ({ rank, done, waitTime }) => {
// 刷新对应UI
setXXX()
}
排队获取票据之后若 5min 之后进房会导致进房失败票据过期,此时会触发QueueVerifyFailed
,根据业务需求,若业务需要唤起重新排队 UI,则需要在该事件处理中执行 world.requeue()
方法,并监听enqueuing
,待资源被释放再次进房;若业务无需唤起重新排队 UI,则可通过设置world._autoEnterAfterQueueVerifyFailed = true
开启 SDK 的自动取票重进功能
IWorldOptions
IWorldOptions
类型定义了初始化 World
需要传入的参数
必填参数
- userId
用户加入世界的唯一标识
- canvas
用于渲染 3D 场景的 canvas 的 DOM 选择器
- appId
在 Console 上注册申请的 AppId,
- token
鉴于安全考虑,需要对用户身份进行鉴权。Token 获取参考 (https://github.com/xverse-lab/tls-sig-api)
- worldId
World 的唯一标识,用于用户隔离,可以通过调用元象后台接口获得
- releaseId
Console 提供了发布管理的功能,可以对 World
下的 Room
和场景资产进行编排,你可以选择发布 1 个房间或者组合发布多个房间,完成发布后会生成一个 releaseId。
World 初始化是二阶段的,也就是说还需要调用 world 的 init 方法才能完成 world 的初始化,init 是一个异步方法,用于执行 World 的初始化,返回一个 Promise
,Promise
resolve 之后就可以进行后续的操作,如果传入参数有误或者网络状况不稳定等等异常情况则会抛出 错误码。
如果遇到碰到错误码的情况
- 如果是网络错误相关的错误,请尝试重新调用
world.init()
方法 - 如果是 UnSupported 错误,则请提示用户目前使用的浏览器环境不支持开启元宇宙
- 如果是 RepeatInitWorld 错误,则已经进入了
World
,不需要再次调用了
异步调用完成之后,就得到了一个创建好具有渲染引擎、Avatar、相机、实时同步等功能的 3D 世界,不过这个时候页面中还看不到任何画面。
初始化 World 实例之后就可以调用 World 实例上的一些方法。
可选参数
- env
环境参数,可选参数, sit
测试环境 或 uat
用户体验环境 或 prod
生产环境;默认 prod
。测试环境会请求到元象的开发环境后台,不保证稳定性,但是能获得最新的更新,一般用于调试。
获取玩家引用
每一个加入 World 的用户,SDK 内部都会自动创建代表该用户的 Avatar 实例,并且原生的将 Avatar 的所有操作同步到其他玩家客户端上。
代表用户自己的 Avatar 实例可以用 getPlayer
方法获取到。
class World {
/**
* 获取玩家 Avatar 的引用,传入的 AvatarClass 必须是 Avatar 的子类
* @returns
*/
getPlayer<T extends Avatar>(AvatarClass?: ConstructorType<T>): T
}
更详细的说明参考 Avatar 章节
创建 Actor
RichSurface、Avatar、SubSequence 等等继承自 Actor 的类创建实例都需要通过 World 的 spawn
方法
更详细的说明参考 Actor 章节
事件
World 在内部状态变化时会触发事件让开发者能够响应 World 内部的状态变化。常用的事件列表如下:
事件名 | 说明 | 回调函数参数 | 建议操作 |
---|---|---|---|
disconnected | SDK 与元象服务器断开时触发 | - | 提示用户断开连接,可以尝试调用 reconnect 方法重连 |
reconnected | SDK 与元象服务器重新连接成功触发 | - | 提示用户重连成功 |
reconnecting | SDK 尝试与元象服务器重新连接时触发 | - | 提示用户重连中 |
repeatLogin | 使用同一个 userId 重复进入 World 时触发,旧的 world 会触发该事件 | - | 提示用户已被挤下线,不允许其他操作 |
roomSwitched | 房间切换时触发 | { prevRoomId: number, targetRoomId: number } | - |
enteringForReconnect | 重连进房时触发 | - | - |
firstEnteringRoom | 初次进房时触发 | - | - |
| userKicked | 元象服务器将 userId 踢下线时出发 | - | 提示用户被踢下线,不允许其他操作 | | fatalError | 发生严重错误时触发 | - | 模态框提示用户 reload 页面 |
全量的事件列表如下:
export interface IWorldEventsMap {
// 断网
disconnected: Event
// 建连/重连成功
reconnected: Event
// 重连中
reconnecting: Event
// 重复登录
repeatLogin: Event
// 被后台踢出
userKicked: Event
// 重连进房
enteringForReconnect: Event
// 初次进房
firstEnteringRoom: Event
// 房间切换时触发
roomSwitched: IRoomSwitchedEvent
// skin切换时触发
skinChanged: ISkinSwitchedEvent
// 任意房间内 Path 切换时触发
pathChanged: IPathChangedEvent
// 点击行进时,点击 navmesh 外的回调事件
pointUnReachable: Event
// 点击行进时,点击 navmesh 内的回调事件
pointReachable: Event
// 排队进度
enqueuing: { rank: number; done: boolean; waitTime: number }
// 世界暂停
pause: Event
// 世界从暂停恢复
resume: Event
// 致命错误,一旦收到该报错,直接提示用户重新reload界面
fatalError: Event
// 排队后由于票据过期导致进房失败
QueueVerifyFailed: Event
// 预创建:扫描 & 收集actor成功
collectActorSuccess: Event
}
更多事件相关的通用操作可以参考事件处理
获取玩家当前所在房间
用户可以在不同房间中 切换,那么就可以通过 World 的 getCurrentRoom
方法获取到玩家当前所在的 Room。
注意在 World 初始化之后,进入某一个 Room 之前这个方法返回的可能是 undefined
const currentRoom = worldInstance.getCurrentRoom()
const roomId = currentRoom?.roomId
根据 ActorId 获取 Actor
用户可以调用 World 的 getActorById
方法获取到对应 id 的 actor 元素.未找到返回 undefined
id 是创建 actor 时传入的参数,用于辨识不同 actor
const actor = worldInstance.getActorById(actorId)
创建 NPC
用户可以调用 world 的getNpc
方法创建 NPC,建议使用 npc 出生点的 bomId 作为唯一 ID
const npcConfig = await ConfigTools.getAvatarConfig(worldInstance, avatarId)
const npc = worldInstance.getNpc(birthPointId, npcConfig)
获取所有房间
调用 World 的 getRoomInstances
方法可以获取到所有 getRoomInstance
创建出的房间实例的引用
代码示例
const rooms = world.getRoomInstances()
获取房间列表配置
调用 World 的 getRoomConfigs
方法可以获取到所有当前 releaseId
下的每个房间的配置数据集合,房间配置数据包括房间 ID、房间名称、房间皮肤列表等等。
代码示例
const roomConfigs = world.getRoomConfigs()
销毁世界
class World {
/**
* 销毁世界
*/
destroy(): void
}
joystick 摇杆
World 提供了 joystick 模块可以控制用户行进位置,参考 joystick
资产预加载
如果需要对一个 releaseId 下的所有资产进行提前下载,在应用运行时就可以不等待网络加载而使用本地资源。
具体参考 资产预加载章节
TODO:
画质设置
可以通过 setPictureQualityLevel
方法对场景的画质进行设置,分为高中低三个档位
class World {
/**
* 设置 画质
* @param name
* @returns
*/
setPictureQualityLevel(level: IPictureQualityLevel): void
}
分辨率设置
可以通过 setSize
设置渲染分辨率
class World {
/**
* 设置 设置渲染分辨率
* @param height
* @param width
* @returns
*/
setSize(height: number, width: number)
}
环境光
设置环境光
可以通过 setEnvLight
方法设置环境光资产,通过 disposeEnvLight
方法销毁现有的环境光
环境光强度设置
可以通过 setEnvLightIntensity
方法对场景内的环境光强度进行设置
函数签名:
class World {
/**
* 设置环境光强度
* @param intensity 环境光强度,默认为1
*/
setEnvLightIntensity(intensity: number): void
}
获取系统时间
// 返回UNIX秒级时间戳,格式化后时间
const [unixTime, formatTime] = await world.getSeverTime()
//UNIX秒级转变毫秒
const timestamp = unixTime * 1000
后台保活
调用world.keepingAlive
接口后,会持续向后台发送心跳,即使用户没有操作也不会被后台踢出房间。
警告:此接口要慎重调用,且不需要时务必要调用stopKeepingAlive
接口清除。
class World {
/**
* 保持与后台的心跳,不会被剔出房间
*/
public keepingAlive(): void
/**
* 停止与后台保活
*/
public stopKeepingAlive(): void
}