Skip to main content

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。

caution

注意: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 的初始化,返回一个 PromisePromise resolve 之后就可以进行后续的操作,如果传入参数有误或者网络状况不稳定等等异常情况则会抛出 错误码

如果遇到碰到错误码的情况

  1. 如果是网络错误相关的错误,请尝试重新调用 world.init() 方法
  2. 如果是 UnSupported 错误,则请提示用户目前使用的浏览器环境不支持开启元宇宙
  3. 如果是 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 内部的状态变化。常用的事件列表如下:

事件名说明回调函数参数建议操作
disconnectedSDK 与元象服务器断开时触发-提示用户断开连接,可以尝试调用 reconnect 方法重连
reconnectedSDK 与元象服务器重新连接成功触发-提示用户重连成功
reconnectingSDK 尝试与元象服务器重新连接时触发-提示用户重连中
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
}