<<<<<<< HEAD
脚本可以为游戏添加自定义的动态行为,为你的用户提供更吸引人的交互体验。 javascript是神奇代码岛支持脚本语言,你可以用它来构建你得游戏功能。
神奇代码岛(Box3)是一个基于网页的多人联机3D创作平台,支持JavaScript编程。 在神奇代码岛,模型、建筑构成了丰富多彩了视觉世界,而JavaScript代码则为这个世界注入了交互玩法的灵魂;无论是对战还是冒险,模拟经营还是角色扮演,都离不开JavaScript的神奇魔力。 现在,就跟着我一起了解JavaScript的神奇魔法吧~
JavaScript(简称“JS”)是当前最流行、应用最广泛的客户端脚本语言,在 Web 开发领域有着举足轻重的地位,是成为一名优秀前端工程师的必备技能之一。 JS 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。既能用在浏览器中控制页面交互,也能用在服务器端作为网站后台(借助 Node.js),还能在各种操作系统下运行,因此 JavaScript 也是一种全栈式的编程语言。
JavaScript 的应用场合极其广泛,简单到幻灯片、照片库、浮动布局和响应按钮点击,复杂到游戏、2D/3D 动画、大型数据库驱动程序等等。 JavaScript 可以用于 Web 开发的各个领域,例如: Web 应用开发:日常生活中我们所浏览的网页都是由 HTML、CSS、JavaScript 构成的,通过 JavaScript 可以实时更新网页中元素的样式,并可以实现人与网页之间的交互(例如监听用户是否点击了鼠标或按下了某个按键等),还可以在网页中添加一些炫酷的动画; 移动应用开发:除了可以进行 Web 应用开发外,JavaScript 还可以用来开发手机或平板电脑上的应用程序,而且我们还可以借助一些优秀的框架(例如 React Native),让开发更加轻松; Web 游戏:在网页中的小游戏,都可以使用 JavaScript 来实现; 后端 Web 应用开发:以前我们都是使用 JavaScript 来进行 Web 应用程序前端部分的开发,但随着 Node.JS(一个 JavaScript 运行环境)的出现,使得 JavaScript 也可以用来开发 Web 应用程序的后端部分。
学习JavaScript,需先掌握Javascript基础,你可以依次掌握: ●变量、字符串、数字、数组等关键功能 ●基础的运算符与逻辑 ●条件语句、循环、函数等代码块 ●对象与属性的学习和了解 ●神奇代码岛相关的API的使用 ●上手操作一些实例教程 学习过程,可以打开地图编辑器(opens new window)边操作变学习哦~当然,学习的方式方法不唯一 除了可以在神奇代码岛的API文档里阅读相关的资料,也可以在下面的外部学习资料里学习相关的内容
●MDN Web Docs(opens new window) ●RUNOOB.COM(opens new window) ●语言中文网(opens new window) ●还有,B站等视频网站也可以搜索相关的视频教学哦~
在脚本中可全局访问的对象。 类、接口类型以及枚举值不在此列出,请查看对应目录下的内容。
全局变量
storage • Conststorage: GameStorage 代表存储服务的全局对象。
voxels • Constvoxels: GameVoxels 控制所有方块。
world • Constworld: GameWorld 代表游戏世界的全局对象。
概述 GameWorld 世界
是整个游戏世界的主要接口,可以通过全局对象world 来使用它。 它对应涵盖了控制环境天气、物理重力、画面滤镜等全局场景属性,还可以在世界中创建、搜索实体,或监听世界中实体和玩家的碰撞、伤害、互动等事件。 在世界之下,还可以创造GameZone 区域
对地图世界进行指定范围的定制。
类 ●GameWorld 世界
事件 几乎所有事件都能在world上进行监听。 ●GameChatEvent 聊天事件
●GameEntityContactEvent 实体碰撞事件
●GamePurchaseSuccessEvent 购买成功事件
是控制所有方块的接口,可通过全局对象voxels使用。 它负责控制地形变化,利用循环语法批量生成/销毁方块,获取某个方块的类型、名称、旋转角度等。
事件 ●GameFluidContactEvent 液体碰撞事件
概述 实体是地图内的游戏对象,用于对物体、玩家等的控制。 实体对象类为GameEntity,可以通过world.createEntity进行创建,或通过world.querySelector等方法获取地图内已存在的实体对象。
●GameEntityContactEvent 实体碰撞事件
玩家指的是进入地图游玩的用户,由 GamePlayer 玩家
控制,此接口可用定义游戏中的玩家属性、操作等等。玩家属于一种特殊的实体,可以在 GameEntity
的player属性上读取到玩家对象。
概述 控制、处理事件流程的公共模块。有关具体事件的信息,请查阅对应功能模块。
类 ●GameEventHandlerToken 事件管理凭据
动作模块负责控制由 Voxa 导入的模型所带有的动作。包括加载特定动作,暂停动作,重播动作和设置默认动作等,主要通过GameMotionController 动作控制器
进行控制。 动作作为实体的一部分,可以通过entity.motion获取该实体的动作控制器。
概述 通过动画模块,可以对GameWorld、GameEntity-bean、GamePlayer
对象添加关键帧动画。动画将在本地播放运行,获得更好的性能,播放更流畅、平滑。 通过对应对象上的animate方法可以创建动画对象 GameAnimation-bean,从而控制动画的播放。
类型 ●GameAnimationPlaybackConfig 动画播放配置参数
枚举 ●GameAnimationDirection - 动画播放方向
●GameAnimationPlaybackState 动画播放状态
概述 数据存储模块,管理游戏中的数据。
类 - GameAnimation Animation 动画,可对World世界、Entity实体及Player玩家等对象添加动画。动画将在本地播放运行,获得更好的性能,播放更流畅、平滑。
currentTime •currentTime:number= 0 动画的当前播放时间(多少动画帧)
playState •playState:GameAnimationPlaybackState= GameAnimationPlaybackState.PENDING 当前动画播放状态
playbackRate •playbackRate:number= 1 每tick动画播放速度
startTime •startTime:number= 0 动画开始的时间tick
target •target:TargetType 动画作用的对象(可为world、player或entity)
控制动画播放
play •play:function 播放或者恢复动画的播放
函数声明: ▸ (playback?: Partial‹GameAnimationPlaybackConfig›):void 参数:
名称 | 类型 |
---|---|
playback? | Partial‹GameAnimationPlaybackConfig› |
cancel •cancel: *function 取消当前播放的动画
和动画有关的事件
onFinish •onFinish:GameEventChannel‹GameAnimationEvent‹KeyframeType, TargetType›› •nextFinish:GameEventFuture‹GameAnimationEvent‹KeyframeType, TargetType›› 当动画结束播放时触发
onReady •onReady:GameEventChannel‹GameAnimationEvent‹KeyframeType, TargetType›› • nextReady: GameEventFuture‹GameAnimationEvent‹KeyframeType, TargetType›› 当动画开始播放时触发
方法
keyframes •keyframes:function 返回所有的动画关键帧
函数声明: ▸ ():Partial‹KeyframeType›[]
then ▸then‹T›(resolve: function,reject?: undefined | function):any 类型参数 ▪T 参数: ▪resolve:function ▸ (event:GameAnimationEvent‹KeyframeType, TargetType›):T 参数:
名称 | 类型 | |
---|---|---|
event | GameAnimationEvent ‹KeyframeType, TargetType› |
▪可选reject:undefined | function 返回值:any
类 - GameBounds3 GameBounds用于指定世界中一个立方体空间区域。
构造函数 +new GameBounds3(lo:GameVector3,hi:GameVector3):GameBounds3 新建一个区域 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
lo | GameVector3 | 区域的低处顶点 | |
hi | GameVector3 | 区域的高处顶点 |
返回值:GameBounds3
属性
hi 区域的高处顶点 •hi:GameVector3
lo 区域的低处顶点 •lo:GameVector3
方法
copy ▸copy(b:GameBounds3):GameBounds3 参数:
名称 | 类型 | |
---|---|---|
b | GameBounds3 |
返回值:GameBounds3
set ▸set(lox: number,loy: number,loz: number,hix: number,hiy: number,hiz: number):void 参数:
名称 | 类型 | |
---|---|---|
lox | number | |
loy | number | |
loz | number | |
hix | number | |
hiy | number | |
hiz | number |
返回值:void
intersect ▸intersect(b:GameBounds3):GameBounds3 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
b | GameBounds3 | 计算与此包围盒相交的部分 |
intersects ▸intersects(b:GameBounds3):boolean 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
b | GameBounds3 | 检测是否与此包围盒相交 |
返回值:boolean
contains ▸contains(b:GameVector3):boolean 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
b | GameVector3 | 检测是否包围了这个3d点 |
返回值:boolean
containsBounds ▸containsBounds(b:GameBounds3):boolean 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
b | GameBounds3 | 检测是否完全包围了此盒 |
返回值:boolean
toString ▸toString():string 返回值:string
StaticfromPoints ▸fromPoints(...points: [GameVector3](%5BGameVector3%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/lqqc61nd3gud9omc))):GameBounds3 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
...points | [GameVector3](%5BGameVector3%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/lqqc61nd3gud9omc)) | 任意数量的3d坐标点, 用来形成包围盒 |
返回值:GameBounds3
类 - GameChatEvent 由聊天触发的事件 通过GameWorld.onChat和GamePlayer.onChat触发
entity •entity:GameEntity 发起聊天的实体
message •message:string 聊天事件中说话的内容
tick •tick:number 聊天事件发生时间
类 - GameClickEvent 当玩家用鼠标点击实体时触发的事件
button •button:ACTION0|ACTION1 被点击的按钮,ACTION0 = 左键,ACTION1 = 右键
clicker •clicker:GameEntity& object 发起点击事件的玩家
clickerPosition •clickerPosition:GameVector3 点击鼠标的瞬间玩家所在位置
distance •distance:number 玩家到被点击实体的距离
entity •entity:GameEntity 被点击的实体
raycast •raycast:GameRaycastResult 玩家 -> 被点击实体的射线检测结果
tick •tick:number 鼠标点击事件发生的时间
类 - GameDamageEvent 当实体收到伤害时触发的事件,由GameWorld.onTakeDamage和GameEntity.onTakeDamage触发
tick •tick:number 事件发生的时间
entity •entity:GameEntity 受到伤害的实体
damage •damage:number 伤害值的大小
attacker •attacker:GameEntity|null 攻击者
damageType •damageType:string 伤害的类型
Class: GameDataStorage 代表数据存储空间的类,能通过 {GameStorage.getDataStorage} 或 {GameStorage.getGroupStorage} 创建。能够以键值对的形式存储数据,提供方法处理空间内键值对相关的操作。
存储空间隔离 当游戏服务器尝试连接指定名称的空间时:
属性与方法
key • key: string 空间名称 (只读)
示例代码
set • set : function 传入指定键与值,无论该键是否存在,均将值设置到此键上。
函数声明:
▸ (key:string, value:JSONValue): Promise <void>
参数:
名称 | 类型 | |
---|---|---|
key | string | 需要设置的键 |
value | JSONValue | 需要设置的值 |
返回值:Promise <void>
当设置完成时 resolve,否则 reject
get • get : function 获取指定键对应的值
函数声明: ▸ (key:string): Promise[ReturnValue](%5BReturnValue%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/ofrqlqsh7eq81xw7))
参数:
名称 | 类型 | |
---|---|---|
key | string | 指定的键 |
返回值:Promise[ReturnValue](%5BReturnValue%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/ofrqlqsh7eq81xw7)) 返回 Promise 对象,当获取完成时 resolve,否则 reject,resolve 时返回对应{ ReturnValue | 键值对内容}。
update • update : function 使用传入的方法更新键值对
函数声明:
▸ (key:string, handler:(prevValue: ReturnValue)=>JSONValue): Promise <void>
参数:
名称 | 类型 | |
---|---|---|
key | string | 需要更新的键 |
handler | (prevValue:ReturnValue)=>JSONValue | 处理更新的方法,接受一个参数,为当前键的值,返回一个更新后的值 |
返回值:Promise <void>
返回 Promise 对象,当更新完成时 resolve,否则 reject。
remove • remove : function 删除指定键值对
函数声明: ▸ (key:string): Promise[ReturnValue](%5BReturnValue%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/ofrqlqsh7eq81xw7))
参数:
名称 | 类型 | |
---|---|---|
key | string | 指定的键 |
返回值:Promise[ReturnValue](%5BReturnValue%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/ofrqlqsh7eq81xw7)) 返回 Promise 对象,resolve 时返回被删除的 { ReturnValue | 键值对内容}。
list • list : function 批量获取键值对
函数声明: ▸ (options:ListPageOptions): Promise[QueryList](%5BQueryList%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dw93mzb6q0d5d181))
参数:
名称 | 类型 | |
---|---|---|
options | ListPageOptions | 批量获取键值对的配置项 |
返回值:Promise[QueryList](%5BQueryList%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dw93mzb6q0d5d181)) 返回 Promise 对象,resolve 时返回{ QueryList | 键值对查询表}。
操作频率限制
服务器维度 对每一个游戏服务器独立生效,与服务器在线玩家数正相关,同一队列中的所有API共享限制。
队列 | API | 限制 |
---|---|---|
写入 | set updateremove | (60 + 玩家数 * 10 )次操作 / 分钟 |
读取 | get update | (120 + 玩家数*20)次操作/分钟 |
注;当前版本下,此处玩家数取固定值70。
吞吐量维度 对每一个 Key 的任意操作有吞吐量的限制。
队列 | API | 限制 |
---|---|---|
写入 | set updateremove | 4M/min |
读取 | get update | 25M/min |
错误码
Code | Status | Error Message | 描述 |
---|---|---|---|
400 | DB_NAME_INVALID | Invalid data storage name. | 存储空间名为空,或不满足限制要求。 |
400 | KEY_INVALID | Invalid data key. | 数据键为空。 |
400 | VALUE_INVALID | Invalid data value. | 数据值为空。 |
400 | PARAMS_INVALID | Invalid parameters. | 参数不合法。 |
429 | REQUEST_THROTTLED | Too Many Requests | 超出操作频率限制 |
500 | SERVER_FETCH_ERROR | Server network error. | 服务由于网络原因请求失败。 |
500 | UNKNOWN | Unknown server error. | 未知的服务器错误。 |
示例代码
console.clear()
const testStorage = storage.getDataStorage('test')
async function storageExample() {
await testStorage.set('keyNumber', 1)
await testStorage.set('keyStr', '字符串')
await testStorage.set('keyBoolean', false)
await testStorage.set('keyJson', { describe: 'json内容' })
let numberValue = await testStorage.get('keyNumber')
let strValue = await testStorage.get('keyStr')
let boolValue = await testStorage.get('keyBoolean')
let jsonValue = await testStorage.get('keyJson')
console.log(`keyNumber 的 value: ${numberValue.value}`)
console.log(`keyStr 的 value: ${strValue.value}`)
console.log(`keyBoolean 的 value: ${boolValue.value}`)
console.log(`keyJson 的 value: ${JSON.stringify(jsonValue.value)}`)
await sleep(1000)
numberValue = await testStorage.remove('keyNumber')
strValue = await testStorage.remove('keyStr')
boolValue = await testStorage.remove('keyBoolean')
jsonValue = await testStorage.remove('keyJson')
console.log('\n==========================\n\n')
console.log(`keyNumber 的 value: ${numberValue}`)
console.log(`keyStr 的 value: ${strValue}`)
console.log(`keyBoolean 的 value: ${boolValue}`)
console.log(`keyJson 的 value: ${JSON.stringify(jsonValue)}`)
await sleep(1000)
await testStorage.update('keyNumber', (preData) => { return 2 })
await testStorage.update('keyStr', (preData) => { return '被更改的字符串' })
await testStorage.update('keyBoolean', (preData) => { return true })
await testStorage.update('keyJson', (preData) => { return { describe: 'json内容被更改' } })
numberValue = await testStorage.get('keyNumber')
strValue = await testStorage.get('keyStr')
boolValue = await testStorage.get('keyBoolean')
jsonValue = await testStorage.get('keyJson')
console.log('\n==========================\n\n')
console.log(`keyNumber 的 value: ${numberValue.value}`)
console.log(`keyStr 的 value: ${strValue.value}`)
console.log(`keyBoolean 的 value: ${boolValue.value}`)
console.log(`keyJson 的 value: ${JSON.stringify(jsonValue.value)}`)
await sleep(1000)
console.log('\n==========================\n\n')
const queryList = await testStorage.list({
// 分页指针,用于指定本次获取的分页起点。
cursor: 0,
// 分页大小,一页内的数据量,默认100。
pageSize: 100
})
while (true) {
for (let value of queryList.getCurrentPage()) {
console.log(`${value.key} 的 value:${JSON.stringify(value.value)}`)
}
// 假如为最后一页,退出循环
if (queryList.isLastPage) break
// 翻到下一页
await queryList.nextPage()
}
}
storageExample()
类 - GameDieEvent 当实体死亡时触发的事件,由GameWorld.onDie和GameEntity.onDie触发
tick •tick:number 事件发生的时间
entity •entity:GameEntity 死亡的实体
attacker •attacker:GameEntity|null 击杀者
damageType •damageType:string 伤害的类型
类 - GameEntity Entity实体是Box3中的游戏对象,用于对物体、玩家等的控制。
属性与方法
控制实体的外观 由GameEntityConfig实现
entity.mesh •mesh:string= ""
实体形状数据(mesh)的hash。如果设为空字符串/'',则实体无mesh。 除非实体为玩家,否则设定实体的mesh之后,mesh就会用来计算实体的边界。 只有提前在场景中放置模型,才能获得模型的Mesh属性。 模型被放置后,会自动保存在文件列表中。模型文件对应的*'mesh/.vb'名称便是 mesh属性。 示例代码
entity.position • position: GameVector3<> = new GameVector3(0, 0, 0) 实体的位置。 示例代码
entity.meshOrientation • meshOrientation: GameQuaternion<> = new GameQuaternion(0, 0, 0, 1) 实体的旋转角度
entity.lookAt (targetPosition:GameVector3, meshFacing?:"X"|"Y"|"Z", up?:GameVector3) : void 将实体旋转至面向指定位置的方向,与图形学中定义的 LookAt 矩阵不是一个东西哦。 通过此方法进行的旋转会瞬时发生,仅影响实体的朝向,不会影响实体的运动状态。 ●position:GameVector3 - 世界坐标,希望让实体朝向的位置 ●meshFacing:"X"|"Y"|"Z" - 定义模型在未旋转状态下的参考方向,处理模型设计时未朝向Z轴时的情况: ○当取X、Z时,定义模型的正方向分别为X、Z轴正方向,上方向为 Y 轴正方向 ○当取Y时,定义模型的正方向为Y轴正方向,上方向为Z轴正方向 ○默认值为Z,即模型设计时朝向Z轴正方向 ●up:GameVector3 - 上向量,默认取 Y 轴正方向
entity.meshScale • meshScale: GameVector3<> = new GameVector3(1 / 64, 1 / 64, 1 / 64) 实体的缩放比例
entity.meshColor • meshColor: GameRGBAColor<> = new GameRGBAColor(1, 1, 1, 1) 实体的颜色
entity.meshInvisible •meshInvisible:boolean= false 可控制实体隐形,当值设为true时,则实体隐形。
entity.meshEmissive • meshEmissive: number = 0 实体的发光度
entity.meshMetalness • meshMetalness: number = 0 实体的金属感
entity.meshShininess • meshShininess: number = 0 实体的反光度,设为1则为非常光滑
entity.meshOffset •meshOffset:GameVector3<>= new GameVector3(0, 0, 0) 实体的位移
控制实体的物理属性 由GameEntityConfig实现
entity.bounds •bounds:GameVector3<>= new GameVector3(1, 1, 1) 实体边界框的半径,沿着x/y/z方向,这是一个只读属性,每帧都会重新计算
entity.collides • collides: boolean = true 如果为假(false),则实体不会碰撞
entity.fixed • fixed: boolean = false 如果为真(true),则实体不会移动
entity.friction • friction: number = 0 控制实体的粘性(0 = 滑,1 = 粘)
entity.gravity • gravity: boolean = true 如果为假(false),则实体不会下落 示例代码
entity.mass • mass: number = 1 实体物理质量
entity.restitution • restitution: number = 0 控制实体的弹性(0 = 软, 1 = 弹)
entity.velocity • velocity: GameVector3<> = new GameVector3(0, 0, 0) 实体的速度 示例代码
entity.contactForce •contactForce:GameVector3<>= new GameVector3(0, 0, 0) 实体受到的碰撞力
entity.entityContacts •entityContacts:GameEntityContact[] = [] 返回正在和玩家/实体发生碰撞的全部实体列表
entity.voxelContacts •voxelContacts:GameVoxelContact[] = [] 返回正在和玩家/实体发生碰撞的全部方块列表
entity.fluidContacts •fluidContacts:GameFluidContact[] = [] 返回正在被玩家/实体触碰的全部液体方块列表
聊天
entity.say •say(message: string):void 让实体说话。 示例代码
互动 允许实体进行互动
entity.enableInteract •enableInteract:boolean= false 是否允许实体进行互动。如果允许互动,走进互动范围之内,实体身上将会出现互动提示。
实体互动范围
entity.interactRadius •interactRadius:number= 16 实体互动范围。数值越小,则需要靠近实体才会出现互动提示。 范围有多个可互动实体,按下键盘[或]键,切换互动目标。
互动提示文本
entity.interactHint •interactHint:string= "" 进入实体互动范围时,实体身上出现的提示文本。
互动提示文本颜色
entity.interactColor •interactColor:GameRGBColor‹›= new GameRGBColor(1, 1, 1) 进入实体互动范围时,提示文本的颜色。 示例代码 与实体互动之前,在场景中必须先有一个实体。 在模型列表中,挑选一个你喜欢的模型,将它放置在场景中,并记住模型的名字。
和实体有关的事件
entity.onClick •onClick:GameEventChannel[GameClickEvent](%5BGameClickEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/mtb7dirtqv6g83o4)) •nextClick:GameEventFuture[GameClickEvent](%5BGameClickEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/mtb7dirtqv6g83o4)) 当玩家用鼠标点击实体时触发的事件
entity.onEntityContact •onEntityContact:GameEventChannel[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) •nextEntityContact:GameEventFuture[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) 当实体触碰另一个实体时触发
entity.onEntitySeparate •onEntitySeparate:GameEventChannel[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) •nextEntitySeparate:GameEventFuture[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) 当实体停止触碰另一个实体时触发
entity.onFluidEnter •onFluidEnter:GameEventChannel[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) •nextFluidEnter:GameEventFuture[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) 当实体进入液体时触发
entity.onFluidLeave •onFluidLeave:GameEventChannel[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) •nextFluidLeave:GameEventFuture[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) 当实体离开液体时触发
entity.onInteract •onInteract:GameEventChannel‹GameInteractEvent› •nextInteract:GameEventFuture‹GameInteractEvent› 当实体进行互动时触发 示例代码
entity.onVoxelContact •onVoxelContact:GameEventChannel[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) •nextVoxelContact:GameEventFuture[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) 当实体触碰方块时触发
entity.onVoxelSeparate •onVoxelSeparate:GameEventChannel[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) •nextVoxelSeparate:GameEventFuture[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) 当实体停止触碰方块时触发
控制玩家
entity.isPlayer •isPlayer:boolean= false 如果为真,则实体为玩家
Optionalplayer •player? :GamePlayer 索引与玩家相关的全部状态和方法
快速查找实体
entity.addTag 为实体添加一个新标签 函数声明: ▸addTag(tag: string):void 参数
名称 | 类型 | 说明 |
---|---|---|
tag | string | 要添加的标签名 |
entity.hasTag 判断实体是否带有某个标签 函数声明: ▸hasTag(tag: string):boolean 参数
名称 | 类型 | 说明 |
---|---|---|
tag | string | 标签名 |
示例代码
entity.id •id:string= "" 已在编辑器中添加的实体名称
entity.removeTag 从实体移除标签 函数声明: ▸removeTag(tag: string):void 参数
名称 | 类型 | 说明 |
---|---|---|
tag | string | 要移除的标签名 |
entity.tags 在编辑器中给实体添加的全部标签
函数声明: ▸tags():string[]
实体的销毁
entity.destroy •destroy:function 销毁实体 函数声明: ▸destroy():void
entity.destroyed •destroyed:boolean= false 如果为真(true),实体就被销毁。
entity.onDestroy •onDestroy:GameEventChannel[GameEntityEvent](%5BGameEntityEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dcqt2gzgkxnxqt2d)) •nextDestroy:GameEventFuture[GameEntityEvent](%5BGameEntityEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dcqt2gzgkxnxqt2d)) 当实体被销毁时触发
控制实体的生命值
entity.enableDamage •enableDamage:boolean= false 如果为真true,则可对实体进行伤害
entity.showHealthBar •showHealthBar:boolean= true 如果为真true,则显示实体的生命值HP
entity.hp •hp:number= 100 实体的当前生命值hp
entity.maxHp •maxHp:number= 100 实体的最大生命值hp
entity.onTakeDamage 实体受到伤害时触发的事件 •onTakeDamage:GameEventChannel[GameDamageEvent](%5BGameDamageEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aivo4orkcmc9m0gm)) •nextTakeDamage:GameEventFuture[GameDamageEvent](%5BGameDamageEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aivo4orkcmc9m0gm))
entity.onDie 实体死亡时触发的事件 •onDie:GameEventChannel[GameDieEvent](%5BGameDieEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/fsnsdr8uvuspan6y)) •nextDie:GameEventFuture[GameDieEvent](%5BGameDieEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/fsnsdr8uvuspan6y))
entity.hurt 可用这个函数来定义对实体的伤害。输入对实体的伤害值。 函数声明: ▸hurt(amount: number,options?:Partial[GameHurtOptions](%5BGameHurtOptions%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dvgk7szaqicsyb4q))):void 参数
名称 | 类型 | 说明 |
---|---|---|
amount | number | 伤害值 |
options? | Partial[GameHurtOptions >](%5BGameHurtOptions%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dvgk7szaqicsyb4q)%3Cbr/) |
伤害的相关配置,选填 |
代码示例
控制实体产生粒子的属性
entity.particleRate •particleRate:number= 0 实体平均每秒产生粒子的数量。如果希望实体停止释放粒子,可以将该属性改为0 示例代码
entity.particleRateSpread •particleRateSpread:number= 0 如果设定了该属性的值,实体每一秒产生粒子的数量将不再是个固定值,而是从区间 [particleRate,particleRate+particleRateSpread) 里随机选取的一个整数。例如,假设particleRate=0,particleRateSpread=3,每秒产生的粒子数量是[0, 0+3) ,即[0, 3)区间里的一个随机整数,也就是可能为0,1,或2 示例代码
entity.particleLimit •particleLimit:number= 100 实体可产生的粒子总数的上限
entity.particleLifetime •particleLifetime:number= 10 粒子的存活时间,以秒为单位 示例代码
entity.particleLifetimeSpread •particleLifetimeSpread:number= 0 如果设定了该属性的值,粒子的存活时间将不再是固定值,而是区间 [particleLifetime,particleLifetime+particleLifetimeSpread) 里的一个随机数,可能为小数 示例代码
entity.particleSize •particleSize:number[]= [1, 1, 1, 1, 1] 该属性的值可以是一个长度为0至5的数组。每个粒子的存活时间被平均分为五个阶段,对于长度为5的数组,数组里的每个值分别指定粒子在各个阶段的大小,其中,第一个值为粒子刚产生是的大小,第五个值为粒子消失时的大小。举几个例子,假设粒子的存活时间被设定为5秒,如果particleSize的值为 ●[25, 25, 25, 25, 25],在粒子存活的5秒内大小不会发生变化,产生时是25,消失时也是25 ●[0, 25, 0, 25, 15],粒子产生时大小为0,然后逐渐变为25,之后又逐渐变为0,再逐渐变为25,最后变为15,可以让该实体所产生的粒子具有逐渐放大缩小的效果 ●[15, 25], 粒子产生时大小为15,1秒后逐渐变大至25,之后又逐渐缩小至最小值 示例代码
entity.particleSizeSpread •particleSizeSpread:number= 0 ●如果设定了该属性,但没设定particleSize的值,每产生一个粒子,会从区间[0,particleSizeSpread)里选取的一个随机数作为它的大小 ●如果同时设定了particleSize和particleSizeSpread两个属性,每产生一个粒子,从区间[0,particleSizeSpread)里选取一个随机数x,这个粒子第i个阶段的大小将为particleSize[i]+x
entity.particleColor •particleColor:GameRGBColor[]= [ new GameRGBColor(1,1,1), new GameRGBColor(1,1,1), new GameRGBColor(1,1,1), new GameRGBColor(1,1,1), new GameRGBColor(1,1,1) ] 类似particleSize,该属性的值可以是一个长度为0至5的数组,数组里的每个值分别指定了粒子在各个阶段的颜色。类似地,可以通过该属性使粒子具有颜色渐变的效果 示例代码
entity.particleVelocity •particleVelocity:GameVector3= new GameVector3(0, 0, 0) 该实体产生的所有粒子的初始速度,如果将该属性设为new GameVector3(x, y, z),x,y,z三个值分别指定粒子在对应三个方向上的速率 示例代码
entity.particleVelocitySpread •particleVelocitySpread:GameVector3= new GameVector3(0, 0, 0) 增加该实体产生的所有粒子初始速度的不确定性,如果将该属性设为new GameVector3(sx, sy, sz),每产生一个粒子,会基于这三个值分别产生一个随机值加到 x/y/z 三个方向所对应的速率上。通过设定这个属性,可以使粒子具有向随机方向运动的效果 示例代码
entity.particleDamping •particleDamping:number= 0 ●如果该属性的值为正数,会短暂减少该实体所产生粒子的初始速度,数值越大,减少初始速度的效果持续得越久 ●如果为负值,会短暂增加粒子的初始速度,数值越小,增加初始速度的效果越明显 示例代码
entity.particleAcceleration •particleAcceleration:GameVector3= new GameVector3(0, 0, 0) 该实体所产生粒子的加速度
entity.particleNoise •particleNoise:number= 0 指定粒子相对于之前运动方向的最大偏离值,数值越大,各个粒子的运动相对原有方向的偏离越明显
entity.particleNoiseFrequency •particleNoiseFrequency:number= 1 指定粒子改变运动方向的频率,数值越大,各个粒子的运动方向越没有规律 示例代码
控制音效 上传音效 编辑器目前内置了34款音效,可以在菜单-[文件管理]的搜索.mp3查看。点击文件后,会弹出声音文件的详情属性。点击位置即可复制文件路径,在脚本中使用对应的方法播放。 如需上传自定义声音,可以在[文件管理]窗口,点击右下角浮动的加号按钮-[上传音频]。 属性
entity.chatSound •chatSound:GameSoundEffect‹›= new GameSoundEffect() 当实体说话时,播放聊天音效。默认为'audio/chat.mp3'。通过entity.say()触发。
entity.hurtSound •hurtSound:GameSoundEffect‹›= new GameSoundEffect() 当实体触发受伤事件时,播放受伤音效。默认为'audio/hurt.mp3'。通过entity.onTakeDamage()触发
entity.dieSound •dieSound:GameSoundEffect‹›= new GameSoundEffect() 当实体触发死亡事件时,播放死亡音效。默认为'audio/die.mp3'。通过entity.onDie()触发
entity.interactSound •interactSound:GameSoundEffect‹›= new GameSoundEffect() 当实体进行互动时,播放互动音效。此音效仅互动的玩家可听见。通过entity.onInteract()触发。
方法
entity.sound •sound:function 在实体的位置播放声音。 参数 spec:{sample, radius, gain, pitch} | string ●sample:string 必填,声音文件路径。可在文件管理器中上传自定义声音。如'audio/chat.mp3' ●radius?:number 可选,声音范围。默认为32。距离实体越近,声音听的越清晰。超出范围的玩家则听不到声音。 ●gain?:number 可选,音量增益。正常为1,数值越大,声音越响。 ●pitch?:number 可选,音高增益。正常为1,大于1,声音播放越快,小于1,声音播放越慢。 示例1
示例2
示例3
动画
entity.animate 可用这个函数来设定实体的动画轨迹 函数声明: ▸animate(keyframes:GameEntityKeyframe[],playbackInfo:Partial[GameAnimationPlaybackConfig](%5BGameAnimationPlaybackConfig%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yccnow4dplv1lldk))):GameAnimation 代码示例
//需要提前在编辑器中添加'单元方块'的模型。
const vox = world.querySelector('#单元方块-1') //获取实体
vox.meshScale = vox.meshScale.scale(4) //让实体变大4倍
const ani = vox.animate([
{ position: [0, 12, 0], meshColor: [1, 1, 0, 1] },
{ position: [0, 12, 127], meshColor: [1, 0, 0, 1] },
{ position: [127, 12, 127], meshColor: [0, 1, 0, 1] },
{ position: [127, 12, 0], meshColor: [0, 0, 1, 1] },
], {
iterations: 3,//兜3圈
direction: GameAnimationDirection.WRAP,//从终点回到起点
duration: 16 * 5, //兜一圈5秒(每秒16帧)
})
ani.onReady(() => {//当动画开始播放时
world.say('开始兜圈')
})
ani.onFinish(() => {//当动画结束播放时
world.say('兜圈结束')
})
动作
entity.motion • motion: GameMotionController<> = new GameMotionController() 实体动作控制器 代码示例
const entity = world.querySelector('#npc')
const entityMotionControl = entity.motion; // MotionController
const motion = entityMotionControl.loadByName('hello'); // MotionHandler 'hello'指代'npc'实体上的其中一个motion动作名称
motion.onFinish(() => {
console.log('Motion End');
});
motion.play()
类 - GameEntityContact 正在发生碰撞的实体
other •other:GameEntity 与此实体碰撞的另一个实体
axis •axis:GameVector3 碰撞的分离轴,也就是碰撞后物体弹飞的方向
force •force:GameVector3 碰撞所产生的力
类 - GameEntityContactEvent 当两个实体碰撞时触发的事件。 由GameWorld.onEntityContact,GameWorld.onEntitySeparate,GameEntity.onEntityContact,GameEntity.onEntitySeparate触发
axis •axis:GameVector3 碰撞的分离轴,也就是碰撞后物体弹飞的方向
entity •entity:GameEntity 碰撞中的第一个实体
force •force:GameVector3 碰撞所产生的力
other •other:GameEntity 碰撞中的第二个实体
tick •tick:number 两个实体碰撞的时间
类 - GameEntityEvent 当创建或销毁实体时触发的事件。 由 GameWorld.onPlayerJoin, GameWorld.onPlayerLeave, GameWorld.onEntityCreate, GameWorld.onEntityDestroy 和 GameEntity.onDestroy 触发
world.onPlayerJoin((entityEvent) => {
// entityEvent.entity
// entityEvent.tick
});
entity •entity:GameEntity 创建/销毁的实体
tick •tick:number 事件发生时间
类 - GameEventHandlerToken 当事件监听被触发时,由 GameEventChannel
返回的token,可用于取消事件监听。
cancel 取消事件监听
函数声明: ▸cancel():void
resume 恢复事件监听
函数声明: ▸ resume(): void
事件列表: ●GameTickEvent 时钟 ●GameClickEvent 点击 ●GameInputEvent 输入 ●GameChatEvent 聊天 ●GameInteractEvent 互动 ●GameEntityEvent 实体创建/销毁 ●GameEntityContactEvent 实体触碰 ●GameVoxelContactEvent 触碰方块 ●GameFluidContactEvent 触碰液体 ●GameDamageEvent 实体伤害 ●GameDieEvent 实体死亡 ●GameTriggerEvent 区域触碰
类 - GameFluidContact 被实体/玩家触碰的液体方块。
voxel •voxel:number 液体方块id
volume •volume:number 液体方块中,被玩家或实体进入的体积比例,大小为(0,1]
当实体进入或离开液体时触发的事件。 由 GameWorld.onFluidEnter, GameWorld.onFluidLeave, GameEntity.onFluidEnter, GameEntity.onFluidLeave 触发
world.onFluidEnter(({entity, tick, voxel}) => {
})
entity •entity:GameEntity 触碰液体的实体
tick •tick:number 实体进入或离开液体的时间
voxel •voxel:number 液体方块id
类 - GameInputEvent 输入事件,在玩家按下或松开按钮时触发。 事件发生的时刻,即为玩家按下/松开按钮的同一刻。 由GameWorld.onPress,GameWorld.onRelease,GamePlayer.onPress,GamePlayer.onRelease触发。 示例代码
点击左键,将鼠标指针位置的方块替换为石头。点击右键,销毁方块。
button •button:GameButtonType 玩家输入的按钮
entity •entity:GameEntity& object 指向按下/松开按钮的玩家
position •position:GameVector3 玩家按下/松开按钮的瞬间所在位置
pressed •pressed:boolean 如果为真,则事件为按下按钮,否则,为松开按钮。
raycast •raycast:GameRaycastResult 按下/松开按钮的瞬间,从玩家视角投射的射线检测结果。
tick •tick:number 按下/松开按钮的时间
类 - GameInteractEvent
参数 ●entity ●targetEntity ●tick
参数
entity •entity:GameEntity 发起互动的实体
targetEntity •targetEntity:GameEntity 收到互动请求的实体
tick •tick:number 事件发生时间
类 - GameMotionController Motion 动作,可对Entity实体带有的动作进行操作,包括加载特定动作,暂停动作,重播动作和设置默认动作等。
示例代码 播放动作
加载特定动作
loadByName • loadByName : function 加载特定动作或动作序列,并返回对应的动作对象
函数声明: ▸ ( configs : "string" | MotionConfig[] | MotionClipConfig): GameMotionHandler 参数:
名称 | 类型 |
---|---|
configs | string |
控制动作播放
pause • pause : function 暂停实体上的动作播放
函数声明: ▸ (): void
resume • resume : function 恢复实体上的动作播放
函数声明: ▸ (): void
设置默认动作
setDefaultMotionByName • setDefaultMotionByName : function 设置默认动作 ●没有其他动作在播放的情况下,默认动作会在游戏运行时自动循环播放 ●调用此函数时,如当前处于默认动作执行状态,则将打断旧默认动作,播放新的默认动作 ●动作名不存在时,此方法不产生任何效果,并抛出包含实体、模型与动作信息的错误
函数声明: ▸ ( motionName : undefined | string): void 参数:
名称 | 类型 |
---|---|
motionName | undefined |
返回值: void
示例代码
const entity = world.querySelector('#npc')
entity.motion.setDefaultMotionByName('FirstMotion');
entity.motion.setDefaultMotionByName(''); // 报错,不存在对应动作
entity.motion.setDefaultMotionByName(); // 设置默认动作为空,即不播放默认动作
类 - GameMotionEvent 动作事件,通过GameMotionHandler.onFinish触发
cancelled •cancelled: bool 动画是否被取消
类 - GameMotionHandler 动作播放的 Handler,用于处理动作中断等行为
示例代码 播放动作
基本
target • target : GameEntity 当前motion的entity对象
控制动作播放
play • play : function 播放当前实体动作 ●会打断当前动作,开始对应动作/序列动作的播放 ●当配置中包含的动作播放结束时,触发 MotionPlayHandler 的 Finish 事件。
函数声明: ▸ (): void
返回值: void
示例代码
const entity = world.querySelector('#npc')
const motion = entity.motion.loadByName('FirstMotion');
motion.play()
cancel • cancel : function 中断此动作播放,并触发 end 事件
函数声明: ▸ (): void
播放结束事件
onFinish • onFinish : GameEventChannel‹GameMotionEvent› • nextFinish: GameEventFuture‹GameMotionEvent› 响应结束状态的监听函数
类 - GamePlayer Player 玩家指的是进入游戏的用户,此接口可用定义游戏中的玩家属性、操作等等。玩家属于一种特殊的实体。
基本
name •name:string= "player" 玩家的昵称。无法控制更改。
boxId •boxId:string= "" 玩家的Box ID(3-15字符)。无法控制更改。 游客的boxID值为空""。
userKey •userKey:string= "" 玩家的唯一识别码(16字符),可以用于存储玩家信息到数据库,无法控制更改。 游客的userKey值为空""。
avatar string 玩家头像信息。
spawnPoint •spawnPoint:GameVector3<>= new GameVector3(64, 140, 64) 玩家的出生点。默认出生点设置在new GameVector3(64, 140, 64)
movementBounds •movementBounds:GameBounds3<>= newGameBounds3(newGameVector3(-50, -50, -50), newGameVector3(178, 178, 178)); 玩家的活动范围限制,如超出此范围,则传回出生点
向玩家发送消息
directMessage ▸directMessage(message: string):void 向玩家直接发送私信
onChat •onChat:GameEventChannel[GameChatEvent](%5BGameChatEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aft5xl7q0dh6puh2)) •nextChat:GameEventFuture[GameChatEvent](%5BGameChatEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aft5xl7q0dh6puh2)) 当发起聊天时调用
dialog •dialog:GameDialogCall 在游戏中显示一个对话框。 示例代码 1
示例代码 2
cancelDialogs •cancelDialogs:function 关闭该玩家的所有打开的对话框。
share (content:string) : void; 为该玩家显示分享弹窗,并能够自定义分享内容。 ●content - 分享弹窗的内容,限制长度为40个字以内,超出后截断,并在末尾添加省略号……。 自动标签 通过此 API 调用弹出的分享弹框的内容末尾,会自动新起一行添加#神奇代码岛 #地图标签,自动添加的内容不计入限制长度内。 编辑模式 编辑模式下,此API弹出的分享弹窗分享的地址是编辑模式的地址。
控制玩家的外观
color •color:GameRGBColor<>= new GameRGBColor(1, 1, 1) 玩家的颜色
emissive •emissive:number= 0 玩家的发光度 示例代码
invisible •invisible:boolean= false 玩家是否隐身 示例代码
skin SkinDescription 此玩家的皮肤配置,用于管理当前玩家皮肤的展示。通过此处修改皮肤不会影响皮肤的隐藏状态,设置前是隐藏的,设置后也还是隐藏着。
皮肤不存在&非法参数 当皮肤名称不存在于项目皮肤库或不符合类型定义时,无事发生,并会在控制台打印警告。
示例
setSkinByName (skinName:string) : void 将指定皮肤套装应用到此玩家上。此方法不会影响皮肤的隐藏状态,设置前是隐藏的,设置后也还是隐藏着。
参数 ●skinName:string - 指定要设置的皮肤名称,将玩家皮肤整体替换为对应的皮肤。 皮肤不存在&非法参数 当皮肤名称不存在于项目皮肤库或不为字符串时,无事发生,并在控制台打印警告。
resetToDefaultSkin () : void 重置此玩家的皮肤配置为默认皮肤配置,效果同 setSkinByName传入了默认皮肤套装名称。
clearSkin () : void 清除地图对此玩家应用的皮肤配置,将此玩家的皮肤配置为仅展示玩家自己的皮肤。
skinInvisible •skinInvisible:GameSkinInvisible 隐藏玩家模型部件接口 示例代码
showName •showName:boolean= true 玩家名字是否显示
showIndicator • showIndicator: boolean = false 玩家标记否显示
scale •scale:number= 1 玩家的缩放比例 示例代码1
metalness •metalness:number= 0 玩家的金属感
shininess •shininess:number= 0 玩家的反光度
addWearable •addWearable:function 在玩家某身体部位附上穿戴配件物体 函数声明: ▸ (spec: Partial‹GameWearable›):GameWearable 参数:
名称 | 类型 |
---|---|
spec | Partial‹GameWearable› |
示例代码
removeWearable •removeWearable:function 把玩家身体部位已附上的穿戴配件物体删除 wearableis the wearable to remove 函数声明: ▸ (wearable:GameWearable):void 参数:
名称 | 类型 |
---|---|
wearable | GameWearable |
示例代码
wearables •wearables:function 列举在玩家上所有的穿戴配件物体 函数声明: • (bodyPart?:GameBodyPart):GameWearable[] 参数:
名称 | 类型 | 说明 |
---|---|---|
bodyPart? | GameBodyPart | 某玩家身体部位,选填 |
示例代码
Web相关
link •link:function 在玩家弹出一个“传送门”窗口,可以跳转到其他地图或任意链接。(目前支持神奇代码岛、编程猫、微信文章、Bilibili视频等链接) 函数声明: ▸ (href: string):void 参数:
名称 | 类型 | 说明 |
---|---|---|
href | string | 链接 URL |
示例代码
url •url:URL 获取该玩家进入地图时所用的URL链接地址, 主要用于获取URL参数, 以便区别对待进来的玩家 示例代码
玩家的复活和死亡
forceRespawn:() 让玩家强制重生,立即返回出生点 •forceRespawn(): void
onRespawn 玩家复活时调用的事件 •onRespawn:GameEventChannel[GameRespawnEvent](%5BGameRespawnEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cshui17169guugxr)) •nextRespawn:GameEventFuture[GameRespawnEvent](%5BGameRespawnEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cshui17169guugxr))
dead 玩家是否已死亡,生命值hp低于0。若玩家死亡,则会倒在地上。 •dead: boolean = false 此属性为只读,不可修改。
控制玩家视角
cameraEntity •cameraEntity:GameEntity| null= null 在第一人称视角(FPS)或第三人称跟随视角(FOLLOW)下,玩家视角所跟随的实体
cameraMode •cameraMode:GameCameraMode 视角模式 ●GameCameraMode.FPS -"fps"- 第一人称视角 ●GameCameraMode.FOLLOW -"follow"- 第三人称跟随视角(默认) ●GameCameraMode.FIXED -"fixed"- 第三人称固定视角 示例代码
cameraPosition •cameraPosition:GameVector3<>= new GameVector3(0, 0, 0) 固定视角(FIXED)下,镜头的眼睛位置
cameraTarget •cameraTarget:GameVector3<>= new GameVector3(0, 0, 0) 固定视角(FIXED)下镜头所朝向的目标点
cameraUp •cameraUp:GameVector3<>= new GameVector3(0, 1, 0) 固定视角(FIXED)下,镜头向上的矢量
cameraFovY • cameraFovY: number = 0.25 垂直方向的视场角
setCameraPitch • setCameraPitch: function 设置玩家视角准心绕水平方向的旋转弧度 函数声明: ▸ (v: number): void 参数:
名称 | 类型 | 说明 |
---|---|---|
v | number | 设置弧度 |
示例代码
setCameraYaw • setCameraYaw: function 设置玩家视角准心绕垂直方向的旋转弧度 函数声明: ▸ (v: number): void 参数:
名称 | 类型 | 说明 |
---|---|---|
v | number | 设置弧度 |
示例代码
enable3DCursor •enable3DCursor:boolean= false 启动玩家的3D光标 示例代码
玩家的输入信息
enableAction0 ●enableAction0:boolean= true 如果为false, 关闭Action0键。PC端为鼠标左键,手机端不会显示A按钮。 示例代码
启动鼠标左键/移动端虚拟按钮A键
enableAction1 ●enableAction1:boolean= true 如果为false, 关闭ActionB键。PC端为鼠标右键,手机端不会显示B按钮。 启动鼠标右键/移动端虚拟按钮B键
action0Button •action0Button:boolean= false 鼠标左键/移动端虚拟按钮A键
action1Button •action1Button:boolean= false 鼠标右键/移动端虚拟按钮B键
crouchButton •crouchButton:boolean= false 下蹲按钮
facingDirection •facingDirection:GameVector3<>= new GameVector3(1, 0, 0) 玩家朝向
cameraPitch • cameraPitch: number= 0 玩家视角准心绕水平方向的旋转弧度 只读
cameraYaw • cameraYaw: number= 0 玩家视角准心绕垂直方向的旋转弧度 只读 PITCHAXIS
ROLLAXIS
YAWAXIS
jumpButton •jumpButton:boolean= false 跳跃按钮
onPress •onPress:GameEventChannel[GameInputEvent](%5BGameInputEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yazeh0kkzogc71tx)) •nextPress:GameEventFuture[GameInputEvent](%5BGameInputEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yazeh0kkzogc71tx)) 当玩家按下按钮时调用
onRelease •onRelease:GameEventChannel[GameInputEvent](%5BGameInputEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yazeh0kkzogc71tx)) •nextRelease:GameEventFuture[GameInputEvent](%5BGameInputEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yazeh0kkzogc71tx)) 当玩家松开按钮时调用
walkButton •walkButton:boolean= false 步行按钮
控制玩家的行动
canFly •canFly:boolean= false 如果为真(true),则允许玩家飞行 示例代码
spectator •spectator:boolean= false 如果为真(true),则玩家是一个幽灵,可以穿墙
enableJump •enableJump:boolean= true 如果为假(false),则不允许玩家跳跃 示例代码
enableDoubleJump •enableDoubleJump:boolean= true 如果为假(false),则不允许玩家二段跳跃 示例代码
walkSpeed •walkSpeed:number= 0.22 最大步行速度
runSpeed •runSpeed:number= 0.4 最大奔跑速度
runAcceleration •runAcceleration:number= 0.35 奔跑加速度
jumpPower •jumpPower:number= 0.96 跳跃力度
jumpSpeedFactor •jumpSpeedFactor:number= 0.85 跳跃速度
jumpAccelerationFactor •jumpAccelerationFactor:number= 0.55 跳跃加速率
doubleJumpPower •doubleJumpPower:number= 0.9 二段跳力度
crouchSpeed •crouchSpeed:number= 0.1 蹲着走路的速度
crouchAcceleration •crouchAcceleration:number= 0.09 蹲着走路的加速度
flySpeed •flySpeed:number= 2 最大飞行速度
flyAcceleration •flyAcceleration:number= 2 飞行加速度
swimAcceleration •swimAcceleration:number= 0.1 游泳加速度
swimSpeed •swimSpeed:number= 0.4 最大游泳速度
walkAcceleration •walkAcceleration:number= 0.19 步行加速度
disableInputDirection GameInputDirection 禁用指定方向的摇杆输入偏移量,当横纵两个方向均被禁用时,将不显示此玩家的触屏虚拟摇杆。
查看玩家的状态
moveState •moveState=GamePlayerMoveState.FALL 玩家的运动状态,初始值为下落
walkState •walkState=GamePlayerWalkState.NONE 玩家的步行状态,初始值为非步行中
控制音效
预设音效
action0Sound •action0Sound:GameSoundEffect‹›= new GameSoundEffect() 当玩家按下'action0'按键(鼠标左键 / 虚拟按钮A)时,播放的音效。
action1Sound •action1Sound:GameSoundEffect‹›= new GameSoundEffect() 当玩家按下'action1'按键(鼠标右键 / 虚拟按钮B)时,播放的音效。
crouchSound •crouchSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家按下'crouchButton '按键进行蹲下时,播放的音效。
jumpSound •jumpSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家按下'jumpButton '按键进行跳跃时,播放的音效。默认为'audio/jump.mp3'
doubleJumpSound •doubleJumpSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家触发二段跳时,播放的音效。默认为'audio/double_jump.mp3'
landSound •landSound:GameSoundEffect‹›= new GameSoundEffect() 玩家落地时,播放的音效。默认为'audio/land.mp3'
enterWaterSound •enterWaterSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家进入液体时,播放的音效。默认为'audio/dive.mp3'
leaveWaterSound •leaveWaterSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家离开液体时,播放的音效。默认为'audio/splash.mp3'
swimSound •swimSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家正在游泳时,播放的音效。默认为'audio/swim.mp3' 注:游泳的音效在前进时才会循环播放。如果在水中静止不动,不会播放音效。
spawnSound •spawnSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家重生时,播放的音效。默认为'audio/spawn.mp3'。通过player.onRespawn()触发
stepSound •stepSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家行走时,每迈出一步,播放的音效。默认为'audio/step.mp3'
startFlySound •startFlySound:GameSoundEffect‹›= new GameSoundEffect() 玩家开始飞行时的音效。
stopFlySound •stopFlySound:GameSoundEffect‹›= new GameSoundEffect() 玩家结束飞行时播放的音效。
播放音效
sound •sound:function 为指定的玩家播放声音,此声音仅该玩家能听见,其他玩家无法听到。 参数: spec:{sample, gain, pitch} | string ●sample:string 必填,声音文件路径。可在文件管理器中上传自定义声音。如'audio/chat.mp3' ●gain?:number 可选,音量增益。正常为1,数值越大,声音越响。 ●pitch?:number 可选,音高增益。正常为1,大于1,声音播放越快,小于1,声音播放越慢。 示例代码1
示例代码2
music •music:GameSoundEffect‹›= new GameSoundEffect() 为指定的玩家播放背景音乐(循环播放),此声音仅该玩家能听见,其他玩家无法听到。 背景音乐的音量会根据用户在[设置-声音]更改。
画面滤镜
colorLUT •colorLUT:string= "" 用于渲染玩家所见游戏世界的色调 示例代码
动画
player.animate 可用这个函数来设定玩家的动画,变化颜色
社交
querySocial (socialType: SocialType) => Promise<number[]> · 查询当前玩家的社交关系,支持查询: · 关注 · 粉丝 · 好友 · 返回玩家 ID 列表
openUserProfileDialog (userId: number) => void 对当前玩家,调起指定ID玩家的个人主页。
商城
openMarketplace ●openMarketplace:function 打开游戏商店对话框,根据玩家传入的“商品ID”显示相应的产品。
函数声明: ▸ (productIds: number[]): void 参数:
名称 | 类型 | 说明 |
---|---|---|
productIds | number[] | 商品ID数组 |
示例代码
world.onPlayerJoin(({ entity }) => {
// product ID1: 160000000000001 ID2: 160000000000002
entity.player.openMarketplace([160000000000001, 160000000000002])
});
投喂记录
getMiaoShells ●getMiaoShells:function 获取此用户在当前地图下累计打赏的喵贝壳
函数声明:
▸ (): Promise <number>
示例代码
world.onPlayerJoin(async ({ entity }) => {
// 获取用户在当前地图下累计打赏的喵贝壳
const count = await entity.player.getMiaoShells()
entity.player.directMessage(`我累计打赏的喵贝壳:${count}`)
})
类 - GamePurchaseSuccessEvent 当玩家成功购买物品时触发的事件
tick • tick: number 购买成功事件发生的时间
userId • userId: string 触发购买事件的玩家userId
productId • productId: number 购买商品的ID
orderId • orderId: number 购买成功的订单号
类 - GameQuaternion
构造函数 +new GameQuaternion(w: number,x: number,y: number,z: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
w | number |
x | number |
y | number |
z | number |
返回值:GameQuaternion
属性
名称 | 类型 | |
---|---|---|
w | number | |
x | number | |
y | number | |
z | number |
方法
add ▸add(v:GameQuaternion):GameQuaternion 参数:
名称 | 类型 | |
---|---|---|
v | GameQuaternion |
返回值:GameQuaternion
angle ▸angle(q:GameQuaternion):number 参数:
名称 | 类型 | |
---|---|---|
q | GameQuaternion |
返回值:number
clone ▸clone():GameQuaternion 返回值:GameQuaternion
copy ▸copy(q:GameQuaternion):GameQuaternion 参数:
名称 | 类型 | |
---|---|---|
q` | GameQuaternion |
返回值:GameQuaternion
div ▸div(q:GameQuaternion):GameQuaternion‹› 参数:
名称 | 类型 | |
---|---|---|
q | GameQuaternion |
返回值:GameQuaternion‹›
dot ▸dot(q:GameQuaternion):number 参数:
名称 | 类型 | |
---|---|---|
q | GameQuaternion |
返回值:number
equals ▸equals(q:GameQuaternion,tolerance: number):boolean 参数:
名称 | 类型 | Default | |
---|---|---|---|
q | GameQuaternion | - | |
tolerance | number | 0.0001 |
返回值:boolean
getAxisAngle ▸getAxisAngle(q: any):object 参数:
名称 | 类型 |
---|---|
q | any |
返回值:object ●angle:number ●axis:GameVector3
inv ▸inv():GameQuaternion 返回值:GameQuaternion
mag ▸mag():number 返回值:number
mul ▸mul(q:GameQuaternion):GameQuaternion 参数:
名称 | 类型 |
---|---|
q | GameQuaternion |
返回值:GameQuaternion
normalize ▸normalize():GameQuaternion 返回值:GameQuaternion
rotateX ▸rotateX(_rad: number):GameQuaternion 参数:
名称 |
---|
_rad |
返回值:GameQuaternion
rotateY ▸rotateY(_rad: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
_rad | number |
返回值:GameQuaternion
rotateZ ▸rotateZ(_rad: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
_rad | number |
返回值:GameQuaternion
set ▸set(w: number,x: number,y: number,z: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
w | number |
x | number |
y | number |
z | number |
返回值:GameQuaternion
slerp ▸slerp(q:GameQuaternion,n: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
q | GameQuaternion |
n | number |
返回值:GameQuaternion
sqrMag ▸sqrMag():number 返回值:number
sub ▸sub(v:GameQuaternion):GameQuaternion 参数:
名称 | 类型 |
---|---|
v | GameQuaternion |
返回值:GameQuaternion
toString ▸toString():string 返回值:string
StaticfromAxisAngle ▸fromAxisAngle(axis:GameVector3,rad: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
axis | GameVector3 |
rad | number |
返回值:GameQuaternion
StaticfromEuler ▸fromEuler(x: number,y: number,z: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
x | number |
y | number |
z | number |
返回值:GameQuaternion
StaticrotationBetween ▸rotationBetween(a:GameVector3,b:GameVector3):GameQuaternion 参数:
名称 | 类型 |
---|---|
a | GameVector3 |
b | GameVector3 |
返回值:GameQuaternion
类 - GameRaycastResult 射线检测(raycast)的结果,包含射线和所击中目标的信息。
direction •direction:GameVector3 射线的方向
distance •distance:number 射线穿越的距离
hit •hit:boolean 如果为真,则射线击中目标
hitEntity •hitEntity:GameEntity| null 射线所击中的实体
hitPosition •hitPosition:GameVector3 射线击中的位置
hitVoxel •hitVoxel:number 射线所击中的方块id (如未击中方块,则为0)
normal •normal:GameVector3 射线所击中平面的法向量
origin •origin:GameVector3 射线的起点
voxelIndex •voxelIndex:GameVector3 如果射线击中的是方块,则返回所击中方块的网格坐标。
类 - GameRespawnEvent 当实体复活时触发的事件
tick • tick: number 事件发生的时间
entity • entity: GameEntity 复活的实体
类 - GameRGBColor
GameRGBColor +new GameRGBColor(r: number,g: number,b: number):GameRGBColor 参数:
名称 | 类型 |
---|---|
r | number |
g | number |
b | number |
示例代码
注意,此处输入的颜色值范围在(0-1) 之间。 如果需要使用 RGB 255,可以将颜色值除于255,即可得到0-1的数值。
方法
add ▸add(rgb:GameRGBColor):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
返回值:GameRGBColor
clone ▸clone():GameRGBColor 返回值:GameRGBColor
copy ▸ copy(c: GameRGBColor): GameRGBColor 参数:
名称 | 类型 |
---|---|
c | GameRGBColor |
返回值:GameRGBColor
div ▸div(rgb:GameRGBColor):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
返回值:GameRGBColor
equals ▸equals(rgb:GameRGBColor,tolerance: number):boolean 参数:
名称 | 类型 | Default |
---|---|---|
rgb | GameRGBColor | - |
tolerance | number | 0.0001 |
返回值:boolean
lerp ▸lerp(rgb:GameRGBColor,n: number):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
n | number |
返回值:GameRGBColor
mul ▸mul(rgb:GameRGBColor):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
返回值:GameRGBColor
set ▸set(r: number,g: number,b: number,a: number):GameRGBColor 参数:
名称 | 类型 |
---|---|
r | number |
g | number |
b | number |
a | number |
返回值:GameRGBColor
sub ▸sub(rgb:GameRGBColor):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
返回值:GameRGBColor
toRGBA ▸toRGBA():GameRGBAColor 返回值:GameRGBAColor
toString ▸toString():string 返回值:string
Staticrandom ▸random():GameRGBColor 返回值:GameRGBColor
类 - GameRGBAColor
GameRGBAColor new GameRGBAColor(r: number,g: number,b: number,a: number):GameRGBAColor 参数:
名称 | 类型 |
---|---|
r | number (0-1) |
g | number (0-1) |
b | number (0-1) |
a | number (0-1) |
示例代码
注意,此处输入的颜色值范围在(0-1) 之间。 如果需要使用 RGB 255,可以将颜色值除于255,即可得到0-1的数值。
方法
add ▸add(rgba:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
返回值:GameRGBAColor
clone ▸clone():GameRGBAColor 返回值:GameRGBAColor
copy ▸copy(c:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
c | GameRGBAColor |
返回值:GameRGBAColor
div ▸div(rgba:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
返回值:GameRGBAColor
equals ▸equals(rgba:GameRGBAColor,tolerance: number):boolean 参数:
名称 | 类型 | Default |
---|---|---|
rgba | GameRGBAColor | - |
tolerance | number | 0.0001 |
返回值:boolean
lerp ▸lerp(rgba:GameRGBAColor,n: number):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
n | number |
返回值:GameRGBAColor
mul ▸mul(rgba:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
返回值:GameRGBAColor
set ▸set(r: number,g: number,b: number,a: number):GameRGBAColor 参数:
名称 | 类型 |
---|---|
r | number |
g | number |
b | number |
a | number |
返回值:GameRGBAColor
sub ▸sub(rgba:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
返回值:GameRGBAColor
toString ▸toString():string 返回值:string
类 - GameStorage 数据存储模块,管理游戏中的数据。
storage 对象是整个 Data Storage API的入口
getDataStorage • getDataStorage : function 连接指定数据存储空间,如果不存在则创建一个新的空间。
函数声明 ▸ (key: string): GameDataStorage
参数:
名称 | 类型 | |
---|---|---|
key | string | 指定空间的名称,长度不超过50个字符 |
返回值:GameDataStorage
示例代码
getGroupStorage • getGroupStorage : function 连接地图组内指定数据存储空间,如果不存在则创建一个新的空间。此方法拿到的GameDataStorage为主图和副图共同维护的数据存储空间。
函数声明 ▸ (key: string): GameDataStorage
参数:
名称 | 类型 | |
---|---|---|
key | string | 指定空间的名称,长度不超过50个字符 |
返回值:GameDataStorage
示例代码
主图获取玩家数据
// 在拓展地图中,如果希望主图和副图共用玩家数据,则都用getGroupStorage获取
const userStorage = storage.getGroupStorage('users')
副图获取玩家数据
const userStorage = storage.getGroupStorage('users')
类 - GameTickEvent 每一刻(tick)触发一次的事件,由GameWorld.onTick触发。 示例代码
world.onTick((tickEvent)
console.log(tickEvent.elapsedTimeMS);
console.log(tickEvent.prevTick);
console.log(tickEvent.skip);
console.log(tickEvent.tick);
})
elapsedTimeMS •elapsedTimeMS:number Wall clock time between ticks 两个时刻之间的时间间隔
prevTick •prevTick:number Last tick which was handled 上一个已处理的时刻
skip •skip:boolean 是否因为代码延迟而跳过了某些时刻
tick •tick:number 事件触发时间
类 - GameTriggerEvent 当实体/玩家触发区域的事件。 由 GameZone.onEnter, GameZone.onLeave, GameZone.nextEnter, GameZone.nextLeave 触发
参数 ●entity ●tick
参数
entity •entity:GameEntity 触发事件的实体
tick •tick:number 触发事件的时间
类 - GameVector3
构造函数 new GameVector3(x: number, y: number, z: number): GameVector3 参数:
名称 | 类型 |
---|---|
x | number |
y | number |
z | number |
返回值:GameVector3
属性
名称 | 类型 |
---|---|
x | number |
y | number |
z | number |
方法
add ▸ add(v: GameVector3): GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
angle ▸angle(v:GameVector3):number 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:number
clone ▸clone():GameVector3 返回值:GameVector3
copy ▸copy(v:GameVector3):void 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:void
cross ▸cross(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
distance ▸distance(v:GameVector3):number 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:number
div ▸div(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
dot ▸dot(v:GameVector3):number 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:number
equals ▸equals(v:GameVector3,tolerance: number):boolean 参数:
名称 | 类型 | Default |
---|---|---|
v | GameVector3 | - |
tolerance | number | 0.0001 |
返回值:boolean
exactEquals ▸exactEquals(v:GameVector3):boolean 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:boolean
lerp ▸lerp(v:GameVector3,n: number):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
n | number |
返回值:GameVector3
mag ▸mag():number 返回值:number
max ▸max(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
min ▸min(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
mul ▸mul(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v` | GameVector3 |
返回值:GameVector3
normalize ▸normalize():GameVector3 返回值:GameVector3
scale ▸scale(n: number):GameVector3 参数:
名称 | 类型 |
---|---|
n | number |
返回值:GameVector3
set ▸set(x: number,y: number,z: number):void 参数:
名称 | 类型 |
---|---|
x | number |
y | number |
z | number |
返回值:void
sqrMag ▸sqrMag():number 返回值:number
sub ▸sub(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
toString ▸toString():string 返回值:string
towards ▸towards(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
VoxelContact方块碰撞参数 被实体触碰的方块属性
x •x:number 被触碰方块的x坐标
y •y:number 被触碰方块的y坐标
z •z:number 被触碰方块的z坐标
voxel •voxel:number 被触碰的方块id
force •force:GameVector3 触碰的力
axis •axis:GameVector3 触碰的分离轴,也就是触碰后物体弹飞的方向
当实体触碰方块时触发的事件。 由 GameWorld.onVoxelContact, GameWorld.onVoxelSeparate, GameEntity.onVoxelContact, GameEntity.onVoxelSeparate 触发
axis •axis:GameVector3 触碰的分离轴,也就是触碰后物体弹飞的方向
entity •entity:GameEntity 触碰到方块的实体
force •force:GameVector3 碰撞力
tick •tick:number 实体触碰方块的时间
voxel •voxel:number 被触碰的方块id
x •x:number 被触碰方块的x坐标
y •y:number 被触碰方块的y坐标
z •z:number 被触碰方块的z坐标
类 - GameVoxels GameVoxels是控制Box3所有方块的接口,你可以使用 voxels 对象控制地形变化,利用循环语法批量生成/销毁方块,获取某个方块的类型、名称、旋转角度等。
Basic 基础
voxels.shape 属性 属性值类型:GameVector3 默认值:{x: 128, y: 128, z: 128} 世界地形最大尺寸。 目前,Box3地形最大可支持128x128x128,未来将开放更大的地形,敬请期待。
Voxel Name 方块名称
voxels.id() 方法 将方块名称转换为方块id 参数 name
名称 | 类型 | 说明 |
---|---|---|
name | string | 方块名称 |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 方块 id |
voxels.name() 方法 将方块id转换为方块名称 参数 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 方块id |
返回值 name
名称 | 类型 | 说明 |
---|---|---|
name | string | 方块名称 |
setVoxel 放置方块 如果你想要地图在非运行状态,通过脚本在场景中快速建造,可以尝试以下操作: 1开启编辑器右上角的调试模式(小虫子图标) 2使用窗口底部的控制台,输入对应的代码。 即使游戏没有运行,也能使部分代码直接生效。 💡提示 使用控制台执行脚本前,请务必要小心,提前做好项目备份工作。一旦代码生效后,有可能造成无法恢复的情况。 要操作方块时,建议先使用空白地图对代码进行充分测试,效果满意后,再操作正式的地图。
voxels.setVoxel() 方法 在指定的坐标位置放置一个方块。 参数 x, y, z, voxel, rotation
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,放置位置的x坐标 |
y | number | 必填,放置位置的y坐标 |
z | number | 必填,放置位置的z坐标 |
voxel | number | string |
rotation | number | string |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 新的方块id |
💡提示 若方块名称为'air' 或者方块id为0,则会打破 简单示例
将脚下的方块全部变成雪地
删除地面至上空的所有方块
方块自动往上增长
利用方块显示字母
利用方块显示文章
创建一个棋盘
voxels.setVoxelId() 方法 使用方块ID,直接在指定的坐标位置放置方块。执行效率比voxels.setVoxel()更快。 参数 x, y, z, voxel
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,放置的方块 x 坐标 |
y | number | 必填,放置的方块 y 坐标 |
z | number | 必填,放置的方块 z 坐标 |
voxel | number | 必填,放置的方块 id |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 返回指定位置的方块id |
getVoxel 获取方块
voxels.getVoxel() 方法 获取某个坐标位置的方块id 参数 x, y, z
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,获取的方块 x 坐标 |
y | number | 必填,获取的方块 y 坐标 |
z | number | 必填,获取的方块 z 坐标 |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 返回指定位置的方块id |
voxels.getVoxelId() 方法 直接获取指定位置的方块ID。执行效率比voxels.getVoxel()更快。 参数 x, y, z
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,获取的方块 x 坐标 |
y | number | 必填,获取的方块 y 坐标 |
z | number | 必填,获取的方块 z 坐标 |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 返回指定位置的方块id |
voxels.getVoxelRotation() 方法 获取某个坐标位置的方块旋转码 参数 x, y, z
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,获取的方块 x 坐标 |
y | number | 必填,获取的方块 y 坐标 |
z | number | 必填,获取的方块 z 坐标 |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 返回指定位置的方块id |
Voxels Type 方块类型
voxels.VoxelTypes 属性 属性值类型:Array 默认值:String[] 返回包含所有方块名称的数组。
Build 快速建造 此处提供一些快速建造特定几何造型的代码片段,可供参考。 实心矩形
空心矩形
实心球体
圆柱体
生成楼梯(+x)
生成楼梯(-x)
💡提示 方块id和名称对照表
方块id | 名称 |
---|---|
0 | air |
3 | add |
5 | subtract |
7 | multiply |
9 | divide |
11 | equal |
13 | exclamation_mark |
15 | question_mark |
17 | zero |
19 | one |
21 | two |
23 | three |
25 | four |
27 | five |
29 | six |
31 | seven |
33 | eight |
35 | nine |
37 | A |
39 | B |
41 | C |
43 | D |
45 | E |
47 | F |
49 | G |
51 | H |
53 | I |
55 | J |
57 | K |
59 | L |
61 | M |
63 | N |
65 | O |
67 | P |
69 | Q |
71 | R |
73 | S |
75 | T |
77 | U |
79 | V |
81 | W |
83 | X |
85 | Y |
87 | Z |
89 | cadet_blue |
91 | sky_blue |
93 | powder_blue |
95 | dark_gray |
97 | light_gray |
99 | olive_green |
101 | yellow_green |
103 | pale_green |
105 | red |
107 | dark_red |
109 | brick_red |
111 | medium_gray |
113 | dark_slate_blue |
115 | pink |
117 | sakura_pink |
119 | orange |
121 | lemon |
123 | stained_glass |
125 | dirt |
127 | grass |
129 | stone |
131 | green_leaf |
133 | acacia |
135 | sand |
137 | plank_01 |
139 | plank_02 |
141 | plank_03 |
143 | plank_04 |
145 | ice_brick |
147 | light_grey_stone_brick |
149 | grey_stone_brick |
151 | gold_trim_brick |
153 | red_brick |
155 | quartz_brick |
157 | lantern_01 |
159 | lantern_02 |
160 | window |
162 | cross_window |
164 | geometric_window_01 |
166 | geometric_window_02 |
169 | snow |
170 | glass |
172 | color_glass |
175 | black |
177 | white |
179 | wooden_box |
181 | board_01 |
183 | board_02 |
185 | stripe_01 |
187 | stripe_02 |
189 | stripe_03 |
191 | stripe_04 |
193 | stripe_05 |
195 | carpet_01 |
197 | carpet_02 |
199 | carpet_03 |
201 | carpet_04 |
203 | carpet_05 |
205 | carpet_06 |
207 | carpet_07 |
209 | palace_eaves_01 |
211 | palace_eaves_02 |
213 | palace_eaves_03 |
215 | palace_eaves_04 |
217 | palace_eaves_05 |
219 | palace_eaves_06 |
221 | palace_eaves_07 |
223 | palace_eaves_08 |
225 | roof_red |
227 | roof_purple |
229 | roof_green |
231 | roof_blue_04 |
233 | roof_yellow |
235 | carpet_08 |
237 | carpet_09 |
239 | carpet_10 |
241 | carpet_11 |
243 | carpet_12 |
245 | carpet_13 |
247 | stainless_steel |
249 | ice_wall |
251 | leaf_01 |
253 | leaf_02 |
255 | palace_roof |
257 | wood |
259 | red_brick_floor |
261 | red_brick_wall |
263 | palace_floor |
264 | palace_carving |
267 | stone_pillar_03 |
269 | stone_pillar_04 |
271 | stone_pillar_05 |
273 | stone_pillar_06 |
275 | stone_wall |
276 | blue_glass |
278 | green_glass |
281 | red_light |
283 | orange_light |
285 | yellow_light |
287 | green_light |
289 | indigo_light |
291 | blue_light |
293 | purple |
295 | pink_light |
297 | mint_green_light |
299 | white_light |
301 | warm_yellow_light |
302 | black_glass |
304 | red_glass |
307 | palace_lamp |
309 | board_03 |
311 | board_04 |
313 | board_05 |
315 | board_06 |
317 | dark_grass |
319 | greenbelt_L |
321 | greenbelt_L1 |
323 | stone_brick_01 |
325 | stone_brick_02 |
327 | dark_stone |
329 | dark_brick_00 |
331 | dark_brick_01 |
333 | dark_brick_02 |
335 | stone_wall_01 |
337 | pink_cake |
339 | macaroon |
341 | biscuit |
343 | snowland |
345 | polar_region |
347 | polar_ice |
349 | blue_surface_01 |
351 | blue_surface_02 |
353 | purple_surface_01 |
355 | purple_surface_02 |
357 | dark_surface |
359 | rock |
361 | palace_cloud |
363 | blue |
364 | water |
367 | turquoise |
369 | dark_orchid |
371 | medium_orchid |
373 | medium_purple |
375 | medium_violet_red |
377 | maroon |
379 | coffee_gray |
381 | peru |
383 | dark_salmon |
385 | navajo_white |
387 | orange_red |
389 | medium_yellow |
391 | medium_green |
393 | sienna |
395 | mint_green |
397 | medium_spring_green |
398 | ice |
401 | crane_roof_01 |
403 | crane_roof_02 |
405 | crane_lantern |
407 | roof_grey |
408 | palace_window |
411 | woodstone_12 |
412 | strawberry_juice |
414 | lime_juice |
416 | blueberry_juice |
418 | lemon_juice |
420 | grape_juice |
422 | orange_juice |
424 | milk |
426 | soy_sauce |
428 | coffee |
430 | peach_juice |
433 | board0 |
435 | board1 |
437 | board2 |
439 | board3 |
441 | board4 |
443 | board5 |
445 | board6 |
447 | board7 |
449 | board8 |
451 | board9 |
453 | board10 |
455 | board11 |
457 | board12 |
459 | board13 |
461 | board14 |
463 | board15 |
465 | lava01 |
467 | lava02 |
469 | windygrass |
471 | conveyor |
473 | ledfloor01 |
475 | ledfloor02 |
477 | yellow_grass |
479 | express_box |
481 | television |
483 | bookshelf |
485 | ampersand |
487 | asterisk |
489 | at |
491 | backslash |
493 | bracket_close |
495 | bracket_open |
497 | caret |
499 | colon |
501 | comma |
503 | dollar |
505 | greater_than |
507 | less_than |
509 | paren_open |
511 | paren_close |
513 | percent |
515 | period |
517 | pound |
519 | quotation_mark |
521 | semicolon |
523 | slash |
525 | tilde |
527 | winter_leaf |
529 | leaf_03 |
531 | leaf_04 |
533 | leaf_05 |
535 | honeycomb_01 |
537 | honeycomb_02 |
539 | white_grass |
541 | palm |
类 - GameWearable 用于在玩家身体部位可穿戴配件物体的参数与函数
参数 ●bodyPart ●color ●emissive ●mesh ●metalness ●offset ●orientation ●player ●scale ●shininess
函数 ●remove
控制穿戴配件的参数
bodyPart •bodyPart:GameBodyPart= GameBodyPart.HEAD 穿戴配件在玩家上的部位
color •color:GameRGBColor‹›= new GameRGBColor(1, 1, 1) 穿戴配件的颜色
emissive •emissive:number= 0 穿戴配件的发光度
mesh •mesh:string= "" 穿戴配件的形状数据 e.g.mesh = 'mesh/my-mesh.vb' 注意:'mesh/my-mesh.vb'必须在文件列表中(Tips: 先将模型加到地图上,再删掉即可。)
metalness •metalness:number= 0 穿戴配件的金属感
offset •offset:GameVector3‹›= new GameVector3(0, 0, 0) 穿戴配件的位移
orientation •orientation:GameQuaternion‹›= new GameQuaternion(0, 1, 0, 0) 穿戴配件的旋转角度
player •player:GamePlayer| null= null 穿戴配件的玩家
scale •scale:GameVector3‹›= new GameVector3(1, 1, 1) 穿戴配件的缩放比例
shininess •shininess:number= 0 穿戴配件的反光度
函数
remove ▸remove():void Returns:void 示例代码
// 在玩家离开液体时把在玩家身上所有的穿戴配件删除
world.onFluidLeave(({ entity }) => {
if (entity.isPlayer) {
const allWearables = entity.player.wearables();
allWearables.forEach((item) => {
item.remove();
});
}
});
类 - GameWorld GameWorld这个类在当前地图是有全局唯一的实例 world,你可以使用world对象控制环境天气、物理重力、画面滤镜等全局场景属性,还可以在世界中创建、搜索实体,或监听世界中实体和玩家的碰撞、伤害、互动等事件。
Basics 基础
world.projectName 属性 属性值类型:string 默认值:无 本张地图名称,对应项目设置中的名称。 该属性是只读的,如需修改地图名称,请在编辑器菜单底部 [项目-编辑资料-地图名称] 进行修改。
world.onTick() 事件 这是世界的计时事件,每64毫秒触发一次,Tick计数加1。 监听此事件可以让世界以64毫秒为间隔循环执行代码。 在理想情况下,每Tick为64毫秒。若网络发生延迟,可能会有变化。 ●onTick: GameEventChannel[GameTickEvent](%5BGameTickEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/iewkxcpddoqrt1vl)) ●nextTick: GameEventFuture[GameTickEvent](%5BGameTickEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/iewkxcpddoqrt1vl)) 返回值 GameTickEvent:{ tick, prevTick, elapsedTimeMS, skip }
名称 | 类型 | 说明 |
---|---|---|
tick | number | 事件发生时间 |
prevTick | number | 上一个已处理的时刻 |
elapsedTimeMS | number | 两个时刻之间的时间间隔(毫秒) |
skip | boolean | 是否因为延迟而跳过了某些 Tick |
示例代码1
示例代码2
world.currentTick 属性 属性值类型:number 默认值:0 世界当前的Tick计数。
Chat 聊天频道
world.say() 方法 向所有玩家广播一条消息。 参数 message
名称 | 类型 | 说明 |
---|---|---|
message | string | 要广播的消息 |
简单示例
循环喊话
高级计时器
world.onChat() 事件 当玩家在聊天窗口说话时触发
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 发起聊天的实体 |
message | string | 聊天事件中说话的内容 |
tick | number | 聊天事件发生时间 |
Player 玩家:加入/离开
world.onPlayerJoin()事件:当玩家加入地图时触发
返回值 GameEntityEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 创建的实体 |
tick | number | 事件发生时间 |
简单示例
所有玩家飞行
特定玩家进入地图提醒
world.onPlayerLeave()事件: 当玩家离开地图时触发 返回值 GameEntityEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 离开地图的实体 |
tick | number | 事件发生时间 |
Input 点击/互动
world.onInteract()事件: 若实体开启了互动功能enableInteract = true,则玩家与实体进行互动时触发。 当玩家走进实体的互动范围,实体身上就会出现按键提示,玩家按下互动按钮(默认为键盘E按键)与该实体进行互动。 触发onInteract事件同时还会触发实体默认的互动音效 返回值 GameInteractEvent{ entity, targetEntity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 发起互动的实体 |
targetEntity | GameEntity | 收到互动请求的实体 |
tick | number | 事件发生时间 |
💡提示 想要和实体进行互动,需要先在编辑器中放置一个模型,并给他取一个名字。 这里的示范,将名字改为了'NPC'。
💡提示 通过通过监听onInteract事件,可以自定义互动时发生的行为。 比如,让实体说话,或让玩家显示一个对话框
world.onClick()事件: 当玩家用鼠标点击实体时触发 返回值 GameInputEvent:{ entity, clicker, button, distance, clickerPosition, raycast, tick}
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 被点击的实体 |
clicker | GameEntity& {isPlayer:true,player:GamePlayer} | 发起点击事件的玩家 |
button | GameButtonType | 点击的按钮,ACTION0 = 左键,ACTION1 = 右键 |
distance | number | 玩家到被点击实体的距离 |
clickerPosition | GameVector3 | 点击鼠标的瞬间玩家所在位置 |
raycast | GameRaycastResult | 按下按钮瞬间,从玩家视角投射的射线检测结果 |
tick | number | 事件发生时间 |
world.onPress()事件: 当玩家按下按钮时触发 返回值 GameInputEvent:{ button, entity, position, pressed, raycast, tick }
名称 | 类型 | 说明 |
---|---|---|
button | GameButtonType | 玩家输入的按钮 |
entity | GameEntity& {isPlayer:true, player:GamePlayer} | 按下按钮的玩家 |
position | GameVector3 | 按下按钮瞬间,玩家的位置 |
pressed | boolean | 是否按下了按钮。若为 true,则为按下了按钮。 |
raycast | GameRaycastResult | 按下按钮瞬间,从玩家视角投射的射线检测结果 |
tick | number | 事件发生时间 |
world.onRelease()事件: 当玩家松开按钮时触发 返回值 GameInputEvent:{ button, entity, position, pressed, raycast, tick }
名称 | 类型 | 说明 |
---|---|---|
button | GameButtonType | 玩家输入的按钮 |
entity | GameEntity& {isPlayer:true, player:GamePlayer} | 按下按钮的玩家 |
position | GameVector3 | 按下按钮瞬间,玩家的位置 |
pressed | boolean | 是否按下了按钮。若为 false,则为松开按钮。 |
raycast | GameRaycastResult | 按下按钮瞬间,从玩家视角向前投射的射线检测结果 |
tick | number | 事件发生时间 |
💡提示 提示:GameWorld 和 GamePlayer 都有触发点击/按下按钮的事件。他们的区别就是: ●GameWorld会监听世界所有实体的事件 ●GamePlayer 只监听玩家本身的事件 通常 GamePlayer.onPress() 会放在 GameWorld.onPlayerJoin() 事件中使用。 详情请阅读 GamePlayer
Entity 实体:创建/销毁
world.createEntity() 方法 创建一个新实体GameEntity或复制一个现有的实体,若实体数量(entityQuota)达到上限,则返回 null。 参数 GameEntityConfig
名称 | 类型 | 说明 |
---|---|---|
config | Partial[GameEntityConfig](%5BGameEntityConfig%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/vim7evgezkmnvhxk)) | 指定实体的一组初始值 |
返回值 GameEntity
名称 | 类型 | 说明 |
---|---|---|
Entity | GameEntity | 根据指定参数创建的一个新实体 |
💡提示 需要提前在编辑器中添加'花'的模型。 添加后可以在地图中删除 (只需确保 设置-文件 页面中已加载 花.vb 模型文件)。
world.entityQuota() 方法 返回脚本当前仍可创建的实体数量 返回值 number
类型 | 说明 |
---|---|
number | 当前仍可创建的实体数量 |
world.onEntityCreate()事件:当实体被创建时触发
返回值 GameEntityEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 被创建的实体 |
tick | number | 事件发生时间 |
world.onEntityDestroy()事件:当实体被销毁时触发
返回值 GameEntityEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 销毁的实体 |
tick | number | 事件发生时间 |
Battle & Health 战斗及生命值 若实体开启了允许伤害的属性(enableDamage = true),可以通过hurt()方法对该实体造成生命值伤害。 伤害: 实体受到伤害,会触发onTakeDamage()事件。 死亡: 实体生命值HP降为0以下时,实体将触发死亡事件onDie(), 倒地不起。 复活: 实体死亡后,可通过增加生命值HP,让实体进行复活,同时触发onRespawn()事件。 强制重生: 如果实体类型为玩家,还可以通过forceRespawn()方法,使玩家强制重生,返回出生点。
world.onTakeDamage() 事件 当实体受到伤害时触发。 ●onTakeDamage:GameEventChannel[GameDamageEvent](%5BGameDamageEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aivo4orkcmc9m0gm)) ●nextTakeDamage:GameEventFuture[GameDamageEvent](%5BGameDamageEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aivo4orkcmc9m0gm)) 返回值 GameDamageEvent:{ entity, attacker, damage, damageType, tick }
名称 | 类型 | 说明 |
---|---|---|
attacker | GameEntity | null |
damage | number | 伤害值 |
damageType | string | 伤害类型 |
entity | GameEntity | 受到伤害的实体 |
tick | number | 事件发生时间 |
world.onDie() 事件 当实体死亡时触发。 ●onDie:GameEventChannel[GameDieEvent](%5BGameDieEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/fsnsdr8uvuspan6y)) ●nextDie:GameEventFuture[GameDieEvent](%5BGameDieEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/fsnsdr8uvuspan6y)) 返回值 GameDieEvent:{ entity, attacker, damageType, tick }
名称 | 类型 | 说明 |
---|---|---|
attacker | GameEntity | null |
damageType | string | 伤害类型 |
entity | GameEntity | 死亡的实体 |
tick | number | 事件发生时间 |
简单示例
死亡5秒后重生
world.onRespawn() 事件 当实体复活时触发。 onRespawn:GameEventChannel[GameRespawnEvent](%5BGameRespawnEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cshui17169guugxr)) nextRespawn:GameEventFuture[GameRespawnEvent](%5BGameRespawnEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cshui17169guugxr)) 返回值 GameRespawnEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 死亡的实体 |
tick | number | 事件发生时间 |
提示 GameWorld 和 GameEntity 拥有相同的触发事件。 他们的区别是 ●GameWorld会触发世界所有的实体事件。 ●GameEntity 只触发实体本身的事件。
Zones 区域
world.addZone() 方法 创建一个区域,用于检测实体进入或离开某个区域。 也可以用来设置环境参数,如雾、雨、天、雪、风、重力等定义区域内的环境参数。 参数 GameZoneConfig
名称 | 类型 | 说明 |
---|---|---|
config | Partial‹GameZoneConfig› | 指定区域的一组初始参数值 |
返回值 GameZone
名称 | 类型 | 说明 |
---|---|---|
GameZone | GameZone | 区域 |
world.removeZone() 方法 删除区域 参数 zone
名称 | 类型 | 说明 |
---|---|---|
zone | GameZone | 要删除的区域 |
world.zones() 方法 返回所有的区域列表 返回值 GameZone[]
名称 | 类型 | 说明 |
---|---|---|
GameZone[] | GameZone | 所有的区域 |
Search 搜索 Game可以用类似jQuery选择器的语法来搜索某些实体。 ●搜索全部:'*' ●搜索名称:'#id' ●搜索标签:'.tag' ●搜索同时包含多个标签:'.tag1 .tag2' ●搜索玩家:'player'
world.querySelector() 方法 搜索满足条件的第一个实体。 参数 selector
名称 | 类型 | 说明 |
---|---|---|
selector | GameSelectorString | 一个选择器搜索模式。 |
返回值 GameEntity | null
名称 | 类型 | 说明 |
---|---|---|
Entity | GameEntity | 符合选择器的首个实体 |
简单示例
示例代码2
world.querySelectorAll() 方法 搜索满足条件的所有实体,返回一个列表。 参数 selector
名称 | 类型 | 说明 |
---|---|---|
selector | GameSelectorString | 一个选择器搜索模式 |
返回值 GameEntity[]
名称 | 类型 | 说明 |
---|---|---|
Entity[] | GameEntity | 符合选择器的全部实体 |
简单示例
搜索所有玩家
💡提示 querySelector 和 querySelectorAll 两者区别是 querySelector 搜索满足条件的第一个实体,如果没有搜索到,则返回 null querySelectorAll 搜索满足条件的所有实体,返回是一个数组,如果没有搜索到实体,则返回空的数组。
world.searchBox() 方法 搜索指定范围中的全部实体 参数 bounds
名称 | 类型 | 说明 |
---|---|---|
bounds | GameBounds3 | 要搜索的范围边界 |
返回值 GameEntity[]
名称 | 类型 | 说明 |
---|---|---|
Entity[] | GameEntity | 范围内的全部实体 |
world.raycast() 方法 射线检测,从origin原点位置向direction方向投射一条隐形的射线,返回碰到的实体或方块。 参数 origin, direction, options
名称 | 类型 | 说明 |
---|---|---|
origin | GameVector3 | 必填,射线的起点 |
direction | GameVector3 | 必填,射线的方向 |
options | GameRaycastOptions | 可选,选项配置参数 |
返回值 GameRaycastResult
名称 | 类型 | 说明 |
---|---|---|
origin | GameVector3 | 射线的起点 |
direction | GameVector3 | 射线的方向 |
distance | number | 射线穿越的距离 |
hit | boolean | 如果为真,则射线击中了目标 |
hitEntity | GameEntity | null |
hitPosition | GameVector3 | 射线击中的位置 |
hitVoxel | number | 射线所击中的方块 id (如未击中方块,则为 0) |
voxelIndex | GameVector3 | 如果射线击中的是方块,则返回所击中方块的网格坐标。 |
normal | GameVector3 | 射线所击中平面的法向量 |
Physics 物理相关 📌
world.gravity 属性 属性值类型:number 默认值:-0.1 世界重力。对应编辑器菜单 [场景-物理-地心引力] 控件属性。 数值越小,行动越笨重。受重力影响最明显的属性是跳跃高度及下落速度。如果重力数值大于0,可以实现反重力。
world.airFriction 属性 属性值类型:number 默认值:0.001 空气阻力。对应编辑器菜单[场景-速度阻尼]控件属性。 数值在0-1之间。数值越大,行走加速度越小。可以用来模拟大风的环境。
world.onEntityContact() 事件 当实体与实体发生碰撞时触发。 ●onEntityContact:GameEventChannel[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) ●nextEntityContact:GameEventFuture[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) 返回值 GameEntityContactEvent:{ entity, other, force, axis, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 碰撞中的第一个实体 |
other | GameEntity | 碰撞中的第二个实体 |
force | GameVector3 | 碰撞所产生的力 |
axis | GameVector3 | 碰撞后物体弹飞的方向 |
tick | number | 事件发生时间 |
简单示例
碰到指定实体加血
碰到实体变身
💡提示 两个实体刚接触的第一下,触发onEntityContact 直到两个实体分开,触发onEntitySeparate
world.onEntitySeparate() 事件 实体与实体结束碰撞时触发。 ●onEntitySeparate:GameEventChannel[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) ●nextEntitySeparate:GameEventFuture[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) 返回值 GameEntityContactEvent:{entity, other, force, axis, tick}
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 碰撞中的第一个实体 |
other | GameEntity | 碰撞中的第二个实体 |
force | GameVector3 | 碰撞所产生的力 |
axis | GameVector3 | 碰撞后物体弹飞的方向 |
tick | number | 事件发生时间 |
world.onVoxelContact() 事件 当实体与方块发生碰撞时触发。 ●onVoxelContact:GameEventChannel[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) ●nextVoxelContact:GameEventFuture[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) 返回值 GameVoxelContactEvent:{ entity, voxel, x, y, z, force, axis, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 触碰方块的实体 |
voxel | number | 被触碰的方块 id |
x | number | 被触碰方块的 x 坐标 |
y | number | 被触碰方块的 y 坐标 |
z | number | 被触碰方块的 z 坐标 |
force | GameVector3 | 碰撞所产生的力 |
axis | GameVector3 | 碰撞后物体弹飞的方向 |
tick | number | 事件发生时间 |
破坏碰到的冰块
检测脚下的方块
world.onVoxelSeparate() 事件 当实体与方块结束碰撞时触发。 ●onVoxelSeparate:GameEventChannel[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) ●nextVoxelSeparate:GameEventFuture[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) 返回值 GameVoxelContactEvent:{ entity, voxel, x, y, z, force, axis, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 触碰方块的实体 |
voxel | number | 被触碰的方块 id |
x | number | 被触碰方块的 x 坐标 |
y | number | 被触碰方块的 y 坐标 |
z | number | 被触碰方块的 z 坐标 |
force | GameVector3 | 碰撞所产生的力 |
axis | GameVector3 | 碰撞后物体弹飞的方向 |
tick | number | 事件发生时间 |
world.onFluidEnter() 事件 当实体进入水里/液体时触发。 ●onFluidEnter:GameEventChannel[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) ●nextFluidEnter:GameEventFuture[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) 返回值 GameFluidContactEvent:{ entity, voxel, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 触碰液体的实体 |
voxel | number | 触碰的液体方块 |
tick | number | 事件发生时间 |
world.onFluidLeave() 事件 当实体离开水里/液体时触发。 ●onFluidLeave:GameEventChannel[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) ●nextFluidLeave:GameEventFutureameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) 返回值 GameFluidContactEvent:{ entity, voxel, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 触碰液体的实体 |
voxel | number | 触碰的液体方块 |
tick | number | 事件发生时间 |
world.addCollisionFilter() 方法 添加碰撞过滤器,关闭两个实体组之间的碰撞。其中两个实体组分别用选择器aSelector、bSelector来定义,可按实体名称、标签、以及是否玩家等条件来筛选。 参数
名称 | 类型 | 说明 |
---|---|---|
aSelector | GameSelectorString | 用于定义第一组实体的选择器 |
bSelector | GameSelectorString | 用于定义第二组实体的选择器 |
返回值 void
world.removeCollisionFilter() 方法 移除碰撞过滤器,不再关闭两个实体组aSelector、bSelector之间的碰撞。 参数
名称 | 类型 | 说明 |
---|---|---|
aSelector | GameSelectorString | 用于定义第一组实体的选择器 |
bSelector | GameSelectorString | 用于定义第二组实体的选择器 |
返回值 void
world.clearCollisionFilters() 方法 清除全部碰撞过滤器。 返回值 void
world.collisionFilters() 方法 返回当前有效的全部碰撞过滤器。 Returns a list of all currently active collision filters 返回值 string[][]
类型 | 说明 |
---|---|
string[][] | 当前有效的全部碰撞过滤器 |
world.testSelector() 方法 测试实体是否符合某个选择器(Selector)的条件。 Test a selector on an entity. 参数
名称 | 类型 | 说明 |
---|---|---|
selector | GameSelectorString | 要测试的选择器 |
entity | GameEntity | 要测试的实体 |
返回值 boolean
类型 | 说明 |
---|---|
boolean | true: 实体符合选择器的条件;false: 实体不符合选择器的条件 |
简单示例
示例代码2
Sound 音乐音效
world.sound() 方法 播放一段声音,所有玩家都能听到。在[文件管理]窗口右下角[上传音频],通过.sound()方法传入声音文件的路径。 参数 spec | string
名称 | 类型 | 说明 |
---|---|---|
sample | string | 必填,声音文件路径。可在文件管理器中上传自定义声音。如'audio/chat.mp3' |
gain | number | 可选,音量增益。正常为 1,数值越大,声音越响。 |
position | GameVector3 | 可选,声音播放的位置。可以指定在某个实体身上发出声音。 |
radius | number | 可选,声音范围。默认为 32,即 2 格方块距离。超出范围的玩家则听不到声音。 |
pitch | number | 可选,音高增益。正常为 1,大于 1,声音播放越快,小于 1,声音播放越慢。 |
简单示例
示例代码2
💡提示 除了world.sound(),Entity和Player也拥有类似播放声音的功能。 使用 entity.sound() 可以在实体的位置播放声音,设置radius范围后,周围的玩家都可以听见声音。 使用 player.sound() 仅某个玩家自己可以听到声音,其他玩家都听不到。 Game世界预设了一些声音属性,在对应的事件触发时播放音效: 当地图开始运行时循环播放的背景音乐, 当任意玩家进入/离开地图时时播放的音效, 当任意方块被放置/破坏时播放的音效。
world.ambientSound 属性 属性值类型:new GameSoundEffect() 默认值:'' 改变地图背景音乐,从地图运行开始循环播放。 背景音乐的音量会根据用户在[设置-声音]更改。
world.playerJoinSound
属性 属性值类型:new GameSoundEffect() 默认值:'' 当玩家进入地图时,播放的音效。通过world.onPlayerJoin()触发。
world.playerLeaveSound
属性 属性值类型:new GameSoundEffect() 默认值:'' 当玩家离开地图时,播放的音效。通过world.onPlayerLeave()触发。
world.placeVoxelSound
属性 属性值类型:new GameSoundEffect() 默认值:'audio/place_block.mp3' 方块被放置时,播放的音效。通过GameVoxels.setVoxel()触发。默认音效为'audio/place_block.mp3'
world.breakVoxelSound
属性 属性值类型:new GameSoundEffect() 默认值:'audio/break_block.mp3' 方块被销毁时,播放的音效。通过GameVoxels.setVoxel()触发。默认音效为'audio/break_block.mp3'
Weather 天气:雾
world.maxFog 属性 属性值类型:number 默认值:1 最大雾量。对应编辑器菜单[场景-全局特效-雾气-最大雾量]控件属性。
world.fogColor 属性 属性值类型:number 默认值:new GameRGBColor(1, 1, 1) 雾的颜色。对应编辑器菜单[场景-全局特效-雾气-颜色]控件属性。
world.fogStartDistance 属性 属性值类型:number 默认值:0 ●fogStartDistance: number = 0 雾起始距离。对应编辑器菜单[场景-全局特效-雾气-起始距离]控件属性。
world.fogHeightOffset 属性 属性值类型:number 默认值:0 雾起始高度。对应编辑器菜单[场景-全局特效-雾气-高度]控件属性。
world.fogUniformDensity 属性 属性值类型:number 默认值:0 雾均匀密度,对应编辑器菜单[场景-全局特效-雾气-均匀雾量]控件属性。 若值大于0,越难看到天空。
world.fogHeightFalloff 属性 属性值类型:number 默认值:0.8 雾衰减的速率。对应编辑器菜单 [场景-全局特效-雾气-高度衰减系数] 控件属性。 数值在0-1之间。值越小,雾越浓。
Weather 天气:雨
world.rainSpeed 属性 属性值类型:number 默认值:1 雨的速度。对应编辑器菜单[场景-全局特效-雨-速度]控件属性。
world.rainColor 属性 属性值类型:GameRGBAColor 默认值:new GameRGBAColor(1, 1, 1, 1) 雨的颜色。对应编辑器菜单[场景-全局特效-雨-颜色]控件属性。
world.rainDirection 属性 属性值类型:GameVector3 默认值:new GameVector3(0, 1, 0) 雨的方向。对应编辑器菜单[场景-全局特效-雨-方向]控件属性。
world.rainDensity 属性 属性值类型:number 默认值:0 雨的密度。对应编辑器菜单[场景-全局特效-雨-密度]控件属性。 密度越大,雨滴越多。
world.rainInterference 属性 属性值类型:number 默认值:0 雨的扰动幅度。对应编辑器菜单[场景-全局特效-雨-不规则性]控件属性。
world.rainSizeLo 属性 属性值类型:number 默认值:0 雨滴的最小直径。
world.rainSizeHi 属性 属性值类型:number 默认值:1 雨滴的最大直径。
Weather 天气:雪
world.snowColor 属性 属性值类型:GameRGBAColor 默认值:new GameRGBAColor(1, 1, 1, 1) 雪花颜色。
world.snowTexture 属性 属性值类型:string 默认值:'' 雪花纹理。此处填写文件管理器中的纹理资源名称。如 'snow/heart.part'
world.snowDensity 属性 属性值类型:number 默认值:0 雪的密度。密度越大,雪花越多。
world.snowFallSpeed 属性 属性值类型:number 默认值:1 雪花下落速度。如果小于0,则反向运动。
world.snowSpinSpeed 属性 属性值类型:GameVector3 默认值:new GameVector3(0, 0, 0) 雪花自旋速度。
world.snowSizeLo 属性 属性值类型:number 默认值:0 雪花最小直径。
world.snowSizeHi 属性 属性值类型:number 默认值:1 雪花最大半径。
Weather 天气: 光照
world.lightMode 属性 属性值类型:string 默认值:'natural' 作用于天空和环境光的照明类型。对应编辑器设置 [场景-日光-日光规律] 控件属性。 目前有提供2种光照模式,'manual'(自定义)或'natural'(动态)。默认为 'natural'。
world.sunFrequency 属性 属性值类型:number 默认值:0 太阳运动的频率,数值越大,昼夜交替越快。 昼夜时间计算公式:timeOfDay = (sunPhase + sunFrequency * tick) % 1
world.sunPhase 属性 属性值类型:number 默认值:0 范围:0-1 太阳从升起至落下,在天空的初始位置。对应编辑器菜单 [场景-日光] 控件属性。 数值在0-1之间。大于0.5时,世界进入黑夜。 仅在日光规律为 natural 状态时生效。 💡提示 关于太阳位置和世界时间的关系: 太阳位置 sunPhase = 0 世界时间为 06:00 太阳位置 sunPhase = 0.25 世界时间为 12:00 太阳位置 sunPhase = 0.5 世界时间为 18:00 太阳位置 sunPhase = 0.75 世界时间为第二天 00:00 太阳位置 sunPhase = 1 世界时间为第二天 06:00
world.sunDirection 属性 属性值类型:GameVector3 默认值:new GameVector3(0, -1, 0) 太阳光照明方向。仅在光照模式为manual自定义模式时生效。
world.sunLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(1000, 1000, 1000) 太阳光颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyLeftLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在-X轴方向的亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyRightLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在+X轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyBottomLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在-Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyTopLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在+Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyFrontLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在-Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyBackLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在+Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
动画
world.animate() 方法 创建一个关键帧动画GameAnimation。 参数
名称 | 类型 | 说明 |
---|---|---|
keyframes | GameWorldKeyframe[] | 关键帧的数据 |
playbackInfo | GameAnimationPlaybackConfig | 动画播放参数 |
返回值
名称 | 类型 | 说明 |
---|---|---|
Animation | GameAnimation | 创建出来的动画对象 |
Web相关
world.url 属性 属性值类型:URL 获取当前地图所在的URL链接地址。
商城
world.onPlayerPurchaseSuccess() 事件 当玩家成功购买物品时触发 ●onPlayerPurchaseSuccess : GameEventChannel< GamePurchaseSuccessEvent > ●nextPlayerPurchaseSuccess : GameEventFuture < GamePurchaseSuccessEvent >
返回值 GamePurchaseSuccessEvent:{ tick, userId, ProductId, orderId }
名称 | 类型 | 说明 |
---|---|---|
tick | number | 购买成功事件发生的时间 |
userId | string | 触发购买事件的玩家userId |
productId | number | 购买商品的ID |
orderId | number | 购买成功的订单号 |
Teleport 传送
world.teleport() 方法 地图组内传送能力,能够令 Player 被传送到其他地图中。此能力受权限影响,无权限用户可见,但调用后直接报错。 参数 mapId, players
名称 | 类型 | 说明 |
---|---|---|
mapId | string | 必填,目标地图id |
players | GameEntity[] | 必填,被传送的玩家entity数组 |
需注意: ●传送进入的地图为独立服务器,因此同一张目标地图,分批次传送不同的人,所进入的是不同服务器。 ●只能在已发布地图中生效 ●players的长度不能超过50 ●players中不能存在游客(没有UserID)
简单示例
1
2
3
4
5
6
7
8
9
10
11
12
while (true) {
try {
let players = world.querySelectorAll('player').slice(0, 50)
players = players.filter(e => e.player.userId !== '' && e.player.userId !== '0' && e.player.userId !== 0)
world.teleport('100001157', players)
break
} catch (e) {
world.say('传送失败:' + e.stack)
}
await sleep(1000)
}
world.say('传送成功 ')
类 - GameZone 区域可用于检测实体进入某个区域或离开。 也可以用来设置环境参数,如雾、雨、天、雪、风、重力等定义区域内的环境参数。
参数 ●bounds ●entities ●selector ●nextEnter ●nextLeave ●onEnter ●onLeave ●remove ●force ●massScale ●fogColor ●fogDensity ●fogEnabled ●fogHeightFalloff ●fogHeightOffset ●fogMax ●fogStartDistance ●rainColor ●rainDensity ●rainDirection ●rainEnabled ●rainInterference ●rainSizeHi ●rainSizeLo ●rainSpeed ●skyBackLight ●skyBottomLight ●skyEnabled ●skyFrontLight ●skyLeftLight ●skyLunarPhase ●skyMode ●skyRightLight ●skySunDirection ●skySunFrequency ●skySunLight ●skySunPhase ●skyTopLight ●snowColor ●snowDensity ●snowEnabled ●snowFallSpeed ●snowSizeHi ●snowSizeLo ●snowSpinSpeed ●snowTexture
bounds •bounds:GameBounds3‹›= new GameBounds3( new GameVector3(0, 0, 0), new GameVector3(0, 0, 0)) 该区域的所指定的检测区域
entities •entities:function 在区域内的全部实体GameEntity
函数声明: ▸ ():GameEntity[]
fogColor •fogColor:GameRGBColor‹›= new GameRGBColor(1, 1, 1) 区域内雾的颜色
fogDensity •fogDensity:number= 0 区域内雾均匀密度
fogEnabled •fogEnabled:boolean= false 区域内雾是否开启 示例代码
fogHeightFalloff •fogHeightFalloff:number= 0.8 区域内雾衰减的速率
fogHeightOffset •fogHeightOffset:number= -8 区域内雾起始高度
fogMax •fogMax:number= 1 区域内最大雾量
fogStartDistance •fogStartDistance:number= 0 区域内雾起始距离
force •force:GameVector3‹›= new GameVector3(0, 0, 0) 对物体施加的力的大小 示例代码
massScale •massScale:number= 0 控制物体的质量对力的影响程度。 0 = 像重力一样 1 = 像风一样
onEnter
nextEnter •onEnter:GameEventChannel‹GameTriggerEvent› •nextEnter:GameEventFuture‹GameTriggerEvent› 有实体进入指定区域时,触发事件
onLeave
NextLeave •onLeave:GameEventChannel‹GameTriggerEvent› •nextLeave:GameEventFuture‹GameTriggerEvent› 有实体离开区域时触发事件 示例代码
rainColor •rainColor:GameRGBAColor‹›= new GameRGBAColor(1, 1, 1, 1) 区域内雨的颜色
rainDensity •rainDensity:number= 0 区域内雨的密度 密度越大,雨滴越多。
rainDirection •rainDirection:GameVector3‹›= new GameVector3(0, 1, 0) 区域内雨的方向
rainEnabled •rainEnabled:boolean= false 区域内雨是否开启 示例代码
rainInterference •rainInterference:number= 0 区域内雨的扰动幅度
rainSizeHi •rainSizeHi:number= 1 区域内雨滴的最大直径
rainSizeLo •rainSizeLo:number= 0 区域内雨滴的最小直径
rainSpeed •rainSpeed:number= 1 区域内雨的速度
remove •remove:function 把该区域删除
函数声明: ▸ ():void
selector •selector:GameSelectorString= "" 触发区域事件的物体搜索条件
skyBackLight •skyBackLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在+Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skyBottomLight •skyBottomLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内境光在-Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skyEnabled •skyEnabled:boolean= false 区域内环境参数是否有效 示例代码
skyFrontLight •skyFrontLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在-Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skyLeftLight •skyLeftLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在-X轴方向的亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skyLunarPhase •skyLunarPhase:number= 0 区域内月亮的相位,数值在0和1之间。若大于0.5时,为上弦月。
skyMode •skyMode:"natural" | "manual"= "natural" 区域内作用于天空和环境光的照明类型。目前有提供2种光照模式,'manual'(自定义)或'natural'(动态)。默认为 'natural'。示例代码
skyRightLight •skyRightLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在+X轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skySunDirection •skySunDirection:GameVector3‹›= new GameVector3(0, -1, 0) 区域内太阳光照明方向。仅在光照模式为manual自定义模式时生效。
skySunFrequency •skySunFrequency:number= 0 区域内太阳运动的频率,数值越大,昼夜交替越快。
skySunLight •skySunLight:GameRGBColor‹›= new GameRGBColor(1000, 1000, 1000) 区域内太阳光颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skySunPhase •skySunPhase:number= 0 区域内太阳从升起至落下,在天空的位置。
skyTopLight •skyTopLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在+Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
snowColor •snowColor:GameRGBAColor‹›= new GameRGBAColor(1, 1, 1, 1) 区域内雪花颜色
snowDensity •snowDensity:number= 0 区域内雪的密度。密度越大,雪花越多。
snowEnabled •snowEnabled:boolean= false 区域内雪是否开启 示例代码
snowFallSpeed •snowFallSpeed:number= 1 区域内雪花下落速度。如果小于0,则反向运动。
snowSizeHi •snowSizeHi:number= 1 区域内雪花最大半径
snowSizeLo •snowSizeLo:number= 0 区域内雪花最小直径
snowSpinSpeed •snowSpinSpeed:number= 0 区域内雪花自旋速度
snowTexture •snowTexture:string= "" 区域内雪花纹理
更多代码示例
// 一半酸雨, 一半樱花飘落的场景效果, 跳起来场景效果消失
world.addZone({
selector: 'player',
bounds: {
lo: [0, 0, 64],
hi: [128, 10, 128],
},
rainEnabled: true,
rainDensity: 0.5,
rainSpeed: 0.5,
snowEnabled: true,
snowDensity: 0.5,
snowTexture: 'snow/bubble.part',
snowFallSpeed: -0.1,
fogEnabled: true,
fogColor: new GameRGBColor(0.5, 1, 0),
fogDensity: 0.02,
})
world.addZone({
selector: 'player',
bounds: {
lo: [0, 0, 0],
hi: [128, 10, 64],
},
rainEnabled: true,
rainDensity: 0.5,
rainSpeed: -0.5,
snowEnabled: true,
snowDensity: 0.5,
snowTexture: 'snow/sakura.part',
snowFallSpeed: 0.1,
fogEnabled: true,
fogColor: new GameRGBColor(1, 0, 0.5),
fogDensity: 0.02,
})
类 - ServerEvent 从客户端发往服务器的自定义事件。
属性
tick number 事件产生时的客户端 Tick。
entity GamePlayerEntity 事件产生的来源用户。
args any 客户端通过该事件发送的数据。
类 - ServerRemoteChannel 管理客户端与服务端通信的系统, 与客户端脚本中的 ClientRemoteChannel
配合使用。
方法
sendClientEvent (entities:GamePlayerEntity|GamePlayerEntity[], clientEvent:any) : void 向指定玩家发送客户端事件。
参数 ●entities:GamePlayerEntity|GamePlayerEntity[] - 玩家实体列表,代表发送对象,传入空数组时不会产生任何效果 ●clientEvent:any - 自定义事件,在客户端接收到时,传入监听器的参数,仅允许可序列化的值
broadcastClientEvent (clientEvent:any) : void 向所有玩家广播客户端事件。
参数 ●clientEvent:any - 自定义事件对象,在客户端接收到时,传入监听器的参数,仅允许可序列化的值
onServerEvent GameEventChannel[ServerEvent](%5BServerEvent%5D(https://box3.yuque.com/staff-khn556/wupvz3/du8np88uv0scn51v)) 监听客户端发来的服务端事件。
Class: QueryList 键值对查询列表,用于批量获取键值对,通过 {GameDataStorage.list} 方法返回。 列表根据配置项被划分为一个或多个分页,每个分页最多包含 { ListPageOptions | pageSize} 个键值对。
基本
isLastPage • isLastPage: boolean 是否为最后一页,如果翻过头了,也会为 true
getCurrentPage • getCurrentPage: function 按 {ListPageOptions | pageSize} 获取当前页的键值对
函数声明: ▸ (): ReturnValue[]
返回值:ReturnValue[] 返回当前页的键值对内容
nextPage • nextPage : function 翻到下一页,执行后 {getCurrentPage} 将返回下一页的键值对内容
函数声明:
▸ (): Promise <void>
返回值:Promise <void>
返回 Promise 对象,resolve表示翻页成功,reject 后表示翻页失败
类型别名 - JSONValue 允许存储的值,类型可以是如下类型之一:
类型 | 描述 |
---|---|
string | 字符串 |
number | 数字 |
boolean | 布尔值 |
{ [x: string]:JSONValue} | 键值对 |
JSONValue[] | JSONValue数组 |
定义
export type JSONValue =
string
| number
| boolean
|{ [x: string]: JSONValue }
| JSONValue[];
类型别名 - ListPageOptions 批量获取键值对的配置项。
定义
●cursor:number ○分页指针,用于指定本次获取的分页起点页码。 ●pageSize?:number ○可选项,分页大小,一页内的数据量,默认100。 ●constraintTarget?:string ○约束目标值的路径,当值是JSON格式时,指定用作排序的值的路径。例如传入 score时,会取值上score属性的值作为排序、最大最小值的限制目标; ○可以级联最多5级,例如a.b.c.d.e,超出视作非法参数,按下一条方式处理; ○当路径不存在或传入非法参数时,以值本身作为目标进行排序,并打印一条警告; ●ascending?:boolean - 是否升序,设置为 true 时为升序,false为降序,不传或传入undefined时不排序; ●max?:number - 最大值,过滤返回对应值的最大值,超出或非数字则不返回该Key,默认不过滤; ●min?:number - 最小值,同max类似。
接口 - GameAnimationPlaybackConfig 用于动画播放配置的参数组
参数 | 类型 | 说明 |
---|---|---|
delay | number | 播放延迟 |
direction | GameAnimationDirection | 播放方向 |
duration | number | 播放时长 |
endDelay | number | 结束延迟 |
iterationStart | number | 反复播放开始时间 |
iterations | number | 反复播放次数 |
startTick | number | 开始时间 |
类型别名 - GameDialogCall GameDialogCall:function 在游戏中显示一个对话框。 目前支持3种对话框样式:文本框 Text/选项框 Select/输入框 Input GameDialogCall = ((params:GameTextDialogParams) => Promise<GameDialogResponse| null> &GameDialogCancelOption) | ((params:GameSelectDialogParams) => Promise<DialogSelectResponse| null> &GameDialogCancelOption) | ((params:GameInputDialogParams) => Promise<GameDialogResponse| null> &GameDialogCancelOption) |
GameDialogParams 对话框类型 ●文本对话框GameTextDialogParams ●选项对话框GameSelectDialogParams ●输入对话框GameInputDialogParams
GameDialogResponse 对话框输入响应 ●DialogSelectResponse
GameDialogParams 对话框属性列表 GameDialogParams:object
类型声明: ●type:GameDialogType 对话框的类型。目前有三种对话框类型,具体可查看GameDialogType ●content: string 对话框显示的正文内容。支持使用'\n' 换行。 ●contentBackgroundColor? :GameRGBAColor 对话框正文窗口的背景颜色。 ●contentTextColor? :GameRGBAColor 对话框正文字体的颜色。 ●title:string 对话框显示的标题名称。 ●titleBackgroundColor? :GameRGBAColor 对话框显示的标题窗口背景颜色。 ●titleTextColor? :GameRGBAColor 对话框显示的标题字体颜色。 ●hasArrow? :undefined | false | true 可选: 如果接下来还有新的对话,在当前对话框中是否显示箭头提示。 仅在文本对话框GameDialogType.TEXT中使用。 ●confirmText? :undefined | string 可选: 仅在输入对话框GameDialogType.INPUT使用。 确认按钮显示的文本。如果为空,按钮文本默认显示为 '确认 | Confirm'. ●options? :string[] 可选: 仅在选项对话框GameDialogType.SELECT中使用。 在对话框中提供一些可供玩家选择的对话选项。 ●placeholder? :undefined | string 可选: 仅在输入对话框GameDialogType.INPUT中使用。 在输入框背景显示的提示文字。 ●lookTarget?:GameVector3|GameEntity 可选: 使相机镜头朝向指定实体或坐标的位置。 ●lookTargetOffset?:GameVector3 可选: 如果相机指定了注视目标,可以设置基于目标位置的偏移。 ●lookUp?:GameVector3 可选: 调整相机抬头向量。使画面上下左右颠倒。 ●lookEye?:GameVector3|GameEntity 可选: 调整相机的位置。 ●lookEyeOffset?:GameVector3 可选: 如果相机位置指定了实体,可以设置基于目标位置的偏移。
GameTextDialogParams 文本对话框参数 GameTextDialogParams:object
类型声明: ●type:GameDialogType.TEXT 对话框类型。文本对话框的类型是GameDialogType.TEXT ●hasArrow? :undefined | false | true 是否显示箭头提示 ●content: string 对话框显示的正文内容。支持使用'\n' 换行。 ●contentBackgroundColor? :GameRGBAColor 正文背景颜色 ●contentTextColor? :GameRGBAColor 正文字体颜色 ●title:string 对话框标题 ●titleBackgroundColor? :GameRGBAColor 标题背景颜色 ●titleTextColor? :GameRGBAColor 标题正文颜色 ●lookTarget? :GameVector3|GameEntity 相机注视的实体 ●lookTargetOffset? :GameVector3 基于相机注视的位置偏移 ●lookUp? :GameVector3 相机抬头向量 ●lookEye?:GameVector3|GameEntity 相机镜头的位置 ●lookEyeOffset ?: GameVector3 基于相机位置的偏移
GameSelectDialogParams 选项对话框参数 GameSelectDialogParams:object
类型声明: ●type:GameDialogType.SELECT 对话框类型。选项对话框的类型是GameDialogType.SELECT ●options? :string[] 选项列表 ●content: string 对话框显示的正文内容。支持使用'\n' 换行。 ●contentBackgroundColor? :GameRGBAColor 正文背景颜色 ●contentTextColor? :GameRGBAColor 正文字体颜色 ●title:string 对话框标题 ●titleBackgroundColor? :GameRGBAColor 标题背景颜色 ●titleTextColor? :GameRGBAColor 标题正文颜色 ●lookTarget? :GameVector3|GameEntity 相机注视的实体 ●lookTargetOffset? :GameVector3 基于相机注视的位置偏移 ●lookUp? :GameVector3 相机抬头向量 ●lookEye?:GameVector3|GameEntity 相机镜头的位置 ●lookEyeOffset?:GameVector3 基于相机位置的偏移
GameInputDialogParams 输入对话框参数 GameInputDialogParams:object
类型声明: ●type:GameDialogType.INPUT 对话框类型。输入对话框的类型是GameDialogType.INPUT ●confirmText? :undefined | string 确认按钮文字 ●placeholder? :undefined | string 输入框提示文字 ●content: string 对话框显示的正文内容。支持使用'\n' 换行。 ●contentBackgroundColor? :GameRGBAColor 正文背景颜色 ●contentTextColor? :GameRGBAColor 正文字体颜色 ●title:string 对话框标题 ●titleBackgroundColor? :GameRGBAColor 标题背景颜色 ●titleTextColor? :GameRGBAColor 标题正文颜色 ●lookTarget? :GameVector3|GameEntity 相机注视的实体 ●lookTargetOffset? :GameVector3 基于相机注视的位置偏移 ●lookUp? :GameVector3 相机抬头向量 ●lookEye?:GameVector3|GameEntity 相机镜头的位置 ●lookEyeOffset ?: GameVector3 基于相机位置的偏移
GameDialogResponse 对话框回应 如果没有完成对话而点击了其他地方,使对话框被取消,则返回null 如果是文本对话框,回应'success' 如果是选项对话框,回应输入框填写的内容字符串 如果是选项对话框,回应DialogSelectResponse GameDialogResponse:DialogSelectResponse| string = 'success' | null
DialogSelectResponse 选项对话框回应 在选项对话框中,玩家点击了按钮,会得到对话框的回应事件。返回被玩家按下的选项信息。 DialogSelectResponse:object
类型声明: ●选项编号index:number(zero-based 从0开始计数) ●选项内容value:string
GameDialogCancelOption GameDialogCancelOption:object
函数声明: ●cancel():function 关闭对话框。
综合示例 1
world.onPlayerJoin(async ({ entity }) => {
// 玩家进入游戏时,弹出一个欢迎对话框
const dialog = entity.player.dialog({
type: GameDialogType.TEXT,
title: "吉吉喵",
content:`你好,${entity.player.name},很高兴认识你。`,
});
// 等待任何一个 [玩家点击或关闭对话框, 3秒后自动把对话框关闭]
Promise.race([
dialog,
(async() => {
await sleep(3000);
dialog.cancel();
})()
]).then( /* 任何一个函数返回 */ );
})
综合示例 2
world.onPlayerJoin(async ({ entity }) => {
// 玩家进入游戏时,弹出一个欢迎对话框
const dialog = entity.player.dialog({
type: GameDialogType.TEXT,
title: "吉吉喵",
content: `你好,${entity.player.name},很高兴认识你。`,
});
// 3秒后自动关闭
setTimeout(()=>{
dialog.cancel();
},3000);
})
接口 - GameEntityConfig 用于控制实体的参数组
参数 | 类型 | 说明 |
---|---|---|
position | GameVector3 | 实体的位置 |
velocity | GameVector3 | 实体朝向某个方向运动的作用力 |
collides | boolean | 实体是否可碰撞 |
mesh | string | mesh决定了实体的外形。'mesh/*.vb' |
meshColor | GameRGBAColor | 实体的颜色 |
meshScale | GameVector3 | 实体的缩放比例 |
meshOrientation | GameQuaternion | 实体的旋转角度 |
meshMetalness | number | 实体的金属感 |
meshEmissive | number | 实体的发光度 |
meshShininess | number | 实体的反光度 |
gravity | boolean | 实体是否会下落 |
fixed | boolean | 实体的位置是否固定不动 |
mass | number | 实体质量 |
friction | number | 实体的粘性(0 = 滑,1 = 粘) |
restitution | number | 实体的弹性(0 = 软, 1 = 弹) |
enableInteract | boolean | 允许实体进行互动 |
interactRadius | number | 进入实体互动的范围。范围越小,需更靠近。 |
interactHint | string | 进入实体互动范围时,实体身上出现的提示文本 |
interactColor | GameRGBAColor | 进入实体互动范围时,提示文本的字体颜色 |
particleRate | number | 实体每秒产生粒子的数量 |
particleRateSpread | number | 增加实体每秒产生粒子数量的随机性 |
particleLimit | number | 实体可产生粒子总数的上限 |
particleLifetime | number | 实体所产生粒子能存活的秒数 |
particleLifetimeSpread | number | 增加实体所产生粒子存活时间的随机性 |
particleSize | number[] | 实体所产生粒子的大小变化 |
particleSizeSpread | number | 增加实体所产生粒子大小的随机性 |
particleColor | GameRGBColor[] | 实体所产生粒子的颜色变化 |
particleVelocity | GameVector3 | 实体所产生粒子的初始速度 |
particleVelocitySpread | GameVector3 | 增加实体所产生粒子初始速度的随机性 |
particleDamping | number | 实体所产生粒子的阻尼系数 |
particleAcceleration | GameVector3 | 实体所产生粒子的加速度 |
particleNoise | number | 实体所产生粒子摆动的最大幅度 |
particleNoiseFrequency | number | 实体所产生粒子摆动的频率 |
chatSound | GameSoundEffect | 实体触发说话事件时播放的音效 |
interactSound | GameSoundEffect | 实体触发互动事件时播放的音效 |
hurtSound | GameSoundEffect | 实体触发受伤事件时播放的音效 |
dieSound | GameSoundEffect | 实体触发死亡事件时播放的音效 |
接口 - GameEntityKeyframe Entity实体动画关键帧参数,可对Entity除音效外的大部分属性做动画效果,例如位移、大小、模型、颜色等等
参数 | 类型 | 说明 |
---|---|---|
duration | number | 播放时长 |
easeIn | GameEasing | 缓入效果 |
easeOut | GameEasing | 缓出效果 |
velocity | GameVector3 | 实体朝向某个方向运动的作用力 |
collides | boolean | 实体是否可碰撞 |
mesh | string | mesh决定了实体的外形。'mesh/*.vb' |
meshColor | GameRGBAColor | 实体的颜色 |
meshScale | GameVector3 | 实体的缩放比例 |
meshOrientation | GameQuaternion | 实体的旋转角度 |
meshMetalness | number | 实体的金属感 |
meshEmissive | number | 实体的发光度 |
meshShininess | number | 实体的反光度 |
gravity | boolean | 实体是否会下落 |
fixed | boolean | 实体的位置是否固定不动 |
mass | number | 实体质量 |
friction | number | 实体的粘性(0 = 滑,1 = 粘) |
restitution | number | 实体的弹性(0 = 软, 1 = 弹) |
enableInteract | boolean | 允许实体进行互动 |
interactRadius | number | 进入实体互动的范围。范围越小,需更靠近。 |
interactHint | string | 进入实体互动范围时,实体身上出现的提示文本 |
interactColor | GameRGBAColor | 进入实体互动范围时,提示文本的字体颜色 |
particleRate | number | 实体每秒产生粒子的数量 |
particleRateSpread | number | 增加实体每秒产生粒子数量的随机性 |
particleLimit | number | 实体可产生粒子总数的上限 |
particleLifetime | number | 实体所产生粒子能存活的秒数 |
particleLifetimeSpread | number | 增加实体所产生粒子存活时间的随机性 |
particleSize | number[] | 实体所产生粒子的大小变化 |
particleSizeSpread | number | 增加实体所产生粒子大小的随机性 |
particleColor | GameRGBColor[] | 实体所产生粒子的颜色变化 |
particleVelocity | GameVector3 | 实体所产生粒子的初始速度 |
particleVelocitySpread | GameVector3 | 增加实体所产生粒子初始速度的随机性 |
particleDamping | number | 实体所产生粒子的阻尼系数 |
particleAcceleration | GameVector3 | 实体所产生粒子的加速度 |
particleNoise | number | 实体所产生粒子摆动的最大幅度 |
particleNoiseFrequency | number | 实体所产生粒子摆动的频率 |
类型别名 - GameEventChannel
描述 EventChannel 可用于监听指定对象的事件。输入事件处理器handler,即得取消此事件处理器的GameEventHandlerToken
,各类用于监听事件的onXXX方法均为此类型的实现。
定义
GameEventChannel
export type GameEventChannel `<EventType>` = (
handler: (event: EventType) => void,
) => GameEventHandlerToken;
●EventType- 泛型参数,用于指定事件类型 ●handler:(event: EventType) => void- 事件发生时调用的处理器
示例
1秒后停止监听onTick
// 1000毫秒后停止报时
const token = world.onTick(() => console.log("tick !"));
setTimeout(() => {
console.log('cancel tick handler');
token.cancel();// 取消记录tick事件
}, 1000);
类型别名 - GameEventFuture
描述 此类型为GameEventChannel 事件频道监听
的单次、Promise版本。 Promise(承诺)提供了另一种处理事件的方式。您可以使用Promise来组织长序列的事件,从而实现结构化编程。 配合 async/await语法使用,可以以类似同步代码的方式组织异步代码。在某些情况下,这可以使代码更简单和更清晰,但必须谨慎使用。 尽管看起来与同步代码十分相似,但异步代码在等待时可以被中断,这意味着世界中的事物可能会在您的代码之外发生变化。 此外,异步代码生成的错误不会显示堆栈跟踪,这可能会加大调试的难度。 请考虑这些因素,并谨慎使用Promise、async/await。
定义
GameEventFuture
export type GameEventFuture `<EventType>` = (
filter?: (event: EventType) => boolean,
) => Promise `<EventType>`;
●EventType- 触发的事件对象的类型 ●filter?:(event: EventType) => boolean - 一个可选的函数,用于检查事件的类型。触发事件前执行该函数并传入事件对象,如果返回false,则不会触发该事件
示例
以 async/await 方式使用
// Wait for 2 players to enter the world
async function waitForPlayers (count) {
while (world.querySelectorAll('player').length < 2) {
const { entity } = await world.nextPlayerJoin();
world.say(entity.player.name + ' joined');
}
}
waitForPlayers.then(() => world.say('game ready'));
接口: GameHurtOptions 攻击/伤害的相关参数
参数 | 类型 | 说明 |
---|---|---|
attacker | GameEntity | 发出攻击的实体 |
damageType | string | 伤害类型,可自行定义 |
接口 - GamePlayerKeyframe Player玩家动画关键帧参数,可对Player的大部分属性做动画效果,例如尺寸、颜色、隐身等等
参数 | 类型 | 说明 |
---|---|---|
duration | number | 播放时长 |
easeIn | GameEasing | 缓入效果 |
easeOut | GameEasing | 缓出效果 |
cameraEntity | GameEntity | 在第一人称视角(FPS)或第三人称跟随视角(FOLLOW)下,玩家视角所跟随的实体 |
cameraMode | GameCameraMode | 视角模式 |
cameraPosition | GameVector3 | 固定视角(FIXED)下,镜头的眼睛位置 |
cameraTarget | GameVector3 | 固定视角(FIXED)下镜头所朝向的目标点 |
cameraUp | GameVector3 | 固定视角(FIXED)下,镜头向上的矢量 |
scale | GameVector3 | 玩家的缩放比例 |
color | GameRGBColor | 玩家的颜色 |
colorLUT | string | 用于渲染玩家所见游戏世界的色调 |
invisible | boolean | 玩家是否隐身 |
emissive | number | 玩家的发光度 |
metalness | number | 玩家的金属感 |
shininess | number | 玩家的反光度 |
showName | boolean | 玩家名字是否显示 |
接口 - GameRaycastOptions 进行射线检测的参数配置
参数 | 类型 | 说明 |
---|---|---|
maxDistance | number | 允许射线穿越的最大距离 |
ignoreFluid | boolean | 如果为真,则射线无视液体 |
ignoreVoxel | boolean | 如果为真,则射线无视方块 |
ignoreEntities | boolean | 如果为真,则射线无视实体 |
ignoreSelector | GameSelectorString | 被射线检测忽略的实体选择器 |
类型别名 - GameSelectorString typeGameSelectorString= string; 选择器(Selectors)可以方便搜索游戏内的全部对象。Game的选择器接口是参照 DOM APIs 而设。
const entities = world.querySelector('*'); // 世界中的全部实体
const theChair = world.querySelector('#chair'); // 模型名称为"chair"的首个实体
const players = world.querySelectorAll('player'); // 游戏中的全部玩家
const boxes = world.querySelectorAll('.box'); // 标签带有"box"的全部实体
const redBox = world.querySelector('.box .red');// 标签同时带有"box"和“red”的首个实体
类型别名 - GameSkinInvisible 玩家身体可隐藏的部位
参数 | 类型 | 说明 |
---|---|---|
hips | boolean | 臀部 |
torso | boolean | 躯干 |
neck | boolean | 颈部 |
head | boolean | 头 |
leftShoulder | boolean | 左肩 |
leftUpperArm | boolean | 左上臂 |
leftLowerArm | boolean | 左下臂 |
leftHand | boolean | 左手 |
leftUpperLeg | boolean | 左上腿 |
leftLowerLeg | boolean | 左下腿 |
leftFoot | boolean | 左脚 |
rightShoulder | boolean | 右肩膀 |
rightUpperArm | boolean | 右上臂 |
rightLowerArm | boolean | 右下臂 |
rightHand | boolean | 右手 |
rightUpperLeg | boolean | 右上腿 |
rightLowerLeg | boolean | 右下腿 |
rightFoot | boolean | 右脚 |
接口 - GameSoundEffect 使用Sound()方法播放声音时,传入的参数。 ●sample ●gain ●gainRange ●pitch ●pitchRange ●radius
属性
sample •sample:string= "" 声音文件路径。可在文件管理器中上传自定义声音。如'audio/chat.mp3' 在指定声音文件路径时,必须确保文件已经上传在文件管理器中。
radius •radius:number= 32 声音范围。默认为32。距离实体越近,声音听的越清晰。
gain •gain:number= 1 音量增益。正常为1,数值越大,声音越响。
gainRange •gainRange:number= 0 音量增益方差。计算公式为:effect.gain + (Math.random() - 0.5) * effect.gainRange
pitch •pitch:number= 1 音高增益。正常为1。大于1,声音播放越快。小于1,声音播放越慢。
pitchRange •pitchRange:number= 0 音高增益方差。计算公式为:effect.pitch + (Math.random() - 0.5) * effect.pitchRange
音效列表
声音 | 默认音频文件 | 说明 |
---|---|---|
ambientSound | 循环播放的背景音乐。 | |
playerJoinSound | 有玩家进入游戏。通过world.onPlayerJoin()触发 | |
playerLeaveSound | 有玩家离开游戏。通过world.onPlayerLeave()触发 | |
placeVoxelSound | 'audio/place_block.mp3' | 方块被放置。通过world.setVoxel()触发 |
breakVoxelSound | 'audio/break_block.mp3' | 方块被破坏。通过world.setVoxel()触发 |
声音 | 默认音频文件 | 说明 |
---|---|---|
chatSound | 实体说话时。通过entity.say()触发 | |
hurtSound | 实体受伤时。通过entity.onTakeDamage()触发 | |
dieSound | 实体死亡时。通过entity.onDie()触发 | |
interactSound | 实体被互动时。通过entity.onInteract()触发 |
声音 | 默认音频文件 | 说明 |
---|---|---|
spawnSound | 'audio/spawn.mp3' | 玩家复活时。 |
jumpSound | 'audio/jump.mp3' | 玩家跳跃时。 |
doubleJumpSound | 'audio/double_jump.mp3' | 玩家二段跳时。 |
landSound | 'audio/land.mp3' | 玩家落地时。 |
enterWaterSound | 'audio/dive.mp3' | 玩家进入液体时。 |
leaveWaterSound | 'audio/splash.mp3' | 玩家离开液体时。 |
stepSound | 'audio/step.mp3' | 玩家正在行走,迈出一步时。 |
swimSound | 'audio/swim.mp3' | 玩家正在游泳,向前划动时。 |
crouchSound | 玩家下蹲时。 | |
startFlySound | 玩家开始飞行时。 | |
stopFlySound | 玩家结束飞行时。 | |
action0Sound | 玩家按下鼠标左键/虚拟按钮A时。 | |
action1Sound | 玩家按下鼠标右键/虚拟按钮B时。 |
上传音效 编辑器目前内置了34款音效,可以在菜单-[文件管理]的搜索.mp3查看。点击文件后,会弹出声音文件的详情属性。点击位置即可复制文件路径,在脚本中使用对应的方法播放。 如需上传自定义声音,可以在[文件管理]窗口,点击右下角浮动的加号按钮-[上传音频]。
在哪里下载优质的音效 在互联网中搜索音效时,希望能注重版权意识。使用了某个作者的作品,请务必在作品详情页注明来源。 这里推荐一些授权素材网站,只要遵守网站的使用协议,你便可以将它们免费用在你的作品中。大部分网站非中文站点,但可以借助浏览器翻译工具,进行阅读。 ●zapsplat ●soundbible ●OpenGameArt ●小森平的免费音效 ●Free SFX ●FreeSound ●SoundJay
接口 - GameWorldKeyframe World世界动画关键帧参数,可对World的大部分属性做动画效果,例如重力、雨、雾、雪、光照等等
参数 | 类型 | 说明 |
---|---|---|
duration | number | 播放时长 |
easeIn | GameEasing | 缓入效果 |
easeOut | GameEasing | 缓出效果 |
gravity | number | 世界重力 |
airFriction | number | 空气阻力 |
maxFog | number | 最大雾量 |
fogColor | GameRGBColor | 雾的颜色 |
fogHeightFalloff | number | 雾衰减的速率 |
fogHeightOffset | number | 雾起始高度 |
fogStartDistance | number | 雾起始距离 |
fogUniformDensity | number | 雾均匀密度 |
rainColor | GameRGBAColor | 雨的颜色 |
rainDensity | number | 雨的密度 |
rainDirection | number | 雨的方向 |
rainInterference | number | 雨的扰动幅度 |
rainSizeHi | number | 雨滴的最大直径 |
rainSizeLo | number | 雨滴的最小直径 |
rainSpeed | number | 雨的速度 |
snowColor | GameRGBAColor | 雪花颜色 |
snowDensity | number | 雪花密度 |
snowFallSpeed | number | 雪花速度 |
snowSizeHi | number | 雪花最大直径 |
snowSizeLo | number | 雪花最小直径 |
snowSpinSpeed | number | 雪花自旋速度 |
snowTexture | string | 雪花纹理 |
lightMode | string | 作用于天空和环境光的照明类型 |
sunFrequency | number | 太阳运动的频率 |
sunDirection | number | 太阳光照明方向 |
sunLight | number | 太阳光颜色亮度 |
sunPhase | number | 太阳从升起至落下,在天空的位置 |
lunarPhase | number | 月亮的相位 |
skyLeftLight | number | 环境光在-X轴方向的颜色亮度 |
skyRightLight | number | 环境光在+X轴方向的颜色亮度 |
skyBottomLight | number | 环境光在-Y轴方向的颜色亮度 |
skyTopLight | number | 环境光在+Y轴方向的颜色亮度 |
skyFrontLight | number | 环境光在+Z轴方向的颜色亮度 |
skyBackLight | number | 环境光在-Z轴方向的颜色亮度 |
接口 - GameZoneConfig 用于区域的参数
参数 | 类型 | 说明 |
---|---|---|
bounds | GameBounds3 | 区域的所指定的检测区域 |
selector | GameSelectorString | 触发区域事件的物体搜索条件 |
force | GameVector3 | 对物体施加的力的大小 |
massScale | number | 控制物体的质量对力的影响程度。 0 = 像重力一样; 1 = 像风一样 |
fogColor | GameRGBColor | 雾的颜色 |
fogDensity | number | 雾均匀密度 |
fogEnabled | boolean | 雾是否开启 |
fogHeightFalloff | number | 雾起始高度 |
fogHeightOffset | number | 雾衰减的速率 |
fogMax | number | 最大雾量 |
fogStartDistance | number | 雾起始距离 |
rainColor | GameRGBAColor | 雨的颜色 |
rainDensity | number | 雨的密度。密度越大,雨滴越多。 |
rainDirection | GameVector3 | 雨的方向 |
rainEnabled | boolean | 雨是否开启 |
rainInterference | number | 雨的扰动幅度 |
rainSizeHi | number | 雨滴的最大直径 |
rainSizeLo | number | 雨滴的最小直径 |
rainSpeed | number | 雨的速度 |
skyBackLight | GameRGBColor | 环境光在+Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skyBottomLight | GameRGBColor | 环境光在-Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skyEnabled | boolean | 环境参数是否有效 |
skyFrontLight | GameRGBColor | 环境光在-Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skyLeftLight | GameRGBColor | 环境光在-X轴方向的亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skyLunarPhase | number | 月亮的相位,数值在0和1之间。若大于0.5时,为上弦月。 |
skyMode | "natural" or "manual" | 作用于天空和环境光的照明类型。目前有提供2种光照模式,'manual'(自定义)或'natural'(动态)。默认为 'natural'。 |
skyRightLight | GameRGBColor | 环境光在+X轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skySunDirection | GameVector3 | 太阳光照明方向。仅在光照模式为manual自定义模式时生效。 |
skySunFrequency | number | 太阳运动的频率,数值越大,昼夜交替越快。 |
skySunLight | GameRGBColor | 太阳光颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skySunPhase | number | 太阳从升起至落下,在天空的位置。 |
skyTopLight | GameRGBColor | 环境光在+Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
snowColor | GameRGBAColor | 雪花颜色 |
snowDensity | number | 雪的密度。密度越大,雪花越多。 |
snowEnabled | boolean | 雪是否开启 |
snowFallSpeed | number | 雪花下落速度。如果小于0,则反向运动。 |
snowSizeHi | number | 雪花最大半径 |
snowSizeLo | number | 雪花最小直径 |
snowSpinSpeed | number | 雪花自旋速度 |
snowTexture | string | 雪花纹理 |
默认值参考 GameZone
{
selector: '',
bounds: {
lo: [0, 0, 0],
hi: [0, 0, 0],
},
force: [0, 0, 0],
massScale: 0,
fogEnabled: false,
fogColor: new GameRGBColor(1, 1, 1),
fogDensity: 0,
fogHeightFalloff: 0.8,
fogHeightOffset: -8,
fogMax: 1,
fogStartDistance: 0,
rainEnabled: false,
rainColor: new GameRGBAColor(1, 1, 1, 1),
rainDensity: 0,
rainSpeed: 1,
rainDirection: new GameVector3(0, 1, 0),
rainInterference: 0,
rainSizeHi: 1,
rainSizeLo: 0,
rainSpeed: 1,
skyEnabled: false,
skyMode: 'natural',
skyBottomLight: new GameRGBColor(0, 0, 0),
skyTopLight: new GameRGBColor(0, 0, 0),
skyBackLight: new GameRGBColor(0, 0, 0),
skyFrontLight: new GameRGBColor(0, 0, 0),
skyLeftLight: new GameRGBColor(0, 0, 0),
skyRightLight: new GameRGBColor(0, 0, 0),
skySunDirection: new GameVector3(0, -1, 0),
skyLunarPhase: 0,
skySunFrequency: 0,
skySunPhase: 0,
skySunLight: new GameRGBColor(1000, 1000, 1000),
snowEnabled: false,
snowColor: new GameRGBAColor(1, 1, 1, 1),
snowDensity: 0,
snowTexture: '',
snowFallSpeed: 1,
snowSizeHi: 1,
snowSizeLo: 0,
snowSpinSpeed: 0,
}
类 - MotionClipConfig 动作序列配置
参数 | 类型 | 说明 |
---|---|---|
iterations | number | 输入Infinity就是无限循环,此时会覆盖掉默认动作 能cancel或者播放新的动作覆盖可选项,默认 1 次 |
motions | (string | MotionConfig)[] |
接口 - MotionConfig
动作配置
参数 | 类型 | 说明 |
---|---|---|
iterations | number | 输入Infinity就是无限循环,此时会覆盖掉默认动作 能cancel或者播放新的动作覆盖可选项,默认 1 次 |
name | string | 动作名字 |
类型别名 - ReturnValue
描述 ReturnValue 表示一个键值对的内容。它可以是一个对象或者 undefined。
定义
定义
export type ReturnValue =
| {
key: string;
value: JSONValue;
updateTime: number;
createTime: number;
}
| undefined;
●key: string: 键名称 ●value: JSONValue: 值内容 ●updateTime: number: key最近更新时间 ●createTime: number: key创建时间
枚举 - GameAnimationDirection 动画的播放方向
属性 | 值 | 说明 |
---|---|---|
ALTERNATE | 'alternate' | 交替 |
ALTERNATE_REVERSE | 'alternate-reverse' | 交替倒放 |
NORMAL | 'normal' | 普通 |
REVERSE | 'reverse' | 倒放 |
WRAP | 'wrap' | 循环 |
WRAP_REVERSE | 'wrap-reverse' | 循环倒放 |
枚举 - GameAnimationPlaybackState 动画播放状态
属性 | 值 | 说明 |
---|---|---|
FINISHED | 'finished' | 已完成 |
PENDING | 'pending' | 挂起等待 |
RUNNING | 'running' | 播放中 |
枚举 - GameBodyPart 玩家身体部位的类型
属性 | 值 | 说明 |
---|---|---|
HIPS | 'hips' | 臀部 |
TORSO | 'torso' | 躯干 |
NECK | 'neck' | 颈部 |
HEAD | 'head' | 头 |
LEFT_SHOULDER | 'leftShoulder' | 左肩 |
LEFT_UPPER_ARM | 'leftUpperArm' | 左上臂 |
LEFT_LOWER_ARM | 'leftLowerArm' | 左下臂 |
LEFT_HAND | 'leftHand' | 左手 |
LEFT_UPPER_LEG | 'leftUpperLeg' | 左上腿 |
LEFT_LOWER_LEG | 'leftLowerLeg' | 左下腿 |
LEFT_FOOT | 'leftFoot' | 左脚 |
RIGHT_SHOULDER | 'rightShoulder' | 右肩膀 |
RIGHT_UPPER_ARM | 'rightUpperArm' | 右上臂 |
RIGHT_LOWER_ARM | 'rightLowerArm' | 右下臂 |
RIGHT_HAND | 'rightHand' | 右手 |
RIGHT_UPPER_LEG | 'rightUpperLeg' | 右上腿 |
RIGHT_LOWER_LEG | 'rightLowerLeg' | 右下腿 |
RIGHT_FOOT | 'rightFoot' | 右脚 |
枚举 - GameButtonType 玩家按下的按钮类型
属性 | 值 | 说明 |
---|---|---|
WALK | 'walk' | 步行按钮 |
RUN | 'run' | 奔跑按钮 |
CROUCH | 'crouch' | 下蹲按钮 |
JUMP | 'jump' | 跳跃按钮 |
DOUBLE_JUMP | 'jump2 | 二段跳按钮 |
FLY | 'fly' | 飞行按钮 |
ACTION0 | 'action0' | 鼠标左键 / 虚拟按钮A |
ACTION1 | 'action1' | 鼠标右键 / 虚拟按钮B |
枚举 - GameCameraMode 玩家的相机视角模式
属性 | 值 | 说明 |
---|---|---|
FIXED | 'fixed' | 第三人称固定视角 |
FOLLOW | 'follow' | 第三人称跟随视角(默认) |
FPS | 'fps' | 第一人称视角 |
枚举 - GameDialogType 对话框样式类型
属性 | 值 | 说明 |
---|---|---|
TEXT | 'text' | 文本样式对话框 |
INPUT | 'input' | 输入样式对话框 |
SELECT | 'select' | 选择样式对话框 |
枚举 - GameEasing 动画的缓动效果,EaseIn缓入,EaseOut缓出
属性 | 值 | 说明 |
---|---|---|
BACK | 'back' | 反向 |
BOUNCE | 'bounce' | 弹性 |
CIRCLE | 'circle' | 圆 |
ELASTIC | 'elastic' | 橡皮筋 |
EXP | 'exp' | 指数 |
LINEAR | 'linear' | 线性 |
NONE | 'none' | 无 |
QUADRATIC | 'quadratic' | 二次方 |
SINE | 'sine' | 正弦波 |
枚举 - GameInputDirection 玩家通过输入设备控制移动时的方向,可用于 GamePlayer.disableInputDirection 禁用对应方向的输入,以控制玩家移动的表现。
属性 | 值 | 说明 |
---|---|---|
NONE | 'none' | 无,代表不禁用 |
VERTICAL | 'vertical' | 垂直方向 |
HORIZONTAL | 'horizontal' | 水平方向 |
BOTH | 'both' | 所有方向 |
PlayerMoveState运动状态 玩家的运动状态
属性 | 值 | 说明 |
---|---|---|
FLYING | 'fly' | 飞行中 |
GROUND | 'ground' | 在地上 |
SWIM | 'swim' | 游泳中 |
FALL | 'fall' | 下落中 |
JUMP | 'jump' | 跳跃中 |
DOUBLE_JUMP | 'jump2' | 二段跳中 |
枚举 - GamePlayerWalkState 玩家的行走状态
属性 | 值 | 说明 |
---|---|---|
NONE | '' | 非行走中 |
CROUCH | 'crouch' | 下蹲行走 |
WALK | 'walk' | 正常步行 |
RUN | 'run' | 奔跑 |
枚举 - SocialType交关系类型,用于在 GamePlayer 玩家
中查询玩家的社交关系。
属性 | 值 | 说明 |
---|---|---|
FOLLOWING | 0 | 关注 |
FOLLOWERS | 1 | 粉丝 |
FRIENDS | 2 | 好友 |
本文档中的代码,如果出现“-snip-”表示省略了上文中重复的代码
voxels.setVoxel()可以指定最多5个参数:X, Y, Z, voxel, rotation
参数X, Y, Z必须是string;voxel, rotation可以是string或者number类型
voxels.setVoxel(X, Y, Z, voxel, rotation)
/*
(x: number, y: number, Z: number, voxel: string | number, rotation?: string | number) : number
*/
如 voxels.setVoxel(1, 1, 1, 'grass', 0)
,可以在x、y、z为1的位置放置一个草方块,旋转(rotation)为0即方块旋转0*90=0度
如 voxels.setVoxel(1, 1, 1, 'grass', 1)
,可以在x、y、z为1的位置放置一个草方块,旋转(rotation)为1即将方块逆时针旋转1*90=90度
又如 voxels.setVoxel(1, 2, 3, 'stone', 2)
,可以在x=1,y=2,z=3的位置放置一个石头,因为旋转(rotation)的值为2,所以会将原始的方块逆时针旋转2*90=180度
voxels.setVoxel(12, 3, 45, 'glass', 3)
,在x=12,y=3,z=45的位置放置一个玻璃方块,逆时针旋转3*90=270度
voxels.setVoxel(12, 3, 45, 'dirt', 4)
,在x=12,y=3,z=45的位置放置一个土方块,逆时针旋转了4*90=360度,所以相当于不旋转,作用效果等于 voxels.setVoxel(12, 3, 45, 'dirt', 0)
说明:rotation值可以不加,默认为0
如果传入的方块存在,使用此方法的返回值会返回第四个参数即voxel对应的方块ID
例如 voxels.setVoxel(1, 2, 3, 'stone')
会返回名为“stone”的方块对应的id
如果方块不存在,会返回0
例如 voxels.setVoxel(1, 2, 3, 'this_is_not_a_block_name')
会返回0
快速建造可以更高效地批量化建筑方块
/**
* 快速建造一个长方体
*
* @param {number | string} voxel - 方块名称或者id
* @param {number} xmin - x的最小值
* @param {number} ymin - y的最小值
* @param {number} zmin - z的最小值
* @param {number} xmax - x的最大值
* @param {number} ymax - y的最大值
* @param {number} zmax - z的最大值
* @param {number | string} rotation - 方块旋转
*/
function quick_build(voxel, xmin, ymin, zmin, xmax, ymax, zmax, rotation=0){
for(let x=xmin;x<=xmax;x++){
for(let y=ymin;y<=ymax;y++){
for(let z=zmin;z<=zmax;z++){
voxels.setVoxel(x, y, z, voxel, rotation)
}
}
}
}
// 定义函数
/**
* 快速建造一个长方体
*
* @param {number | string} voxel - 方块名称或者id
* @param {number} xmin - x的最小值
* @param {number} ymin - y的最小值
* @param {number} zmin - z的最小值
* @param {number} xmax - x的最大值
* @param {number} ymax - y的最大值
* @param {number} zmax - z的最大值
* @param {number | string} rotation - 方块旋转
*/
function quick_build(voxel, xmin, ymin, zmin, xmax, ymax, zmax, rotation=0){
for(let x=xmin;x<=xmax;x++){
for(let y=ymin;y<=ymax;y++){
for(let z=zmin;z<=zmax;z++){
voxels.setVoxel(x, y, z, voxel, rotation)
}
}
}
}
// 调用函数
// 调用快速建造函数用“grass”(草方块)建造一个起于{x=1,y=1,z=1},止于{x=100,y=64,z=101},所有方块都旋转3*90=270度的长方体
quick_build('grass', 1, 1, 1, 100, 64, 101, 3)
// 调用快速建造函数用“stone”(草方块)建造一个起于{x=2,y=3,z=4},止于{x=100,y=64,z=101},此时不传入参数rotation,方块默认不旋转
quick_build('stone', 2, 3, 4, 100, 64, 101, 3)
有时候并不知道xmin,ymin,zmin,xmax,ymax,zmax到底该传入什么值,以下两种方法可以解决:
例如:
var pos1 = new GameVector3(1,1,1)
var pos2 = new GameVector3(5,5,5)
因为pos1的x、y、z值都小于pos2的x、y、z值,所以此时应如此传入:
quick_build('方块名', pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos3.z)
function quick_build(voxel, xmin, ymin, zmin, xmax, ymax, zmax, rotation=0){
-snip-
}
function quick_build_pro(voxel, pos1, pos2, rotation=0){
// 判断pos1和pos2的位置关系并正确传入
if(pos1.x<=pos2.x&&pos1.y<=pos2.y&&pos1.z<=pos2.z){ // 当pos1的xyz坐标均小于等于pos2的xyz坐标时的调用方式
quick_build(voxel, pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z, rotation)
}
else if(pos1.x>pos2.x&&pos1.y>pos2.y&&pos1.z>pos2.z){ // 当pos2的xyz坐标均小于pos1的xyz坐标时的调用方式
quick_build(voxel, pos2.x, pos2.y, pos2.z, pos1.x, pos1.y, pos1.z, rotation)
}
else{ // 否则输出错误
console.error('不支持的判断类型')
}
}
/**
* 快速建造一个球体
*
* @param {GameVector3} centerPos - 球体中心位置
* @param {number | string} voxel - 方块id或名称
* @param {number} r - 球体半径
* @param {number | string} rotation - 方块旋转
*/
function ball(centerPos, r, voxel, rotation=0){
// 创建嵌套循环,这样创建的妙处在于不必遍历地图每个方块,如果遍历地图每个方块的话地图会崩溃
for(let x=centerPos.x-r;x<=centerPos.x+r;x++){
for(let y=centerPos.y-r;y<=centerPos.y+r;y++){
for(let z=centerPos.z-r;z<=centerPos.z+r;z++){
const position2 = new GameVector3(x, y, z);
// 计算两个位置之间的距离
const distance1 = Math.sqrt(Math.pow(position2.x - centerPos.x, 2) + Math.pow(position2.y - centerPos.y, 2) + Math.pow(position2.z - centerPos.z, 2));
if(distance1<=r){// 如果距离小于传入的r的值,则放置方块
voxels.setVoxel(x,y,z,voxel,rotation)
}
}
}
}
}
因为神奇代码岛的服务器能力问题,当r过大时可能会导致服务器崩溃,所以不要传入一个较大的值
function ball(centerPos, r, voxel, rotation=0){
-snip-
}
var center = new GameVector3(50, 50, 50)
ball(center, 10, 'dirt', 2) // 以{x=50,y=50,z=50}为球体中心、填充旋转了2*90=180度的“dirt”(草方块),半径为10,快速建造一个球体
function pyramid(l, pos, voxel, rotation){
let cx = pos.x;
let cy = pos.y;
let cz = pos.z;
let height = l;
let xend = cx + l;
let zend = cz + l;
for(let y = cy; y < cy + height; y++){
let ylevel = y - cy;
let xstart = cx + ylevel;
let xend = cx + l - ylevel;
let zstart = cz + ylevel;
let zend = cz + l - ylevel;
for(let x = xstart; x < xend; x++){
for(let z = zstart; z < zend; z++){
voxels.setVoxel(x, y, z, voxel, rotation);
}
}
}
}
function pyramid(l, pos, voxel, rotation){
-snip-
}
var pos = new GameVector3(60,10,60)
pyramid(5, pos, 'stone', 3); // 在{x:60,y:10,z:60}使用“stone”(石头)建造一个底面为5*5,高度为5的三棱锥,所有方块逆时针旋转3*90=270度
var admin = ['tangyuan儿','爱肝作品的小诚吖_赤炎宗','意柳','芸游XY','外向的雷电猴(巅峰队)','长恨.原一颗狼星','星光烈火龙','KO轩','唱跳rap只因']
var adminpro = ['阿兹卡班毕业生','羽帆','SAZ','KyTT','执着的树毛虫','奶油.','奶油','奶油a','高冷的小魏1y','谢常浩然','怂怂的小彤e2','耐心的大黄鸡mSos','QTK.十字铁路DCB']
const heimingdan = ['忧郁的宇宙熊','一只咸鸭蛋bn','SAX']//黑名单
// var victory = false
var lzxglist = ['JB6tX5vKo/o0R0gN']
var msglist = ['等你发言','等你发言']
var dmm = false;
var zbznc = '';
var dcz = [];
var dctime = 0;
var zbtime = 0;
var beizhuadao = [];
var dmmrenshu=0;
// console.clear()
function use_duihuanma(entity){
try{
if(entity.duihuanma){
entity.player.cancelDialogs()
}
const date = new Date(Date.now());
const year = date.getFullYear()
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
if(entity.duihuanma.startsWith('wansheng_code')){
if(entity.duihuanma.indexOf('&')!=-1){
entity.duihuanmainlist = entity.duihuanma.split('&')
console.log(entity.duihuanmainlist)
if(entity.duihuanmainlist[1]==String(entity.player.userId*3+2023)&&entity.duihuanmainlist[2]==String(entity.player.name.length)&&entity.duihuanmainlist[5]==String(month+day)&&entity.duihuanmainlist[6]==String(hour)&&parseInt(entity.duihuanmainlist[8])/3%1==0){
if(((parseInt(entity.duihuanmainlist[3])-99)/2)%9==parseInt(entity.duihuanmainlist[4])){
if(minute-parseInt(entity.duihuanmainlist[7])<=5){
dialog(`系统`,`兑换成功!\n获得${(parseInt(entity.duihuanmainlist[3])-99)/4}经验`,entity);
entity.exp+=(parseInt(entity.duihuanmainlist[3])-99)/4;
entity.used_duihuanma.push(entity.duihuanma);
savePlayer(entity);
}
else{
dialog(`错误`,`此兑换码已过期`,entity)
}
}
else{
dialog(`错误`,`此兑换码不存在`,entity)
}
}
else{
dialog(`错误`,`此兑换码不存在`,entity)
}
}
}
else if(entity.duihuanma=='示例兑换码'){
dialog(`系统`,`兑换成功,获得10exp`,entity)
entity.exp+=10
savePlayer(entity)
}
else{
dialog(`错误`,`兑换码不存在`,entity)
}
}
catch(e){
return
}
}
var Storage = storage.getGroupStorage('cundang'); // 获取数据库,名称为 cundang
const CorrespondingName = { // 在此添加排行榜对应的单位和名称(无名称 则表示不显示名称)
'exp': ['经验', '无名称']
};
const unsavedData = { // 玩家初始无需保存的数据,可增添或删除
victory: false,
ingjf: false,
cankick: true,
dmmzy: '',
dmmshoudao: false
};
const savedData = { // 玩家初始需要保存的数据,可增添或删除
exp: 50,
bag: [],
greenlzxg: false,
zhutu_position_x: 3,
zhutu_position_y:6,
zhutu_position_z:4,
chun_position_x: 3,
chun_position_y:6,
chun_position_z:4,
xia_position_x: 3,
xia_position_y:6,
xia_position_z:4,
qiu_position_x: 3,
qiu_position_y:6,
qiu_position_z:4,
dong_position_x: 3,
dong_position_y:6,
dong_position_z:4,
adminlevel: 0,
canplay: true,
used_duihuanma: [],
skins: ['原版皮肤'],
usingskin: '原版',
last_team: 0
};
/**
* 初始化玩家数据
*
* @param {GameEntity} entity
*/
function initPlayer(entity) { // 初始化玩家数据
Object.assign(entity, savedData);
Object.assign(entity, unsavedData);
};
/**
* 获取玩家数据
*
* @param {GameEntity} entity
*/
function getPlayerData(entity) { // 获取玩家数据
var data = { 'name': entity.player.name };
for (let i in savedData) { // 遍历savedData,获取玩家当前数据
data[i] = entity[i];
};
return data;
};
/**
* 存档
*
* @param {GameEntity} entity
*/
async function savePlayer(entity) { // 存档
await Storage.update(entity.player.userId, () => { // 更新玩家数据存档
return getPlayerData(entity);
});
};
/**
* 删档
*
* @param {GameEntity} entity
*/
async function deletePlayer(entity) { // 删档
entity.save = false
await Storage.remove(entity.player.userId); // 删除玩家数据存档
};
async function deletePlayerById(id) { // 删档
await Storage.remove(id); // 删除玩家数据存档
};
/**
* 读档
*
* @param {GameEntity} entity
*/
async function loadPlayer(entity) { // 读档
initPlayer(entity);
var data = await Storage.get(entity.player.userId); // 获取数据
if (data) { // 如果数据存在
Object.assign(entity, data.value);
entity.player.directMessage('已为您读取数据!');
} else { // 如果数据不存在
await Storage.set(entity.player.userId, getPlayerData(entity));
entity.player.directMessage('已为您创建数据!');
};
};
/**
* 清档
*/
async function deleteAllData() { // 清档
var sqlDataList = await Storage.list({ // 将数据库内的所有数据分页
cursor: 0
});
world.querySelectorAll('player').forEach(x => x.save = false);
try {
while (true) {
for (let sqlData of sqlDataList.getCurrentPage()) { // 遍历获取数据
await Storage.remove(sqlData.key)
}
if (sqlDataList.isLastPage) break; // 如果已经是最后一页,退出循环
await sqlDataList.nextPage(); // 下一页
};
} catch (e) {}
};
/**
* 显示排行榜
*
* @param {string} type
*/
async function leaderBoard(type) { // 排行榜
var list = [];
var sqlDataList = await Storage.list({ // 将数据库内的所有数据分页
cursor: 0
});
while (true) {
for (let sqlData of sqlDataList.getCurrentPage()) { // 遍历获取数据
list.includes([sqlData.value['name'], sqlData.value[type]]) ? null : list.push([sqlData.value['name'], sqlData.value[type]]);
}
list = list.sort((a, b) => b[1] - a[1]).slice(0, 100);
if (sqlDataList.isLastPage) break; // 如果已经是最后一页,退出循环
await sqlDataList.nextPage(); // 下一页
};
return list.map((value, num) => // 将列表里的所有项依次替换成字符串
`第${num + 1}名 | ${value[0]} | ${value[1]} ${CorrespondingName[type][0]}${CorrespondingName[type][1] != '无名称' ? CorrespondingName[type][1] : ''}`
).join("\n"); // 按照 换行 的间隔组合成字符串
};
require('./防止想不开.js')
require('./宠物.js')
function find(name){
const a = world.querySelectorAll`player`;
for(let i in a)if(a[i].player.name == name)return a[i];
}
//私聊
async function chats(entity, other, text) {
other.player.directMessage('收到一条私信')
const has = await other.player.dialog({
type: GameDialogType.SELECT,
title: "私聊",
titleTextColor: new GameRGBAColor(0, 0, 0, 1),
titleBackgroundColor: new GameRGBAColor(0.968, 0.702, 0.392, 1),
content: `${entity.player.name}:\n${text}`,
options: ['回复', '取消'],
});
if (!has || has === null) {
entity.player.directMessage('TA阅读了消息,但没有回复');
return;
}
if (has.value === '回复') {
entity.player.directMessage('对方收到了你的私信')
const returns = await other.player.dialog({
type: GameDialogType.INPUT,
title: "私聊-回复",
titleTextColor: new GameRGBAColor(0, 0, 0, 1),
titleBackgroundColor: new GameRGBAColor(0.968, 0.702, 0.392, 1),
content: `${other.player.name},请输入回复内容`,
confirmText: '发送',
placeholder: '输入回复内容',
});
if (!returns || returns === null) {
return;
}
chats(other, entity, returns)
}
else if (has.value === '取消') {
entity.player.directMessage('对方收到了你的私信')
}
}
world.onPlayerJoin(({ entity }) => {
entity.player.interactTimes = 0;
entity.enableInteract = true;
entity.interactRadius = 1.5;
if(entity.player.name=='阿兹卡班毕业生'||entity.player.name=='奶油.'||entity.player.name=='SAZ'||entity.player.name=='羽帆'){
entity.interactHint = `与 【作者认证】 ${entity.player.name} 互动`;
}
else if(admin.includes(entity.player.name||entity.adminlevel==1)){
entity.interactHint = `与 【管理员认证】 ${entity.player.name} 互动`;
}
else if(adminpro.includes(entity.player.name||entity.adminlevel>1)){
entity.interactHint = `与 【高级管理员】 ${entity.player.name} 互动`;
}
else{
entity.interactHint = `与 ${entity.player.name} 互动`;
}
entity.onInteract(async ({ entity, targetEntity }) => {
targetEntity.player.directMessage('你被 ' + entity.player.name + ' 访问了')
while (!entity.destroyed) {
const others = await entity.player.dialog({
type: GameDialogType.SELECT,
title: targetEntity.player.name + '',
titleTextColor: new GameRGBAColor(0, 0, 0, 1),
titleBackgroundColor: new GameRGBAColor(0.968, 0.702, 0.392, 1),
content: `你要干啥`,
options: ['和TA私聊','没啥,就看看'],
})
if (!others || others === null) {
return;
}
if (others.value == '和TA私聊') {
const chating = await entity.player.dialog({
type: GameDialogType.INPUT,
title: "私聊",
titleTextColor: new GameRGBAColor(0, 0, 0, 1),
titleBackgroundColor: new GameRGBAColor(0.968, 0.702, 0.392, 1),
content: `${entity.player.name},请输入私聊内容`,
confirmText: '发送',
placeholder: '输入私聊内容',
});
if (!chating || chating === null) {
return;
}
chats(entity, targetEntity, chating)
return;
}
}
})
})
async function dialog(title,content,entity){
const result = await entity.player.dialog({
type: GameDialogType.TEXT,
title: title,
content: content,
});
}
world.onPlayerJoin(({entity})=>{
entity.player.jumpPower=0.7
entity.player.doubleJumpPower=0.7
})
world.onPlayerJoin(async({ entity }) => {
// entity.player.enableDoubleJump=false
const dialog = entity.player.dialog({
type: GameDialogType.TEXT,
title: "作者&协作者们",
content: `${entity.player.name},欢迎来到毕业生跑酷pro,下面是对于本地图的一些介绍:\n
· 老版地图不再更新,但关卡与pro版不同,链接:https://box3.codemao.cn/p/bysrun
· 地图有sql存档,妈妈再也不用担心我把存档搞丢啦!
· 地图有一个小彩蛋,你能找到吗?
· 如有bug请在评论区@作者!
· 经验计算规则:第一次游玩赠送50经验,以后每碰到一个新的存档点经验+1
· 在游戏中违规被作者看到可能会被踢出/封禁
· 加入Q群763919859领粒子效果!
· 与朋友一起竞速吧!
最后,祝您在毕业生跑酷pro玩得愉快!`,
});
const resultawa = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '注意',
content: `本地图(含旧版)已经一周年,进群763919859领取1周年福利`,
options:['确定']
});
if(!resultawa || resultawa === null){
return;
}
else if(resultawa.value=='确定'){
entity.player.link(`http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=HNz3yHNTngoeIwY6G-u_MJYeuKg9yY49&authKey=JMwkO%2BkIFr5qfXArsrAu98%2BUV50d6wTeeCxejnH36Wt6UeEi4a2wjb5N38l1n6w3&noverify=0&group_code=763919859`, {isConfirm: false, isNewTab: true});
}
const result3 = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '注意',
content: `本地图的通关实况出来啦!是否进入外部网站观看?(不会覆盖当前标签页)`,
options:['确定','不了']
});
if(!result3 || result3 === null){
return;
}
else if(result3.value!='不了'){
entity.player.link(`https://www.bilibili.com/video/BV1fe411Q7kL/?share_source=copy_web&vd_source=47fb8dc2c290d3efba51bb252a91c38d`, {isConfirm: false, isNewTab: true});
}
if(entity.player.name == '阿兹卡班毕业生'||entity.player.name=='羽帆'||entity.player.name=='SAZ'){
world.say(`作者 ${entity.player.name} 来辣~`)
}
else{
world.say(`欢迎 ${entity.player.name} 进入毕业生跑酷pro!`)
}
});
function addWearable(entity, data) {
// 这一步是把角度转成弧度
const orientation = new GameQuaternion(0, 0, 0, 1)
.rotateZ(data.rotate[2] * Math.PI / 180)
.rotateX(data.rotate[0] * Math.PI / 180)
.rotateY(data.rotate[1] * Math.PI / 180)
// 将上面声明的配置一一对应地传递给传递API
entity.player.addWearable({
bodyPart: data.bodyPart,
mesh: data.mesh,
orientation: orientation,
scale: data.scale,
offset: data.offset,
})
}
const zuozhe = [
{ bodyPart: GameBodyPart.HEAD, name: '头', mesh: 'mesh/绿宝石块.vb', offset: [1, 0, 0], rotate: [45, 45, 45], scale: [0.5, 0.5, 0.5] },
{ bodyPart: GameBodyPart.HEAD, name: '头', mesh: 'mesh/钻石.vb', offset: [-1, 0, 0], rotate: [45, 45, 45], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.TORSO, name: '躯干', mesh: 'mesh/1楼.vb', offset: [0, 0.1, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.TORSO, name: '臀部', mesh: 'mesh/光轮2000.vb', offset: [0, -0.3, 0], rotate: [0, 0, 30], scale: [0.7, 0.7, 0.7] },
// { bodyPart: GameBodyPart.LEFT_UPPER_ARM, name: '左上臂', mesh: 'mesh/1楼.vb', offset: [0.1, 0.07,-0.02], rotate: [-128, 120, -85], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_UPPER_ARM, name: '右上臂', mesh: 'mesh/1楼.vb', offset: [-0.1, 0.07,-0.02], rotate: [-45, -120, -85], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.LEFT_LOWER_ARM, name: '左下臂', mesh: 'mesh/1楼.vb', offset: [0, 0.11, 0], rotate: [-128, 120, -85], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_LOWER_ARM, name: '右下臂', mesh: 'mesh/1楼.vb', offset: [0, 0.09, 0], rotate: [-45, -120, -85], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.LEFT_UPPER_LEG, name: '左上腿', mesh: 'mesh/1楼.vb', offset: [0, -0.05, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_UPPER_LEG, name: '右上腿', mesh: 'mesh/雾雨魔理沙上腿.vb', offset: [0, -0.1, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.LEFT_LOWER_LEG, name: '左下腿', mesh: 'mesh/雾雨魔理沙下腿.vb', offset: [0, 0.07, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_LOWER_LEG, name: '右下腿', mesh: 'mesh/雾雨魔理沙下腿.vb', offset: [0, 0.07, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.LEFT_FOOT, name: '左脚', mesh: 'mesh/雾雨魔理沙脚.vb', offset: [0, 0.06, 0.05], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_LOWER_ARM, name: '右手', mesh: 'mesh/我的世界_钻石剑.vb', offset: [-0.2, 0.2, 0.2], rotate: [-45, 90, -45], scale: [1, 1, 1] },
// { bodyPart: GameBodyPart.LEFT_LOWER_ARM, name: '左手', mesh: 'mesh/我的世界·附魔三叉戟.vb', offset: [0.15, 0.15, 0.09], rotate: [110, 243
// , 180], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_LOWER_ARM, name: '右手', mesh: 'mesh/皇冠.vb', offset: [-0.16, 0.05, 0.1], rotate: [-138, 60, 95], scale: [0.5, 0.5, 0.5] },
]
const yufan = [
{ bodyPart: GameBodyPart.HEAD, name: '头', mesh: 'mesh/小鱼干.vb', offset: [1.3, 0, 0], rotate: [45, -45, 45], scale: [0.01, 0.01, 0.01] }
]
const saz = [
{bodyPart: GameBodyPart.RIGHT_LOWER_ARM, name: '右下臂', mesh: 'mesh/我的世界附魔钻石剑.vb', offset: [-0.4, 0.4, 0.25], rotate: [135, 135, 135], scale: [1, 1, 1]},
{bodyPart: GameBodyPart.HEAD_LOWER_ARM, name: '头', mesh: 'mesh/墨镜.vb', offset: [0, 0.8, 0.25], rotate: [0, 90, 0], scale: [0.2, 0.3, 0.3]}
]
function chuandaipeijian(entity){
if(entity.player.name==`阿兹卡班毕业生`){
for (const data of zuozhe) {
addWearable(entity, data)
}
entity.player.directMessage(`穿戴配件成功`);
}
else if(entity.player.name=='KyTT'||entity.player.name=='羽帆'){
for (const data of yufan) {
addWearable(entity, data)
}
entity.player.directMessage(`穿戴配件成功`);
}
else if(entity.player.name==`SAZ`){
for (const data of saz) {
addWearable(entity, data)
}
entity.player.directMessage(`穿戴配件成功`);
}
// else if(entity.player.name==`KyTT`){
// for (const data of kytt) {
// addWearable(entity, data)
// }
// }
// 有bug
// if(hmd in entity.player.name){
// // 隐藏所有身体部件!
// for (const bodyPart in entity.player.skinInvisible) {
// entity.player.skinInvisible[bodyPart] = true;
// }
// }
// if(entity.player.name=='阿兹卡班毕业生'){
// entity.player.setSkinByName('苦力怕皮肤');
// }
}
world.onPlayerJoin(async({entity})=>{
chuandaipeijian(entity)
})
//sql相关
world.onPlayerLeave(async({entity})=>{
entity.save != false ? await savePlayer(entity) : null; // 存档
savePlayer(entity);
})
const points = world.querySelectorAll('.存档点')
points.forEach((e)=>{
e.onEntityContact(({other})=>{
const spawnPoint = e.position.add({x: 0,y: 2.5,z: 0});
if(spawnPoint.equals(other.player.spawnPoint))return;
other.player.spawnPoint = spawnPoint;
other.zhutu_position_x=e.position.x;
other.zhutu_position_y=e.position.y+2.5;
other.zhutu_position_z=e.position.z;
savePlayer(other);
other.player.directMessage('存档成功,经验+1!');
if(other.victory==false){
other.exp+=1;
}
})
})
world.onFluidEnter(({entity, tick, voxel}) => {
const voxelName = voxels.name(voxel)
if (voxelName=='water'&&entity.ingjf==false){
entity.player.forceRespawn()
entity.player.directMessage(`落水重生`)
}
})
world.onChat(({message,entity})=>{
var huancun = msglist[0];
msglist[0]=entity.player.name+':\n'+message;
for(var i=1;i<=2;i++){
msglist[i] = huancun;
huancun = msglist[i+1]
}
world.say(`${entity.player.name}:${message}`)
if(entity.player.name!='阿兹卡班毕业生'&&(message==`ban 阿兹卡班毕业生`||message==`kick 阿兹卡班毕业生`)){
dialog(`作者`,`胆子很大啊!敢封禁/踢出作者!`,entity);
entity.position.set(2,6,10);
}
})
world.onPlayerJoin(({entity})=>{
world.onChat(({message,entity:user})=>{
if(user.player.name='阿兹卡班毕业生'){
// if(message.startsWith('push admin')){
// console.log(message.slice(11));
// if(entity.player.name==message.slice(11)){
// entity.isadmin=true;
// savePlayer(entity);
// world.say('恭喜'+entity.player.name+'成为管理员');
// dialog(`阿兹卡班毕业生`,`恭喜你入选管理员,希望你为毕业生跑酷pro做出贡献\n刷新后生效`,entity);
// }
// }
// if(message.startsWith('kick')){
// console.log(message.slice(5));
// if(entity.player.name==message.slice(5)){
// entity.position.set(2,6,10);
// dialog(``,`你被踢出`,entity);
// entity.player.kick()
// }
// }
// else if(message.startsWith('ban')){
// console.log(message.slice(5));
// if(entity.player.name==message.slice(4)){
// entity.canplay=false;
// savePlayer(entity);
// entity.position.set(2,6,10);
// dialog(``,`你被封禁,移至小黑屋,请退出游戏`,entity);
// world.say(entity.player.name+'被作者封禁');
// }
// }
// else if(message.startsWith('canplay')){
// console.log(message.slice(8));
// if(entity.player.name==message.slice(8)){
// entity.canplay=true;
// entity.position.set(2,10,10);
// dialog(``,`已解除封禁\n为了防止sql存档异常,请右键sql存档或者踩一个存档点`,entity);
// savePlayer(entity);
// }
// }
// else if(message.startsWith('e')){
// if(entity.player.name==message.slice(11)){
// entity.e=true;
// }
// }
// else if(message.startsWith('cannotcommand')){
// if(entity.player.name==message.slice(14)){
// entity.e=false;
// }
// }
}
})
})
// })
// world.onPlayerJoin(({entity})=>{
// entity.player.onChat(({message,entity:user})=>{world.say(`${user.player.name}:${message}`)})
// })
// npc交互
const xiaoheiwu = world.querySelector('#小黑屋');
xiaoheiwu.enableInteract = true; // 允许进行互动
xiaoheiwu.interactRadius = 5; // 实体的互动范围
xiaoheiwu.interactHint = `小黑屋\n不想被关进小黑屋就安分守己哦~`; // 互动提示框显示实体的名称
xiaoheiwu.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
const stone2023 = world.querySelector('#2023');
stone2023.enableInteract = true; // 允许进行互动
stone2023.interactRadius = 5; // 实体的互动范围
stone2023.interactHint = `2023纪念石`; // 互动提示框显示实体的名称
stone2023.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
// stone2023.onInteract(({entity})=>{
// entity.player.link(`https://azkbbys.gitbook.io/azkbbys/celebrate/on-going/2024-happy-new-year`, {isConfirm: false, isNewTab: true});
// })
const tzxyg1 = world.querySelector('#跳转下一关-1');
tzxyg1.enableInteract = true; // 允许进行互动
tzxyg1.interactRadius = 2; // 实体的互动范围
tzxyg1.interactHint = `互动跳转下一关`; // 互动提示框显示实体的名称
tzxyg1.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
tzxyg1.onInteract(({entity})=>{
entity.position.set(123,15,30)
})
const boat = world.querySelector('#船');
boat.enableInteract = true; // 允许进行互动
boat.interactRadius = 2; // 实体的互动范围
boat.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
boat.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
boat.onInteract(({entity})=>{
dialog(`小船`,`嘿!发现彩蛋啦!\n给你上上色~\n加入Q群763919859领取更多福利!`,entity)
entity.player.color=new GameRGBColor(0,1,1)
})
const caidanflower = world.querySelector('#彩蛋花');
caidanflower.enableInteract = true; // 允许进行互动
caidanflower.interactRadius = 2; // 实体的互动范围
caidanflower.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
caidanflower.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
caidanflower.onInteract(({entity})=>{
dialog(`花`,`嘿!发现彩蛋啦!\n给你1经验!可以重复领取!顺便给你上上色吧~别忘了手动点击保存哦\n加入Q群763919859领取更多福利!`,entity)
entity.exp+=1
entity.player.color=new GameRGBColor(0.1,0,1)
})
const xuanzefutu = world.querySelector('#dream-1');
xuanzefutu.enableInteract = true; // 允许进行互动
xuanzefutu.interactRadius = 5; // 实体的互动范围
xuanzefutu.interactHint = `选择附图`; // 互动提示框显示实体的名称
xuanzefutu.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
xuanzefutu.onInteract(async({entity})=>{
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '选择附图',
content:`点击附图名称,查看详情`,
options:['春','夏']
});
if(!result || result.value === null){
return;
}
else if(result.value=='春'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '地图详情',
content:`地图主题:春\n\n点击按钮进入地图`,
options:['进入地图','就是看看']
});
if(!result || result.value === null){
return;
}
else if(result.value=='进入地图'){
entity.player.link(`https://dao3.fun/play/6d789dabd5e09ca687ce`, {isConfirm: false, isNewTab: false});
}
}
else if(result.value=='夏'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '地图详情',
content:`地图主题:夏\n\n点击按钮进入地图`,
options:['进入地图','就是看看']
});
if(!result || result.value === null){
return;
}
else if(result.value=='进入地图'){
entity.player.link(`https://dao3.fun/play/54230e5fd4ecbaecc0ee`, {isConfirm: false, isNewTab: false});
}
}
})
const tiaoguandream = world.querySelector('#跳关dream');
tiaoguandream.enableInteract = true; // 允许进行互动
tiaoguandream.interactRadius = 5; // 实体的互动范围
tiaoguandream.interactHint = `跳关`; // 互动提示框显示实体的名称
tiaoguandream.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
tiaoguandream.onInteract(async({entity})=>{
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '选择',
content:`确定花费40exp跳关么`,
options:['是','否']
});
if(!result || result.value === null){
return;
}
else if(result.value=='是'){
if(entity.exp>=40){
entity.exp-=40;
entity.position.set(79,19,18)
savePlayer(entity)
entity.player.directMessage('跳关成功')
}
else{
dialog('错误','经验不足',entity)
}
}
})
const end = world.querySelector('#终点');
// end.enableInteract = true; // 允许进行互动
// end.interactRadius = 2; // 实体的互动范围
end.onEntityContact(async({other})=>{
if(other.victory==false){
other.position.set(4,7,4)
other.player.color= new GameRGBColor(0,1,0)
other.player.canFly=true
other.player.spectator=true
dialog(`系统`,`恭喜你通关了!!!\n已开启您的飞行权限\n经验+50`,other)
world.say(`恭喜${other.player.name}通关游戏!`)
other.exp+=50
other.zhutu_position_x=savedData.zhutu_position_x
other.zhutu_position_y=savedData.zhutu_position_y
other.zhutu_position_z=savedData.zhutu_position_z
savePlayer(other)
other.victory=true
}
else{
dialog(`系统`,`你已经通过关了,按下右键-重来可以重来`,other)
}
})
// 碰撞过滤
world.addCollisionFilter('player','player')
//黑名单
world.onPlayerJoin(({entity}) => {
if(heimingdan.includes(entity.player.name)){
entity.player.kick()
}
})
// 管理员代码
world.onChat(({ entity, message }) => {
if(adminpro.includes(entity.player.name)||entity.adminlevel>1){
if (message.startsWith('$')) {
try {
world.say('<~ ' + eval(message.slice(1)))
}
catch (err) {
world.say('<~ ' + err)
}
}
}
})
const particle_greenCrystal = {
particleRate: 500,
particleLifetime: 0.4,
particleSize: [4, 3, 2, 1, 0.25],
particleColor: [
new GameRGBColor(1, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(1, 1, 1)
],
}
const test_green = {
particleRate: 500,
particleLifetime: 999,
particleSize: [4, 3, 2, 1, 0.25],
particleColor: [
new GameRGBColor(1, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(1, 1, 1)
],
}
const particle_purpleCrystal = {
particleRate: 500,
particleLifetime: 0.4,
particleSize: [4, 3, 2, 1, 0.25],
particleColor: [
new GameRGBColor(0, 0, 1),
new GameRGBColor(0, 0, 1),
new GameRGBColor(1, 0, 1),
new GameRGBColor(1, 0, 1),
new GameRGBColor(1, 1, 1)
],
}
const wcbl = {
particleRate: 700,
particleLifetime: 1.5,
particleSize: [1.5, 1.5, 1.5, 1.5, 1.5],
particleColor: [
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 0, 1),
new GameRGBColor(1, 0, 1),
new GameRGBColor(0, 1, 1),
new GameRGBColor(1, 1, 1)
],
}
world.onPlayerJoin(async({entity})=>{
await loadPlayer(entity)
if(entity.player.name=='阿兹卡班毕业生'){
entity.player.color=new GameRGBColor(1,0,1)
Object.assign(entity, wcbl)
}
else if(admin.includes(entity.player.name)||adminpro.includes(entity.player.name)||entity.adminlevel>0){
Object.assign(entity, particle_purpleCrystal)
}
else if(entity.greenlzxg==true||lzxglist.includes(entity.player.userKey)||lzxglist.includes(entity.player.name)){
Object.assign(entity, particle_greenCrystal)
}
// 管理员sql与地图管理员列表同步
// if(admin.includes(entity.player.name)){
// entity.isadmin=true;
// }
// if(entity.isPlayer==true&&admin.includes(entity.player.name)==false){
// admin.push(entity.player.name)
// }
// 检测网址中是否含有兑换码,如含有则使用
var playerurl_string = entity.player.url;
var playerurl = new URL(playerurl_string);
entity.duihuanma = playerurl.searchParams.get('code')
use_duihuanma(entity)
// 位置设置
entity.position.set(entity.zhutu_position_x,entity.zhutu_position_y,entity.zhutu_position_z)
entity.player.spawnPoint.set(entity.zhutu_position_x,entity.zhutu_position_y,entity.zhutu_position_z)
// 更换皮肤
if(entity.usingskin!='原版'){
entity.player.setSkinByName(entity.usingskin);
}
// 检测组队
try{
entity.playerurl_string = entity.player.url;
entity.playerurl = new URL(entity.playerurl_string);
const date = new Date(Date.now());
const month = date.getMonth() + 1;
const day = date.getDate();
if(entity.playerurl.searchParams.get('serverId')&&entity.playerurl.searchParams.get('teamId')&&entity.last_team!=month+day){
entity.can=true;
world.querySelectorAll('player').forEach((e)=>{
e.playerurl_string = e.player.url;
e.playerurl = new URL(e.playerurl_string);
if(e.playerurl.searchParams.get('serverId')&&e.playerurl.searchParams.get('teamId')){}
else{
entity.can=false
}
})
if(entity.can==true){
entity.exp += 10000
entity.last_team = month+day
savePlayer(entity)
dialog(`组队福利领取成功`,`${entity.player.name},欢迎使用组队功能来到本地图,1w经验已自动领取\n若您是队长,可以截图队伍界面后联系毕业生领取管理员`,entity)
}
else{
dialog(`组队福利领取失败`,`${entity.player.name},偷偷改链接是没用的哦~`,entity)
}
}
else{
if(entity.last_team==month+day){
dialog(`组队福利领取失败`,`${entity.player.name},今天你已领过组队福利,请明天再来!`,entity)
}
}
}
catch(e){}
})
// 右键菜单
world.onPress(async({button,entity})=>{
if(button==='action1'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '游戏菜单',
content:`你有${entity.exp}经验\n`+ `你的血量:`+entity.hp+`/`+entity.maxHp+`\n你的坐标:`+entity.position,
options:['赞助毕业生,得顶级福利','选择附图','关于gameUi','兑换码','sql存档','sql删档','经验排行榜','皮肤库','商店','背包','重来','脱离卡点','进入/离开挂机房','进入/退出俯视全图','切换人称','bug反馈','禁言玩家说话','管理员工具']
});
if(!result || result.value === null){
return;
}
else if(result.value=='赞助毕业生,得顶级福利'){
entity.player.link(`https://azkbbys.gitbook.io/azkbbys/zzbys`, {isConfirm: false, isNewTab: true})
}
else if(result.value=='选择附图'){
entity.position.set(97,40,74);
dialog(`系统`,`你已进入附图选择区域,与dream互动即可选择附图,要退出请右键点击“脱离卡点”`,entity)
}
else if(result.value=='关于gameUi'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: 'gameUi',
content:`选择你要进行的操作`,
options:['取消操作','关闭gameUi','刷新gameUi内容/开启gameUi','刷新gameUi大小']
});
if(!result || result.value === null){
return;
}
else if(result.value=='关闭gameUi'){
remoteChannel.sendClientEvent(entity, {type:'command',args:'close'})
entity.player.directMessage(`已关闭`)
}
else if(result.value=='刷新gameUi内容/开启gameUi'){
remoteChannel.sendClientEvent(entity, {
type:'command',
args:'open'
})
remoteChannel.sendClientEvent(entity, {
type:'玩家信息1',
args:{
avatar:entity.player.avatar,
name:entity.player.name,
player_title:entity.player_title
}
})
entity.player.directMessage(`刷新/开启成功`)
}
else if(result.value=='刷新gameUi大小'){
remoteChannel.sendClientEvent(entity, {
type: '刷新大小',
args: null
})
entity.player.directMessage(`当前暂不支持刷新,请刷新网页即可`)
}
}
else if(result.value=='兑换码'){
entity.duihuanma = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '兑换',
content: `输入你所获得的兑换码\n兑换码可以在Q群763919859获得!`,
confirmText: '确认',
});
if(!entity.duihuanma || entity.duihuanma === null){
entity.player.link(`http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Atg_SCPUyp2d8yAAxjaozzjFH3eu198J&authKey=ohyqS%2FYbJ%2F3C%2BkzrFVQSS7wJoeifKFxeo8SNr4KsX7fey6sx%2Fy%2FX7JEF%2Bvtkryd1&noverify=0&group_code=763919859`, {isConfirm: false, isNewTab: true})
}
else if(entity.used_duihuanma.includes(entity.duihuanma)==true){
dialog(`错误`,`这个兑换码已经使用过了`,entity)
}
else{
use_duihuanma(entity)
}
}
else if(result.value=='sql存档'){
savePlayer(entity);
dialog(`系统`,`存档成功!\n每次踩到存档点会自动进行所有数据的保存`,entity)
}
else if(result.value=='sql删档'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '你确定要删档吗?',
content:`你确定要删档吗?\n删档后一切数据将消失!\n不能后悔!`,
options:['不确定','算了','没想好','不删','删了吧']
});
if(result.value=='删了吧'){
Object.assign(entity, savedData);
savePlayer(entity);
entity.player.kick();
}
}
else if(result.value=='经验排行榜'){
await entity.player.dialog({
type: 'select',
title: '排行',
content: await leaderBoard('exp'),
options: ['确认']
});
}
else if(result.value=='皮肤库'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '选择皮肤',
content:`请选择要使用的皮肤`,
options:entity.skins
});
if(!result || result.value === null){
entity.player.resetToDefaultSkin()
entity.usingskin = '原版'
}
else if(result.value!='原版皮肤'){
entity.usingskin = result.value;
entity.player.setSkinByName(result.value)
}
else{
entity.player.resetToDefaultSkin()
entity.usingskin = '原版'
}
savePlayer(entity)
entity.player.directMessage('切换成功')
}
else if(result.value=='商店'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '你要买点啥?',
content:`你要买点啥?\n你有${entity.exp}经验\n说明:名称(价格)(备注)`,
options:['退出',
'永久绿色粒子效果(150exp)(全图同步)',
'永久苦力怕皮肤(500exp)(全图同步)(鬼知道作者把皮肤做成了啥样)',
'永久史蒂夫皮肤(500exp)(全图同步)(还原度还是可以的吧)',
'一次性飞行特权(70exp)(开启飞行权限,仅能在一个地图使用!有效期:2s)',
'一次性飞行变速器(5exp)(更改飞行速度,仅能在一个地图使用!使用前提:已经开启飞行)',
'缩小药水(70exp)(一次性,将角色大小缩小50%,不可叠加使用)',
'还原药水(1exp)(一次性,将角色大小还原',
'放大药水(70exp)(一次性,将角色大小增大50%,不可叠加使用)']
});
if(!result || result.value === null){
return;
}
else if(result.value=='永久绿色粒子效果(150exp)(全图同步)'){
if(entity.exp>=150){
entity.exp-=150;
entity.greenlzxg=true;
savePlayer(entity);
entity.player.directMessage(`购买成功,已自动使用,刷新后生效`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='永久苦力怕皮肤(500exp)(全图同步)(鬼知道作者把皮肤做成了啥样)'){
if(entity.exp>=500&&entity.skins.includes('苦力怕')==false){
entity.exp-=500;
entity.skins.push('苦力怕')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入皮肤库,可右键点击“皮肤库”使用`)
}
else{
dialog(`错误`,`经验不够或已拥有皮肤`,entity)
}
}
else if(result.value=='永久史蒂夫皮肤(500exp)(全图同步)(还原度还是可以的吧)'){
if(entity.exp>=500&&entity.skins.includes('史蒂夫')==false){
entity.exp-=500;
entity.skins.push('史蒂夫')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入皮肤库,可右键点击“皮肤库”使用`)
}
else{
dialog(`错误`,`经验不够或已拥有皮肤`,entity)
}
}
else if(result.value=='一次性飞行特权(70exp)(开启飞行权限,仅能在一个地图使用!有效期:2s)'){
if(entity.exp>=80){
entity.exp-=80;
entity.bag.push('一次性飞行特权')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='一次性飞行变速器(5exp)(更改飞行速度,仅能在一个地图使用!使用前提:已经开启飞行)'){
if(entity.exp>=5){
entity.exp-=5;
entity.bag.push('一次性飞行变速器')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='缩小药水(70exp)(一次性,将角色大小缩小50%,不可叠加使用)'){
if(entity.exp>=70){
entity.exp-=70;
entity.bag.push('一次性缩小药水')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='还原药水(1exp)(一次性,将角色大小还原'){
if(entity.exp>=1){
entity.exp-=1;
entity.bag.push('一次性还原药水')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='放大药水(70exp)(一次性,将角色大小增大50%,不可叠加使用)'){
if(entity.exp>=70){
entity.exp-=70;
entity.bag.push('一次性放大药水')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
}
else if(result.value=='背包'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '你要使用啥?',
content:`你要使用啥?\n警告:点击后立即使用无确认\n退出请点X`,
options:entity.bag
});
if(!result || result.value === null){
return;
}
else if(result.value=='一次性飞行特权'){
entity.player.canFly=true;
let index = entity.bag.indexOf('一次性飞行特权');
if (index !== -1) {
entity.bag.splice(index, 1);
}
savePlayer(entity)
entity.player.canFly=true;
entity.player.directMessage('使用成功,2s后降落');
await sleep(2000);
entity.player.canFly=false;
}
else if(result.value=='一次性飞行变速器'){
let index = entity.bag.indexOf('一次性飞行变速器');
if (index !== -1) {
entity.bag.splice(index, 1);
}
const flyspeed = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '自定义飞行速度',
content: `输入飞行速度,不要试探服务器极限`,
confirmText: '确认',
});
entity.player.flySpeed=flyspeed
savePlayer(entity)
entity.player.directMessage('使用成功')
}
else if(result.value=='一次性缩小药水'){
let index = entity.bag.indexOf('一次性缩小药水');
if (index !== -1) {
entity.bag.splice(index, 1);
}
entity.player.scale=0.5
savePlayer(entity)
entity.player.directMessage('使用成功')
}
else if(result.value=='一次性还原药水'){
let index = entity.bag.indexOf('一次性还原药水');
if (index !== -1) {
entity.bag.splice(index, 1);
}
entity.player.scale=1
savePlayer(entity)
entity.player.directMessage('使用成功')
}
else if(result.value=='一次性放大药水'){
let index = entity.bag.indexOf('一次性放大药水');
if (index !== -1) {
entity.bag.splice(index, 1);
}
entity.player.scale=1.5
savePlayer(entity)
entity.player.directMessage('使用成功')
}
else if(result.value=='无限飞行羽翼'){
entity.player.canFly=true;
entity.player.directMessage('使用成功')
}
}
else if(result.value=='重来'){
if(entity.canplay==false){
dialog(`系统`,`你在封禁中,不能出来`,entity)
}
else{
entity.player.spectator=false;
entity.player.directMessage(`重来`)
entity.victory = false
entity.player.canFly=false
entity.hp=100
entity.player.color = new GameRGBColor(1,1,1)
entity.position.set(4,5,4)
entity.ingjf=false;
}
}
else if(result.value=='脱离卡点'){
if(entity.canplay==false){
dialog(`系统`,`你在封禁中,不能出来`,entity)
}
else{
entity.player.forceRespawn()
entity.ingjf=false;
entity.player.directMessage('脱离成功!')
}
}
else if(result.value=='进入/离开挂机房'){
if(entity.canplay==false){
dialog(`系统`,`你在封禁中,不能出来`,entity)
}
else{
if(entity.ingjf==true){
entity.player.forceRespawn();
entity.ingjf=false;
}
else{
entity.position.set(97,6,74);
entity.ingjf=true;
}
}
}
else if(result.value=='进入/退出俯视全图'){
if(entity.fsqting==false){
const fsqt = world.querySelector('#俯视全图')
entity.player.cameraEntity=fsqt
entity.player.directMessage('正在俯视全图,再次点击按钮可退出')
entity.fsqting=true
}
else{
entity.player.cameraEntity=entity
entity.fsqting=false
}
}
else if(result.value=='切换人称'){
if (entity.player.cameraMode === GameCameraMode.FOLLOW) {
entity.player.cameraMode = GameCameraMode.FPS
entity.player.directMessage(`切换成功`)
}
else {
entity.player.cameraMode = GameCameraMode.FOLLOW
entity.player.directMessage(`切换成功`)
}
}
else if(result.value=='bug反馈'){
dialog(`作者`,`反馈问题请发在评论区,也可以发作者邮箱oyroyroyr@163.com,如果采纳会赠送地图绿色粒子特效`,entity)
}
else if(result.value=='禁言玩家说话'){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '禁言玩家说话',
content: `你想要说啥`,
confirmText: '“警告!非禁言玩家尽量不要使用!”',
});
if(!result || result === null){
return;
}
else {
world.say(entity.player.name+':'+result)
}
}
else if(result.value=='管理员工具'){
if(admin.includes(entity.player.name)||entity.adminlevel>0||adminpro.includes(entity.player.name)){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '管理员工具',
content: `选择你需要使用的工具`,
options:['管理员命令文档','飞行','降落','开启/关闭穿墙','玩家传送器','传送至某玩家','集体传送附图!','计时器','广播公告','躲猫猫模式']
});
if(!result || result.value === null){
return;
}
else if(result.value=='管理员命令文档'){
entity.player.link(`https://azkbbys.gitbook.io/azkbbys/docs/bysrunpro/bysrunpro-admin-code-tutorial`, {isConfirm: false, isNewTab: true})
}
else if(result.value=='飞行'){
entity.player.canFly=true
entity.player.directMessage('您可以飞行了')
}
else if(result.value=='降落'){
entity.player.canFly=false
entity.player.directMessage('降落成功')
const allWearables = entity.player.wearables();
// allWearables.forEach((item) => {
// item.remove();
// });
}
else if(result.value=='开启/关闭穿墙'){
if(entity.player.spectator==false){
entity.player.spectator=true
}
else{
entity.player.spectator=false
}
}
else if(result.value=='玩家传送器'){
const playernamelist = []
world.querySelectorAll('player').forEach((e)=>{
if(e.player.name!=entity.player.name)
playernamelist.push(e.player.name)
})
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '传送至某玩家',
content: `你要传送谁到你的位置`,
options:playernamelist
});
if(!result || result.value === null){
return;
}
else{
for (const e of world.querySelectorAll('player')){;
if(e.player.name==result.value){;
e.position.x=entity.position.x
e.position.y=entity.position.y
e.position.z=entity.position.z
entity.player.directMessage('传送成功!')
};
};
}
}
else if(result.value=='传送至某玩家'){
const playernamelist = []
world.querySelectorAll('player').forEach((e)=>{
if(e.player.name!=entity.player.name)
playernamelist.push(e.player.name)
})
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '传送至某玩家',
content: `你要传送你到谁的位置`,
options:playernamelist
});
if(!result || result.value === null){
return;
}
else{
for (const e of world.querySelectorAll('player')){;
if(e.player.name==result.value){;
entity.position.x=e.position.x
entity.position.y=e.position.y
entity.position.z=e.position.z
entity.player.directMessage('传送成功!')
};
};
}
}
else if(result.value=='集体传送附图!'){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '集体传送',
content: `请输入密码(找作者要)`,
confirmText: '确认',
});
if(!result || result === null){
return;
}
else if(result=='123456'){
world.say('管理员开启了集体传送,3s后全体传送至附图《春》')
await sleep(3000)
world.querySelectorAll('player').forEach((e)=>{
e.player.link(`https://dao3.fun/play/6d789dabd5e09ca687ce`, {isConfirm: false, isNewTab: false})
})
}
}
else if(result.value=='计时器'){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '计时器',
content: `你想计时多久`,
confirmText: '“确定”',
});
console.log(entity.count)
if(entity.count=true){
let s = 0
let m = 0
let h = 0
while(entity.count==true){
s++
if(s>=60){;m++;s=0}
if(m>=60){;h++;m=0}
if(h>=3){;entity.player.directMessage('计时最多3小时');return;}
entity.player.directMessage(h+':'+m+':'+s)
await sleep(1000)
}
}
else{
entity.player.directMessage('计时器关闭!')
}
}
else if(result.value=='广播公告'){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '广播公告',
content: `输入广播内容`,
confirmText: '确认广播',
});
world.say(result)
}
else if(result.value='躲猫猫模式'){
// entity.player.directMessage('因为重启服务器代码失效,现在禁用躲猫猫模式')
const zbz = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '躲猫猫模式',
content: `输入抓捕者`,
confirmText: '确认',
});
zbznc = zbz;
while(1){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '躲猫猫模式',
content: `输入躲藏者昵称,输入@以结束添加`,
confirmText: '确认',
});
if(result!=`@`){
dcz.push(result);
entity.player.directMessage(`添加成功,${result}`)
dmmrenshu+=1;
}
else{
break;
}
}
const a = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '躲猫猫模式',
content: `输入躲藏时间,单位秒,不可包含小数`,
confirmText: '确认',
});
dctime = parseInt(a)*16
const b = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '躲猫猫模式',
content: `输入抓捕时间,单位秒,不可包含小数`,
confirmText: '确认',
});
zbtime = parseInt(b)*16;
if(dmm==false){
dmm = true;
world.say(`管理员 ${entity.player.name} 开启了躲猫猫模式`)
dialog(`提示`,`已开启躲猫猫模式`,entity)
}
else{
dialog(`提示`,`错误:\n已经有另外一个管理员开启了躲猫猫模式`,entity)
}
}
else if(result.value='穿戴配件'){
chuandaipeijian(entity)
}
}
}
}
else if(button=='action3'){
entity.player.cameraEntity=entity
}
})
// 模型运动
const lotus_leaf = world.querySelector('#荷叶-2') //获取实体
lotus_leaf.fixed = true//不受外力影响
lotus_leaf.collides = true//允许碰撞
const startPos_lotus_leaf = [63.7, 3.1, 3.7]//初始位置
const endPos_lotus_leaf = [75, 3.1, 3.7]
const ani_lotus_leaf = lotus_leaf.animate([
{ position: startPos_lotus_leaf, duration: 0 },
{ position: startPos_lotus_leaf, duration: 2 },
{ position: endPos_lotus_leaf, duration: 0 },
{ position: endPos_lotus_leaf, duration: 2 },
{ position: startPos_lotus_leaf, duration: 0 },
], {
duration: 16 * 4, //一个循环共用时
iterations: 1,//只播放1次
direction: GameAnimationDirection.WRAP,//让实体从终点回到起点
})
world.onPlayerJoin(({entity}) => {
ani_lotus_leaf.play({
duration: 16 * 4, //播放一个循环共用时20秒(每秒16帧),
iterations: Infinity,//动画无限次循环播放
direction: GameAnimationDirection.WRAP,//让动画实体从终点回到起点
})
})
// gui
// const { GameEasyGUI } = require("./GameEasyGUI.js"); //导入GameEasyGUI.js
// world.onPlayerJoin(async ({ entity }) => {
// var mygui = new GameEasyGUI("myGUI", entity);
// entity.gui = mygui; //创建一个gui对象
// var dom = mygui.document;
// var msg1 = dom.createXml("label", {
// height: 20,
// width: 200,
// color: "#fff",
// fontSize: 18,
// x: 10,
// y: 70,
// id:"msg1"
// });
// var group = dom.createXml("group", {
// width: 240,
// height: 160,
// borderColor: "rgba(0,0,0,0)",
// backgroundColor: "rgba(0,0,0,0.45)",
// right:20,
// top:50
// }).appendChild(dom.createXml("label", {
// height: 20,
// width: 100,
// color: "#fff",
// fontSize: 20,
// x: 10,
// y: 10,
// text: "聊天消息"
// })).appendChild(msg1); //将创建好的元素插入group中
// dom.appendChild(group); //将元素插入document中
// mygui.render(); //渲染gui
// var button = dom.createXml("button",{
// text:"戳我发消息(防禁言)",
// x:10,
// y:120,
// percentWidth:90,
// height:30,
// color:"#fa0"
// });
// button.addEventListener("click",async function({entity}){
// const result = await entity.player.dialog({
// type: GameDialogType.INPUT,
// title: '发言',
// content: `你想要说啥`,
// confirmText: '确定发送,反悔请点X',
// });
// if(!result || result === null){
// return;
// }
// else {
// world.say(entity.player.name+':'+result)
// msglist[0]=entity.player.name+':'+result
// }
// })
// group.appendChild(button);
// mygui.reload(); //刷新
// });
// //循环显示信息
// world.onTick(()=>{
// world.querySelectorAll('player').forEach((e)=>{
// if(e.gui){
// let dom = e.gui.document;
// let msg1 = dom.getElementById("msg1");
// msg1.setAttribute("text",msglist[0]);
// }
// })
// })
world.onPlayerJoin(({entity})=>{
world.onTick(({tick})=>{
if(dmm==true&&entity.dmmshoudao==false){
if(zbznc==entity.player.name){
entity.player.directMessage(`你是抓捕者`);
entity.player.color=new GameRGBColor(1,0,0);
entity.dmmzy='抓捕';
dialog(`操作说明`,`碰到躲藏者(黑色的人)即可抓获`,entity)
entity.dmmshoudao=true;
entity.position.set(2,6,10);
entity.player.canFly=true;
}
else if(dcz.includes(entity.player.name)){
entity.player.directMessage(`你是躲藏者,快开始躲藏吧!`);
entity.dmmzy='躲藏';
dialog(`操作说明`,`不要被红色昵称的抓捕者碰到!`,entity)
entity.player.color=new GameRGBColor(0,0,0);
entity.dmmshoudao=true;
entity.player.canFly=true;
}
}
if(dmm==true){
if(dctime==0){
if(dctime==0&&entity.dmmzy=='抓捕'){
entity.player.forceRespawn()
// dctime-=16;
}
}
}
})
})
world.onTick(async({tick})=>{
if(dmm==true){
if(dctime>=0){
if(tick%16==0){
dctime-=16;
world.say(`躲猫猫-躲藏时间还剩${dctime/16}秒`)
world.clearCollisionFilters()
// entity.dmmshoudao=true
}
}
else if(zbtime!=0){
if(tick%16==0){
zbtime-=16;
world.say(`躲猫猫-抓捕时间还剩${zbtime/16}秒`)
}
}
else{
dmm=false;
world.say(`躲猫猫结束,如3s后服务器未自行重启,请管理员输入\$while(1){} 进行重启`)
await sleep(3000)
while(1){}
}
}
})
world.onEntityContact(({entity,other})=>{
if(entity.dmmzy=='抓捕'){
if(other.dmmzy=='躲藏'&&beizhuadao.includes(entity.player.name)==false){
beizhuadao.push(other.player.name);
world.say(`抓捕者抓到了${other.player.name}`)
entity.player.directMessage(`恭喜抓到人了!经验+10`);
entity.exp+=10;
savePlayer(entity)
other.player.directMessage(`被抓到了了!经验+5`);
other.exp+=5;
savePlayer(other)
other.player.color=new GameRGBColor(1,1,1);
}
}
})
//挂机检测
// world.onPlayerJoin(({entity})=>{
// entity.xcundang= 0
// entity.ycundang= 0
// entity.zcundang= 0
// entity.i=0
// world.onTick(async({tick})=>{
// if(tick%16==0){
// if(entity.xcundang==entity.position.x&&entity.ycundang==entity.position.y&&entity.zcundang==entity.position.z){
// entity.i+=1
// console.log('挂机',entity.i)
// }
// else{
// entity.i=0
// entity.xcundang=entity.position.x
// entity.ycundang=entity.position.y
// entity.zcundang=entity.position.z
// }
// if(entity.i==130&&entity.cankick==true){
// entity.player.cancelDialogs()
// dialog('系统','你已在当前位置停留了5min,若继续停留,10s后将踢出游戏!\n挂机会导致服务器变卡,甚至崩服,为了服务器的健康,现在禁止挂机',entity)
// }
// else if(entity.i>=140&&entity.cankick==true){
// entity.i=0
// entity.player.kick()
// }
// }
// })
// })
world.onTick(({tick})=>{
if(tick%960==0){
const date = new Date(Date.now());
const minute = date.getMinutes()
if(minute==0){
world.say('整点福利:全体玩家经验+10')
world.querySelectorAll('player').forEach((e)=>{
e.exp+=10
savePlayer(e)
})
}
}
})
// 服务端、客户端信息交流/gameUi控制
world.onTick(({tick})=>{
remoteChannel.sendClientEvent(world.querySelectorAll('player'), {
type:'世界信息',
args:{
message: msglist[0]
}
})
world.querySelectorAll('player').forEach((e)=>{
remoteChannel.sendClientEvent(e, {
type:'玩家信息1',
args:{
avatar:e.player.avatar,
name:e.player.name,
player_title:e.player_title
}
})
remoteChannel.sendClientEvent(e, {
type:'玩家信息2',
args:{
wintimes: e.wintimes,
exp: e.exp,
x: e.position.x,
y: e.position.y,
z: e.position.z
}
})
})
})
console.clear()
const mscale = 1 / 16
const Quat = new GameQuaternion(0, 0, 0, 1)
function buddyFollow(entity, mesh, y) {
const buddy = world.createEntity({
mesh,
position: entity.position,
meshScale: [mscale, mscale, mscale],
gravity: false, //不受重力影响
fixed: false, //可推移
collides: false, //不可碰撞
friction: 0, //无摩擦力
mass: 0.01, //非常轻
})
const tgPos = entity.position
const budPos = buddy.position
const facing = entity.player.facingDirection//玩家的朝向
const ratio = 0.1//追随的灵敏度, 最好设在0.5左右, 1.0表示立即移到玩家位置
const dist = 2 //与玩家保持的距离
const yOffset = y //y轴位移, 保持僚机在头顶或脚下
const ticker = world.onTick(() => {
//要让小精灵跟在玩家背后, 需要计算xz轴的位移: 玩家朝向的反方向
const xOffset = -facing.x * dist
const zOffset = -facing.z * dist
//当前位置与目标位置在xyz轴的差距
const xDiff = tgPos.x - budPos.x
const yDiff = tgPos.y - budPos.y
const zDiff = tgPos.z - budPos.z
//计算xyz方向上 当前位置向目标位置靠拢的速度
const vx = (xDiff + xOffset) * ratio
const vy = (yDiff + yOffset) * ratio
const vz = (zDiff + zOffset) * ratio
buddy.velocity.set(vx, vy, vz)//设置僚机速度
if (buddy.velocity.sqrMag() > 0.005) {//速度要足够大, 才触发转向, 防止抖动
buddy.meshOrientation = Quat.rotateY(Math.atan2(zDiff, xDiff)) //让小精灵一直面向玩家
}
})
return () => {
ticker.cancel() //关掉tick循环
buddy.destroy() //移除实体
}
}
world.onPlayerJoin(({ entity }) => {
entity.setPet = buddyFollow(entity, 'mesh/皮卡丘.vb', -1) //给玩家增加宠物
})
world.onPlayerLeave(({ entity }) => {
//玩家离开地图时, 切记一定要关掉tick循环以及销毁小精灵实体, 否则随着人数增加, 服务器积累到一定程度就会崩溃
entity.setPet() //干掉宠物
})
world.onPlayerJoin(({entity})=>{
world.onTick(({tick})=>{
if(entity.position.x<0){
entity.velocity.x=1;
entity.player.directMessage('别想不开啊,跳虚空干啥?')
}
else if(entity.position.x>127){
entity.velocity.x=-1;
entity.player.directMessage('别想不开啊,跳虚空干啥?')
}
if(entity.position.z<0){
entity.velocity.z=1;
entity.player.directMessage('别想不开啊,跳虚空干啥?')
}
else if(entity.position.z>127){
entity.velocity.z=-1;
entity.player.directMessage('别想不开啊,跳虚空干啥?')
}
})
})
=======
脚本可以为游戏添加自定义的动态行为,为你的用户提供更吸引人的交互体验。 javascript是神奇代码岛支持脚本语言,你可以用它来构建你得游戏功能。
神奇代码岛(Box3)是一个基于网页的多人联机3D创作平台,支持JavaScript编程。 在神奇代码岛,模型、建筑构成了丰富多彩了视觉世界,而JavaScript代码则为这个世界注入了交互玩法的灵魂;无论是对战还是冒险,模拟经营还是角色扮演,都离不开JavaScript的神奇魔力。 现在,就跟着我一起了解JavaScript的神奇魔法吧~
JavaScript(简称“JS”)是当前最流行、应用最广泛的客户端脚本语言,在 Web 开发领域有着举足轻重的地位,是成为一名优秀前端工程师的必备技能之一。 JS 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。既能用在浏览器中控制页面交互,也能用在服务器端作为网站后台(借助 Node.js),还能在各种操作系统下运行,因此 JavaScript 也是一种全栈式的编程语言。
JavaScript 的应用场合极其广泛,简单到幻灯片、照片库、浮动布局和响应按钮点击,复杂到游戏、2D/3D 动画、大型数据库驱动程序等等。 JavaScript 可以用于 Web 开发的各个领域,例如: Web 应用开发:日常生活中我们所浏览的网页都是由 HTML、CSS、JavaScript 构成的,通过 JavaScript 可以实时更新网页中元素的样式,并可以实现人与网页之间的交互(例如监听用户是否点击了鼠标或按下了某个按键等),还可以在网页中添加一些炫酷的动画; 移动应用开发:除了可以进行 Web 应用开发外,JavaScript 还可以用来开发手机或平板电脑上的应用程序,而且我们还可以借助一些优秀的框架(例如 React Native),让开发更加轻松; Web 游戏:在网页中的小游戏,都可以使用 JavaScript 来实现; 后端 Web 应用开发:以前我们都是使用 JavaScript 来进行 Web 应用程序前端部分的开发,但随着 Node.JS(一个 JavaScript 运行环境)的出现,使得 JavaScript 也可以用来开发 Web 应用程序的后端部分。
学习JavaScript,需先掌握Javascript基础,你可以依次掌握: ●变量、字符串、数字、数组等关键功能 ●基础的运算符与逻辑 ●条件语句、循环、函数等代码块 ●对象与属性的学习和了解 ●神奇代码岛相关的API的使用 ●上手操作一些实例教程 学习过程,可以打开地图编辑器(opens new window)边操作变学习哦~当然,学习的方式方法不唯一 除了可以在神奇代码岛的API文档里阅读相关的资料,也可以在下面的外部学习资料里学习相关的内容
●MDN Web Docs(opens new window) ●RUNOOB.COM(opens new window) ●语言中文网(opens new window) ●还有,B站等视频网站也可以搜索相关的视频教学哦~
在脚本中可全局访问的对象。 类、接口类型以及枚举值不在此列出,请查看对应目录下的内容。
全局变量
storage • Conststorage: GameStorage 代表存储服务的全局对象。
voxels • Constvoxels: GameVoxels 控制所有方块。
world • Constworld: GameWorld 代表游戏世界的全局对象。
概述 GameWorld 世界
是整个游戏世界的主要接口,可以通过全局对象world 来使用它。 它对应涵盖了控制环境天气、物理重力、画面滤镜等全局场景属性,还可以在世界中创建、搜索实体,或监听世界中实体和玩家的碰撞、伤害、互动等事件。 在世界之下,还可以创造GameZone 区域
对地图世界进行指定范围的定制。
类 ●GameWorld 世界
事件 几乎所有事件都能在world上进行监听。 ●GameChatEvent 聊天事件
●GameEntityContactEvent 实体碰撞事件
●GamePurchaseSuccessEvent 购买成功事件
是控制所有方块的接口,可通过全局对象voxels使用。 它负责控制地形变化,利用循环语法批量生成/销毁方块,获取某个方块的类型、名称、旋转角度等。
事件 ●GameFluidContactEvent 液体碰撞事件
概述 实体是地图内的游戏对象,用于对物体、玩家等的控制。 实体对象类为GameEntity,可以通过world.createEntity进行创建,或通过world.querySelector等方法获取地图内已存在的实体对象。
●GameEntityContactEvent 实体碰撞事件
玩家指的是进入地图游玩的用户,由 GamePlayer 玩家
控制,此接口可用定义游戏中的玩家属性、操作等等。玩家属于一种特殊的实体,可以在 GameEntity
的player属性上读取到玩家对象。
概述 控制、处理事件流程的公共模块。有关具体事件的信息,请查阅对应功能模块。
类 ●GameEventHandlerToken 事件管理凭据
动作模块负责控制由 Voxa 导入的模型所带有的动作。包括加载特定动作,暂停动作,重播动作和设置默认动作等,主要通过GameMotionController 动作控制器
进行控制。 动作作为实体的一部分,可以通过entity.motion获取该实体的动作控制器。
概述 通过动画模块,可以对GameWorld、GameEntity-bean、GamePlayer
对象添加关键帧动画。动画将在本地播放运行,获得更好的性能,播放更流畅、平滑。 通过对应对象上的animate方法可以创建动画对象 GameAnimation-bean,从而控制动画的播放。
类型 ●GameAnimationPlaybackConfig 动画播放配置参数
枚举 ●GameAnimationDirection - 动画播放方向
●GameAnimationPlaybackState 动画播放状态
概述 数据存储模块,管理游戏中的数据。
类 - GameAnimation Animation 动画,可对World世界、Entity实体及Player玩家等对象添加动画。动画将在本地播放运行,获得更好的性能,播放更流畅、平滑。
currentTime •currentTime:number= 0 动画的当前播放时间(多少动画帧)
playState •playState:GameAnimationPlaybackState= GameAnimationPlaybackState.PENDING 当前动画播放状态
playbackRate •playbackRate:number= 1 每tick动画播放速度
startTime •startTime:number= 0 动画开始的时间tick
target •target:TargetType 动画作用的对象(可为world、player或entity)
控制动画播放
play •play:function 播放或者恢复动画的播放
函数声明: ▸ (playback?: Partial‹GameAnimationPlaybackConfig›):void 参数:
名称 | 类型 |
---|---|
playback? | Partial‹GameAnimationPlaybackConfig› |
cancel •cancel: *function 取消当前播放的动画
和动画有关的事件
onFinish •onFinish:GameEventChannel‹GameAnimationEvent‹KeyframeType, TargetType›› •nextFinish:GameEventFuture‹GameAnimationEvent‹KeyframeType, TargetType›› 当动画结束播放时触发
onReady •onReady:GameEventChannel‹GameAnimationEvent‹KeyframeType, TargetType›› • nextReady: GameEventFuture‹GameAnimationEvent‹KeyframeType, TargetType›› 当动画开始播放时触发
方法
keyframes •keyframes:function 返回所有的动画关键帧
函数声明: ▸ ():Partial‹KeyframeType›[]
then ▸then‹T›(resolve: function,reject?: undefined | function):any 类型参数 ▪T 参数: ▪resolve:function ▸ (event:GameAnimationEvent‹KeyframeType, TargetType›):T 参数:
名称 | 类型 | |
---|---|---|
event | GameAnimationEvent ‹KeyframeType, TargetType› |
▪可选reject:undefined | function 返回值:any
类 - GameBounds3 GameBounds用于指定世界中一个立方体空间区域。
构造函数 +new GameBounds3(lo:GameVector3,hi:GameVector3):GameBounds3 新建一个区域 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
lo | GameVector3 | 区域的低处顶点 | |
hi | GameVector3 | 区域的高处顶点 |
返回值:GameBounds3
属性
hi 区域的高处顶点 •hi:GameVector3
lo 区域的低处顶点 •lo:GameVector3
方法
copy ▸copy(b:GameBounds3):GameBounds3 参数:
名称 | 类型 | |
---|---|---|
b | GameBounds3 |
返回值:GameBounds3
set ▸set(lox: number,loy: number,loz: number,hix: number,hiy: number,hiz: number):void 参数:
名称 | 类型 | |
---|---|---|
lox | number | |
loy | number | |
loz | number | |
hix | number | |
hiy | number | |
hiz | number |
返回值:void
intersect ▸intersect(b:GameBounds3):GameBounds3 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
b | GameBounds3 | 计算与此包围盒相交的部分 |
intersects ▸intersects(b:GameBounds3):boolean 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
b | GameBounds3 | 检测是否与此包围盒相交 |
返回值:boolean
contains ▸contains(b:GameVector3):boolean 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
b | GameVector3 | 检测是否包围了这个3d点 |
返回值:boolean
containsBounds ▸containsBounds(b:GameBounds3):boolean 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
b | GameBounds3 | 检测是否完全包围了此盒 |
返回值:boolean
toString ▸toString():string 返回值:string
StaticfromPoints ▸fromPoints(...points: [GameVector3](%5BGameVector3%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/lqqc61nd3gud9omc))):GameBounds3 参数:
名称 | 类型 | 说明 | |
---|---|---|---|
...points | [GameVector3](%5BGameVector3%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/lqqc61nd3gud9omc)) | 任意数量的3d坐标点, 用来形成包围盒 |
返回值:GameBounds3
类 - GameChatEvent 由聊天触发的事件 通过GameWorld.onChat和GamePlayer.onChat触发
entity •entity:GameEntity 发起聊天的实体
message •message:string 聊天事件中说话的内容
tick •tick:number 聊天事件发生时间
类 - GameClickEvent 当玩家用鼠标点击实体时触发的事件
button •button:ACTION0|ACTION1 被点击的按钮,ACTION0 = 左键,ACTION1 = 右键
clicker •clicker:GameEntity& object 发起点击事件的玩家
clickerPosition •clickerPosition:GameVector3 点击鼠标的瞬间玩家所在位置
distance •distance:number 玩家到被点击实体的距离
entity •entity:GameEntity 被点击的实体
raycast •raycast:GameRaycastResult 玩家 -> 被点击实体的射线检测结果
tick •tick:number 鼠标点击事件发生的时间
类 - GameDamageEvent 当实体收到伤害时触发的事件,由GameWorld.onTakeDamage和GameEntity.onTakeDamage触发
tick •tick:number 事件发生的时间
entity •entity:GameEntity 受到伤害的实体
damage •damage:number 伤害值的大小
attacker •attacker:GameEntity|null 攻击者
damageType •damageType:string 伤害的类型
Class: GameDataStorage 代表数据存储空间的类,能通过 {GameStorage.getDataStorage} 或 {GameStorage.getGroupStorage} 创建。能够以键值对的形式存储数据,提供方法处理空间内键值对相关的操作。
存储空间隔离 当游戏服务器尝试连接指定名称的空间时:
属性与方法
key • key: string 空间名称 (只读)
示例代码
set • set : function 传入指定键与值,无论该键是否存在,均将值设置到此键上。
函数声明:
▸ (key:string, value:JSONValue): Promise <void>
参数:
名称 | 类型 | |
---|---|---|
key | string | 需要设置的键 |
value | JSONValue | 需要设置的值 |
返回值:Promise <void>
当设置完成时 resolve,否则 reject
get • get : function 获取指定键对应的值
函数声明: ▸ (key:string): Promise[ReturnValue](%5BReturnValue%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/ofrqlqsh7eq81xw7))
参数:
名称 | 类型 | |
---|---|---|
key | string | 指定的键 |
返回值:Promise[ReturnValue](%5BReturnValue%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/ofrqlqsh7eq81xw7)) 返回 Promise 对象,当获取完成时 resolve,否则 reject,resolve 时返回对应{ ReturnValue | 键值对内容}。
update • update : function 使用传入的方法更新键值对
函数声明:
▸ (key:string, handler:(prevValue: ReturnValue)=>JSONValue): Promise <void>
参数:
名称 | 类型 | |
---|---|---|
key | string | 需要更新的键 |
handler | (prevValue:ReturnValue)=>JSONValue | 处理更新的方法,接受一个参数,为当前键的值,返回一个更新后的值 |
返回值:Promise <void>
返回 Promise 对象,当更新完成时 resolve,否则 reject。
remove • remove : function 删除指定键值对
函数声明: ▸ (key:string): Promise[ReturnValue](%5BReturnValue%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/ofrqlqsh7eq81xw7))
参数:
名称 | 类型 | |
---|---|---|
key | string | 指定的键 |
返回值:Promise[ReturnValue](%5BReturnValue%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/ofrqlqsh7eq81xw7)) 返回 Promise 对象,resolve 时返回被删除的 { ReturnValue | 键值对内容}。
list • list : function 批量获取键值对
函数声明: ▸ (options:ListPageOptions): Promise[QueryList](%5BQueryList%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dw93mzb6q0d5d181))
参数:
名称 | 类型 | |
---|---|---|
options | ListPageOptions | 批量获取键值对的配置项 |
返回值:Promise[QueryList](%5BQueryList%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dw93mzb6q0d5d181)) 返回 Promise 对象,resolve 时返回{ QueryList | 键值对查询表}。
操作频率限制
服务器维度 对每一个游戏服务器独立生效,与服务器在线玩家数正相关,同一队列中的所有API共享限制。
队列 | API | 限制 |
---|---|---|
写入 | set updateremove | (60 + 玩家数 * 10 )次操作 / 分钟 |
读取 | get update | (120 + 玩家数*20)次操作/分钟 |
注;当前版本下,此处玩家数取固定值70。
吞吐量维度 对每一个 Key 的任意操作有吞吐量的限制。
队列 | API | 限制 |
---|---|---|
写入 | set updateremove | 4M/min |
读取 | get update | 25M/min |
错误码
Code | Status | Error Message | 描述 |
---|---|---|---|
400 | DB_NAME_INVALID | Invalid data storage name. | 存储空间名为空,或不满足限制要求。 |
400 | KEY_INVALID | Invalid data key. | 数据键为空。 |
400 | VALUE_INVALID | Invalid data value. | 数据值为空。 |
400 | PARAMS_INVALID | Invalid parameters. | 参数不合法。 |
429 | REQUEST_THROTTLED | Too Many Requests | 超出操作频率限制 |
500 | SERVER_FETCH_ERROR | Server network error. | 服务由于网络原因请求失败。 |
500 | UNKNOWN | Unknown server error. | 未知的服务器错误。 |
示例代码
console.clear()
const testStorage = storage.getDataStorage('test')
async function storageExample() {
await testStorage.set('keyNumber', 1)
await testStorage.set('keyStr', '字符串')
await testStorage.set('keyBoolean', false)
await testStorage.set('keyJson', { describe: 'json内容' })
let numberValue = await testStorage.get('keyNumber')
let strValue = await testStorage.get('keyStr')
let boolValue = await testStorage.get('keyBoolean')
let jsonValue = await testStorage.get('keyJson')
console.log(`keyNumber 的 value: ${numberValue.value}`)
console.log(`keyStr 的 value: ${strValue.value}`)
console.log(`keyBoolean 的 value: ${boolValue.value}`)
console.log(`keyJson 的 value: ${JSON.stringify(jsonValue.value)}`)
await sleep(1000)
numberValue = await testStorage.remove('keyNumber')
strValue = await testStorage.remove('keyStr')
boolValue = await testStorage.remove('keyBoolean')
jsonValue = await testStorage.remove('keyJson')
console.log('\n==========================\n\n')
console.log(`keyNumber 的 value: ${numberValue}`)
console.log(`keyStr 的 value: ${strValue}`)
console.log(`keyBoolean 的 value: ${boolValue}`)
console.log(`keyJson 的 value: ${JSON.stringify(jsonValue)}`)
await sleep(1000)
await testStorage.update('keyNumber', (preData) => { return 2 })
await testStorage.update('keyStr', (preData) => { return '被更改的字符串' })
await testStorage.update('keyBoolean', (preData) => { return true })
await testStorage.update('keyJson', (preData) => { return { describe: 'json内容被更改' } })
numberValue = await testStorage.get('keyNumber')
strValue = await testStorage.get('keyStr')
boolValue = await testStorage.get('keyBoolean')
jsonValue = await testStorage.get('keyJson')
console.log('\n==========================\n\n')
console.log(`keyNumber 的 value: ${numberValue.value}`)
console.log(`keyStr 的 value: ${strValue.value}`)
console.log(`keyBoolean 的 value: ${boolValue.value}`)
console.log(`keyJson 的 value: ${JSON.stringify(jsonValue.value)}`)
await sleep(1000)
console.log('\n==========================\n\n')
const queryList = await testStorage.list({
// 分页指针,用于指定本次获取的分页起点。
cursor: 0,
// 分页大小,一页内的数据量,默认100。
pageSize: 100
})
while (true) {
for (let value of queryList.getCurrentPage()) {
console.log(`${value.key} 的 value:${JSON.stringify(value.value)}`)
}
// 假如为最后一页,退出循环
if (queryList.isLastPage) break
// 翻到下一页
await queryList.nextPage()
}
}
storageExample()
类 - GameDieEvent 当实体死亡时触发的事件,由GameWorld.onDie和GameEntity.onDie触发
tick •tick:number 事件发生的时间
entity •entity:GameEntity 死亡的实体
attacker •attacker:GameEntity|null 击杀者
damageType •damageType:string 伤害的类型
类 - GameEntity Entity实体是Box3中的游戏对象,用于对物体、玩家等的控制。
属性与方法
控制实体的外观 由GameEntityConfig实现
entity.mesh •mesh:string= ""
实体形状数据(mesh)的hash。如果设为空字符串/'',则实体无mesh。 除非实体为玩家,否则设定实体的mesh之后,mesh就会用来计算实体的边界。 只有提前在场景中放置模型,才能获得模型的Mesh属性。 模型被放置后,会自动保存在文件列表中。模型文件对应的*'mesh/.vb'名称便是 mesh属性。 示例代码
entity.position • position: GameVector3<> = new GameVector3(0, 0, 0) 实体的位置。 示例代码
entity.meshOrientation • meshOrientation: GameQuaternion<> = new GameQuaternion(0, 0, 0, 1) 实体的旋转角度
entity.lookAt (targetPosition:GameVector3, meshFacing?:"X"|"Y"|"Z", up?:GameVector3) : void 将实体旋转至面向指定位置的方向,与图形学中定义的 LookAt 矩阵不是一个东西哦。 通过此方法进行的旋转会瞬时发生,仅影响实体的朝向,不会影响实体的运动状态。 ●position:GameVector3 - 世界坐标,希望让实体朝向的位置 ●meshFacing:"X"|"Y"|"Z" - 定义模型在未旋转状态下的参考方向,处理模型设计时未朝向Z轴时的情况: ○当取X、Z时,定义模型的正方向分别为X、Z轴正方向,上方向为 Y 轴正方向 ○当取Y时,定义模型的正方向为Y轴正方向,上方向为Z轴正方向 ○默认值为Z,即模型设计时朝向Z轴正方向 ●up:GameVector3 - 上向量,默认取 Y 轴正方向
entity.meshScale • meshScale: GameVector3<> = new GameVector3(1 / 64, 1 / 64, 1 / 64) 实体的缩放比例
entity.meshColor • meshColor: GameRGBAColor<> = new GameRGBAColor(1, 1, 1, 1) 实体的颜色
entity.meshInvisible •meshInvisible:boolean= false 可控制实体隐形,当值设为true时,则实体隐形。
entity.meshEmissive • meshEmissive: number = 0 实体的发光度
entity.meshMetalness • meshMetalness: number = 0 实体的金属感
entity.meshShininess • meshShininess: number = 0 实体的反光度,设为1则为非常光滑
entity.meshOffset •meshOffset:GameVector3<>= new GameVector3(0, 0, 0) 实体的位移
控制实体的物理属性 由GameEntityConfig实现
entity.bounds •bounds:GameVector3<>= new GameVector3(1, 1, 1) 实体边界框的半径,沿着x/y/z方向,这是一个只读属性,每帧都会重新计算
entity.collides • collides: boolean = true 如果为假(false),则实体不会碰撞
entity.fixed • fixed: boolean = false 如果为真(true),则实体不会移动
entity.friction • friction: number = 0 控制实体的粘性(0 = 滑,1 = 粘)
entity.gravity • gravity: boolean = true 如果为假(false),则实体不会下落 示例代码
entity.mass • mass: number = 1 实体物理质量
entity.restitution • restitution: number = 0 控制实体的弹性(0 = 软, 1 = 弹)
entity.velocity • velocity: GameVector3<> = new GameVector3(0, 0, 0) 实体的速度 示例代码
entity.contactForce •contactForce:GameVector3<>= new GameVector3(0, 0, 0) 实体受到的碰撞力
entity.entityContacts •entityContacts:GameEntityContact[] = [] 返回正在和玩家/实体发生碰撞的全部实体列表
entity.voxelContacts •voxelContacts:GameVoxelContact[] = [] 返回正在和玩家/实体发生碰撞的全部方块列表
entity.fluidContacts •fluidContacts:GameFluidContact[] = [] 返回正在被玩家/实体触碰的全部液体方块列表
聊天
entity.say •say(message: string):void 让实体说话。 示例代码
互动 允许实体进行互动
entity.enableInteract •enableInteract:boolean= false 是否允许实体进行互动。如果允许互动,走进互动范围之内,实体身上将会出现互动提示。
实体互动范围
entity.interactRadius •interactRadius:number= 16 实体互动范围。数值越小,则需要靠近实体才会出现互动提示。 范围有多个可互动实体,按下键盘[或]键,切换互动目标。
互动提示文本
entity.interactHint •interactHint:string= "" 进入实体互动范围时,实体身上出现的提示文本。
互动提示文本颜色
entity.interactColor •interactColor:GameRGBColor‹›= new GameRGBColor(1, 1, 1) 进入实体互动范围时,提示文本的颜色。 示例代码 与实体互动之前,在场景中必须先有一个实体。 在模型列表中,挑选一个你喜欢的模型,将它放置在场景中,并记住模型的名字。
和实体有关的事件
entity.onClick •onClick:GameEventChannel[GameClickEvent](%5BGameClickEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/mtb7dirtqv6g83o4)) •nextClick:GameEventFuture[GameClickEvent](%5BGameClickEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/mtb7dirtqv6g83o4)) 当玩家用鼠标点击实体时触发的事件
entity.onEntityContact •onEntityContact:GameEventChannel[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) •nextEntityContact:GameEventFuture[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) 当实体触碰另一个实体时触发
entity.onEntitySeparate •onEntitySeparate:GameEventChannel[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) •nextEntitySeparate:GameEventFuture[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) 当实体停止触碰另一个实体时触发
entity.onFluidEnter •onFluidEnter:GameEventChannel[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) •nextFluidEnter:GameEventFuture[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) 当实体进入液体时触发
entity.onFluidLeave •onFluidLeave:GameEventChannel[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) •nextFluidLeave:GameEventFuture[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) 当实体离开液体时触发
entity.onInteract •onInteract:GameEventChannel‹GameInteractEvent› •nextInteract:GameEventFuture‹GameInteractEvent› 当实体进行互动时触发 示例代码
entity.onVoxelContact •onVoxelContact:GameEventChannel[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) •nextVoxelContact:GameEventFuture[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) 当实体触碰方块时触发
entity.onVoxelSeparate •onVoxelSeparate:GameEventChannel[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) •nextVoxelSeparate:GameEventFuture[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) 当实体停止触碰方块时触发
控制玩家
entity.isPlayer •isPlayer:boolean= false 如果为真,则实体为玩家
Optionalplayer •player? :GamePlayer 索引与玩家相关的全部状态和方法
快速查找实体
entity.addTag 为实体添加一个新标签 函数声明: ▸addTag(tag: string):void 参数
名称 | 类型 | 说明 |
---|---|---|
tag | string | 要添加的标签名 |
entity.hasTag 判断实体是否带有某个标签 函数声明: ▸hasTag(tag: string):boolean 参数
名称 | 类型 | 说明 |
---|---|---|
tag | string | 标签名 |
示例代码
entity.id •id:string= "" 已在编辑器中添加的实体名称
entity.removeTag 从实体移除标签 函数声明: ▸removeTag(tag: string):void 参数
名称 | 类型 | 说明 |
---|---|---|
tag | string | 要移除的标签名 |
entity.tags 在编辑器中给实体添加的全部标签
函数声明: ▸tags():string[]
实体的销毁
entity.destroy •destroy:function 销毁实体 函数声明: ▸destroy():void
entity.destroyed •destroyed:boolean= false 如果为真(true),实体就被销毁。
entity.onDestroy •onDestroy:GameEventChannel[GameEntityEvent](%5BGameEntityEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dcqt2gzgkxnxqt2d)) •nextDestroy:GameEventFuture[GameEntityEvent](%5BGameEntityEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dcqt2gzgkxnxqt2d)) 当实体被销毁时触发
控制实体的生命值
entity.enableDamage •enableDamage:boolean= false 如果为真true,则可对实体进行伤害
entity.showHealthBar •showHealthBar:boolean= true 如果为真true,则显示实体的生命值HP
entity.hp •hp:number= 100 实体的当前生命值hp
entity.maxHp •maxHp:number= 100 实体的最大生命值hp
entity.onTakeDamage 实体受到伤害时触发的事件 •onTakeDamage:GameEventChannel[GameDamageEvent](%5BGameDamageEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aivo4orkcmc9m0gm)) •nextTakeDamage:GameEventFuture[GameDamageEvent](%5BGameDamageEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aivo4orkcmc9m0gm))
entity.onDie 实体死亡时触发的事件 •onDie:GameEventChannel[GameDieEvent](%5BGameDieEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/fsnsdr8uvuspan6y)) •nextDie:GameEventFuture[GameDieEvent](%5BGameDieEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/fsnsdr8uvuspan6y))
entity.hurt 可用这个函数来定义对实体的伤害。输入对实体的伤害值。 函数声明: ▸hurt(amount: number,options?:Partial[GameHurtOptions](%5BGameHurtOptions%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dvgk7szaqicsyb4q))):void 参数
名称 | 类型 | 说明 |
---|---|---|
amount | number | 伤害值 |
options? | Partial[GameHurtOptions >](%5BGameHurtOptions%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/dvgk7szaqicsyb4q)%3Cbr/) |
伤害的相关配置,选填 |
代码示例
控制实体产生粒子的属性
entity.particleRate •particleRate:number= 0 实体平均每秒产生粒子的数量。如果希望实体停止释放粒子,可以将该属性改为0 示例代码
entity.particleRateSpread •particleRateSpread:number= 0 如果设定了该属性的值,实体每一秒产生粒子的数量将不再是个固定值,而是从区间 [particleRate,particleRate+particleRateSpread) 里随机选取的一个整数。例如,假设particleRate=0,particleRateSpread=3,每秒产生的粒子数量是[0, 0+3) ,即[0, 3)区间里的一个随机整数,也就是可能为0,1,或2 示例代码
entity.particleLimit •particleLimit:number= 100 实体可产生的粒子总数的上限
entity.particleLifetime •particleLifetime:number= 10 粒子的存活时间,以秒为单位 示例代码
entity.particleLifetimeSpread •particleLifetimeSpread:number= 0 如果设定了该属性的值,粒子的存活时间将不再是固定值,而是区间 [particleLifetime,particleLifetime+particleLifetimeSpread) 里的一个随机数,可能为小数 示例代码
entity.particleSize •particleSize:number[]= [1, 1, 1, 1, 1] 该属性的值可以是一个长度为0至5的数组。每个粒子的存活时间被平均分为五个阶段,对于长度为5的数组,数组里的每个值分别指定粒子在各个阶段的大小,其中,第一个值为粒子刚产生是的大小,第五个值为粒子消失时的大小。举几个例子,假设粒子的存活时间被设定为5秒,如果particleSize的值为 ●[25, 25, 25, 25, 25],在粒子存活的5秒内大小不会发生变化,产生时是25,消失时也是25 ●[0, 25, 0, 25, 15],粒子产生时大小为0,然后逐渐变为25,之后又逐渐变为0,再逐渐变为25,最后变为15,可以让该实体所产生的粒子具有逐渐放大缩小的效果 ●[15, 25], 粒子产生时大小为15,1秒后逐渐变大至25,之后又逐渐缩小至最小值 示例代码
entity.particleSizeSpread •particleSizeSpread:number= 0 ●如果设定了该属性,但没设定particleSize的值,每产生一个粒子,会从区间[0,particleSizeSpread)里选取的一个随机数作为它的大小 ●如果同时设定了particleSize和particleSizeSpread两个属性,每产生一个粒子,从区间[0,particleSizeSpread)里选取一个随机数x,这个粒子第i个阶段的大小将为particleSize[i]+x
entity.particleColor •particleColor:GameRGBColor[]= [ new GameRGBColor(1,1,1), new GameRGBColor(1,1,1), new GameRGBColor(1,1,1), new GameRGBColor(1,1,1), new GameRGBColor(1,1,1) ] 类似particleSize,该属性的值可以是一个长度为0至5的数组,数组里的每个值分别指定了粒子在各个阶段的颜色。类似地,可以通过该属性使粒子具有颜色渐变的效果 示例代码
entity.particleVelocity •particleVelocity:GameVector3= new GameVector3(0, 0, 0) 该实体产生的所有粒子的初始速度,如果将该属性设为new GameVector3(x, y, z),x,y,z三个值分别指定粒子在对应三个方向上的速率 示例代码
entity.particleVelocitySpread •particleVelocitySpread:GameVector3= new GameVector3(0, 0, 0) 增加该实体产生的所有粒子初始速度的不确定性,如果将该属性设为new GameVector3(sx, sy, sz),每产生一个粒子,会基于这三个值分别产生一个随机值加到 x/y/z 三个方向所对应的速率上。通过设定这个属性,可以使粒子具有向随机方向运动的效果 示例代码
entity.particleDamping •particleDamping:number= 0 ●如果该属性的值为正数,会短暂减少该实体所产生粒子的初始速度,数值越大,减少初始速度的效果持续得越久 ●如果为负值,会短暂增加粒子的初始速度,数值越小,增加初始速度的效果越明显 示例代码
entity.particleAcceleration •particleAcceleration:GameVector3= new GameVector3(0, 0, 0) 该实体所产生粒子的加速度
entity.particleNoise •particleNoise:number= 0 指定粒子相对于之前运动方向的最大偏离值,数值越大,各个粒子的运动相对原有方向的偏离越明显
entity.particleNoiseFrequency •particleNoiseFrequency:number= 1 指定粒子改变运动方向的频率,数值越大,各个粒子的运动方向越没有规律 示例代码
控制音效 上传音效 编辑器目前内置了34款音效,可以在菜单-[文件管理]的搜索.mp3查看。点击文件后,会弹出声音文件的详情属性。点击位置即可复制文件路径,在脚本中使用对应的方法播放。 如需上传自定义声音,可以在[文件管理]窗口,点击右下角浮动的加号按钮-[上传音频]。 属性
entity.chatSound •chatSound:GameSoundEffect‹›= new GameSoundEffect() 当实体说话时,播放聊天音效。默认为'audio/chat.mp3'。通过entity.say()触发。
entity.hurtSound •hurtSound:GameSoundEffect‹›= new GameSoundEffect() 当实体触发受伤事件时,播放受伤音效。默认为'audio/hurt.mp3'。通过entity.onTakeDamage()触发
entity.dieSound •dieSound:GameSoundEffect‹›= new GameSoundEffect() 当实体触发死亡事件时,播放死亡音效。默认为'audio/die.mp3'。通过entity.onDie()触发
entity.interactSound •interactSound:GameSoundEffect‹›= new GameSoundEffect() 当实体进行互动时,播放互动音效。此音效仅互动的玩家可听见。通过entity.onInteract()触发。
方法
entity.sound •sound:function 在实体的位置播放声音。 参数 spec:{sample, radius, gain, pitch} | string ●sample:string 必填,声音文件路径。可在文件管理器中上传自定义声音。如'audio/chat.mp3' ●radius?:number 可选,声音范围。默认为32。距离实体越近,声音听的越清晰。超出范围的玩家则听不到声音。 ●gain?:number 可选,音量增益。正常为1,数值越大,声音越响。 ●pitch?:number 可选,音高增益。正常为1,大于1,声音播放越快,小于1,声音播放越慢。 示例1
示例2
示例3
动画
entity.animate 可用这个函数来设定实体的动画轨迹 函数声明: ▸animate(keyframes:GameEntityKeyframe[],playbackInfo:Partial[GameAnimationPlaybackConfig](%5BGameAnimationPlaybackConfig%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yccnow4dplv1lldk))):GameAnimation 代码示例
//需要提前在编辑器中添加'单元方块'的模型。
const vox = world.querySelector('#单元方块-1') //获取实体
vox.meshScale = vox.meshScale.scale(4) //让实体变大4倍
const ani = vox.animate([
{ position: [0, 12, 0], meshColor: [1, 1, 0, 1] },
{ position: [0, 12, 127], meshColor: [1, 0, 0, 1] },
{ position: [127, 12, 127], meshColor: [0, 1, 0, 1] },
{ position: [127, 12, 0], meshColor: [0, 0, 1, 1] },
], {
iterations: 3,//兜3圈
direction: GameAnimationDirection.WRAP,//从终点回到起点
duration: 16 * 5, //兜一圈5秒(每秒16帧)
})
ani.onReady(() => {//当动画开始播放时
world.say('开始兜圈')
})
ani.onFinish(() => {//当动画结束播放时
world.say('兜圈结束')
})
动作
entity.motion • motion: GameMotionController<> = new GameMotionController() 实体动作控制器 代码示例
const entity = world.querySelector('#npc')
const entityMotionControl = entity.motion; // MotionController
const motion = entityMotionControl.loadByName('hello'); // MotionHandler 'hello'指代'npc'实体上的其中一个motion动作名称
motion.onFinish(() => {
console.log('Motion End');
});
motion.play()
类 - GameEntityContact 正在发生碰撞的实体
other •other:GameEntity 与此实体碰撞的另一个实体
axis •axis:GameVector3 碰撞的分离轴,也就是碰撞后物体弹飞的方向
force •force:GameVector3 碰撞所产生的力
类 - GameEntityContactEvent 当两个实体碰撞时触发的事件。 由GameWorld.onEntityContact,GameWorld.onEntitySeparate,GameEntity.onEntityContact,GameEntity.onEntitySeparate触发
axis •axis:GameVector3 碰撞的分离轴,也就是碰撞后物体弹飞的方向
entity •entity:GameEntity 碰撞中的第一个实体
force •force:GameVector3 碰撞所产生的力
other •other:GameEntity 碰撞中的第二个实体
tick •tick:number 两个实体碰撞的时间
类 - GameEntityEvent 当创建或销毁实体时触发的事件。 由 GameWorld.onPlayerJoin, GameWorld.onPlayerLeave, GameWorld.onEntityCreate, GameWorld.onEntityDestroy 和 GameEntity.onDestroy 触发
world.onPlayerJoin((entityEvent) => {
// entityEvent.entity
// entityEvent.tick
});
entity •entity:GameEntity 创建/销毁的实体
tick •tick:number 事件发生时间
类 - GameEventHandlerToken 当事件监听被触发时,由 GameEventChannel
返回的token,可用于取消事件监听。
cancel 取消事件监听
函数声明: ▸cancel():void
resume 恢复事件监听
函数声明: ▸ resume(): void
事件列表: ●GameTickEvent 时钟 ●GameClickEvent 点击 ●GameInputEvent 输入 ●GameChatEvent 聊天 ●GameInteractEvent 互动 ●GameEntityEvent 实体创建/销毁 ●GameEntityContactEvent 实体触碰 ●GameVoxelContactEvent 触碰方块 ●GameFluidContactEvent 触碰液体 ●GameDamageEvent 实体伤害 ●GameDieEvent 实体死亡 ●GameTriggerEvent 区域触碰
类 - GameFluidContact 被实体/玩家触碰的液体方块。
voxel •voxel:number 液体方块id
volume •volume:number 液体方块中,被玩家或实体进入的体积比例,大小为(0,1]
当实体进入或离开液体时触发的事件。 由 GameWorld.onFluidEnter, GameWorld.onFluidLeave, GameEntity.onFluidEnter, GameEntity.onFluidLeave 触发
world.onFluidEnter(({entity, tick, voxel}) => {
})
entity •entity:GameEntity 触碰液体的实体
tick •tick:number 实体进入或离开液体的时间
voxel •voxel:number 液体方块id
类 - GameInputEvent 输入事件,在玩家按下或松开按钮时触发。 事件发生的时刻,即为玩家按下/松开按钮的同一刻。 由GameWorld.onPress,GameWorld.onRelease,GamePlayer.onPress,GamePlayer.onRelease触发。 示例代码
点击左键,将鼠标指针位置的方块替换为石头。点击右键,销毁方块。
button •button:GameButtonType 玩家输入的按钮
entity •entity:GameEntity& object 指向按下/松开按钮的玩家
position •position:GameVector3 玩家按下/松开按钮的瞬间所在位置
pressed •pressed:boolean 如果为真,则事件为按下按钮,否则,为松开按钮。
raycast •raycast:GameRaycastResult 按下/松开按钮的瞬间,从玩家视角投射的射线检测结果。
tick •tick:number 按下/松开按钮的时间
类 - GameInteractEvent
参数 ●entity ●targetEntity ●tick
参数
entity •entity:GameEntity 发起互动的实体
targetEntity •targetEntity:GameEntity 收到互动请求的实体
tick •tick:number 事件发生时间
类 - GameMotionController Motion 动作,可对Entity实体带有的动作进行操作,包括加载特定动作,暂停动作,重播动作和设置默认动作等。
示例代码 播放动作
加载特定动作
loadByName • loadByName : function 加载特定动作或动作序列,并返回对应的动作对象
函数声明: ▸ ( configs : "string" | MotionConfig[] | MotionClipConfig): GameMotionHandler 参数:
名称 | 类型 |
---|---|
configs | string |
控制动作播放
pause • pause : function 暂停实体上的动作播放
函数声明: ▸ (): void
resume • resume : function 恢复实体上的动作播放
函数声明: ▸ (): void
设置默认动作
setDefaultMotionByName • setDefaultMotionByName : function 设置默认动作 ●没有其他动作在播放的情况下,默认动作会在游戏运行时自动循环播放 ●调用此函数时,如当前处于默认动作执行状态,则将打断旧默认动作,播放新的默认动作 ●动作名不存在时,此方法不产生任何效果,并抛出包含实体、模型与动作信息的错误
函数声明: ▸ ( motionName : undefined | string): void 参数:
名称 | 类型 |
---|---|
motionName | undefined |
返回值: void
示例代码
const entity = world.querySelector('#npc')
entity.motion.setDefaultMotionByName('FirstMotion');
entity.motion.setDefaultMotionByName(''); // 报错,不存在对应动作
entity.motion.setDefaultMotionByName(); // 设置默认动作为空,即不播放默认动作
类 - GameMotionEvent 动作事件,通过GameMotionHandler.onFinish触发
cancelled •cancelled: bool 动画是否被取消
类 - GameMotionHandler 动作播放的 Handler,用于处理动作中断等行为
示例代码 播放动作
基本
target • target : GameEntity 当前motion的entity对象
控制动作播放
play • play : function 播放当前实体动作 ●会打断当前动作,开始对应动作/序列动作的播放 ●当配置中包含的动作播放结束时,触发 MotionPlayHandler 的 Finish 事件。
函数声明: ▸ (): void
返回值: void
示例代码
const entity = world.querySelector('#npc')
const motion = entity.motion.loadByName('FirstMotion');
motion.play()
cancel • cancel : function 中断此动作播放,并触发 end 事件
函数声明: ▸ (): void
播放结束事件
onFinish • onFinish : GameEventChannel‹GameMotionEvent› • nextFinish: GameEventFuture‹GameMotionEvent› 响应结束状态的监听函数
类 - GamePlayer Player 玩家指的是进入游戏的用户,此接口可用定义游戏中的玩家属性、操作等等。玩家属于一种特殊的实体。
基本
name •name:string= "player" 玩家的昵称。无法控制更改。
boxId •boxId:string= "" 玩家的Box ID(3-15字符)。无法控制更改。 游客的boxID值为空""。
userKey •userKey:string= "" 玩家的唯一识别码(16字符),可以用于存储玩家信息到数据库,无法控制更改。 游客的userKey值为空""。
avatar string 玩家头像信息。
spawnPoint •spawnPoint:GameVector3<>= new GameVector3(64, 140, 64) 玩家的出生点。默认出生点设置在new GameVector3(64, 140, 64)
movementBounds •movementBounds:GameBounds3<>= newGameBounds3(newGameVector3(-50, -50, -50), newGameVector3(178, 178, 178)); 玩家的活动范围限制,如超出此范围,则传回出生点
向玩家发送消息
directMessage ▸directMessage(message: string):void 向玩家直接发送私信
onChat •onChat:GameEventChannel[GameChatEvent](%5BGameChatEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aft5xl7q0dh6puh2)) •nextChat:GameEventFuture[GameChatEvent](%5BGameChatEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aft5xl7q0dh6puh2)) 当发起聊天时调用
dialog •dialog:GameDialogCall 在游戏中显示一个对话框。 示例代码 1
示例代码 2
cancelDialogs •cancelDialogs:function 关闭该玩家的所有打开的对话框。
share (content:string) : void; 为该玩家显示分享弹窗,并能够自定义分享内容。 ●content - 分享弹窗的内容,限制长度为40个字以内,超出后截断,并在末尾添加省略号……。 自动标签 通过此 API 调用弹出的分享弹框的内容末尾,会自动新起一行添加#神奇代码岛 #地图标签,自动添加的内容不计入限制长度内。 编辑模式 编辑模式下,此API弹出的分享弹窗分享的地址是编辑模式的地址。
控制玩家的外观
color •color:GameRGBColor<>= new GameRGBColor(1, 1, 1) 玩家的颜色
emissive •emissive:number= 0 玩家的发光度 示例代码
invisible •invisible:boolean= false 玩家是否隐身 示例代码
skin SkinDescription 此玩家的皮肤配置,用于管理当前玩家皮肤的展示。通过此处修改皮肤不会影响皮肤的隐藏状态,设置前是隐藏的,设置后也还是隐藏着。
皮肤不存在&非法参数 当皮肤名称不存在于项目皮肤库或不符合类型定义时,无事发生,并会在控制台打印警告。
示例
setSkinByName (skinName:string) : void 将指定皮肤套装应用到此玩家上。此方法不会影响皮肤的隐藏状态,设置前是隐藏的,设置后也还是隐藏着。
参数 ●skinName:string - 指定要设置的皮肤名称,将玩家皮肤整体替换为对应的皮肤。 皮肤不存在&非法参数 当皮肤名称不存在于项目皮肤库或不为字符串时,无事发生,并在控制台打印警告。
resetToDefaultSkin () : void 重置此玩家的皮肤配置为默认皮肤配置,效果同 setSkinByName传入了默认皮肤套装名称。
clearSkin () : void 清除地图对此玩家应用的皮肤配置,将此玩家的皮肤配置为仅展示玩家自己的皮肤。
skinInvisible •skinInvisible:GameSkinInvisible 隐藏玩家模型部件接口 示例代码
showName •showName:boolean= true 玩家名字是否显示
showIndicator • showIndicator: boolean = false 玩家标记否显示
scale •scale:number= 1 玩家的缩放比例 示例代码1
metalness •metalness:number= 0 玩家的金属感
shininess •shininess:number= 0 玩家的反光度
addWearable •addWearable:function 在玩家某身体部位附上穿戴配件物体 函数声明: ▸ (spec: Partial‹GameWearable›):GameWearable 参数:
名称 | 类型 |
---|---|
spec | Partial‹GameWearable› |
示例代码
removeWearable •removeWearable:function 把玩家身体部位已附上的穿戴配件物体删除 wearableis the wearable to remove 函数声明: ▸ (wearable:GameWearable):void 参数:
名称 | 类型 |
---|---|
wearable | GameWearable |
示例代码
wearables •wearables:function 列举在玩家上所有的穿戴配件物体 函数声明: • (bodyPart?:GameBodyPart):GameWearable[] 参数:
名称 | 类型 | 说明 |
---|---|---|
bodyPart? | GameBodyPart | 某玩家身体部位,选填 |
示例代码
Web相关
link •link:function 在玩家弹出一个“传送门”窗口,可以跳转到其他地图或任意链接。(目前支持神奇代码岛、编程猫、微信文章、Bilibili视频等链接) 函数声明: ▸ (href: string):void 参数:
名称 | 类型 | 说明 |
---|---|---|
href | string | 链接 URL |
示例代码
url •url:URL 获取该玩家进入地图时所用的URL链接地址, 主要用于获取URL参数, 以便区别对待进来的玩家 示例代码
玩家的复活和死亡
forceRespawn:() 让玩家强制重生,立即返回出生点 •forceRespawn(): void
onRespawn 玩家复活时调用的事件 •onRespawn:GameEventChannel[GameRespawnEvent](%5BGameRespawnEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cshui17169guugxr)) •nextRespawn:GameEventFuture[GameRespawnEvent](%5BGameRespawnEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cshui17169guugxr))
dead 玩家是否已死亡,生命值hp低于0。若玩家死亡,则会倒在地上。 •dead: boolean = false 此属性为只读,不可修改。
控制玩家视角
cameraEntity •cameraEntity:GameEntity| null= null 在第一人称视角(FPS)或第三人称跟随视角(FOLLOW)下,玩家视角所跟随的实体
cameraMode •cameraMode:GameCameraMode 视角模式 ●GameCameraMode.FPS -"fps"- 第一人称视角 ●GameCameraMode.FOLLOW -"follow"- 第三人称跟随视角(默认) ●GameCameraMode.FIXED -"fixed"- 第三人称固定视角 示例代码
cameraPosition •cameraPosition:GameVector3<>= new GameVector3(0, 0, 0) 固定视角(FIXED)下,镜头的眼睛位置
cameraTarget •cameraTarget:GameVector3<>= new GameVector3(0, 0, 0) 固定视角(FIXED)下镜头所朝向的目标点
cameraUp •cameraUp:GameVector3<>= new GameVector3(0, 1, 0) 固定视角(FIXED)下,镜头向上的矢量
cameraFovY • cameraFovY: number = 0.25 垂直方向的视场角
setCameraPitch • setCameraPitch: function 设置玩家视角准心绕水平方向的旋转弧度 函数声明: ▸ (v: number): void 参数:
名称 | 类型 | 说明 |
---|---|---|
v | number | 设置弧度 |
示例代码
setCameraYaw • setCameraYaw: function 设置玩家视角准心绕垂直方向的旋转弧度 函数声明: ▸ (v: number): void 参数:
名称 | 类型 | 说明 |
---|---|---|
v | number | 设置弧度 |
示例代码
enable3DCursor •enable3DCursor:boolean= false 启动玩家的3D光标 示例代码
玩家的输入信息
enableAction0 ●enableAction0:boolean= true 如果为false, 关闭Action0键。PC端为鼠标左键,手机端不会显示A按钮。 示例代码
启动鼠标左键/移动端虚拟按钮A键
enableAction1 ●enableAction1:boolean= true 如果为false, 关闭ActionB键。PC端为鼠标右键,手机端不会显示B按钮。 启动鼠标右键/移动端虚拟按钮B键
action0Button •action0Button:boolean= false 鼠标左键/移动端虚拟按钮A键
action1Button •action1Button:boolean= false 鼠标右键/移动端虚拟按钮B键
crouchButton •crouchButton:boolean= false 下蹲按钮
facingDirection •facingDirection:GameVector3<>= new GameVector3(1, 0, 0) 玩家朝向
cameraPitch • cameraPitch: number= 0 玩家视角准心绕水平方向的旋转弧度 只读
cameraYaw • cameraYaw: number= 0 玩家视角准心绕垂直方向的旋转弧度 只读 PITCHAXIS
ROLLAXIS
YAWAXIS
jumpButton •jumpButton:boolean= false 跳跃按钮
onPress •onPress:GameEventChannel[GameInputEvent](%5BGameInputEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yazeh0kkzogc71tx)) •nextPress:GameEventFuture[GameInputEvent](%5BGameInputEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yazeh0kkzogc71tx)) 当玩家按下按钮时调用
onRelease •onRelease:GameEventChannel[GameInputEvent](%5BGameInputEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yazeh0kkzogc71tx)) •nextRelease:GameEventFuture[GameInputEvent](%5BGameInputEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yazeh0kkzogc71tx)) 当玩家松开按钮时调用
walkButton •walkButton:boolean= false 步行按钮
控制玩家的行动
canFly •canFly:boolean= false 如果为真(true),则允许玩家飞行 示例代码
spectator •spectator:boolean= false 如果为真(true),则玩家是一个幽灵,可以穿墙
enableJump •enableJump:boolean= true 如果为假(false),则不允许玩家跳跃 示例代码
enableDoubleJump •enableDoubleJump:boolean= true 如果为假(false),则不允许玩家二段跳跃 示例代码
walkSpeed •walkSpeed:number= 0.22 最大步行速度
runSpeed •runSpeed:number= 0.4 最大奔跑速度
runAcceleration •runAcceleration:number= 0.35 奔跑加速度
jumpPower •jumpPower:number= 0.96 跳跃力度
jumpSpeedFactor •jumpSpeedFactor:number= 0.85 跳跃速度
jumpAccelerationFactor •jumpAccelerationFactor:number= 0.55 跳跃加速率
doubleJumpPower •doubleJumpPower:number= 0.9 二段跳力度
crouchSpeed •crouchSpeed:number= 0.1 蹲着走路的速度
crouchAcceleration •crouchAcceleration:number= 0.09 蹲着走路的加速度
flySpeed •flySpeed:number= 2 最大飞行速度
flyAcceleration •flyAcceleration:number= 2 飞行加速度
swimAcceleration •swimAcceleration:number= 0.1 游泳加速度
swimSpeed •swimSpeed:number= 0.4 最大游泳速度
walkAcceleration •walkAcceleration:number= 0.19 步行加速度
disableInputDirection GameInputDirection 禁用指定方向的摇杆输入偏移量,当横纵两个方向均被禁用时,将不显示此玩家的触屏虚拟摇杆。
查看玩家的状态
moveState •moveState=GamePlayerMoveState.FALL 玩家的运动状态,初始值为下落
walkState •walkState=GamePlayerWalkState.NONE 玩家的步行状态,初始值为非步行中
控制音效
预设音效
action0Sound •action0Sound:GameSoundEffect‹›= new GameSoundEffect() 当玩家按下'action0'按键(鼠标左键 / 虚拟按钮A)时,播放的音效。
action1Sound •action1Sound:GameSoundEffect‹›= new GameSoundEffect() 当玩家按下'action1'按键(鼠标右键 / 虚拟按钮B)时,播放的音效。
crouchSound •crouchSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家按下'crouchButton '按键进行蹲下时,播放的音效。
jumpSound •jumpSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家按下'jumpButton '按键进行跳跃时,播放的音效。默认为'audio/jump.mp3'
doubleJumpSound •doubleJumpSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家触发二段跳时,播放的音效。默认为'audio/double_jump.mp3'
landSound •landSound:GameSoundEffect‹›= new GameSoundEffect() 玩家落地时,播放的音效。默认为'audio/land.mp3'
enterWaterSound •enterWaterSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家进入液体时,播放的音效。默认为'audio/dive.mp3'
leaveWaterSound •leaveWaterSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家离开液体时,播放的音效。默认为'audio/splash.mp3'
swimSound •swimSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家正在游泳时,播放的音效。默认为'audio/swim.mp3' 注:游泳的音效在前进时才会循环播放。如果在水中静止不动,不会播放音效。
spawnSound •spawnSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家重生时,播放的音效。默认为'audio/spawn.mp3'。通过player.onRespawn()触发
stepSound •stepSound:GameSoundEffect‹›= new GameSoundEffect() 当玩家行走时,每迈出一步,播放的音效。默认为'audio/step.mp3'
startFlySound •startFlySound:GameSoundEffect‹›= new GameSoundEffect() 玩家开始飞行时的音效。
stopFlySound •stopFlySound:GameSoundEffect‹›= new GameSoundEffect() 玩家结束飞行时播放的音效。
播放音效
sound •sound:function 为指定的玩家播放声音,此声音仅该玩家能听见,其他玩家无法听到。 参数: spec:{sample, gain, pitch} | string ●sample:string 必填,声音文件路径。可在文件管理器中上传自定义声音。如'audio/chat.mp3' ●gain?:number 可选,音量增益。正常为1,数值越大,声音越响。 ●pitch?:number 可选,音高增益。正常为1,大于1,声音播放越快,小于1,声音播放越慢。 示例代码1
示例代码2
music •music:GameSoundEffect‹›= new GameSoundEffect() 为指定的玩家播放背景音乐(循环播放),此声音仅该玩家能听见,其他玩家无法听到。 背景音乐的音量会根据用户在[设置-声音]更改。
画面滤镜
colorLUT •colorLUT:string= "" 用于渲染玩家所见游戏世界的色调 示例代码
动画
player.animate 可用这个函数来设定玩家的动画,变化颜色
社交
querySocial (socialType: SocialType) => Promise<number[]> · 查询当前玩家的社交关系,支持查询: · 关注 · 粉丝 · 好友 · 返回玩家 ID 列表
openUserProfileDialog (userId: number) => void 对当前玩家,调起指定ID玩家的个人主页。
商城
openMarketplace ●openMarketplace:function 打开游戏商店对话框,根据玩家传入的“商品ID”显示相应的产品。
函数声明: ▸ (productIds: number[]): void 参数:
名称 | 类型 | 说明 |
---|---|---|
productIds | number[] | 商品ID数组 |
示例代码
world.onPlayerJoin(({ entity }) => {
// product ID1: 160000000000001 ID2: 160000000000002
entity.player.openMarketplace([160000000000001, 160000000000002])
});
投喂记录
getMiaoShells ●getMiaoShells:function 获取此用户在当前地图下累计打赏的喵贝壳
函数声明:
▸ (): Promise <number>
示例代码
world.onPlayerJoin(async ({ entity }) => {
// 获取用户在当前地图下累计打赏的喵贝壳
const count = await entity.player.getMiaoShells()
entity.player.directMessage(`我累计打赏的喵贝壳:${count}`)
})
类 - GamePurchaseSuccessEvent 当玩家成功购买物品时触发的事件
tick • tick: number 购买成功事件发生的时间
userId • userId: string 触发购买事件的玩家userId
productId • productId: number 购买商品的ID
orderId • orderId: number 购买成功的订单号
类 - GameQuaternion
构造函数 +new GameQuaternion(w: number,x: number,y: number,z: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
w | number |
x | number |
y | number |
z | number |
返回值:GameQuaternion
属性
名称 | 类型 | |
---|---|---|
w | number | |
x | number | |
y | number | |
z | number |
方法
add ▸add(v:GameQuaternion):GameQuaternion 参数:
名称 | 类型 | |
---|---|---|
v | GameQuaternion |
返回值:GameQuaternion
angle ▸angle(q:GameQuaternion):number 参数:
名称 | 类型 | |
---|---|---|
q | GameQuaternion |
返回值:number
clone ▸clone():GameQuaternion 返回值:GameQuaternion
copy ▸copy(q:GameQuaternion):GameQuaternion 参数:
名称 | 类型 | |
---|---|---|
q` | GameQuaternion |
返回值:GameQuaternion
div ▸div(q:GameQuaternion):GameQuaternion‹› 参数:
名称 | 类型 | |
---|---|---|
q | GameQuaternion |
返回值:GameQuaternion‹›
dot ▸dot(q:GameQuaternion):number 参数:
名称 | 类型 | |
---|---|---|
q | GameQuaternion |
返回值:number
equals ▸equals(q:GameQuaternion,tolerance: number):boolean 参数:
名称 | 类型 | Default | |
---|---|---|---|
q | GameQuaternion | - | |
tolerance | number | 0.0001 |
返回值:boolean
getAxisAngle ▸getAxisAngle(q: any):object 参数:
名称 | 类型 |
---|---|
q | any |
返回值:object ●angle:number ●axis:GameVector3
inv ▸inv():GameQuaternion 返回值:GameQuaternion
mag ▸mag():number 返回值:number
mul ▸mul(q:GameQuaternion):GameQuaternion 参数:
名称 | 类型 |
---|---|
q | GameQuaternion |
返回值:GameQuaternion
normalize ▸normalize():GameQuaternion 返回值:GameQuaternion
rotateX ▸rotateX(_rad: number):GameQuaternion 参数:
名称 |
---|
_rad |
返回值:GameQuaternion
rotateY ▸rotateY(_rad: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
_rad | number |
返回值:GameQuaternion
rotateZ ▸rotateZ(_rad: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
_rad | number |
返回值:GameQuaternion
set ▸set(w: number,x: number,y: number,z: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
w | number |
x | number |
y | number |
z | number |
返回值:GameQuaternion
slerp ▸slerp(q:GameQuaternion,n: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
q | GameQuaternion |
n | number |
返回值:GameQuaternion
sqrMag ▸sqrMag():number 返回值:number
sub ▸sub(v:GameQuaternion):GameQuaternion 参数:
名称 | 类型 |
---|---|
v | GameQuaternion |
返回值:GameQuaternion
toString ▸toString():string 返回值:string
StaticfromAxisAngle ▸fromAxisAngle(axis:GameVector3,rad: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
axis | GameVector3 |
rad | number |
返回值:GameQuaternion
StaticfromEuler ▸fromEuler(x: number,y: number,z: number):GameQuaternion 参数:
名称 | 类型 |
---|---|
x | number |
y | number |
z | number |
返回值:GameQuaternion
StaticrotationBetween ▸rotationBetween(a:GameVector3,b:GameVector3):GameQuaternion 参数:
名称 | 类型 |
---|---|
a | GameVector3 |
b | GameVector3 |
返回值:GameQuaternion
类 - GameRaycastResult 射线检测(raycast)的结果,包含射线和所击中目标的信息。
direction •direction:GameVector3 射线的方向
distance •distance:number 射线穿越的距离
hit •hit:boolean 如果为真,则射线击中目标
hitEntity •hitEntity:GameEntity| null 射线所击中的实体
hitPosition •hitPosition:GameVector3 射线击中的位置
hitVoxel •hitVoxel:number 射线所击中的方块id (如未击中方块,则为0)
normal •normal:GameVector3 射线所击中平面的法向量
origin •origin:GameVector3 射线的起点
voxelIndex •voxelIndex:GameVector3 如果射线击中的是方块,则返回所击中方块的网格坐标。
类 - GameRespawnEvent 当实体复活时触发的事件
tick • tick: number 事件发生的时间
entity • entity: GameEntity 复活的实体
类 - GameRGBColor
GameRGBColor +new GameRGBColor(r: number,g: number,b: number):GameRGBColor 参数:
名称 | 类型 |
---|---|
r | number |
g | number |
b | number |
示例代码
注意,此处输入的颜色值范围在(0-1) 之间。 如果需要使用 RGB 255,可以将颜色值除于255,即可得到0-1的数值。
方法
add ▸add(rgb:GameRGBColor):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
返回值:GameRGBColor
clone ▸clone():GameRGBColor 返回值:GameRGBColor
copy ▸ copy(c: GameRGBColor): GameRGBColor 参数:
名称 | 类型 |
---|---|
c | GameRGBColor |
返回值:GameRGBColor
div ▸div(rgb:GameRGBColor):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
返回值:GameRGBColor
equals ▸equals(rgb:GameRGBColor,tolerance: number):boolean 参数:
名称 | 类型 | Default |
---|---|---|
rgb | GameRGBColor | - |
tolerance | number | 0.0001 |
返回值:boolean
lerp ▸lerp(rgb:GameRGBColor,n: number):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
n | number |
返回值:GameRGBColor
mul ▸mul(rgb:GameRGBColor):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
返回值:GameRGBColor
set ▸set(r: number,g: number,b: number,a: number):GameRGBColor 参数:
名称 | 类型 |
---|---|
r | number |
g | number |
b | number |
a | number |
返回值:GameRGBColor
sub ▸sub(rgb:GameRGBColor):GameRGBColor 参数:
名称 | 类型 |
---|---|
rgb | GameRGBColor |
返回值:GameRGBColor
toRGBA ▸toRGBA():GameRGBAColor 返回值:GameRGBAColor
toString ▸toString():string 返回值:string
Staticrandom ▸random():GameRGBColor 返回值:GameRGBColor
类 - GameRGBAColor
GameRGBAColor new GameRGBAColor(r: number,g: number,b: number,a: number):GameRGBAColor 参数:
名称 | 类型 |
---|---|
r | number (0-1) |
g | number (0-1) |
b | number (0-1) |
a | number (0-1) |
示例代码
注意,此处输入的颜色值范围在(0-1) 之间。 如果需要使用 RGB 255,可以将颜色值除于255,即可得到0-1的数值。
方法
add ▸add(rgba:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
返回值:GameRGBAColor
clone ▸clone():GameRGBAColor 返回值:GameRGBAColor
copy ▸copy(c:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
c | GameRGBAColor |
返回值:GameRGBAColor
div ▸div(rgba:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
返回值:GameRGBAColor
equals ▸equals(rgba:GameRGBAColor,tolerance: number):boolean 参数:
名称 | 类型 | Default |
---|---|---|
rgba | GameRGBAColor | - |
tolerance | number | 0.0001 |
返回值:boolean
lerp ▸lerp(rgba:GameRGBAColor,n: number):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
n | number |
返回值:GameRGBAColor
mul ▸mul(rgba:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
返回值:GameRGBAColor
set ▸set(r: number,g: number,b: number,a: number):GameRGBAColor 参数:
名称 | 类型 |
---|---|
r | number |
g | number |
b | number |
a | number |
返回值:GameRGBAColor
sub ▸sub(rgba:GameRGBAColor):GameRGBAColor 参数:
名称 | 类型 |
---|---|
rgba | GameRGBAColor |
返回值:GameRGBAColor
toString ▸toString():string 返回值:string
类 - GameStorage 数据存储模块,管理游戏中的数据。
storage 对象是整个 Data Storage API的入口
getDataStorage • getDataStorage : function 连接指定数据存储空间,如果不存在则创建一个新的空间。
函数声明 ▸ (key: string): GameDataStorage
参数:
名称 | 类型 | |
---|---|---|
key | string | 指定空间的名称,长度不超过50个字符 |
返回值:GameDataStorage
示例代码
getGroupStorage • getGroupStorage : function 连接地图组内指定数据存储空间,如果不存在则创建一个新的空间。此方法拿到的GameDataStorage为主图和副图共同维护的数据存储空间。
函数声明 ▸ (key: string): GameDataStorage
参数:
名称 | 类型 | |
---|---|---|
key | string | 指定空间的名称,长度不超过50个字符 |
返回值:GameDataStorage
示例代码
主图获取玩家数据
// 在拓展地图中,如果希望主图和副图共用玩家数据,则都用getGroupStorage获取
const userStorage = storage.getGroupStorage('users')
副图获取玩家数据
const userStorage = storage.getGroupStorage('users')
类 - GameTickEvent 每一刻(tick)触发一次的事件,由GameWorld.onTick触发。 示例代码
world.onTick((tickEvent)
console.log(tickEvent.elapsedTimeMS);
console.log(tickEvent.prevTick);
console.log(tickEvent.skip);
console.log(tickEvent.tick);
})
elapsedTimeMS •elapsedTimeMS:number Wall clock time between ticks 两个时刻之间的时间间隔
prevTick •prevTick:number Last tick which was handled 上一个已处理的时刻
skip •skip:boolean 是否因为代码延迟而跳过了某些时刻
tick •tick:number 事件触发时间
类 - GameTriggerEvent 当实体/玩家触发区域的事件。 由 GameZone.onEnter, GameZone.onLeave, GameZone.nextEnter, GameZone.nextLeave 触发
参数 ●entity ●tick
参数
entity •entity:GameEntity 触发事件的实体
tick •tick:number 触发事件的时间
类 - GameVector3
构造函数 new GameVector3(x: number, y: number, z: number): GameVector3 参数:
名称 | 类型 |
---|---|
x | number |
y | number |
z | number |
返回值:GameVector3
属性
名称 | 类型 |
---|---|
x | number |
y | number |
z | number |
方法
add ▸ add(v: GameVector3): GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
angle ▸angle(v:GameVector3):number 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:number
clone ▸clone():GameVector3 返回值:GameVector3
copy ▸copy(v:GameVector3):void 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:void
cross ▸cross(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
distance ▸distance(v:GameVector3):number 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:number
div ▸div(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
dot ▸dot(v:GameVector3):number 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:number
equals ▸equals(v:GameVector3,tolerance: number):boolean 参数:
名称 | 类型 | Default |
---|---|---|
v | GameVector3 | - |
tolerance | number | 0.0001 |
返回值:boolean
exactEquals ▸exactEquals(v:GameVector3):boolean 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:boolean
lerp ▸lerp(v:GameVector3,n: number):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
n | number |
返回值:GameVector3
mag ▸mag():number 返回值:number
max ▸max(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
min ▸min(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
mul ▸mul(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v` | GameVector3 |
返回值:GameVector3
normalize ▸normalize():GameVector3 返回值:GameVector3
scale ▸scale(n: number):GameVector3 参数:
名称 | 类型 |
---|---|
n | number |
返回值:GameVector3
set ▸set(x: number,y: number,z: number):void 参数:
名称 | 类型 |
---|---|
x | number |
y | number |
z | number |
返回值:void
sqrMag ▸sqrMag():number 返回值:number
sub ▸sub(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
toString ▸toString():string 返回值:string
towards ▸towards(v:GameVector3):GameVector3 参数:
名称 | 类型 |
---|---|
v | GameVector3 |
返回值:GameVector3
VoxelContact方块碰撞参数 被实体触碰的方块属性
x •x:number 被触碰方块的x坐标
y •y:number 被触碰方块的y坐标
z •z:number 被触碰方块的z坐标
voxel •voxel:number 被触碰的方块id
force •force:GameVector3 触碰的力
axis •axis:GameVector3 触碰的分离轴,也就是触碰后物体弹飞的方向
当实体触碰方块时触发的事件。 由 GameWorld.onVoxelContact, GameWorld.onVoxelSeparate, GameEntity.onVoxelContact, GameEntity.onVoxelSeparate 触发
axis •axis:GameVector3 触碰的分离轴,也就是触碰后物体弹飞的方向
entity •entity:GameEntity 触碰到方块的实体
force •force:GameVector3 碰撞力
tick •tick:number 实体触碰方块的时间
voxel •voxel:number 被触碰的方块id
x •x:number 被触碰方块的x坐标
y •y:number 被触碰方块的y坐标
z •z:number 被触碰方块的z坐标
类 - GameVoxels GameVoxels是控制Box3所有方块的接口,你可以使用 voxels 对象控制地形变化,利用循环语法批量生成/销毁方块,获取某个方块的类型、名称、旋转角度等。
Basic 基础
voxels.shape 属性 属性值类型:GameVector3 默认值:{x: 128, y: 128, z: 128} 世界地形最大尺寸。 目前,Box3地形最大可支持128x128x128,未来将开放更大的地形,敬请期待。
Voxel Name 方块名称
voxels.id() 方法 将方块名称转换为方块id 参数 name
名称 | 类型 | 说明 |
---|---|---|
name | string | 方块名称 |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 方块 id |
voxels.name() 方法 将方块id转换为方块名称 参数 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 方块id |
返回值 name
名称 | 类型 | 说明 |
---|---|---|
name | string | 方块名称 |
setVoxel 放置方块 如果你想要地图在非运行状态,通过脚本在场景中快速建造,可以尝试以下操作: 1开启编辑器右上角的调试模式(小虫子图标) 2使用窗口底部的控制台,输入对应的代码。 即使游戏没有运行,也能使部分代码直接生效。 💡提示 使用控制台执行脚本前,请务必要小心,提前做好项目备份工作。一旦代码生效后,有可能造成无法恢复的情况。 要操作方块时,建议先使用空白地图对代码进行充分测试,效果满意后,再操作正式的地图。
voxels.setVoxel() 方法 在指定的坐标位置放置一个方块。 参数 x, y, z, voxel, rotation
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,放置位置的x坐标 |
y | number | 必填,放置位置的y坐标 |
z | number | 必填,放置位置的z坐标 |
voxel | number | string |
rotation | number | string |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 新的方块id |
💡提示 若方块名称为'air' 或者方块id为0,则会打破 简单示例
将脚下的方块全部变成雪地
删除地面至上空的所有方块
方块自动往上增长
利用方块显示字母
利用方块显示文章
创建一个棋盘
voxels.setVoxelId() 方法 使用方块ID,直接在指定的坐标位置放置方块。执行效率比voxels.setVoxel()更快。 参数 x, y, z, voxel
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,放置的方块 x 坐标 |
y | number | 必填,放置的方块 y 坐标 |
z | number | 必填,放置的方块 z 坐标 |
voxel | number | 必填,放置的方块 id |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 返回指定位置的方块id |
getVoxel 获取方块
voxels.getVoxel() 方法 获取某个坐标位置的方块id 参数 x, y, z
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,获取的方块 x 坐标 |
y | number | 必填,获取的方块 y 坐标 |
z | number | 必填,获取的方块 z 坐标 |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 返回指定位置的方块id |
voxels.getVoxelId() 方法 直接获取指定位置的方块ID。执行效率比voxels.getVoxel()更快。 参数 x, y, z
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,获取的方块 x 坐标 |
y | number | 必填,获取的方块 y 坐标 |
z | number | 必填,获取的方块 z 坐标 |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 返回指定位置的方块id |
voxels.getVoxelRotation() 方法 获取某个坐标位置的方块旋转码 参数 x, y, z
名称 | 类型 | 说明 |
---|---|---|
x | number | 必填,获取的方块 x 坐标 |
y | number | 必填,获取的方块 y 坐标 |
z | number | 必填,获取的方块 z 坐标 |
返回值 id
名称 | 类型 | 说明 |
---|---|---|
id | number | 返回指定位置的方块id |
Voxels Type 方块类型
voxels.VoxelTypes 属性 属性值类型:Array 默认值:String[] 返回包含所有方块名称的数组。
Build 快速建造 此处提供一些快速建造特定几何造型的代码片段,可供参考。 实心矩形
空心矩形
实心球体
圆柱体
生成楼梯(+x)
生成楼梯(-x)
💡提示 方块id和名称对照表
方块id | 名称 |
---|---|
0 | air |
3 | add |
5 | subtract |
7 | multiply |
9 | divide |
11 | equal |
13 | exclamation_mark |
15 | question_mark |
17 | zero |
19 | one |
21 | two |
23 | three |
25 | four |
27 | five |
29 | six |
31 | seven |
33 | eight |
35 | nine |
37 | A |
39 | B |
41 | C |
43 | D |
45 | E |
47 | F |
49 | G |
51 | H |
53 | I |
55 | J |
57 | K |
59 | L |
61 | M |
63 | N |
65 | O |
67 | P |
69 | Q |
71 | R |
73 | S |
75 | T |
77 | U |
79 | V |
81 | W |
83 | X |
85 | Y |
87 | Z |
89 | cadet_blue |
91 | sky_blue |
93 | powder_blue |
95 | dark_gray |
97 | light_gray |
99 | olive_green |
101 | yellow_green |
103 | pale_green |
105 | red |
107 | dark_red |
109 | brick_red |
111 | medium_gray |
113 | dark_slate_blue |
115 | pink |
117 | sakura_pink |
119 | orange |
121 | lemon |
123 | stained_glass |
125 | dirt |
127 | grass |
129 | stone |
131 | green_leaf |
133 | acacia |
135 | sand |
137 | plank_01 |
139 | plank_02 |
141 | plank_03 |
143 | plank_04 |
145 | ice_brick |
147 | light_grey_stone_brick |
149 | grey_stone_brick |
151 | gold_trim_brick |
153 | red_brick |
155 | quartz_brick |
157 | lantern_01 |
159 | lantern_02 |
160 | window |
162 | cross_window |
164 | geometric_window_01 |
166 | geometric_window_02 |
169 | snow |
170 | glass |
172 | color_glass |
175 | black |
177 | white |
179 | wooden_box |
181 | board_01 |
183 | board_02 |
185 | stripe_01 |
187 | stripe_02 |
189 | stripe_03 |
191 | stripe_04 |
193 | stripe_05 |
195 | carpet_01 |
197 | carpet_02 |
199 | carpet_03 |
201 | carpet_04 |
203 | carpet_05 |
205 | carpet_06 |
207 | carpet_07 |
209 | palace_eaves_01 |
211 | palace_eaves_02 |
213 | palace_eaves_03 |
215 | palace_eaves_04 |
217 | palace_eaves_05 |
219 | palace_eaves_06 |
221 | palace_eaves_07 |
223 | palace_eaves_08 |
225 | roof_red |
227 | roof_purple |
229 | roof_green |
231 | roof_blue_04 |
233 | roof_yellow |
235 | carpet_08 |
237 | carpet_09 |
239 | carpet_10 |
241 | carpet_11 |
243 | carpet_12 |
245 | carpet_13 |
247 | stainless_steel |
249 | ice_wall |
251 | leaf_01 |
253 | leaf_02 |
255 | palace_roof |
257 | wood |
259 | red_brick_floor |
261 | red_brick_wall |
263 | palace_floor |
264 | palace_carving |
267 | stone_pillar_03 |
269 | stone_pillar_04 |
271 | stone_pillar_05 |
273 | stone_pillar_06 |
275 | stone_wall |
276 | blue_glass |
278 | green_glass |
281 | red_light |
283 | orange_light |
285 | yellow_light |
287 | green_light |
289 | indigo_light |
291 | blue_light |
293 | purple |
295 | pink_light |
297 | mint_green_light |
299 | white_light |
301 | warm_yellow_light |
302 | black_glass |
304 | red_glass |
307 | palace_lamp |
309 | board_03 |
311 | board_04 |
313 | board_05 |
315 | board_06 |
317 | dark_grass |
319 | greenbelt_L |
321 | greenbelt_L1 |
323 | stone_brick_01 |
325 | stone_brick_02 |
327 | dark_stone |
329 | dark_brick_00 |
331 | dark_brick_01 |
333 | dark_brick_02 |
335 | stone_wall_01 |
337 | pink_cake |
339 | macaroon |
341 | biscuit |
343 | snowland |
345 | polar_region |
347 | polar_ice |
349 | blue_surface_01 |
351 | blue_surface_02 |
353 | purple_surface_01 |
355 | purple_surface_02 |
357 | dark_surface |
359 | rock |
361 | palace_cloud |
363 | blue |
364 | water |
367 | turquoise |
369 | dark_orchid |
371 | medium_orchid |
373 | medium_purple |
375 | medium_violet_red |
377 | maroon |
379 | coffee_gray |
381 | peru |
383 | dark_salmon |
385 | navajo_white |
387 | orange_red |
389 | medium_yellow |
391 | medium_green |
393 | sienna |
395 | mint_green |
397 | medium_spring_green |
398 | ice |
401 | crane_roof_01 |
403 | crane_roof_02 |
405 | crane_lantern |
407 | roof_grey |
408 | palace_window |
411 | woodstone_12 |
412 | strawberry_juice |
414 | lime_juice |
416 | blueberry_juice |
418 | lemon_juice |
420 | grape_juice |
422 | orange_juice |
424 | milk |
426 | soy_sauce |
428 | coffee |
430 | peach_juice |
433 | board0 |
435 | board1 |
437 | board2 |
439 | board3 |
441 | board4 |
443 | board5 |
445 | board6 |
447 | board7 |
449 | board8 |
451 | board9 |
453 | board10 |
455 | board11 |
457 | board12 |
459 | board13 |
461 | board14 |
463 | board15 |
465 | lava01 |
467 | lava02 |
469 | windygrass |
471 | conveyor |
473 | ledfloor01 |
475 | ledfloor02 |
477 | yellow_grass |
479 | express_box |
481 | television |
483 | bookshelf |
485 | ampersand |
487 | asterisk |
489 | at |
491 | backslash |
493 | bracket_close |
495 | bracket_open |
497 | caret |
499 | colon |
501 | comma |
503 | dollar |
505 | greater_than |
507 | less_than |
509 | paren_open |
511 | paren_close |
513 | percent |
515 | period |
517 | pound |
519 | quotation_mark |
521 | semicolon |
523 | slash |
525 | tilde |
527 | winter_leaf |
529 | leaf_03 |
531 | leaf_04 |
533 | leaf_05 |
535 | honeycomb_01 |
537 | honeycomb_02 |
539 | white_grass |
541 | palm |
类 - GameWearable 用于在玩家身体部位可穿戴配件物体的参数与函数
参数 ●bodyPart ●color ●emissive ●mesh ●metalness ●offset ●orientation ●player ●scale ●shininess
函数 ●remove
控制穿戴配件的参数
bodyPart •bodyPart:GameBodyPart= GameBodyPart.HEAD 穿戴配件在玩家上的部位
color •color:GameRGBColor‹›= new GameRGBColor(1, 1, 1) 穿戴配件的颜色
emissive •emissive:number= 0 穿戴配件的发光度
mesh •mesh:string= "" 穿戴配件的形状数据 e.g.mesh = 'mesh/my-mesh.vb' 注意:'mesh/my-mesh.vb'必须在文件列表中(Tips: 先将模型加到地图上,再删掉即可。)
metalness •metalness:number= 0 穿戴配件的金属感
offset •offset:GameVector3‹›= new GameVector3(0, 0, 0) 穿戴配件的位移
orientation •orientation:GameQuaternion‹›= new GameQuaternion(0, 1, 0, 0) 穿戴配件的旋转角度
player •player:GamePlayer| null= null 穿戴配件的玩家
scale •scale:GameVector3‹›= new GameVector3(1, 1, 1) 穿戴配件的缩放比例
shininess •shininess:number= 0 穿戴配件的反光度
函数
remove ▸remove():void Returns:void 示例代码
// 在玩家离开液体时把在玩家身上所有的穿戴配件删除
world.onFluidLeave(({ entity }) => {
if (entity.isPlayer) {
const allWearables = entity.player.wearables();
allWearables.forEach((item) => {
item.remove();
});
}
});
类 - GameWorld GameWorld这个类在当前地图是有全局唯一的实例 world,你可以使用world对象控制环境天气、物理重力、画面滤镜等全局场景属性,还可以在世界中创建、搜索实体,或监听世界中实体和玩家的碰撞、伤害、互动等事件。
Basics 基础
world.projectName 属性 属性值类型:string 默认值:无 本张地图名称,对应项目设置中的名称。 该属性是只读的,如需修改地图名称,请在编辑器菜单底部 [项目-编辑资料-地图名称] 进行修改。
world.onTick() 事件 这是世界的计时事件,每64毫秒触发一次,Tick计数加1。 监听此事件可以让世界以64毫秒为间隔循环执行代码。 在理想情况下,每Tick为64毫秒。若网络发生延迟,可能会有变化。 ●onTick: GameEventChannel[GameTickEvent](%5BGameTickEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/iewkxcpddoqrt1vl)) ●nextTick: GameEventFuture[GameTickEvent](%5BGameTickEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/iewkxcpddoqrt1vl)) 返回值 GameTickEvent:{ tick, prevTick, elapsedTimeMS, skip }
名称 | 类型 | 说明 |
---|---|---|
tick | number | 事件发生时间 |
prevTick | number | 上一个已处理的时刻 |
elapsedTimeMS | number | 两个时刻之间的时间间隔(毫秒) |
skip | boolean | 是否因为延迟而跳过了某些 Tick |
示例代码1
示例代码2
world.currentTick 属性 属性值类型:number 默认值:0 世界当前的Tick计数。
Chat 聊天频道
world.say() 方法 向所有玩家广播一条消息。 参数 message
名称 | 类型 | 说明 |
---|---|---|
message | string | 要广播的消息 |
简单示例
循环喊话
高级计时器
world.onChat() 事件 当玩家在聊天窗口说话时触发
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 发起聊天的实体 |
message | string | 聊天事件中说话的内容 |
tick | number | 聊天事件发生时间 |
Player 玩家:加入/离开
world.onPlayerJoin()事件:当玩家加入地图时触发
返回值 GameEntityEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 创建的实体 |
tick | number | 事件发生时间 |
简单示例
所有玩家飞行
特定玩家进入地图提醒
world.onPlayerLeave()事件: 当玩家离开地图时触发 返回值 GameEntityEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 离开地图的实体 |
tick | number | 事件发生时间 |
Input 点击/互动
world.onInteract()事件: 若实体开启了互动功能enableInteract = true,则玩家与实体进行互动时触发。 当玩家走进实体的互动范围,实体身上就会出现按键提示,玩家按下互动按钮(默认为键盘E按键)与该实体进行互动。 触发onInteract事件同时还会触发实体默认的互动音效 返回值 GameInteractEvent{ entity, targetEntity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 发起互动的实体 |
targetEntity | GameEntity | 收到互动请求的实体 |
tick | number | 事件发生时间 |
💡提示 想要和实体进行互动,需要先在编辑器中放置一个模型,并给他取一个名字。 这里的示范,将名字改为了'NPC'。
💡提示 通过通过监听onInteract事件,可以自定义互动时发生的行为。 比如,让实体说话,或让玩家显示一个对话框
world.onClick()事件: 当玩家用鼠标点击实体时触发 返回值 GameInputEvent:{ entity, clicker, button, distance, clickerPosition, raycast, tick}
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 被点击的实体 |
clicker | GameEntity& {isPlayer:true,player:GamePlayer} | 发起点击事件的玩家 |
button | GameButtonType | 点击的按钮,ACTION0 = 左键,ACTION1 = 右键 |
distance | number | 玩家到被点击实体的距离 |
clickerPosition | GameVector3 | 点击鼠标的瞬间玩家所在位置 |
raycast | GameRaycastResult | 按下按钮瞬间,从玩家视角投射的射线检测结果 |
tick | number | 事件发生时间 |
world.onPress()事件: 当玩家按下按钮时触发 返回值 GameInputEvent:{ button, entity, position, pressed, raycast, tick }
名称 | 类型 | 说明 |
---|---|---|
button | GameButtonType | 玩家输入的按钮 |
entity | GameEntity& {isPlayer:true, player:GamePlayer} | 按下按钮的玩家 |
position | GameVector3 | 按下按钮瞬间,玩家的位置 |
pressed | boolean | 是否按下了按钮。若为 true,则为按下了按钮。 |
raycast | GameRaycastResult | 按下按钮瞬间,从玩家视角投射的射线检测结果 |
tick | number | 事件发生时间 |
world.onRelease()事件: 当玩家松开按钮时触发 返回值 GameInputEvent:{ button, entity, position, pressed, raycast, tick }
名称 | 类型 | 说明 |
---|---|---|
button | GameButtonType | 玩家输入的按钮 |
entity | GameEntity& {isPlayer:true, player:GamePlayer} | 按下按钮的玩家 |
position | GameVector3 | 按下按钮瞬间,玩家的位置 |
pressed | boolean | 是否按下了按钮。若为 false,则为松开按钮。 |
raycast | GameRaycastResult | 按下按钮瞬间,从玩家视角向前投射的射线检测结果 |
tick | number | 事件发生时间 |
💡提示 提示:GameWorld 和 GamePlayer 都有触发点击/按下按钮的事件。他们的区别就是: ●GameWorld会监听世界所有实体的事件 ●GamePlayer 只监听玩家本身的事件 通常 GamePlayer.onPress() 会放在 GameWorld.onPlayerJoin() 事件中使用。 详情请阅读 GamePlayer
Entity 实体:创建/销毁
world.createEntity() 方法 创建一个新实体GameEntity或复制一个现有的实体,若实体数量(entityQuota)达到上限,则返回 null。 参数 GameEntityConfig
名称 | 类型 | 说明 |
---|---|---|
config | Partial[GameEntityConfig](%5BGameEntityConfig%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/vim7evgezkmnvhxk)) | 指定实体的一组初始值 |
返回值 GameEntity
名称 | 类型 | 说明 |
---|---|---|
Entity | GameEntity | 根据指定参数创建的一个新实体 |
💡提示 需要提前在编辑器中添加'花'的模型。 添加后可以在地图中删除 (只需确保 设置-文件 页面中已加载 花.vb 模型文件)。
world.entityQuota() 方法 返回脚本当前仍可创建的实体数量 返回值 number
类型 | 说明 |
---|---|
number | 当前仍可创建的实体数量 |
world.onEntityCreate()事件:当实体被创建时触发
返回值 GameEntityEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 被创建的实体 |
tick | number | 事件发生时间 |
world.onEntityDestroy()事件:当实体被销毁时触发
返回值 GameEntityEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 销毁的实体 |
tick | number | 事件发生时间 |
Battle & Health 战斗及生命值 若实体开启了允许伤害的属性(enableDamage = true),可以通过hurt()方法对该实体造成生命值伤害。 伤害: 实体受到伤害,会触发onTakeDamage()事件。 死亡: 实体生命值HP降为0以下时,实体将触发死亡事件onDie(), 倒地不起。 复活: 实体死亡后,可通过增加生命值HP,让实体进行复活,同时触发onRespawn()事件。 强制重生: 如果实体类型为玩家,还可以通过forceRespawn()方法,使玩家强制重生,返回出生点。
world.onTakeDamage() 事件 当实体受到伤害时触发。 ●onTakeDamage:GameEventChannel[GameDamageEvent](%5BGameDamageEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aivo4orkcmc9m0gm)) ●nextTakeDamage:GameEventFuture[GameDamageEvent](%5BGameDamageEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/aivo4orkcmc9m0gm)) 返回值 GameDamageEvent:{ entity, attacker, damage, damageType, tick }
名称 | 类型 | 说明 |
---|---|---|
attacker | GameEntity | null |
damage | number | 伤害值 |
damageType | string | 伤害类型 |
entity | GameEntity | 受到伤害的实体 |
tick | number | 事件发生时间 |
world.onDie() 事件 当实体死亡时触发。 ●onDie:GameEventChannel[GameDieEvent](%5BGameDieEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/fsnsdr8uvuspan6y)) ●nextDie:GameEventFuture[GameDieEvent](%5BGameDieEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/fsnsdr8uvuspan6y)) 返回值 GameDieEvent:{ entity, attacker, damageType, tick }
名称 | 类型 | 说明 |
---|---|---|
attacker | GameEntity | null |
damageType | string | 伤害类型 |
entity | GameEntity | 死亡的实体 |
tick | number | 事件发生时间 |
简单示例
死亡5秒后重生
world.onRespawn() 事件 当实体复活时触发。 onRespawn:GameEventChannel[GameRespawnEvent](%5BGameRespawnEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cshui17169guugxr)) nextRespawn:GameEventFuture[GameRespawnEvent](%5BGameRespawnEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cshui17169guugxr)) 返回值 GameRespawnEvent:{ entity, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 死亡的实体 |
tick | number | 事件发生时间 |
提示 GameWorld 和 GameEntity 拥有相同的触发事件。 他们的区别是 ●GameWorld会触发世界所有的实体事件。 ●GameEntity 只触发实体本身的事件。
Zones 区域
world.addZone() 方法 创建一个区域,用于检测实体进入或离开某个区域。 也可以用来设置环境参数,如雾、雨、天、雪、风、重力等定义区域内的环境参数。 参数 GameZoneConfig
名称 | 类型 | 说明 |
---|---|---|
config | Partial‹GameZoneConfig› | 指定区域的一组初始参数值 |
返回值 GameZone
名称 | 类型 | 说明 |
---|---|---|
GameZone | GameZone | 区域 |
world.removeZone() 方法 删除区域 参数 zone
名称 | 类型 | 说明 |
---|---|---|
zone | GameZone | 要删除的区域 |
world.zones() 方法 返回所有的区域列表 返回值 GameZone[]
名称 | 类型 | 说明 |
---|---|---|
GameZone[] | GameZone | 所有的区域 |
Search 搜索 Game可以用类似jQuery选择器的语法来搜索某些实体。 ●搜索全部:'*' ●搜索名称:'#id' ●搜索标签:'.tag' ●搜索同时包含多个标签:'.tag1 .tag2' ●搜索玩家:'player'
world.querySelector() 方法 搜索满足条件的第一个实体。 参数 selector
名称 | 类型 | 说明 |
---|---|---|
selector | GameSelectorString | 一个选择器搜索模式。 |
返回值 GameEntity | null
名称 | 类型 | 说明 |
---|---|---|
Entity | GameEntity | 符合选择器的首个实体 |
简单示例
示例代码2
world.querySelectorAll() 方法 搜索满足条件的所有实体,返回一个列表。 参数 selector
名称 | 类型 | 说明 |
---|---|---|
selector | GameSelectorString | 一个选择器搜索模式 |
返回值 GameEntity[]
名称 | 类型 | 说明 |
---|---|---|
Entity[] | GameEntity | 符合选择器的全部实体 |
简单示例
搜索所有玩家
💡提示 querySelector 和 querySelectorAll 两者区别是 querySelector 搜索满足条件的第一个实体,如果没有搜索到,则返回 null querySelectorAll 搜索满足条件的所有实体,返回是一个数组,如果没有搜索到实体,则返回空的数组。
world.searchBox() 方法 搜索指定范围中的全部实体 参数 bounds
名称 | 类型 | 说明 |
---|---|---|
bounds | GameBounds3 | 要搜索的范围边界 |
返回值 GameEntity[]
名称 | 类型 | 说明 |
---|---|---|
Entity[] | GameEntity | 范围内的全部实体 |
world.raycast() 方法 射线检测,从origin原点位置向direction方向投射一条隐形的射线,返回碰到的实体或方块。 参数 origin, direction, options
名称 | 类型 | 说明 |
---|---|---|
origin | GameVector3 | 必填,射线的起点 |
direction | GameVector3 | 必填,射线的方向 |
options | GameRaycastOptions | 可选,选项配置参数 |
返回值 GameRaycastResult
名称 | 类型 | 说明 |
---|---|---|
origin | GameVector3 | 射线的起点 |
direction | GameVector3 | 射线的方向 |
distance | number | 射线穿越的距离 |
hit | boolean | 如果为真,则射线击中了目标 |
hitEntity | GameEntity | null |
hitPosition | GameVector3 | 射线击中的位置 |
hitVoxel | number | 射线所击中的方块 id (如未击中方块,则为 0) |
voxelIndex | GameVector3 | 如果射线击中的是方块,则返回所击中方块的网格坐标。 |
normal | GameVector3 | 射线所击中平面的法向量 |
Physics 物理相关 📌
world.gravity 属性 属性值类型:number 默认值:-0.1 世界重力。对应编辑器菜单 [场景-物理-地心引力] 控件属性。 数值越小,行动越笨重。受重力影响最明显的属性是跳跃高度及下落速度。如果重力数值大于0,可以实现反重力。
world.airFriction 属性 属性值类型:number 默认值:0.001 空气阻力。对应编辑器菜单[场景-速度阻尼]控件属性。 数值在0-1之间。数值越大,行走加速度越小。可以用来模拟大风的环境。
world.onEntityContact() 事件 当实体与实体发生碰撞时触发。 ●onEntityContact:GameEventChannel[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) ●nextEntityContact:GameEventFuture[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) 返回值 GameEntityContactEvent:{ entity, other, force, axis, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 碰撞中的第一个实体 |
other | GameEntity | 碰撞中的第二个实体 |
force | GameVector3 | 碰撞所产生的力 |
axis | GameVector3 | 碰撞后物体弹飞的方向 |
tick | number | 事件发生时间 |
简单示例
碰到指定实体加血
碰到实体变身
💡提示 两个实体刚接触的第一下,触发onEntityContact 直到两个实体分开,触发onEntitySeparate
world.onEntitySeparate() 事件 实体与实体结束碰撞时触发。 ●onEntitySeparate:GameEventChannel[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) ●nextEntitySeparate:GameEventFuture[GameEntityContactEvent](%5BGameEntityContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/cx43ln010fi1npng)) 返回值 GameEntityContactEvent:{entity, other, force, axis, tick}
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 碰撞中的第一个实体 |
other | GameEntity | 碰撞中的第二个实体 |
force | GameVector3 | 碰撞所产生的力 |
axis | GameVector3 | 碰撞后物体弹飞的方向 |
tick | number | 事件发生时间 |
world.onVoxelContact() 事件 当实体与方块发生碰撞时触发。 ●onVoxelContact:GameEventChannel[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) ●nextVoxelContact:GameEventFuture[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) 返回值 GameVoxelContactEvent:{ entity, voxel, x, y, z, force, axis, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 触碰方块的实体 |
voxel | number | 被触碰的方块 id |
x | number | 被触碰方块的 x 坐标 |
y | number | 被触碰方块的 y 坐标 |
z | number | 被触碰方块的 z 坐标 |
force | GameVector3 | 碰撞所产生的力 |
axis | GameVector3 | 碰撞后物体弹飞的方向 |
tick | number | 事件发生时间 |
破坏碰到的冰块
检测脚下的方块
world.onVoxelSeparate() 事件 当实体与方块结束碰撞时触发。 ●onVoxelSeparate:GameEventChannel[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) ●nextVoxelSeparate:GameEventFuture[GameVoxelContactEvent](%5BGameVoxelContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yq8us26l3irc2m0w)) 返回值 GameVoxelContactEvent:{ entity, voxel, x, y, z, force, axis, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 触碰方块的实体 |
voxel | number | 被触碰的方块 id |
x | number | 被触碰方块的 x 坐标 |
y | number | 被触碰方块的 y 坐标 |
z | number | 被触碰方块的 z 坐标 |
force | GameVector3 | 碰撞所产生的力 |
axis | GameVector3 | 碰撞后物体弹飞的方向 |
tick | number | 事件发生时间 |
world.onFluidEnter() 事件 当实体进入水里/液体时触发。 ●onFluidEnter:GameEventChannel[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) ●nextFluidEnter:GameEventFuture[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) 返回值 GameFluidContactEvent:{ entity, voxel, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 触碰液体的实体 |
voxel | number | 触碰的液体方块 |
tick | number | 事件发生时间 |
world.onFluidLeave() 事件 当实体离开水里/液体时触发。 ●onFluidLeave:GameEventChannel[GameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) ●nextFluidLeave:GameEventFutureameFluidContactEvent](%5BGameFluidContactEvent%5D(https://box3.yuque.com/org-wiki-box3-ev7rl4/wupvz3/yqghak2c6vyayb10)) 返回值 GameFluidContactEvent:{ entity, voxel, tick }
名称 | 类型 | 说明 |
---|---|---|
entity | GameEntity | 触碰液体的实体 |
voxel | number | 触碰的液体方块 |
tick | number | 事件发生时间 |
world.addCollisionFilter() 方法 添加碰撞过滤器,关闭两个实体组之间的碰撞。其中两个实体组分别用选择器aSelector、bSelector来定义,可按实体名称、标签、以及是否玩家等条件来筛选。 参数
名称 | 类型 | 说明 |
---|---|---|
aSelector | GameSelectorString | 用于定义第一组实体的选择器 |
bSelector | GameSelectorString | 用于定义第二组实体的选择器 |
返回值 void
world.removeCollisionFilter() 方法 移除碰撞过滤器,不再关闭两个实体组aSelector、bSelector之间的碰撞。 参数
名称 | 类型 | 说明 |
---|---|---|
aSelector | GameSelectorString | 用于定义第一组实体的选择器 |
bSelector | GameSelectorString | 用于定义第二组实体的选择器 |
返回值 void
world.clearCollisionFilters() 方法 清除全部碰撞过滤器。 返回值 void
world.collisionFilters() 方法 返回当前有效的全部碰撞过滤器。 Returns a list of all currently active collision filters 返回值 string[][]
类型 | 说明 |
---|---|
string[][] | 当前有效的全部碰撞过滤器 |
world.testSelector() 方法 测试实体是否符合某个选择器(Selector)的条件。 Test a selector on an entity. 参数
名称 | 类型 | 说明 |
---|---|---|
selector | GameSelectorString | 要测试的选择器 |
entity | GameEntity | 要测试的实体 |
返回值 boolean
类型 | 说明 |
---|---|
boolean | true: 实体符合选择器的条件;false: 实体不符合选择器的条件 |
简单示例
示例代码2
Sound 音乐音效
world.sound() 方法 播放一段声音,所有玩家都能听到。在[文件管理]窗口右下角[上传音频],通过.sound()方法传入声音文件的路径。 参数 spec | string
名称 | 类型 | 说明 |
---|---|---|
sample | string | 必填,声音文件路径。可在文件管理器中上传自定义声音。如'audio/chat.mp3' |
gain | number | 可选,音量增益。正常为 1,数值越大,声音越响。 |
position | GameVector3 | 可选,声音播放的位置。可以指定在某个实体身上发出声音。 |
radius | number | 可选,声音范围。默认为 32,即 2 格方块距离。超出范围的玩家则听不到声音。 |
pitch | number | 可选,音高增益。正常为 1,大于 1,声音播放越快,小于 1,声音播放越慢。 |
简单示例
示例代码2
💡提示 除了world.sound(),Entity和Player也拥有类似播放声音的功能。 使用 entity.sound() 可以在实体的位置播放声音,设置radius范围后,周围的玩家都可以听见声音。 使用 player.sound() 仅某个玩家自己可以听到声音,其他玩家都听不到。 Game世界预设了一些声音属性,在对应的事件触发时播放音效: 当地图开始运行时循环播放的背景音乐, 当任意玩家进入/离开地图时时播放的音效, 当任意方块被放置/破坏时播放的音效。
world.ambientSound 属性 属性值类型:new GameSoundEffect() 默认值:'' 改变地图背景音乐,从地图运行开始循环播放。 背景音乐的音量会根据用户在[设置-声音]更改。
world.playerJoinSound
属性 属性值类型:new GameSoundEffect() 默认值:'' 当玩家进入地图时,播放的音效。通过world.onPlayerJoin()触发。
world.playerLeaveSound
属性 属性值类型:new GameSoundEffect() 默认值:'' 当玩家离开地图时,播放的音效。通过world.onPlayerLeave()触发。
world.placeVoxelSound
属性 属性值类型:new GameSoundEffect() 默认值:'audio/place_block.mp3' 方块被放置时,播放的音效。通过GameVoxels.setVoxel()触发。默认音效为'audio/place_block.mp3'
world.breakVoxelSound
属性 属性值类型:new GameSoundEffect() 默认值:'audio/break_block.mp3' 方块被销毁时,播放的音效。通过GameVoxels.setVoxel()触发。默认音效为'audio/break_block.mp3'
Weather 天气:雾
world.maxFog 属性 属性值类型:number 默认值:1 最大雾量。对应编辑器菜单[场景-全局特效-雾气-最大雾量]控件属性。
world.fogColor 属性 属性值类型:number 默认值:new GameRGBColor(1, 1, 1) 雾的颜色。对应编辑器菜单[场景-全局特效-雾气-颜色]控件属性。
world.fogStartDistance 属性 属性值类型:number 默认值:0 ●fogStartDistance: number = 0 雾起始距离。对应编辑器菜单[场景-全局特效-雾气-起始距离]控件属性。
world.fogHeightOffset 属性 属性值类型:number 默认值:0 雾起始高度。对应编辑器菜单[场景-全局特效-雾气-高度]控件属性。
world.fogUniformDensity 属性 属性值类型:number 默认值:0 雾均匀密度,对应编辑器菜单[场景-全局特效-雾气-均匀雾量]控件属性。 若值大于0,越难看到天空。
world.fogHeightFalloff 属性 属性值类型:number 默认值:0.8 雾衰减的速率。对应编辑器菜单 [场景-全局特效-雾气-高度衰减系数] 控件属性。 数值在0-1之间。值越小,雾越浓。
Weather 天气:雨
world.rainSpeed 属性 属性值类型:number 默认值:1 雨的速度。对应编辑器菜单[场景-全局特效-雨-速度]控件属性。
world.rainColor 属性 属性值类型:GameRGBAColor 默认值:new GameRGBAColor(1, 1, 1, 1) 雨的颜色。对应编辑器菜单[场景-全局特效-雨-颜色]控件属性。
world.rainDirection 属性 属性值类型:GameVector3 默认值:new GameVector3(0, 1, 0) 雨的方向。对应编辑器菜单[场景-全局特效-雨-方向]控件属性。
world.rainDensity 属性 属性值类型:number 默认值:0 雨的密度。对应编辑器菜单[场景-全局特效-雨-密度]控件属性。 密度越大,雨滴越多。
world.rainInterference 属性 属性值类型:number 默认值:0 雨的扰动幅度。对应编辑器菜单[场景-全局特效-雨-不规则性]控件属性。
world.rainSizeLo 属性 属性值类型:number 默认值:0 雨滴的最小直径。
world.rainSizeHi 属性 属性值类型:number 默认值:1 雨滴的最大直径。
Weather 天气:雪
world.snowColor 属性 属性值类型:GameRGBAColor 默认值:new GameRGBAColor(1, 1, 1, 1) 雪花颜色。
world.snowTexture 属性 属性值类型:string 默认值:'' 雪花纹理。此处填写文件管理器中的纹理资源名称。如 'snow/heart.part'
world.snowDensity 属性 属性值类型:number 默认值:0 雪的密度。密度越大,雪花越多。
world.snowFallSpeed 属性 属性值类型:number 默认值:1 雪花下落速度。如果小于0,则反向运动。
world.snowSpinSpeed 属性 属性值类型:GameVector3 默认值:new GameVector3(0, 0, 0) 雪花自旋速度。
world.snowSizeLo 属性 属性值类型:number 默认值:0 雪花最小直径。
world.snowSizeHi 属性 属性值类型:number 默认值:1 雪花最大半径。
Weather 天气: 光照
world.lightMode 属性 属性值类型:string 默认值:'natural' 作用于天空和环境光的照明类型。对应编辑器设置 [场景-日光-日光规律] 控件属性。 目前有提供2种光照模式,'manual'(自定义)或'natural'(动态)。默认为 'natural'。
world.sunFrequency 属性 属性值类型:number 默认值:0 太阳运动的频率,数值越大,昼夜交替越快。 昼夜时间计算公式:timeOfDay = (sunPhase + sunFrequency * tick) % 1
world.sunPhase 属性 属性值类型:number 默认值:0 范围:0-1 太阳从升起至落下,在天空的初始位置。对应编辑器菜单 [场景-日光] 控件属性。 数值在0-1之间。大于0.5时,世界进入黑夜。 仅在日光规律为 natural 状态时生效。 💡提示 关于太阳位置和世界时间的关系: 太阳位置 sunPhase = 0 世界时间为 06:00 太阳位置 sunPhase = 0.25 世界时间为 12:00 太阳位置 sunPhase = 0.5 世界时间为 18:00 太阳位置 sunPhase = 0.75 世界时间为第二天 00:00 太阳位置 sunPhase = 1 世界时间为第二天 06:00
world.sunDirection 属性 属性值类型:GameVector3 默认值:new GameVector3(0, -1, 0) 太阳光照明方向。仅在光照模式为manual自定义模式时生效。
world.sunLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(1000, 1000, 1000) 太阳光颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyLeftLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在-X轴方向的亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyRightLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在+X轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyBottomLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在-Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyTopLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在+Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyFrontLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在-Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
world.skyBackLight 属性 属性值类型:GameRGBColor 默认值:new GameRGBColor(0, 0, 0) 环境光在+Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。 颜色值大于0时,颜色越亮。
动画
world.animate() 方法 创建一个关键帧动画GameAnimation。 参数
名称 | 类型 | 说明 |
---|---|---|
keyframes | GameWorldKeyframe[] | 关键帧的数据 |
playbackInfo | GameAnimationPlaybackConfig | 动画播放参数 |
返回值
名称 | 类型 | 说明 |
---|---|---|
Animation | GameAnimation | 创建出来的动画对象 |
Web相关
world.url 属性 属性值类型:URL 获取当前地图所在的URL链接地址。
商城
world.onPlayerPurchaseSuccess() 事件 当玩家成功购买物品时触发 ●onPlayerPurchaseSuccess : GameEventChannel< GamePurchaseSuccessEvent > ●nextPlayerPurchaseSuccess : GameEventFuture < GamePurchaseSuccessEvent >
返回值 GamePurchaseSuccessEvent:{ tick, userId, ProductId, orderId }
名称 | 类型 | 说明 |
---|---|---|
tick | number | 购买成功事件发生的时间 |
userId | string | 触发购买事件的玩家userId |
productId | number | 购买商品的ID |
orderId | number | 购买成功的订单号 |
Teleport 传送
world.teleport() 方法 地图组内传送能力,能够令 Player 被传送到其他地图中。此能力受权限影响,无权限用户可见,但调用后直接报错。 参数 mapId, players
名称 | 类型 | 说明 |
---|---|---|
mapId | string | 必填,目标地图id |
players | GameEntity[] | 必填,被传送的玩家entity数组 |
需注意: ●传送进入的地图为独立服务器,因此同一张目标地图,分批次传送不同的人,所进入的是不同服务器。 ●只能在已发布地图中生效 ●players的长度不能超过50 ●players中不能存在游客(没有UserID)
简单示例
1
2
3
4
5
6
7
8
9
10
11
12
while (true) {
try {
let players = world.querySelectorAll('player').slice(0, 50)
players = players.filter(e => e.player.userId !== '' && e.player.userId !== '0' && e.player.userId !== 0)
world.teleport('100001157', players)
break
} catch (e) {
world.say('传送失败:' + e.stack)
}
await sleep(1000)
}
world.say('传送成功 ')
类 - GameZone 区域可用于检测实体进入某个区域或离开。 也可以用来设置环境参数,如雾、雨、天、雪、风、重力等定义区域内的环境参数。
参数 ●bounds ●entities ●selector ●nextEnter ●nextLeave ●onEnter ●onLeave ●remove ●force ●massScale ●fogColor ●fogDensity ●fogEnabled ●fogHeightFalloff ●fogHeightOffset ●fogMax ●fogStartDistance ●rainColor ●rainDensity ●rainDirection ●rainEnabled ●rainInterference ●rainSizeHi ●rainSizeLo ●rainSpeed ●skyBackLight ●skyBottomLight ●skyEnabled ●skyFrontLight ●skyLeftLight ●skyLunarPhase ●skyMode ●skyRightLight ●skySunDirection ●skySunFrequency ●skySunLight ●skySunPhase ●skyTopLight ●snowColor ●snowDensity ●snowEnabled ●snowFallSpeed ●snowSizeHi ●snowSizeLo ●snowSpinSpeed ●snowTexture
bounds •bounds:GameBounds3‹›= new GameBounds3( new GameVector3(0, 0, 0), new GameVector3(0, 0, 0)) 该区域的所指定的检测区域
entities •entities:function 在区域内的全部实体GameEntity
函数声明: ▸ ():GameEntity[]
fogColor •fogColor:GameRGBColor‹›= new GameRGBColor(1, 1, 1) 区域内雾的颜色
fogDensity •fogDensity:number= 0 区域内雾均匀密度
fogEnabled •fogEnabled:boolean= false 区域内雾是否开启 示例代码
fogHeightFalloff •fogHeightFalloff:number= 0.8 区域内雾衰减的速率
fogHeightOffset •fogHeightOffset:number= -8 区域内雾起始高度
fogMax •fogMax:number= 1 区域内最大雾量
fogStartDistance •fogStartDistance:number= 0 区域内雾起始距离
force •force:GameVector3‹›= new GameVector3(0, 0, 0) 对物体施加的力的大小 示例代码
massScale •massScale:number= 0 控制物体的质量对力的影响程度。 0 = 像重力一样 1 = 像风一样
onEnter
nextEnter •onEnter:GameEventChannel‹GameTriggerEvent› •nextEnter:GameEventFuture‹GameTriggerEvent› 有实体进入指定区域时,触发事件
onLeave
NextLeave •onLeave:GameEventChannel‹GameTriggerEvent› •nextLeave:GameEventFuture‹GameTriggerEvent› 有实体离开区域时触发事件 示例代码
rainColor •rainColor:GameRGBAColor‹›= new GameRGBAColor(1, 1, 1, 1) 区域内雨的颜色
rainDensity •rainDensity:number= 0 区域内雨的密度 密度越大,雨滴越多。
rainDirection •rainDirection:GameVector3‹›= new GameVector3(0, 1, 0) 区域内雨的方向
rainEnabled •rainEnabled:boolean= false 区域内雨是否开启 示例代码
rainInterference •rainInterference:number= 0 区域内雨的扰动幅度
rainSizeHi •rainSizeHi:number= 1 区域内雨滴的最大直径
rainSizeLo •rainSizeLo:number= 0 区域内雨滴的最小直径
rainSpeed •rainSpeed:number= 1 区域内雨的速度
remove •remove:function 把该区域删除
函数声明: ▸ ():void
selector •selector:GameSelectorString= "" 触发区域事件的物体搜索条件
skyBackLight •skyBackLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在+Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skyBottomLight •skyBottomLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内境光在-Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skyEnabled •skyEnabled:boolean= false 区域内环境参数是否有效 示例代码
skyFrontLight •skyFrontLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在-Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skyLeftLight •skyLeftLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在-X轴方向的亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skyLunarPhase •skyLunarPhase:number= 0 区域内月亮的相位,数值在0和1之间。若大于0.5时,为上弦月。
skyMode •skyMode:"natural" | "manual"= "natural" 区域内作用于天空和环境光的照明类型。目前有提供2种光照模式,'manual'(自定义)或'natural'(动态)。默认为 'natural'。示例代码
skyRightLight •skyRightLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在+X轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skySunDirection •skySunDirection:GameVector3‹›= new GameVector3(0, -1, 0) 区域内太阳光照明方向。仅在光照模式为manual自定义模式时生效。
skySunFrequency •skySunFrequency:number= 0 区域内太阳运动的频率,数值越大,昼夜交替越快。
skySunLight •skySunLight:GameRGBColor‹›= new GameRGBColor(1000, 1000, 1000) 区域内太阳光颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
skySunPhase •skySunPhase:number= 0 区域内太阳从升起至落下,在天空的位置。
skyTopLight •skyTopLight:GameRGBColor‹›= new GameRGBColor(0, 0, 0) 区域内环境光在+Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。
snowColor •snowColor:GameRGBAColor‹›= new GameRGBAColor(1, 1, 1, 1) 区域内雪花颜色
snowDensity •snowDensity:number= 0 区域内雪的密度。密度越大,雪花越多。
snowEnabled •snowEnabled:boolean= false 区域内雪是否开启 示例代码
snowFallSpeed •snowFallSpeed:number= 1 区域内雪花下落速度。如果小于0,则反向运动。
snowSizeHi •snowSizeHi:number= 1 区域内雪花最大半径
snowSizeLo •snowSizeLo:number= 0 区域内雪花最小直径
snowSpinSpeed •snowSpinSpeed:number= 0 区域内雪花自旋速度
snowTexture •snowTexture:string= "" 区域内雪花纹理
更多代码示例
<<<<<<< HEAD// 一半酸雨, 一半樱花飘落的场景效果, 跳起来场景效果消失
world.addZone({
selector: 'player',
bounds: {
lo: [0, 0, 64],
hi: [128, 10, 128],
},
rainEnabled: true,
rainDensity: 0.5,
rainSpeed: 0.5,
snowEnabled: true,
snowDensity: 0.5,
snowTexture: 'snow/bubble.part',
snowFallSpeed: -0.1,
fogEnabled: true,
fogColor: new GameRGBColor(0.5, 1, 0),
fogDensity: 0.02,
})
world.addZone({
selector: 'player',
bounds: {
lo: [0, 0, 0],
hi: [128, 10, 64],
},
rainEnabled: true,
rainDensity: 0.5,
rainSpeed: -0.5,
snowEnabled: true,
snowDensity: 0.5,
snowTexture: 'snow/sakura.part',
snowFallSpeed: 0.1,
fogEnabled: true,
fogColor: new GameRGBColor(1, 0, 0.5),
fogDensity: 0.02,
})
=======
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 一半酸雨, 一半樱花飘落的场景效果, 跳起来场景效果消失
world.addZone({
selector: 'player',
bounds: {
lo: [0, 0, 64],
hi: [128, 10, 128],
},
rainEnabled: true,
rainDensity: 0.5,
rainSpeed: 0.5,
snowEnabled: true,
snowDensity: 0.5,
snowTexture: 'snow/bubble.part',
snowFallSpeed: -0.1,
fogEnabled: true,
fogColor: new GameRGBColor(0.5, 1, 0),
fogDensity: 0.02,
})
world.addZone({
selector: 'player',
bounds: {
lo: [0, 0, 0],
hi: [128, 10, 64],
},
rainEnabled: true,
rainDensity: 0.5,
rainSpeed: -0.5,
snowEnabled: true,
snowDensity: 0.5,
snowTexture: 'snow/sakura.part',
snowFallSpeed: 0.1,
fogEnabled: true,
fogColor: new GameRGBColor(1, 0, 0.5),
fogDensity: 0.02,
})
类 - ServerEvent 从客户端发往服务器的自定义事件。
属性
tick number 事件产生时的客户端 Tick。
entity GamePlayerEntity 事件产生的来源用户。
args any 客户端通过该事件发送的数据。
类 - ServerRemoteChannel 管理客户端与服务端通信的系统, 与客户端脚本中的 ClientRemoteChannel
配合使用。
方法
sendClientEvent (entities:GamePlayerEntity|GamePlayerEntity[], clientEvent:any) : void 向指定玩家发送客户端事件。
参数 ●entities:GamePlayerEntity|GamePlayerEntity[] - 玩家实体列表,代表发送对象,传入空数组时不会产生任何效果 ●clientEvent:any - 自定义事件,在客户端接收到时,传入监听器的参数,仅允许可序列化的值
broadcastClientEvent (clientEvent:any) : void 向所有玩家广播客户端事件。
参数 ●clientEvent:any - 自定义事件对象,在客户端接收到时,传入监听器的参数,仅允许可序列化的值
onServerEvent GameEventChannel[ServerEvent](%5BServerEvent%5D(https://box3.yuque.com/staff-khn556/wupvz3/du8np88uv0scn51v)) 监听客户端发来的服务端事件。
Class: QueryList 键值对查询列表,用于批量获取键值对,通过 {GameDataStorage.list} 方法返回。 列表根据配置项被划分为一个或多个分页,每个分页最多包含 { ListPageOptions | pageSize} 个键值对。
基本
isLastPage • isLastPage: boolean 是否为最后一页,如果翻过头了,也会为 true
getCurrentPage • getCurrentPage: function 按 {ListPageOptions | pageSize} 获取当前页的键值对
函数声明: ▸ (): ReturnValue[]
返回值:ReturnValue[] 返回当前页的键值对内容
nextPage • nextPage : function 翻到下一页,执行后 {getCurrentPage} 将返回下一页的键值对内容
函数声明:
▸ (): Promise <void>
返回值:Promise <void>
返回 Promise 对象,resolve表示翻页成功,reject 后表示翻页失败
类型别名 - JSONValue 允许存储的值,类型可以是如下类型之一:
类型 | 描述 |
---|---|
string | 字符串 |
number | 数字 |
boolean | 布尔值 |
{ [x: string]:JSONValue} | 键值对 |
JSONValue[] | JSONValue数组 |
定义
<<<<<<< HEADexport type JSONValue =
string
| number
| boolean
|{ [x: string]: JSONValue }
| JSONValue[];
=======
1
2
3
4
5
6
export type JSONValue =
string
| number
| boolean
|{ [x: string]: JSONValue }
| JSONValue[];
类型别名 - ListPageOptions 批量获取键值对的配置项。
定义
●cursor:number ○分页指针,用于指定本次获取的分页起点页码。 ●pageSize?:number ○可选项,分页大小,一页内的数据量,默认100。 ●constraintTarget?:string ○约束目标值的路径,当值是JSON格式时,指定用作排序的值的路径。例如传入 score时,会取值上score属性的值作为排序、最大最小值的限制目标; ○可以级联最多5级,例如a.b.c.d.e,超出视作非法参数,按下一条方式处理; ○当路径不存在或传入非法参数时,以值本身作为目标进行排序,并打印一条警告; ●ascending?:boolean - 是否升序,设置为 true 时为升序,false为降序,不传或传入undefined时不排序; ●max?:number - 最大值,过滤返回对应值的最大值,超出或非数字则不返回该Key,默认不过滤; ●min?:number - 最小值,同max类似。
接口 - GameAnimationPlaybackConfig 用于动画播放配置的参数组
参数 | 类型 | 说明 |
---|---|---|
delay | number | 播放延迟 |
direction | GameAnimationDirection | 播放方向 |
duration | number | 播放时长 |
endDelay | number | 结束延迟 |
iterationStart | number | 反复播放开始时间 |
iterations | number | 反复播放次数 |
startTick | number | 开始时间 |
类型别名 - GameDialogCall GameDialogCall:function 在游戏中显示一个对话框。 目前支持3种对话框样式:文本框 Text/选项框 Select/输入框 Input GameDialogCall = ((params:GameTextDialogParams) => Promise<GameDialogResponse| null> &GameDialogCancelOption) | ((params:GameSelectDialogParams) => Promise<DialogSelectResponse| null> &GameDialogCancelOption) | ((params:GameInputDialogParams) => Promise<GameDialogResponse| null> &GameDialogCancelOption) |
GameDialogParams 对话框类型 ●文本对话框GameTextDialogParams ●选项对话框GameSelectDialogParams ●输入对话框GameInputDialogParams
GameDialogResponse 对话框输入响应 ●DialogSelectResponse
GameDialogParams 对话框属性列表 GameDialogParams:object
类型声明: ●type:GameDialogType 对话框的类型。目前有三种对话框类型,具体可查看GameDialogType ●content: string 对话框显示的正文内容。支持使用'\n' 换行。 ●contentBackgroundColor? :GameRGBAColor 对话框正文窗口的背景颜色。 ●contentTextColor? :GameRGBAColor 对话框正文字体的颜色。 ●title:string 对话框显示的标题名称。 ●titleBackgroundColor? :GameRGBAColor 对话框显示的标题窗口背景颜色。 ●titleTextColor? :GameRGBAColor 对话框显示的标题字体颜色。 ●hasArrow? :undefined | false | true 可选: 如果接下来还有新的对话,在当前对话框中是否显示箭头提示。 仅在文本对话框GameDialogType.TEXT中使用。 ●confirmText? :undefined | string 可选: 仅在输入对话框GameDialogType.INPUT使用。 确认按钮显示的文本。如果为空,按钮文本默认显示为 '确认 | Confirm'. ●options? :string[] 可选: 仅在选项对话框GameDialogType.SELECT中使用。 在对话框中提供一些可供玩家选择的对话选项。 ●placeholder? :undefined | string 可选: 仅在输入对话框GameDialogType.INPUT中使用。 在输入框背景显示的提示文字。 ●lookTarget?:GameVector3|GameEntity 可选: 使相机镜头朝向指定实体或坐标的位置。 ●lookTargetOffset?:GameVector3 可选: 如果相机指定了注视目标,可以设置基于目标位置的偏移。 ●lookUp?:GameVector3 可选: 调整相机抬头向量。使画面上下左右颠倒。 ●lookEye?:GameVector3|GameEntity 可选: 调整相机的位置。 ●lookEyeOffset?:GameVector3 可选: 如果相机位置指定了实体,可以设置基于目标位置的偏移。
GameTextDialogParams 文本对话框参数 GameTextDialogParams:object
类型声明: ●type:GameDialogType.TEXT 对话框类型。文本对话框的类型是GameDialogType.TEXT ●hasArrow? :undefined | false | true 是否显示箭头提示 ●content: string 对话框显示的正文内容。支持使用'\n' 换行。 ●contentBackgroundColor? :GameRGBAColor 正文背景颜色 ●contentTextColor? :GameRGBAColor 正文字体颜色 ●title:string 对话框标题 ●titleBackgroundColor? :GameRGBAColor 标题背景颜色 ●titleTextColor? :GameRGBAColor 标题正文颜色 ●lookTarget? :GameVector3|GameEntity 相机注视的实体 ●lookTargetOffset? :GameVector3 基于相机注视的位置偏移 ●lookUp? :GameVector3 相机抬头向量 ●lookEye?:GameVector3|GameEntity 相机镜头的位置 ●lookEyeOffset ?: GameVector3 基于相机位置的偏移
GameSelectDialogParams 选项对话框参数 GameSelectDialogParams:object
类型声明: ●type:GameDialogType.SELECT 对话框类型。选项对话框的类型是GameDialogType.SELECT ●options? :string[] 选项列表 ●content: string 对话框显示的正文内容。支持使用'\n' 换行。 ●contentBackgroundColor? :GameRGBAColor 正文背景颜色 ●contentTextColor? :GameRGBAColor 正文字体颜色 ●title:string 对话框标题 ●titleBackgroundColor? :GameRGBAColor 标题背景颜色 ●titleTextColor? :GameRGBAColor 标题正文颜色 ●lookTarget? :GameVector3|GameEntity 相机注视的实体 ●lookTargetOffset? :GameVector3 基于相机注视的位置偏移 ●lookUp? :GameVector3 相机抬头向量 ●lookEye?:GameVector3|GameEntity 相机镜头的位置 ●lookEyeOffset?:GameVector3 基于相机位置的偏移
GameInputDialogParams 输入对话框参数 GameInputDialogParams:object
类型声明: ●type:GameDialogType.INPUT 对话框类型。输入对话框的类型是GameDialogType.INPUT ●confirmText? :undefined | string 确认按钮文字 ●placeholder? :undefined | string 输入框提示文字 ●content: string 对话框显示的正文内容。支持使用'\n' 换行。 ●contentBackgroundColor? :GameRGBAColor 正文背景颜色 ●contentTextColor? :GameRGBAColor 正文字体颜色 ●title:string 对话框标题 ●titleBackgroundColor? :GameRGBAColor 标题背景颜色 ●titleTextColor? :GameRGBAColor 标题正文颜色 ●lookTarget? :GameVector3|GameEntity 相机注视的实体 ●lookTargetOffset? :GameVector3 基于相机注视的位置偏移 ●lookUp? :GameVector3 相机抬头向量 ●lookEye?:GameVector3|GameEntity 相机镜头的位置 ●lookEyeOffset ?: GameVector3 基于相机位置的偏移
GameDialogResponse 对话框回应 如果没有完成对话而点击了其他地方,使对话框被取消,则返回null 如果是文本对话框,回应'success' 如果是选项对话框,回应输入框填写的内容字符串 如果是选项对话框,回应DialogSelectResponse GameDialogResponse:DialogSelectResponse| string = 'success' | null
DialogSelectResponse 选项对话框回应 在选项对话框中,玩家点击了按钮,会得到对话框的回应事件。返回被玩家按下的选项信息。 DialogSelectResponse:object
类型声明: ●选项编号index:number(zero-based 从0开始计数) ●选项内容value:string
GameDialogCancelOption GameDialogCancelOption:object
函数声明: ●cancel():function 关闭对话框。
综合示例 1
world.onPlayerJoin(async ({ entity }) => {
// 玩家进入游戏时,弹出一个欢迎对话框
const dialog = entity.player.dialog({
type: GameDialogType.TEXT,
title: "吉吉喵",
content:`你好,${entity.player.name},很高兴认识你。`,
});
// 等待任何一个 [玩家点击或关闭对话框, 3秒后自动把对话框关闭]
Promise.race([
dialog,
(async() => {
await sleep(3000);
dialog.cancel();
})()
]).then( /* 任何一个函数返回 */ );
})
综合示例 2
world.onPlayerJoin(async ({ entity }) => {
// 玩家进入游戏时,弹出一个欢迎对话框
const dialog = entity.player.dialog({
type: GameDialogType.TEXT,
title: "吉吉喵",
content: `你好,${entity.player.name},很高兴认识你。`,
});
// 3秒后自动关闭
setTimeout(()=>{
dialog.cancel();
},3000);
})
接口 - GameEntityConfig 用于控制实体的参数组
参数 | 类型 | 说明 |
---|---|---|
position | GameVector3 | 实体的位置 |
velocity | GameVector3 | 实体朝向某个方向运动的作用力 |
collides | boolean | 实体是否可碰撞 |
mesh | string | mesh决定了实体的外形。'mesh/*.vb' |
meshColor | GameRGBAColor | 实体的颜色 |
meshScale | GameVector3 | 实体的缩放比例 |
meshOrientation | GameQuaternion | 实体的旋转角度 |
meshMetalness | number | 实体的金属感 |
meshEmissive | number | 实体的发光度 |
meshShininess | number | 实体的反光度 |
gravity | boolean | 实体是否会下落 |
fixed | boolean | 实体的位置是否固定不动 |
mass | number | 实体质量 |
friction | number | 实体的粘性(0 = 滑,1 = 粘) |
restitution | number | 实体的弹性(0 = 软, 1 = 弹) |
enableInteract | boolean | 允许实体进行互动 |
interactRadius | number | 进入实体互动的范围。范围越小,需更靠近。 |
interactHint | string | 进入实体互动范围时,实体身上出现的提示文本 |
interactColor | GameRGBAColor | 进入实体互动范围时,提示文本的字体颜色 |
particleRate | number | 实体每秒产生粒子的数量 |
particleRateSpread | number | 增加实体每秒产生粒子数量的随机性 |
particleLimit | number | 实体可产生粒子总数的上限 |
particleLifetime | number | 实体所产生粒子能存活的秒数 |
particleLifetimeSpread | number | 增加实体所产生粒子存活时间的随机性 |
particleSize | number[] | 实体所产生粒子的大小变化 |
particleSizeSpread | number | 增加实体所产生粒子大小的随机性 |
particleColor | GameRGBColor[] | 实体所产生粒子的颜色变化 |
particleVelocity | GameVector3 | 实体所产生粒子的初始速度 |
particleVelocitySpread | GameVector3 | 增加实体所产生粒子初始速度的随机性 |
particleDamping | number | 实体所产生粒子的阻尼系数 |
particleAcceleration | GameVector3 | 实体所产生粒子的加速度 |
particleNoise | number | 实体所产生粒子摆动的最大幅度 |
particleNoiseFrequency | number | 实体所产生粒子摆动的频率 |
chatSound | GameSoundEffect | 实体触发说话事件时播放的音效 |
interactSound | GameSoundEffect | 实体触发互动事件时播放的音效 |
hurtSound | GameSoundEffect | 实体触发受伤事件时播放的音效 |
dieSound | GameSoundEffect | 实体触发死亡事件时播放的音效 |
接口 - GameEntityKeyframe Entity实体动画关键帧参数,可对Entity除音效外的大部分属性做动画效果,例如位移、大小、模型、颜色等等
参数 | 类型 | 说明 |
---|---|---|
duration | number | 播放时长 |
easeIn | GameEasing | 缓入效果 |
easeOut | GameEasing | 缓出效果 |
velocity | GameVector3 | 实体朝向某个方向运动的作用力 |
collides | boolean | 实体是否可碰撞 |
mesh | string | mesh决定了实体的外形。'mesh/*.vb' |
meshColor | GameRGBAColor | 实体的颜色 |
meshScale | GameVector3 | 实体的缩放比例 |
meshOrientation | GameQuaternion | 实体的旋转角度 |
meshMetalness | number | 实体的金属感 |
meshEmissive | number | 实体的发光度 |
meshShininess | number | 实体的反光度 |
gravity | boolean | 实体是否会下落 |
fixed | boolean | 实体的位置是否固定不动 |
mass | number | 实体质量 |
friction | number | 实体的粘性(0 = 滑,1 = 粘) |
restitution | number | 实体的弹性(0 = 软, 1 = 弹) |
enableInteract | boolean | 允许实体进行互动 |
interactRadius | number | 进入实体互动的范围。范围越小,需更靠近。 |
interactHint | string | 进入实体互动范围时,实体身上出现的提示文本 |
interactColor | GameRGBAColor | 进入实体互动范围时,提示文本的字体颜色 |
particleRate | number | 实体每秒产生粒子的数量 |
particleRateSpread | number | 增加实体每秒产生粒子数量的随机性 |
particleLimit | number | 实体可产生粒子总数的上限 |
particleLifetime | number | 实体所产生粒子能存活的秒数 |
particleLifetimeSpread | number | 增加实体所产生粒子存活时间的随机性 |
particleSize | number[] | 实体所产生粒子的大小变化 |
particleSizeSpread | number | 增加实体所产生粒子大小的随机性 |
particleColor | GameRGBColor[] | 实体所产生粒子的颜色变化 |
particleVelocity | GameVector3 | 实体所产生粒子的初始速度 |
particleVelocitySpread | GameVector3 | 增加实体所产生粒子初始速度的随机性 |
particleDamping | number | 实体所产生粒子的阻尼系数 |
particleAcceleration | GameVector3 | 实体所产生粒子的加速度 |
particleNoise | number | 实体所产生粒子摆动的最大幅度 |
particleNoiseFrequency | number | 实体所产生粒子摆动的频率 |
类型别名 - GameEventChannel
描述 EventChannel 可用于监听指定对象的事件。输入事件处理器handler,即得取消此事件处理器的GameEventHandlerToken
,各类用于监听事件的onXXX方法均为此类型的实现。
定义
GameEventChannel
export type GameEventChannel `<EventType>` = (
handler: (event: EventType) => void,
) => GameEventHandlerToken;
●EventType- 泛型参数,用于指定事件类型 ●handler:(event: EventType) => void- 事件发生时调用的处理器
示例
1秒后停止监听onTick
// 1000毫秒后停止报时
const token = world.onTick(() => console.log("tick !"));
setTimeout(() => {
console.log('cancel tick handler');
token.cancel();// 取消记录tick事件
}, 1000);
类型别名 - GameEventFuture
描述 此类型为GameEventChannel 事件频道监听
的单次、Promise版本。 Promise(承诺)提供了另一种处理事件的方式。您可以使用Promise来组织长序列的事件,从而实现结构化编程。 配合 async/await语法使用,可以以类似同步代码的方式组织异步代码。在某些情况下,这可以使代码更简单和更清晰,但必须谨慎使用。 尽管看起来与同步代码十分相似,但异步代码在等待时可以被中断,这意味着世界中的事物可能会在您的代码之外发生变化。 此外,异步代码生成的错误不会显示堆栈跟踪,这可能会加大调试的难度。 请考虑这些因素,并谨慎使用Promise、async/await。
定义
GameEventFuture
export type GameEventFuture `<EventType>` = (
filter?: (event: EventType) => boolean,
) => Promise `<EventType>`;
●EventType- 触发的事件对象的类型 ●filter?:(event: EventType) => boolean - 一个可选的函数,用于检查事件的类型。触发事件前执行该函数并传入事件对象,如果返回false,则不会触发该事件
示例
以 async/await 方式使用
// Wait for 2 players to enter the world
async function waitForPlayers (count) {
while (world.querySelectorAll('player').length < 2) {
const { entity } = await world.nextPlayerJoin();
world.say(entity.player.name + ' joined');
}
}
waitForPlayers.then(() => world.say('game ready'));
接口: GameHurtOptions 攻击/伤害的相关参数
参数 | 类型 | 说明 |
---|---|---|
attacker | GameEntity | 发出攻击的实体 |
damageType | string | 伤害类型,可自行定义 |
接口 - GamePlayerKeyframe Player玩家动画关键帧参数,可对Player的大部分属性做动画效果,例如尺寸、颜色、隐身等等
参数 | 类型 | 说明 |
---|---|---|
duration | number | 播放时长 |
easeIn | GameEasing | 缓入效果 |
easeOut | GameEasing | 缓出效果 |
cameraEntity | GameEntity | 在第一人称视角(FPS)或第三人称跟随视角(FOLLOW)下,玩家视角所跟随的实体 |
cameraMode | GameCameraMode | 视角模式 |
cameraPosition | GameVector3 | 固定视角(FIXED)下,镜头的眼睛位置 |
cameraTarget | GameVector3 | 固定视角(FIXED)下镜头所朝向的目标点 |
cameraUp | GameVector3 | 固定视角(FIXED)下,镜头向上的矢量 |
scale | GameVector3 | 玩家的缩放比例 |
color | GameRGBColor | 玩家的颜色 |
colorLUT | string | 用于渲染玩家所见游戏世界的色调 |
invisible | boolean | 玩家是否隐身 |
emissive | number | 玩家的发光度 |
metalness | number | 玩家的金属感 |
shininess | number | 玩家的反光度 |
showName | boolean | 玩家名字是否显示 |
接口 - GameRaycastOptions 进行射线检测的参数配置
参数 | 类型 | 说明 |
---|---|---|
maxDistance | number | 允许射线穿越的最大距离 |
ignoreFluid | boolean | 如果为真,则射线无视液体 |
ignoreVoxel | boolean | 如果为真,则射线无视方块 |
ignoreEntities | boolean | 如果为真,则射线无视实体 |
ignoreSelector | GameSelectorString | 被射线检测忽略的实体选择器 |
类型别名 - GameSelectorString typeGameSelectorString= string; 选择器(Selectors)可以方便搜索游戏内的全部对象。Game的选择器接口是参照 DOM APIs 而设。
const entities = world.querySelector('*'); // 世界中的全部实体
const theChair = world.querySelector('#chair'); // 模型名称为"chair"的首个实体
const players = world.querySelectorAll('player'); // 游戏中的全部玩家
const boxes = world.querySelectorAll('.box'); // 标签带有"box"的全部实体
const redBox = world.querySelector('.box .red');// 标签同时带有"box"和“red”的首个实体
类型别名 - GameSkinInvisible 玩家身体可隐藏的部位
参数 | 类型 | 说明 |
---|---|---|
hips | boolean | 臀部 |
torso | boolean | 躯干 |
neck | boolean | 颈部 |
head | boolean | 头 |
leftShoulder | boolean | 左肩 |
leftUpperArm | boolean | 左上臂 |
leftLowerArm | boolean | 左下臂 |
leftHand | boolean | 左手 |
leftUpperLeg | boolean | 左上腿 |
leftLowerLeg | boolean | 左下腿 |
leftFoot | boolean | 左脚 |
rightShoulder | boolean | 右肩膀 |
rightUpperArm | boolean | 右上臂 |
rightLowerArm | boolean | 右下臂 |
rightHand | boolean | 右手 |
rightUpperLeg | boolean | 右上腿 |
rightLowerLeg | boolean | 右下腿 |
rightFoot | boolean | 右脚 |
接口 - GameSoundEffect 使用Sound()方法播放声音时,传入的参数。 ●sample ●gain ●gainRange ●pitch ●pitchRange ●radius
属性
sample •sample:string= "" 声音文件路径。可在文件管理器中上传自定义声音。如'audio/chat.mp3' 在指定声音文件路径时,必须确保文件已经上传在文件管理器中。
radius •radius:number= 32 声音范围。默认为32。距离实体越近,声音听的越清晰。
gain •gain:number= 1 音量增益。正常为1,数值越大,声音越响。
gainRange •gainRange:number= 0 音量增益方差。计算公式为:effect.gain + (Math.random() - 0.5) * effect.gainRange
pitch •pitch:number= 1 音高增益。正常为1。大于1,声音播放越快。小于1,声音播放越慢。
pitchRange •pitchRange:number= 0 音高增益方差。计算公式为:effect.pitch + (Math.random() - 0.5) * effect.pitchRange
音效列表
声音 | 默认音频文件 | 说明 |
---|---|---|
ambientSound | 循环播放的背景音乐。 | |
playerJoinSound | 有玩家进入游戏。通过world.onPlayerJoin()触发 | |
playerLeaveSound | 有玩家离开游戏。通过world.onPlayerLeave()触发 | |
placeVoxelSound | 'audio/place_block.mp3' | 方块被放置。通过world.setVoxel()触发 |
breakVoxelSound | 'audio/break_block.mp3' | 方块被破坏。通过world.setVoxel()触发 |
声音 | 默认音频文件 | 说明 |
---|---|---|
chatSound | 实体说话时。通过entity.say()触发 | |
hurtSound | 实体受伤时。通过entity.onTakeDamage()触发 | |
dieSound | 实体死亡时。通过entity.onDie()触发 | |
interactSound | 实体被互动时。通过entity.onInteract()触发 |
声音 | 默认音频文件 | 说明 |
---|---|---|
spawnSound | 'audio/spawn.mp3' | 玩家复活时。 |
jumpSound | 'audio/jump.mp3' | 玩家跳跃时。 |
doubleJumpSound | 'audio/double_jump.mp3' | 玩家二段跳时。 |
landSound | 'audio/land.mp3' | 玩家落地时。 |
enterWaterSound | 'audio/dive.mp3' | 玩家进入液体时。 |
leaveWaterSound | 'audio/splash.mp3' | 玩家离开液体时。 |
stepSound | 'audio/step.mp3' | 玩家正在行走,迈出一步时。 |
swimSound | 'audio/swim.mp3' | 玩家正在游泳,向前划动时。 |
crouchSound | 玩家下蹲时。 | |
startFlySound | 玩家开始飞行时。 | |
stopFlySound | 玩家结束飞行时。 | |
action0Sound | 玩家按下鼠标左键/虚拟按钮A时。 | |
action1Sound | 玩家按下鼠标右键/虚拟按钮B时。 |
上传音效 编辑器目前内置了34款音效,可以在菜单-[文件管理]的搜索.mp3查看。点击文件后,会弹出声音文件的详情属性。点击位置即可复制文件路径,在脚本中使用对应的方法播放。 如需上传自定义声音,可以在[文件管理]窗口,点击右下角浮动的加号按钮-[上传音频]。
在哪里下载优质的音效 在互联网中搜索音效时,希望能注重版权意识。使用了某个作者的作品,请务必在作品详情页注明来源。 这里推荐一些授权素材网站,只要遵守网站的使用协议,你便可以将它们免费用在你的作品中。大部分网站非中文站点,但可以借助浏览器翻译工具,进行阅读。 ●zapsplat ●soundbible ●OpenGameArt ●小森平的免费音效 ●Free SFX ●FreeSound ●SoundJay
接口 - GameWorldKeyframe World世界动画关键帧参数,可对World的大部分属性做动画效果,例如重力、雨、雾、雪、光照等等
参数 | 类型 | 说明 |
---|---|---|
duration | number | 播放时长 |
easeIn | GameEasing | 缓入效果 |
easeOut | GameEasing | 缓出效果 |
gravity | number | 世界重力 |
airFriction | number | 空气阻力 |
maxFog | number | 最大雾量 |
fogColor | GameRGBColor | 雾的颜色 |
fogHeightFalloff | number | 雾衰减的速率 |
fogHeightOffset | number | 雾起始高度 |
fogStartDistance | number | 雾起始距离 |
fogUniformDensity | number | 雾均匀密度 |
rainColor | GameRGBAColor | 雨的颜色 |
rainDensity | number | 雨的密度 |
rainDirection | number | 雨的方向 |
rainInterference | number | 雨的扰动幅度 |
rainSizeHi | number | 雨滴的最大直径 |
rainSizeLo | number | 雨滴的最小直径 |
rainSpeed | number | 雨的速度 |
snowColor | GameRGBAColor | 雪花颜色 |
snowDensity | number | 雪花密度 |
snowFallSpeed | number | 雪花速度 |
snowSizeHi | number | 雪花最大直径 |
snowSizeLo | number | 雪花最小直径 |
snowSpinSpeed | number | 雪花自旋速度 |
snowTexture | string | 雪花纹理 |
lightMode | string | 作用于天空和环境光的照明类型 |
sunFrequency | number | 太阳运动的频率 |
sunDirection | number | 太阳光照明方向 |
sunLight | number | 太阳光颜色亮度 |
sunPhase | number | 太阳从升起至落下,在天空的位置 |
lunarPhase | number | 月亮的相位 |
skyLeftLight | number | 环境光在-X轴方向的颜色亮度 |
skyRightLight | number | 环境光在+X轴方向的颜色亮度 |
skyBottomLight | number | 环境光在-Y轴方向的颜色亮度 |
skyTopLight | number | 环境光在+Y轴方向的颜色亮度 |
skyFrontLight | number | 环境光在+Z轴方向的颜色亮度 |
skyBackLight | number | 环境光在-Z轴方向的颜色亮度 |
接口 - GameZoneConfig 用于区域的参数
参数 | 类型 | 说明 |
---|---|---|
bounds | GameBounds3 | 区域的所指定的检测区域 |
selector | GameSelectorString | 触发区域事件的物体搜索条件 |
force | GameVector3 | 对物体施加的力的大小 |
massScale | number | 控制物体的质量对力的影响程度。 0 = 像重力一样; 1 = 像风一样 |
fogColor | GameRGBColor | 雾的颜色 |
fogDensity | number | 雾均匀密度 |
fogEnabled | boolean | 雾是否开启 |
fogHeightFalloff | number | 雾起始高度 |
fogHeightOffset | number | 雾衰减的速率 |
fogMax | number | 最大雾量 |
fogStartDistance | number | 雾起始距离 |
rainColor | GameRGBAColor | 雨的颜色 |
rainDensity | number | 雨的密度。密度越大,雨滴越多。 |
rainDirection | GameVector3 | 雨的方向 |
rainEnabled | boolean | 雨是否开启 |
rainInterference | number | 雨的扰动幅度 |
rainSizeHi | number | 雨滴的最大直径 |
rainSizeLo | number | 雨滴的最小直径 |
rainSpeed | number | 雨的速度 |
skyBackLight | GameRGBColor | 环境光在+Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skyBottomLight | GameRGBColor | 环境光在-Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skyEnabled | boolean | 环境参数是否有效 |
skyFrontLight | GameRGBColor | 环境光在-Z轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skyLeftLight | GameRGBColor | 环境光在-X轴方向的亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skyLunarPhase | number | 月亮的相位,数值在0和1之间。若大于0.5时,为上弦月。 |
skyMode | "natural" or "manual" | 作用于天空和环境光的照明类型。目前有提供2种光照模式,'manual'(自定义)或'natural'(动态)。默认为 'natural'。 |
skyRightLight | GameRGBColor | 环境光在+X轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skySunDirection | GameVector3 | 太阳光照明方向。仅在光照模式为manual自定义模式时生效。 |
skySunFrequency | number | 太阳运动的频率,数值越大,昼夜交替越快。 |
skySunLight | GameRGBColor | 太阳光颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
skySunPhase | number | 太阳从升起至落下,在天空的位置。 |
skyTopLight | GameRGBColor | 环境光在+Y轴方向的颜色亮度。仅在光照模式为manual自定义模式时生效。颜色值大于0时,颜色越亮。 |
snowColor | GameRGBAColor | 雪花颜色 |
snowDensity | number | 雪的密度。密度越大,雪花越多。 |
snowEnabled | boolean | 雪是否开启 |
snowFallSpeed | number | 雪花下落速度。如果小于0,则反向运动。 |
snowSizeHi | number | 雪花最大半径 |
snowSizeLo | number | 雪花最小直径 |
snowSpinSpeed | number | 雪花自旋速度 |
snowTexture | string | 雪花纹理 |
默认值参考 GameZone
{
selector: '',
bounds: {
lo: [0, 0, 0],
hi: [0, 0, 0],
},
force: [0, 0, 0],
massScale: 0,
fogEnabled: false,
fogColor: new GameRGBColor(1, 1, 1),
fogDensity: 0,
fogHeightFalloff: 0.8,
fogHeightOffset: -8,
fogMax: 1,
fogStartDistance: 0,
rainEnabled: false,
rainColor: new GameRGBAColor(1, 1, 1, 1),
rainDensity: 0,
rainSpeed: 1,
rainDirection: new GameVector3(0, 1, 0),
rainInterference: 0,
rainSizeHi: 1,
rainSizeLo: 0,
rainSpeed: 1,
skyEnabled: false,
skyMode: 'natural',
skyBottomLight: new GameRGBColor(0, 0, 0),
skyTopLight: new GameRGBColor(0, 0, 0),
skyBackLight: new GameRGBColor(0, 0, 0),
skyFrontLight: new GameRGBColor(0, 0, 0),
skyLeftLight: new GameRGBColor(0, 0, 0),
skyRightLight: new GameRGBColor(0, 0, 0),
skySunDirection: new GameVector3(0, -1, 0),
skyLunarPhase: 0,
skySunFrequency: 0,
skySunPhase: 0,
skySunLight: new GameRGBColor(1000, 1000, 1000),
snowEnabled: false,
snowColor: new GameRGBAColor(1, 1, 1, 1),
snowDensity: 0,
snowTexture: '',
snowFallSpeed: 1,
snowSizeHi: 1,
snowSizeLo: 0,
snowSpinSpeed: 0,
}
类 - MotionClipConfig 动作序列配置
参数 | 类型 | 说明 |
---|---|---|
iterations | number | 输入Infinity就是无限循环,此时会覆盖掉默认动作 能cancel或者播放新的动作覆盖可选项,默认 1 次 |
motions | (string | MotionConfig)[] |
接口 - MotionConfig
动作配置
参数 | 类型 | 说明 |
---|---|---|
iterations | number | 输入Infinity就是无限循环,此时会覆盖掉默认动作 能cancel或者播放新的动作覆盖可选项,默认 1 次 |
name | string | 动作名字 |
类型别名 - ReturnValue
描述 ReturnValue 表示一个键值对的内容。它可以是一个对象或者 undefined。
定义
定义
export type ReturnValue =
| {
key: string;
value: JSONValue;
updateTime: number;
createTime: number;
}
| undefined;
●key: string: 键名称 ●value: JSONValue: 值内容 ●updateTime: number: key最近更新时间 ●createTime: number: key创建时间
枚举 - GameAnimationDirection 动画的播放方向
属性 | 值 | 说明 |
---|---|---|
ALTERNATE | 'alternate' | 交替 |
ALTERNATE_REVERSE | 'alternate-reverse' | 交替倒放 |
NORMAL | 'normal' | 普通 |
REVERSE | 'reverse' | 倒放 |
WRAP | 'wrap' | 循环 |
WRAP_REVERSE | 'wrap-reverse' | 循环倒放 |
枚举 - GameAnimationPlaybackState 动画播放状态
属性 | 值 | 说明 |
---|---|---|
FINISHED | 'finished' | 已完成 |
PENDING | 'pending' | 挂起等待 |
RUNNING | 'running' | 播放中 |
枚举 - GameBodyPart 玩家身体部位的类型
属性 | 值 | 说明 |
---|---|---|
HIPS | 'hips' | 臀部 |
TORSO | 'torso' | 躯干 |
NECK | 'neck' | 颈部 |
HEAD | 'head' | 头 |
LEFT_SHOULDER | 'leftShoulder' | 左肩 |
LEFT_UPPER_ARM | 'leftUpperArm' | 左上臂 |
LEFT_LOWER_ARM | 'leftLowerArm' | 左下臂 |
LEFT_HAND | 'leftHand' | 左手 |
LEFT_UPPER_LEG | 'leftUpperLeg' | 左上腿 |
LEFT_LOWER_LEG | 'leftLowerLeg' | 左下腿 |
LEFT_FOOT | 'leftFoot' | 左脚 |
RIGHT_SHOULDER | 'rightShoulder' | 右肩膀 |
RIGHT_UPPER_ARM | 'rightUpperArm' | 右上臂 |
RIGHT_LOWER_ARM | 'rightLowerArm' | 右下臂 |
RIGHT_HAND | 'rightHand' | 右手 |
RIGHT_UPPER_LEG | 'rightUpperLeg' | 右上腿 |
RIGHT_LOWER_LEG | 'rightLowerLeg' | 右下腿 |
RIGHT_FOOT | 'rightFoot' | 右脚 |
枚举 - GameButtonType 玩家按下的按钮类型
属性 | 值 | 说明 |
---|---|---|
WALK | 'walk' | 步行按钮 |
RUN | 'run' | 奔跑按钮 |
CROUCH | 'crouch' | 下蹲按钮 |
JUMP | 'jump' | 跳跃按钮 |
DOUBLE_JUMP | 'jump2 | 二段跳按钮 |
FLY | 'fly' | 飞行按钮 |
ACTION0 | 'action0' | 鼠标左键 / 虚拟按钮A |
ACTION1 | 'action1' | 鼠标右键 / 虚拟按钮B |
枚举 - GameCameraMode 玩家的相机视角模式
属性 | 值 | 说明 |
---|---|---|
FIXED | 'fixed' | 第三人称固定视角 |
FOLLOW | 'follow' | 第三人称跟随视角(默认) |
FPS | 'fps' | 第一人称视角 |
枚举 - GameDialogType 对话框样式类型
属性 | 值 | 说明 |
---|---|---|
TEXT | 'text' | 文本样式对话框 |
INPUT | 'input' | 输入样式对话框 |
SELECT | 'select' | 选择样式对话框 |
枚举 - GameEasing 动画的缓动效果,EaseIn缓入,EaseOut缓出
属性 | 值 | 说明 |
---|---|---|
BACK | 'back' | 反向 |
BOUNCE | 'bounce' | 弹性 |
CIRCLE | 'circle' | 圆 |
ELASTIC | 'elastic' | 橡皮筋 |
EXP | 'exp' | 指数 |
LINEAR | 'linear' | 线性 |
NONE | 'none' | 无 |
QUADRATIC | 'quadratic' | 二次方 |
SINE | 'sine' | 正弦波 |
枚举 - GameInputDirection 玩家通过输入设备控制移动时的方向,可用于 GamePlayer.disableInputDirection 禁用对应方向的输入,以控制玩家移动的表现。
属性 | 值 | 说明 |
---|---|---|
NONE | 'none' | 无,代表不禁用 |
VERTICAL | 'vertical' | 垂直方向 |
HORIZONTAL | 'horizontal' | 水平方向 |
BOTH | 'both' | 所有方向 |
PlayerMoveState运动状态 玩家的运动状态
属性 | 值 | 说明 |
---|---|---|
FLYING | 'fly' | 飞行中 |
GROUND | 'ground' | 在地上 |
SWIM | 'swim' | 游泳中 |
FALL | 'fall' | 下落中 |
JUMP | 'jump' | 跳跃中 |
DOUBLE_JUMP | 'jump2' | 二段跳中 |
枚举 - GamePlayerWalkState 玩家的行走状态
属性 | 值 | 说明 |
---|---|---|
NONE | '' | 非行走中 |
CROUCH | 'crouch' | 下蹲行走 |
WALK | 'walk' | 正常步行 |
RUN | 'run' | 奔跑 |
枚举 - SocialType交关系类型,用于在 GamePlayer 玩家
中查询玩家的社交关系。
属性 | 值 | 说明 |
---|---|---|
FOLLOWING | 0 | 关注 |
FOLLOWERS | 1 | 粉丝 |
FRIENDS | 2 | 好友 |
本文档中的代码,如果出现“-snip-”表示省略了上文中重复的代码
voxels.setVoxel()可以指定最多5个参数:X, Y, Z, voxel, rotation
参数X, Y, Z必须是string;voxel, rotation可以是string或者number类型
voxels.setVoxel(X, Y, Z, voxel, rotation)
/*
(x: number, y: number, Z: number, voxel: string | number, rotation?: string | number) : number
*/
如 voxels.setVoxel(1, 1, 1, 'grass', 0)
,可以在x、y、z为1的位置放置一个草方块,旋转(rotation)为0即方块旋转0*90=0度
如 voxels.setVoxel(1, 1, 1, 'grass', 1)
,可以在x、y、z为1的位置放置一个草方块,旋转(rotation)为1即将方块逆时针旋转1*90=90度
又如 voxels.setVoxel(1, 2, 3, 'stone', 2)
,可以在x=1,y=2,z=3的位置放置一个石头,因为旋转(rotation)的值为2,所以会将原始的方块逆时针旋转2*90=180度
voxels.setVoxel(12, 3, 45, 'glass', 3)
,在x=12,y=3,z=45的位置放置一个玻璃方块,逆时针旋转3*90=270度
voxels.setVoxel(12, 3, 45, 'dirt', 4)
,在x=12,y=3,z=45的位置放置一个土方块,逆时针旋转了4*90=360度,所以相当于不旋转,作用效果等于 voxels.setVoxel(12, 3, 45, 'dirt', 0)
说明:rotation值可以不加,默认为0
如果传入的方块存在,使用此方法的返回值会返回第四个参数即voxel对应的方块ID
例如 voxels.setVoxel(1, 2, 3, 'stone')
会返回名为“stone”的方块对应的id
如果方块不存在,会返回0
例如 voxels.setVoxel(1, 2, 3, 'this_is_not_a_block_name')
会返回0
快速建造可以更高效地批量化建筑方块
/**
* 快速建造一个长方体
*
* @param {number | string} voxel - 方块名称或者id
* @param {number} xmin - x的最小值
* @param {number} ymin - y的最小值
* @param {number} zmin - z的最小值
* @param {number} xmax - x的最大值
* @param {number} ymax - y的最大值
* @param {number} zmax - z的最大值
* @param {number | string} rotation - 方块旋转
*/
function quick_build(voxel, xmin, ymin, zmin, xmax, ymax, zmax, rotation=0){
for(let x=xmin;x<=xmax;x++){
for(let y=ymin;y<=ymax;y++){
for(let z=zmin;z<=zmax;z++){
voxels.setVoxel(x, y, z, voxel, rotation)
}
}
}
}
// 定义函数
/**
* 快速建造一个长方体
*
* @param {number | string} voxel - 方块名称或者id
* @param {number} xmin - x的最小值
* @param {number} ymin - y的最小值
* @param {number} zmin - z的最小值
* @param {number} xmax - x的最大值
* @param {number} ymax - y的最大值
* @param {number} zmax - z的最大值
* @param {number | string} rotation - 方块旋转
*/
function quick_build(voxel, xmin, ymin, zmin, xmax, ymax, zmax, rotation=0){
for(let x=xmin;x<=xmax;x++){
for(let y=ymin;y<=ymax;y++){
for(let z=zmin;z<=zmax;z++){
voxels.setVoxel(x, y, z, voxel, rotation)
}
}
}
}
// 调用函数
// 调用快速建造函数用“grass”(草方块)建造一个起于{x=1,y=1,z=1},止于{x=100,y=64,z=101},所有方块都旋转3*90=270度的长方体
quick_build('grass', 1, 1, 1, 100, 64, 101, 3)
// 调用快速建造函数用“stone”(草方块)建造一个起于{x=2,y=3,z=4},止于{x=100,y=64,z=101},此时不传入参数rotation,方块默认不旋转
quick_build('stone', 2, 3, 4, 100, 64, 101, 3)
有时候并不知道xmin,ymin,zmin,xmax,ymax,zmax到底该传入什么值,以下两种方法可以解决:
例如:
var pos1 = new GameVector3(1,1,1)
var pos2 = new GameVector3(5,5,5)
因为pos1的x、y、z值都小于pos2的x、y、z值,所以此时应如此传入:
quick_build('方块名', pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos3.z)
function quick_build(voxel, xmin, ymin, zmin, xmax, ymax, zmax, rotation=0){
-snip-
}
function quick_build_pro(voxel, pos1, pos2, rotation=0){
// 判断pos1和pos2的位置关系并正确传入
if(pos1.x<=pos2.x&&pos1.y<=pos2.y&&pos1.z<=pos2.z){ // 当pos1的xyz坐标均小于等于pos2的xyz坐标时的调用方式
quick_build(voxel, pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z, rotation)
}
else if(pos1.x>pos2.x&&pos1.y>pos2.y&&pos1.z>pos2.z){ // 当pos2的xyz坐标均小于pos1的xyz坐标时的调用方式
quick_build(voxel, pos2.x, pos2.y, pos2.z, pos1.x, pos1.y, pos1.z, rotation)
}
else{ // 否则输出错误
console.error('不支持的判断类型')
}
}
/**
* 快速建造一个球体
*
* @param {GameVector3} centerPos - 球体中心位置
* @param {number | string} voxel - 方块id或名称
* @param {number} r - 球体半径
* @param {number | string} rotation - 方块旋转
*/
function ball(centerPos, r, voxel, rotation=0){
// 创建嵌套循环,这样创建的妙处在于不必遍历地图每个方块,如果遍历地图每个方块的话地图会崩溃
for(let x=centerPos.x-r;x<=centerPos.x+r;x++){
for(let y=centerPos.y-r;y<=centerPos.y+r;y++){
for(let z=centerPos.z-r;z<=centerPos.z+r;z++){
const position2 = new GameVector3(x, y, z);
// 计算两个位置之间的距离
const distance1 = Math.sqrt(Math.pow(position2.x - centerPos.x, 2) + Math.pow(position2.y - centerPos.y, 2) + Math.pow(position2.z - centerPos.z, 2));
if(distance1<=r){// 如果距离小于传入的r的值,则放置方块
voxels.setVoxel(x,y,z,voxel,rotation)
}
}
}
}
}
因为神奇代码岛的服务器能力问题,当r过大时可能会导致服务器崩溃,所以不要传入一个较大的值
function ball(centerPos, r, voxel, rotation=0){
-snip-
}
var center = new GameVector3(50, 50, 50)
ball(center, 10, 'dirt', 2) // 以{x=50,y=50,z=50}为球体中心、填充旋转了2*90=180度的“dirt”(草方块),半径为10,快速建造一个球体
function pyramid(l, pos, voxel, rotation){
let cx = pos.x;
let cy = pos.y;
let cz = pos.z;
let height = l;
let xend = cx + l;
let zend = cz + l;
for(let y = cy; y < cy + height; y++){
let ylevel = y - cy;
let xstart = cx + ylevel;
let xend = cx + l - ylevel;
let zstart = cz + ylevel;
let zend = cz + l - ylevel;
for(let x = xstart; x < xend; x++){
for(let z = zstart; z < zend; z++){
voxels.setVoxel(x, y, z, voxel, rotation);
}
}
}
}
function pyramid(l, pos, voxel, rotation){
-snip-
}
var pos = new GameVector3(60,10,60)
pyramid(5, pos, 'stone', 3); // 在{x:60,y:10,z:60}使用“stone”(石头)建造一个底面为5*5,高度为5的三棱锥,所有方块逆时针旋转3*90=270度
var admin = ['tangyuan儿','爱肝作品的小诚吖_赤炎宗','意柳','芸游XY','外向的雷电猴(巅峰队)','长恨.原一颗狼星','星光烈火龙','KO轩','唱跳rap只因']
var adminpro = ['阿兹卡班毕业生','羽帆','SAZ','KyTT','执着的树毛虫','奶油.','奶油','奶油a','高冷的小魏1y','谢常浩然','怂怂的小彤e2','耐心的大黄鸡mSos','QTK.十字铁路DCB']
const heimingdan = ['忧郁的宇宙熊','一只咸鸭蛋bn','SAX']//黑名单
// var victory = false
var lzxglist = ['JB6tX5vKo/o0R0gN']
var msglist = ['等你发言','等你发言']
var dmm = false;
var zbznc = '';
var dcz = [];
var dctime = 0;
var zbtime = 0;
var beizhuadao = [];
var dmmrenshu=0;
// console.clear()
function use_duihuanma(entity){
try{
if(entity.duihuanma){
entity.player.cancelDialogs()
}
const date = new Date(Date.now());
const year = date.getFullYear()
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
if(entity.duihuanma.startsWith('wansheng_code')){
if(entity.duihuanma.indexOf('&')!=-1){
entity.duihuanmainlist = entity.duihuanma.split('&')
console.log(entity.duihuanmainlist)
if(entity.duihuanmainlist[1]==String(entity.player.userId*3+2023)&&entity.duihuanmainlist[2]==String(entity.player.name.length)&&entity.duihuanmainlist[5]==String(month+day)&&entity.duihuanmainlist[6]==String(hour)&&parseInt(entity.duihuanmainlist[8])/3%1==0){
if(((parseInt(entity.duihuanmainlist[3])-99)/2)%9==parseInt(entity.duihuanmainlist[4])){
if(minute-parseInt(entity.duihuanmainlist[7])<=5){
dialog(`系统`,`兑换成功!\n获得${(parseInt(entity.duihuanmainlist[3])-99)/4}经验`,entity);
entity.exp+=(parseInt(entity.duihuanmainlist[3])-99)/4;
entity.used_duihuanma.push(entity.duihuanma);
savePlayer(entity);
}
else{
dialog(`错误`,`此兑换码已过期`,entity)
}
}
else{
dialog(`错误`,`此兑换码不存在`,entity)
}
}
else{
dialog(`错误`,`此兑换码不存在`,entity)
}
}
}
else if(entity.duihuanma=='示例兑换码'){
dialog(`系统`,`兑换成功,获得10exp`,entity)
entity.exp+=10
savePlayer(entity)
}
else{
dialog(`错误`,`兑换码不存在`,entity)
}
}
catch(e){
return
}
}
var Storage = storage.getGroupStorage('cundang'); // 获取数据库,名称为 cundang
const CorrespondingName = { // 在此添加排行榜对应的单位和名称(无名称 则表示不显示名称)
'exp': ['经验', '无名称']
};
const unsavedData = { // 玩家初始无需保存的数据,可增添或删除
victory: false,
ingjf: false,
cankick: true,
dmmzy: '',
dmmshoudao: false
};
const savedData = { // 玩家初始需要保存的数据,可增添或删除
exp: 50,
bag: [],
greenlzxg: false,
zhutu_position_x: 3,
zhutu_position_y:6,
zhutu_position_z:4,
chun_position_x: 3,
chun_position_y:6,
chun_position_z:4,
xia_position_x: 3,
xia_position_y:6,
xia_position_z:4,
qiu_position_x: 3,
qiu_position_y:6,
qiu_position_z:4,
dong_position_x: 3,
dong_position_y:6,
dong_position_z:4,
adminlevel: 0,
canplay: true,
used_duihuanma: [],
skins: ['原版皮肤'],
usingskin: '原版',
last_team: 0
};
/**
* 初始化玩家数据
*
* @param {GameEntity} entity
*/
function initPlayer(entity) { // 初始化玩家数据
Object.assign(entity, savedData);
Object.assign(entity, unsavedData);
};
/**
* 获取玩家数据
*
* @param {GameEntity} entity
*/
function getPlayerData(entity) { // 获取玩家数据
var data = { 'name': entity.player.name };
for (let i in savedData) { // 遍历savedData,获取玩家当前数据
data[i] = entity[i];
};
return data;
};
/**
* 存档
*
* @param {GameEntity} entity
*/
async function savePlayer(entity) { // 存档
await Storage.update(entity.player.userId, () => { // 更新玩家数据存档
return getPlayerData(entity);
});
};
/**
* 删档
*
* @param {GameEntity} entity
*/
async function deletePlayer(entity) { // 删档
entity.save = false
await Storage.remove(entity.player.userId); // 删除玩家数据存档
};
async function deletePlayerById(id) { // 删档
await Storage.remove(id); // 删除玩家数据存档
};
/**
* 读档
*
* @param {GameEntity} entity
*/
async function loadPlayer(entity) { // 读档
initPlayer(entity);
var data = await Storage.get(entity.player.userId); // 获取数据
if (data) { // 如果数据存在
Object.assign(entity, data.value);
entity.player.directMessage('已为您读取数据!');
} else { // 如果数据不存在
await Storage.set(entity.player.userId, getPlayerData(entity));
entity.player.directMessage('已为您创建数据!');
};
};
/**
* 清档
*/
async function deleteAllData() { // 清档
var sqlDataList = await Storage.list({ // 将数据库内的所有数据分页
cursor: 0
});
world.querySelectorAll('player').forEach(x => x.save = false);
try {
while (true) {
for (let sqlData of sqlDataList.getCurrentPage()) { // 遍历获取数据
await Storage.remove(sqlData.key)
}
if (sqlDataList.isLastPage) break; // 如果已经是最后一页,退出循环
await sqlDataList.nextPage(); // 下一页
};
} catch (e) {}
};
/**
* 显示排行榜
*
* @param {string} type
*/
async function leaderBoard(type) { // 排行榜
var list = [];
var sqlDataList = await Storage.list({ // 将数据库内的所有数据分页
cursor: 0
});
while (true) {
for (let sqlData of sqlDataList.getCurrentPage()) { // 遍历获取数据
list.includes([sqlData.value['name'], sqlData.value[type]]) ? null : list.push([sqlData.value['name'], sqlData.value[type]]);
}
list = list.sort((a, b) => b[1] - a[1]).slice(0, 100);
if (sqlDataList.isLastPage) break; // 如果已经是最后一页,退出循环
await sqlDataList.nextPage(); // 下一页
};
return list.map((value, num) => // 将列表里的所有项依次替换成字符串
`第${num + 1}名 | ${value[0]} | ${value[1]} ${CorrespondingName[type][0]}${CorrespondingName[type][1] != '无名称' ? CorrespondingName[type][1] : ''}`
).join("\n"); // 按照 换行 的间隔组合成字符串
};
require('./防止想不开.js')
require('./宠物.js')
function find(name){
const a = world.querySelectorAll`player`;
for(let i in a)if(a[i].player.name == name)return a[i];
}
//私聊
async function chats(entity, other, text) {
other.player.directMessage('收到一条私信')
const has = await other.player.dialog({
type: GameDialogType.SELECT,
title: "私聊",
titleTextColor: new GameRGBAColor(0, 0, 0, 1),
titleBackgroundColor: new GameRGBAColor(0.968, 0.702, 0.392, 1),
content: `${entity.player.name}:\n${text}`,
options: ['回复', '取消'],
});
if (!has || has === null) {
entity.player.directMessage('TA阅读了消息,但没有回复');
return;
}
if (has.value === '回复') {
entity.player.directMessage('对方收到了你的私信')
const returns = await other.player.dialog({
type: GameDialogType.INPUT,
title: "私聊-回复",
titleTextColor: new GameRGBAColor(0, 0, 0, 1),
titleBackgroundColor: new GameRGBAColor(0.968, 0.702, 0.392, 1),
content: `${other.player.name},请输入回复内容`,
confirmText: '发送',
placeholder: '输入回复内容',
});
if (!returns || returns === null) {
return;
}
chats(other, entity, returns)
}
else if (has.value === '取消') {
entity.player.directMessage('对方收到了你的私信')
}
}
world.onPlayerJoin(({ entity }) => {
entity.player.interactTimes = 0;
entity.enableInteract = true;
entity.interactRadius = 1.5;
if(entity.player.name=='阿兹卡班毕业生'||entity.player.name=='奶油.'||entity.player.name=='SAZ'||entity.player.name=='羽帆'){
entity.interactHint = `与 【作者认证】 ${entity.player.name} 互动`;
}
else if(admin.includes(entity.player.name||entity.adminlevel==1)){
entity.interactHint = `与 【管理员认证】 ${entity.player.name} 互动`;
}
else if(adminpro.includes(entity.player.name||entity.adminlevel>1)){
entity.interactHint = `与 【高级管理员】 ${entity.player.name} 互动`;
}
else{
entity.interactHint = `与 ${entity.player.name} 互动`;
}
entity.onInteract(async ({ entity, targetEntity }) => {
targetEntity.player.directMessage('你被 ' + entity.player.name + ' 访问了')
while (!entity.destroyed) {
const others = await entity.player.dialog({
type: GameDialogType.SELECT,
title: targetEntity.player.name + '',
titleTextColor: new GameRGBAColor(0, 0, 0, 1),
titleBackgroundColor: new GameRGBAColor(0.968, 0.702, 0.392, 1),
content: `你要干啥`,
options: ['和TA私聊','没啥,就看看'],
})
if (!others || others === null) {
return;
}
if (others.value == '和TA私聊') {
const chating = await entity.player.dialog({
type: GameDialogType.INPUT,
title: "私聊",
titleTextColor: new GameRGBAColor(0, 0, 0, 1),
titleBackgroundColor: new GameRGBAColor(0.968, 0.702, 0.392, 1),
content: `${entity.player.name},请输入私聊内容`,
confirmText: '发送',
placeholder: '输入私聊内容',
});
if (!chating || chating === null) {
return;
}
chats(entity, targetEntity, chating)
return;
}
}
})
})
async function dialog(title,content,entity){
const result = await entity.player.dialog({
type: GameDialogType.TEXT,
title: title,
content: content,
});
}
world.onPlayerJoin(({entity})=>{
entity.player.jumpPower=0.7
entity.player.doubleJumpPower=0.7
})
world.onPlayerJoin(async({ entity }) => {
// entity.player.enableDoubleJump=false
const dialog = entity.player.dialog({
type: GameDialogType.TEXT,
title: "作者&协作者们",
content: `${entity.player.name},欢迎来到毕业生跑酷pro,下面是对于本地图的一些介绍:\n
· 老版地图不再更新,但关卡与pro版不同,链接:https://box3.codemao.cn/p/bysrun
· 地图有sql存档,妈妈再也不用担心我把存档搞丢啦!
· 地图有一个小彩蛋,你能找到吗?
· 如有bug请在评论区@作者!
· 经验计算规则:第一次游玩赠送50经验,以后每碰到一个新的存档点经验+1
· 在游戏中违规被作者看到可能会被踢出/封禁
· 加入Q群763919859领粒子效果!
· 与朋友一起竞速吧!
最后,祝您在毕业生跑酷pro玩得愉快!`,
});
const resultawa = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '注意',
content: `本地图(含旧版)已经一周年,进群763919859领取1周年福利`,
options:['确定']
});
if(!resultawa || resultawa === null){
return;
}
else if(resultawa.value=='确定'){
entity.player.link(`http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=HNz3yHNTngoeIwY6G-u_MJYeuKg9yY49&authKey=JMwkO%2BkIFr5qfXArsrAu98%2BUV50d6wTeeCxejnH36Wt6UeEi4a2wjb5N38l1n6w3&noverify=0&group_code=763919859`, {isConfirm: false, isNewTab: true});
}
const result3 = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '注意',
content: `本地图的通关实况出来啦!是否进入外部网站观看?(不会覆盖当前标签页)`,
options:['确定','不了']
});
if(!result3 || result3 === null){
return;
}
else if(result3.value!='不了'){
entity.player.link(`https://www.bilibili.com/video/BV1fe411Q7kL/?share_source=copy_web&vd_source=47fb8dc2c290d3efba51bb252a91c38d`, {isConfirm: false, isNewTab: true});
}
if(entity.player.name == '阿兹卡班毕业生'||entity.player.name=='羽帆'||entity.player.name=='SAZ'){
world.say(`作者 ${entity.player.name} 来辣~`)
}
else{
world.say(`欢迎 ${entity.player.name} 进入毕业生跑酷pro!`)
}
});
function addWearable(entity, data) {
// 这一步是把角度转成弧度
const orientation = new GameQuaternion(0, 0, 0, 1)
.rotateZ(data.rotate[2] * Math.PI / 180)
.rotateX(data.rotate[0] * Math.PI / 180)
.rotateY(data.rotate[1] * Math.PI / 180)
// 将上面声明的配置一一对应地传递给传递API
entity.player.addWearable({
bodyPart: data.bodyPart,
mesh: data.mesh,
orientation: orientation,
scale: data.scale,
offset: data.offset,
})
}
const zuozhe = [
{ bodyPart: GameBodyPart.HEAD, name: '头', mesh: 'mesh/绿宝石块.vb', offset: [1, 0, 0], rotate: [45, 45, 45], scale: [0.5, 0.5, 0.5] },
{ bodyPart: GameBodyPart.HEAD, name: '头', mesh: 'mesh/钻石.vb', offset: [-1, 0, 0], rotate: [45, 45, 45], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.TORSO, name: '躯干', mesh: 'mesh/1楼.vb', offset: [0, 0.1, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.TORSO, name: '臀部', mesh: 'mesh/光轮2000.vb', offset: [0, -0.3, 0], rotate: [0, 0, 30], scale: [0.7, 0.7, 0.7] },
// { bodyPart: GameBodyPart.LEFT_UPPER_ARM, name: '左上臂', mesh: 'mesh/1楼.vb', offset: [0.1, 0.07,-0.02], rotate: [-128, 120, -85], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_UPPER_ARM, name: '右上臂', mesh: 'mesh/1楼.vb', offset: [-0.1, 0.07,-0.02], rotate: [-45, -120, -85], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.LEFT_LOWER_ARM, name: '左下臂', mesh: 'mesh/1楼.vb', offset: [0, 0.11, 0], rotate: [-128, 120, -85], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_LOWER_ARM, name: '右下臂', mesh: 'mesh/1楼.vb', offset: [0, 0.09, 0], rotate: [-45, -120, -85], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.LEFT_UPPER_LEG, name: '左上腿', mesh: 'mesh/1楼.vb', offset: [0, -0.05, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_UPPER_LEG, name: '右上腿', mesh: 'mesh/雾雨魔理沙上腿.vb', offset: [0, -0.1, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.LEFT_LOWER_LEG, name: '左下腿', mesh: 'mesh/雾雨魔理沙下腿.vb', offset: [0, 0.07, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_LOWER_LEG, name: '右下腿', mesh: 'mesh/雾雨魔理沙下腿.vb', offset: [0, 0.07, 0], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.LEFT_FOOT, name: '左脚', mesh: 'mesh/雾雨魔理沙脚.vb', offset: [0, 0.06, 0.05], rotate: [0, 90, 0], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_LOWER_ARM, name: '右手', mesh: 'mesh/我的世界_钻石剑.vb', offset: [-0.2, 0.2, 0.2], rotate: [-45, 90, -45], scale: [1, 1, 1] },
// { bodyPart: GameBodyPart.LEFT_LOWER_ARM, name: '左手', mesh: 'mesh/我的世界·附魔三叉戟.vb', offset: [0.15, 0.15, 0.09], rotate: [110, 243
// , 180], scale: [0.5, 0.5, 0.5] },
// { bodyPart: GameBodyPart.RIGHT_LOWER_ARM, name: '右手', mesh: 'mesh/皇冠.vb', offset: [-0.16, 0.05, 0.1], rotate: [-138, 60, 95], scale: [0.5, 0.5, 0.5] },
]
const yufan = [
{ bodyPart: GameBodyPart.HEAD, name: '头', mesh: 'mesh/小鱼干.vb', offset: [1.3, 0, 0], rotate: [45, -45, 45], scale: [0.01, 0.01, 0.01] }
]
const saz = [
{bodyPart: GameBodyPart.RIGHT_LOWER_ARM, name: '右下臂', mesh: 'mesh/我的世界附魔钻石剑.vb', offset: [-0.4, 0.4, 0.25], rotate: [135, 135, 135], scale: [1, 1, 1]},
{bodyPart: GameBodyPart.HEAD_LOWER_ARM, name: '头', mesh: 'mesh/墨镜.vb', offset: [0, 0.8, 0.25], rotate: [0, 90, 0], scale: [0.2, 0.3, 0.3]}
]
function chuandaipeijian(entity){
if(entity.player.name==`阿兹卡班毕业生`){
for (const data of zuozhe) {
addWearable(entity, data)
}
entity.player.directMessage(`穿戴配件成功`);
}
else if(entity.player.name=='KyTT'||entity.player.name=='羽帆'){
for (const data of yufan) {
addWearable(entity, data)
}
entity.player.directMessage(`穿戴配件成功`);
}
else if(entity.player.name==`SAZ`){
for (const data of saz) {
addWearable(entity, data)
}
entity.player.directMessage(`穿戴配件成功`);
}
// else if(entity.player.name==`KyTT`){
// for (const data of kytt) {
// addWearable(entity, data)
// }
// }
// 有bug
// if(hmd in entity.player.name){
// // 隐藏所有身体部件!
// for (const bodyPart in entity.player.skinInvisible) {
// entity.player.skinInvisible[bodyPart] = true;
// }
// }
// if(entity.player.name=='阿兹卡班毕业生'){
// entity.player.setSkinByName('苦力怕皮肤');
// }
}
world.onPlayerJoin(async({entity})=>{
chuandaipeijian(entity)
})
//sql相关
world.onPlayerLeave(async({entity})=>{
entity.save != false ? await savePlayer(entity) : null; // 存档
savePlayer(entity);
})
const points = world.querySelectorAll('.存档点')
points.forEach((e)=>{
e.onEntityContact(({other})=>{
const spawnPoint = e.position.add({x: 0,y: 2.5,z: 0});
if(spawnPoint.equals(other.player.spawnPoint))return;
other.player.spawnPoint = spawnPoint;
other.zhutu_position_x=e.position.x;
other.zhutu_position_y=e.position.y+2.5;
other.zhutu_position_z=e.position.z;
savePlayer(other);
other.player.directMessage('存档成功,经验+1!');
if(other.victory==false){
other.exp+=1;
}
})
})
world.onFluidEnter(({entity, tick, voxel}) => {
const voxelName = voxels.name(voxel)
if (voxelName=='water'&&entity.ingjf==false){
entity.player.forceRespawn()
entity.player.directMessage(`落水重生`)
}
})
world.onChat(({message,entity})=>{
var huancun = msglist[0];
msglist[0]=entity.player.name+':\n'+message;
for(var i=1;i<=2;i++){
msglist[i] = huancun;
huancun = msglist[i+1]
}
world.say(`${entity.player.name}:${message}`)
if(entity.player.name!='阿兹卡班毕业生'&&(message==`ban 阿兹卡班毕业生`||message==`kick 阿兹卡班毕业生`)){
dialog(`作者`,`胆子很大啊!敢封禁/踢出作者!`,entity);
entity.position.set(2,6,10);
}
})
world.onPlayerJoin(({entity})=>{
world.onChat(({message,entity:user})=>{
if(user.player.name='阿兹卡班毕业生'){
// if(message.startsWith('push admin')){
// console.log(message.slice(11));
// if(entity.player.name==message.slice(11)){
// entity.isadmin=true;
// savePlayer(entity);
// world.say('恭喜'+entity.player.name+'成为管理员');
// dialog(`阿兹卡班毕业生`,`恭喜你入选管理员,希望你为毕业生跑酷pro做出贡献\n刷新后生效`,entity);
// }
// }
// if(message.startsWith('kick')){
// console.log(message.slice(5));
// if(entity.player.name==message.slice(5)){
// entity.position.set(2,6,10);
// dialog(``,`你被踢出`,entity);
// entity.player.kick()
// }
// }
// else if(message.startsWith('ban')){
// console.log(message.slice(5));
// if(entity.player.name==message.slice(4)){
// entity.canplay=false;
// savePlayer(entity);
// entity.position.set(2,6,10);
// dialog(``,`你被封禁,移至小黑屋,请退出游戏`,entity);
// world.say(entity.player.name+'被作者封禁');
// }
// }
// else if(message.startsWith('canplay')){
// console.log(message.slice(8));
// if(entity.player.name==message.slice(8)){
// entity.canplay=true;
// entity.position.set(2,10,10);
// dialog(``,`已解除封禁\n为了防止sql存档异常,请右键sql存档或者踩一个存档点`,entity);
// savePlayer(entity);
// }
// }
// else if(message.startsWith('e')){
// if(entity.player.name==message.slice(11)){
// entity.e=true;
// }
// }
// else if(message.startsWith('cannotcommand')){
// if(entity.player.name==message.slice(14)){
// entity.e=false;
// }
// }
}
})
})
// })
// world.onPlayerJoin(({entity})=>{
// entity.player.onChat(({message,entity:user})=>{world.say(`${user.player.name}:${message}`)})
// })
// npc交互
const xiaoheiwu = world.querySelector('#小黑屋');
xiaoheiwu.enableInteract = true; // 允许进行互动
xiaoheiwu.interactRadius = 5; // 实体的互动范围
xiaoheiwu.interactHint = `小黑屋\n不想被关进小黑屋就安分守己哦~`; // 互动提示框显示实体的名称
xiaoheiwu.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
const stone2023 = world.querySelector('#2023');
stone2023.enableInteract = true; // 允许进行互动
stone2023.interactRadius = 5; // 实体的互动范围
stone2023.interactHint = `2023纪念石`; // 互动提示框显示实体的名称
stone2023.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
// stone2023.onInteract(({entity})=>{
// entity.player.link(`https://azkbbys.gitbook.io/azkbbys/celebrate/on-going/2024-happy-new-year`, {isConfirm: false, isNewTab: true});
// })
const tzxyg1 = world.querySelector('#跳转下一关-1');
tzxyg1.enableInteract = true; // 允许进行互动
tzxyg1.interactRadius = 2; // 实体的互动范围
tzxyg1.interactHint = `互动跳转下一关`; // 互动提示框显示实体的名称
tzxyg1.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
tzxyg1.onInteract(({entity})=>{
entity.position.set(123,15,30)
})
const boat = world.querySelector('#船');
boat.enableInteract = true; // 允许进行互动
boat.interactRadius = 2; // 实体的互动范围
boat.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
boat.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
boat.onInteract(({entity})=>{
dialog(`小船`,`嘿!发现彩蛋啦!\n给你上上色~\n加入Q群763919859领取更多福利!`,entity)
entity.player.color=new GameRGBColor(0,1,1)
})
const caidanflower = world.querySelector('#彩蛋花');
caidanflower.enableInteract = true; // 允许进行互动
caidanflower.interactRadius = 2; // 实体的互动范围
caidanflower.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
caidanflower.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
caidanflower.onInteract(({entity})=>{
dialog(`花`,`嘿!发现彩蛋啦!\n给你1经验!可以重复领取!顺便给你上上色吧~别忘了手动点击保存哦\n加入Q群763919859领取更多福利!`,entity)
entity.exp+=1
entity.player.color=new GameRGBColor(0.1,0,1)
})
const xuanzefutu = world.querySelector('#dream-1');
xuanzefutu.enableInteract = true; // 允许进行互动
xuanzefutu.interactRadius = 5; // 实体的互动范围
xuanzefutu.interactHint = `选择附图`; // 互动提示框显示实体的名称
xuanzefutu.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
xuanzefutu.onInteract(async({entity})=>{
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '选择附图',
content:`点击附图名称,查看详情`,
options:['春','夏']
});
if(!result || result.value === null){
return;
}
else if(result.value=='春'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '地图详情',
content:`地图主题:春\n\n点击按钮进入地图`,
options:['进入地图','就是看看']
});
if(!result || result.value === null){
return;
}
else if(result.value=='进入地图'){
entity.player.link(`https://dao3.fun/play/6d789dabd5e09ca687ce`, {isConfirm: false, isNewTab: false});
}
}
else if(result.value=='夏'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '地图详情',
content:`地图主题:夏\n\n点击按钮进入地图`,
options:['进入地图','就是看看']
});
if(!result || result.value === null){
return;
}
else if(result.value=='进入地图'){
entity.player.link(`https://dao3.fun/play/54230e5fd4ecbaecc0ee`, {isConfirm: false, isNewTab: false});
}
}
})
const tiaoguandream = world.querySelector('#跳关dream');
tiaoguandream.enableInteract = true; // 允许进行互动
tiaoguandream.interactRadius = 5; // 实体的互动范围
tiaoguandream.interactHint = `跳关`; // 互动提示框显示实体的名称
tiaoguandream.interactColor = new GameRGBColor(1,1,1); // 互动提示的文字颜色
tiaoguandream.onInteract(async({entity})=>{
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '选择',
content:`确定花费40exp跳关么`,
options:['是','否']
});
if(!result || result.value === null){
return;
}
else if(result.value=='是'){
if(entity.exp>=40){
entity.exp-=40;
entity.position.set(79,19,18)
savePlayer(entity)
entity.player.directMessage('跳关成功')
}
else{
dialog('错误','经验不足',entity)
}
}
})
const end = world.querySelector('#终点');
// end.enableInteract = true; // 允许进行互动
// end.interactRadius = 2; // 实体的互动范围
end.onEntityContact(async({other})=>{
if(other.victory==false){
other.position.set(4,7,4)
other.player.color= new GameRGBColor(0,1,0)
other.player.canFly=true
other.player.spectator=true
dialog(`系统`,`恭喜你通关了!!!\n已开启您的飞行权限\n经验+50`,other)
world.say(`恭喜${other.player.name}通关游戏!`)
other.exp+=50
other.zhutu_position_x=savedData.zhutu_position_x
other.zhutu_position_y=savedData.zhutu_position_y
other.zhutu_position_z=savedData.zhutu_position_z
savePlayer(other)
other.victory=true
}
else{
dialog(`系统`,`你已经通过关了,按下右键-重来可以重来`,other)
}
})
// 碰撞过滤
world.addCollisionFilter('player','player')
//黑名单
world.onPlayerJoin(({entity}) => {
if(heimingdan.includes(entity.player.name)){
entity.player.kick()
}
})
// 管理员代码
world.onChat(({ entity, message }) => {
if(adminpro.includes(entity.player.name)||entity.adminlevel>1){
if (message.startsWith('$')) {
try {
world.say('<~ ' + eval(message.slice(1)))
}
catch (err) {
world.say('<~ ' + err)
}
}
}
})
const particle_greenCrystal = {
particleRate: 500,
particleLifetime: 0.4,
particleSize: [4, 3, 2, 1, 0.25],
particleColor: [
new GameRGBColor(1, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(1, 1, 1)
],
}
const test_green = {
particleRate: 500,
particleLifetime: 999,
particleSize: [4, 3, 2, 1, 0.25],
particleColor: [
new GameRGBColor(1, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 1, 0),
new GameRGBColor(1, 1, 1)
],
}
const particle_purpleCrystal = {
particleRate: 500,
particleLifetime: 0.4,
particleSize: [4, 3, 2, 1, 0.25],
particleColor: [
new GameRGBColor(0, 0, 1),
new GameRGBColor(0, 0, 1),
new GameRGBColor(1, 0, 1),
new GameRGBColor(1, 0, 1),
new GameRGBColor(1, 1, 1)
],
}
const wcbl = {
particleRate: 700,
particleLifetime: 1.5,
particleSize: [1.5, 1.5, 1.5, 1.5, 1.5],
particleColor: [
new GameRGBColor(0, 1, 0),
new GameRGBColor(0, 0, 1),
new GameRGBColor(1, 0, 1),
new GameRGBColor(0, 1, 1),
new GameRGBColor(1, 1, 1)
],
}
world.onPlayerJoin(async({entity})=>{
await loadPlayer(entity)
if(entity.player.name=='阿兹卡班毕业生'){
entity.player.color=new GameRGBColor(1,0,1)
Object.assign(entity, wcbl)
}
else if(admin.includes(entity.player.name)||adminpro.includes(entity.player.name)||entity.adminlevel>0){
Object.assign(entity, particle_purpleCrystal)
}
else if(entity.greenlzxg==true||lzxglist.includes(entity.player.userKey)||lzxglist.includes(entity.player.name)){
Object.assign(entity, particle_greenCrystal)
}
// 管理员sql与地图管理员列表同步
// if(admin.includes(entity.player.name)){
// entity.isadmin=true;
// }
// if(entity.isPlayer==true&&admin.includes(entity.player.name)==false){
// admin.push(entity.player.name)
// }
// 检测网址中是否含有兑换码,如含有则使用
var playerurl_string = entity.player.url;
var playerurl = new URL(playerurl_string);
entity.duihuanma = playerurl.searchParams.get('code')
use_duihuanma(entity)
// 位置设置
entity.position.set(entity.zhutu_position_x,entity.zhutu_position_y,entity.zhutu_position_z)
entity.player.spawnPoint.set(entity.zhutu_position_x,entity.zhutu_position_y,entity.zhutu_position_z)
// 更换皮肤
if(entity.usingskin!='原版'){
entity.player.setSkinByName(entity.usingskin);
}
// 检测组队
try{
entity.playerurl_string = entity.player.url;
entity.playerurl = new URL(entity.playerurl_string);
const date = new Date(Date.now());
const month = date.getMonth() + 1;
const day = date.getDate();
if(entity.playerurl.searchParams.get('serverId')&&entity.playerurl.searchParams.get('teamId')&&entity.last_team!=month+day){
entity.can=true;
world.querySelectorAll('player').forEach((e)=>{
e.playerurl_string = e.player.url;
e.playerurl = new URL(e.playerurl_string);
if(e.playerurl.searchParams.get('serverId')&&e.playerurl.searchParams.get('teamId')){}
else{
entity.can=false
}
})
if(entity.can==true){
entity.exp += 10000
entity.last_team = month+day
savePlayer(entity)
dialog(`组队福利领取成功`,`${entity.player.name},欢迎使用组队功能来到本地图,1w经验已自动领取\n若您是队长,可以截图队伍界面后联系毕业生领取管理员`,entity)
}
else{
dialog(`组队福利领取失败`,`${entity.player.name},偷偷改链接是没用的哦~`,entity)
}
}
else{
if(entity.last_team==month+day){
dialog(`组队福利领取失败`,`${entity.player.name},今天你已领过组队福利,请明天再来!`,entity)
}
}
}
catch(e){}
})
// 右键菜单
world.onPress(async({button,entity})=>{
if(button==='action1'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '游戏菜单',
content:`你有${entity.exp}经验\n`+ `你的血量:`+entity.hp+`/`+entity.maxHp+`\n你的坐标:`+entity.position,
options:['赞助毕业生,得顶级福利','选择附图','关于gameUi','兑换码','sql存档','sql删档','经验排行榜','皮肤库','商店','背包','重来','脱离卡点','进入/离开挂机房','进入/退出俯视全图','切换人称','bug反馈','禁言玩家说话','管理员工具']
});
if(!result || result.value === null){
return;
}
else if(result.value=='赞助毕业生,得顶级福利'){
entity.player.link(`https://azkbbys.gitbook.io/azkbbys/zzbys`, {isConfirm: false, isNewTab: true})
}
else if(result.value=='选择附图'){
entity.position.set(97,40,74);
dialog(`系统`,`你已进入附图选择区域,与dream互动即可选择附图,要退出请右键点击“脱离卡点”`,entity)
}
else if(result.value=='关于gameUi'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: 'gameUi',
content:`选择你要进行的操作`,
options:['取消操作','关闭gameUi','刷新gameUi内容/开启gameUi','刷新gameUi大小']
});
if(!result || result.value === null){
return;
}
else if(result.value=='关闭gameUi'){
remoteChannel.sendClientEvent(entity, {type:'command',args:'close'})
entity.player.directMessage(`已关闭`)
}
else if(result.value=='刷新gameUi内容/开启gameUi'){
remoteChannel.sendClientEvent(entity, {
type:'command',
args:'open'
})
remoteChannel.sendClientEvent(entity, {
type:'玩家信息1',
args:{
avatar:entity.player.avatar,
name:entity.player.name,
player_title:entity.player_title
}
})
entity.player.directMessage(`刷新/开启成功`)
}
else if(result.value=='刷新gameUi大小'){
remoteChannel.sendClientEvent(entity, {
type: '刷新大小',
args: null
})
entity.player.directMessage(`当前暂不支持刷新,请刷新网页即可`)
}
}
else if(result.value=='兑换码'){
entity.duihuanma = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '兑换',
content: `输入你所获得的兑换码\n兑换码可以在Q群763919859获得!`,
confirmText: '确认',
});
if(!entity.duihuanma || entity.duihuanma === null){
entity.player.link(`http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Atg_SCPUyp2d8yAAxjaozzjFH3eu198J&authKey=ohyqS%2FYbJ%2F3C%2BkzrFVQSS7wJoeifKFxeo8SNr4KsX7fey6sx%2Fy%2FX7JEF%2Bvtkryd1&noverify=0&group_code=763919859`, {isConfirm: false, isNewTab: true})
}
else if(entity.used_duihuanma.includes(entity.duihuanma)==true){
dialog(`错误`,`这个兑换码已经使用过了`,entity)
}
else{
use_duihuanma(entity)
}
}
else if(result.value=='sql存档'){
savePlayer(entity);
dialog(`系统`,`存档成功!\n每次踩到存档点会自动进行所有数据的保存`,entity)
}
else if(result.value=='sql删档'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '你确定要删档吗?',
content:`你确定要删档吗?\n删档后一切数据将消失!\n不能后悔!`,
options:['不确定','算了','没想好','不删','删了吧']
});
if(result.value=='删了吧'){
Object.assign(entity, savedData);
savePlayer(entity);
entity.player.kick();
}
}
else if(result.value=='经验排行榜'){
await entity.player.dialog({
type: 'select',
title: '排行',
content: await leaderBoard('exp'),
options: ['确认']
});
}
else if(result.value=='皮肤库'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '选择皮肤',
content:`请选择要使用的皮肤`,
options:entity.skins
});
if(!result || result.value === null){
entity.player.resetToDefaultSkin()
entity.usingskin = '原版'
}
else if(result.value!='原版皮肤'){
entity.usingskin = result.value;
entity.player.setSkinByName(result.value)
}
else{
entity.player.resetToDefaultSkin()
entity.usingskin = '原版'
}
savePlayer(entity)
entity.player.directMessage('切换成功')
}
else if(result.value=='商店'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '你要买点啥?',
content:`你要买点啥?\n你有${entity.exp}经验\n说明:名称(价格)(备注)`,
options:['退出',
'永久绿色粒子效果(150exp)(全图同步)',
'永久苦力怕皮肤(500exp)(全图同步)(鬼知道作者把皮肤做成了啥样)',
'永久史蒂夫皮肤(500exp)(全图同步)(还原度还是可以的吧)',
'一次性飞行特权(70exp)(开启飞行权限,仅能在一个地图使用!有效期:2s)',
'一次性飞行变速器(5exp)(更改飞行速度,仅能在一个地图使用!使用前提:已经开启飞行)',
'缩小药水(70exp)(一次性,将角色大小缩小50%,不可叠加使用)',
'还原药水(1exp)(一次性,将角色大小还原',
'放大药水(70exp)(一次性,将角色大小增大50%,不可叠加使用)']
});
if(!result || result.value === null){
return;
}
else if(result.value=='永久绿色粒子效果(150exp)(全图同步)'){
if(entity.exp>=150){
entity.exp-=150;
entity.greenlzxg=true;
savePlayer(entity);
entity.player.directMessage(`购买成功,已自动使用,刷新后生效`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='永久苦力怕皮肤(500exp)(全图同步)(鬼知道作者把皮肤做成了啥样)'){
if(entity.exp>=500&&entity.skins.includes('苦力怕')==false){
entity.exp-=500;
entity.skins.push('苦力怕')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入皮肤库,可右键点击“皮肤库”使用`)
}
else{
dialog(`错误`,`经验不够或已拥有皮肤`,entity)
}
}
else if(result.value=='永久史蒂夫皮肤(500exp)(全图同步)(还原度还是可以的吧)'){
if(entity.exp>=500&&entity.skins.includes('史蒂夫')==false){
entity.exp-=500;
entity.skins.push('史蒂夫')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入皮肤库,可右键点击“皮肤库”使用`)
}
else{
dialog(`错误`,`经验不够或已拥有皮肤`,entity)
}
}
else if(result.value=='一次性飞行特权(70exp)(开启飞行权限,仅能在一个地图使用!有效期:2s)'){
if(entity.exp>=80){
entity.exp-=80;
entity.bag.push('一次性飞行特权')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='一次性飞行变速器(5exp)(更改飞行速度,仅能在一个地图使用!使用前提:已经开启飞行)'){
if(entity.exp>=5){
entity.exp-=5;
entity.bag.push('一次性飞行变速器')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='缩小药水(70exp)(一次性,将角色大小缩小50%,不可叠加使用)'){
if(entity.exp>=70){
entity.exp-=70;
entity.bag.push('一次性缩小药水')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='还原药水(1exp)(一次性,将角色大小还原'){
if(entity.exp>=1){
entity.exp-=1;
entity.bag.push('一次性还原药水')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
else if(result.value=='放大药水(70exp)(一次性,将角色大小增大50%,不可叠加使用)'){
if(entity.exp>=70){
entity.exp-=70;
entity.bag.push('一次性放大药水')
savePlayer(entity);
entity.player.directMessage(`购买成功,已放入背包`)
}
else{
dialog(`错误`,`经验不够!`,entity)
}
}
}
else if(result.value=='背包'){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '你要使用啥?',
content:`你要使用啥?\n警告:点击后立即使用无确认\n退出请点X`,
options:entity.bag
});
if(!result || result.value === null){
return;
}
else if(result.value=='一次性飞行特权'){
entity.player.canFly=true;
let index = entity.bag.indexOf('一次性飞行特权');
if (index !== -1) {
entity.bag.splice(index, 1);
}
savePlayer(entity)
entity.player.canFly=true;
entity.player.directMessage('使用成功,2s后降落');
await sleep(2000);
entity.player.canFly=false;
}
else if(result.value=='一次性飞行变速器'){
let index = entity.bag.indexOf('一次性飞行变速器');
if (index !== -1) {
entity.bag.splice(index, 1);
}
const flyspeed = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '自定义飞行速度',
content: `输入飞行速度,不要试探服务器极限`,
confirmText: '确认',
});
entity.player.flySpeed=flyspeed
savePlayer(entity)
entity.player.directMessage('使用成功')
}
else if(result.value=='一次性缩小药水'){
let index = entity.bag.indexOf('一次性缩小药水');
if (index !== -1) {
entity.bag.splice(index, 1);
}
entity.player.scale=0.5
savePlayer(entity)
entity.player.directMessage('使用成功')
}
else if(result.value=='一次性还原药水'){
let index = entity.bag.indexOf('一次性还原药水');
if (index !== -1) {
entity.bag.splice(index, 1);
}
entity.player.scale=1
savePlayer(entity)
entity.player.directMessage('使用成功')
}
else if(result.value=='一次性放大药水'){
let index = entity.bag.indexOf('一次性放大药水');
if (index !== -1) {
entity.bag.splice(index, 1);
}
entity.player.scale=1.5
savePlayer(entity)
entity.player.directMessage('使用成功')
}
else if(result.value=='无限飞行羽翼'){
entity.player.canFly=true;
entity.player.directMessage('使用成功')
}
}
else if(result.value=='重来'){
if(entity.canplay==false){
dialog(`系统`,`你在封禁中,不能出来`,entity)
}
else{
entity.player.spectator=false;
entity.player.directMessage(`重来`)
entity.victory = false
entity.player.canFly=false
entity.hp=100
entity.player.color = new GameRGBColor(1,1,1)
entity.position.set(4,5,4)
entity.ingjf=false;
}
}
else if(result.value=='脱离卡点'){
if(entity.canplay==false){
dialog(`系统`,`你在封禁中,不能出来`,entity)
}
else{
entity.player.forceRespawn()
entity.ingjf=false;
entity.player.directMessage('脱离成功!')
}
}
else if(result.value=='进入/离开挂机房'){
if(entity.canplay==false){
dialog(`系统`,`你在封禁中,不能出来`,entity)
}
else{
if(entity.ingjf==true){
entity.player.forceRespawn();
entity.ingjf=false;
}
else{
entity.position.set(97,6,74);
entity.ingjf=true;
}
}
}
else if(result.value=='进入/退出俯视全图'){
if(entity.fsqting==false){
const fsqt = world.querySelector('#俯视全图')
entity.player.cameraEntity=fsqt
entity.player.directMessage('正在俯视全图,再次点击按钮可退出')
entity.fsqting=true
}
else{
entity.player.cameraEntity=entity
entity.fsqting=false
}
}
else if(result.value=='切换人称'){
if (entity.player.cameraMode === GameCameraMode.FOLLOW) {
entity.player.cameraMode = GameCameraMode.FPS
entity.player.directMessage(`切换成功`)
}
else {
entity.player.cameraMode = GameCameraMode.FOLLOW
entity.player.directMessage(`切换成功`)
}
}
else if(result.value=='bug反馈'){
dialog(`作者`,`反馈问题请发在评论区,也可以发作者邮箱oyroyroyr@163.com,如果采纳会赠送地图绿色粒子特效`,entity)
}
else if(result.value=='禁言玩家说话'){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '禁言玩家说话',
content: `你想要说啥`,
confirmText: '“警告!非禁言玩家尽量不要使用!”',
});
if(!result || result === null){
return;
}
else {
world.say(entity.player.name+':'+result)
}
}
else if(result.value=='管理员工具'){
if(admin.includes(entity.player.name)||entity.adminlevel>0||adminpro.includes(entity.player.name)){
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '管理员工具',
content: `选择你需要使用的工具`,
options:['管理员命令文档','飞行','降落','开启/关闭穿墙','玩家传送器','传送至某玩家','集体传送附图!','计时器','广播公告','躲猫猫模式']
});
if(!result || result.value === null){
return;
}
else if(result.value=='管理员命令文档'){
entity.player.link(`https://azkbbys.gitbook.io/azkbbys/docs/bysrunpro/bysrunpro-admin-code-tutorial`, {isConfirm: false, isNewTab: true})
}
else if(result.value=='飞行'){
entity.player.canFly=true
entity.player.directMessage('您可以飞行了')
}
else if(result.value=='降落'){
entity.player.canFly=false
entity.player.directMessage('降落成功')
const allWearables = entity.player.wearables();
// allWearables.forEach((item) => {
// item.remove();
// });
}
else if(result.value=='开启/关闭穿墙'){
if(entity.player.spectator==false){
entity.player.spectator=true
}
else{
entity.player.spectator=false
}
}
else if(result.value=='玩家传送器'){
const playernamelist = []
world.querySelectorAll('player').forEach((e)=>{
if(e.player.name!=entity.player.name)
playernamelist.push(e.player.name)
})
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '传送至某玩家',
content: `你要传送谁到你的位置`,
options:playernamelist
});
if(!result || result.value === null){
return;
}
else{
for (const e of world.querySelectorAll('player')){;
if(e.player.name==result.value){;
e.position.x=entity.position.x
e.position.y=entity.position.y
e.position.z=entity.position.z
entity.player.directMessage('传送成功!')
};
};
}
}
else if(result.value=='传送至某玩家'){
const playernamelist = []
world.querySelectorAll('player').forEach((e)=>{
if(e.player.name!=entity.player.name)
playernamelist.push(e.player.name)
})
const result = await entity.player.dialog({
type: GameDialogType.SELECT,
title: '传送至某玩家',
content: `你要传送你到谁的位置`,
options:playernamelist
});
if(!result || result.value === null){
return;
}
else{
for (const e of world.querySelectorAll('player')){;
if(e.player.name==result.value){;
entity.position.x=e.position.x
entity.position.y=e.position.y
entity.position.z=e.position.z
entity.player.directMessage('传送成功!')
};
};
}
}
else if(result.value=='集体传送附图!'){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '集体传送',
content: `请输入密码(找作者要)`,
confirmText: '确认',
});
if(!result || result === null){
return;
}
else if(result=='123456'){
world.say('管理员开启了集体传送,3s后全体传送至附图《春》')
await sleep(3000)
world.querySelectorAll('player').forEach((e)=>{
e.player.link(`https://dao3.fun/play/6d789dabd5e09ca687ce`, {isConfirm: false, isNewTab: false})
})
}
}
else if(result.value=='计时器'){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '计时器',
content: `你想计时多久`,
confirmText: '“确定”',
});
console.log(entity.count)
if(entity.count=true){
let s = 0
let m = 0
let h = 0
while(entity.count==true){
s++
if(s>=60){;m++;s=0}
if(m>=60){;h++;m=0}
if(h>=3){;entity.player.directMessage('计时最多3小时');return;}
entity.player.directMessage(h+':'+m+':'+s)
await sleep(1000)
}
}
else{
entity.player.directMessage('计时器关闭!')
}
}
else if(result.value=='广播公告'){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '广播公告',
content: `输入广播内容`,
confirmText: '确认广播',
});
world.say(result)
}
else if(result.value='躲猫猫模式'){
// entity.player.directMessage('因为重启服务器代码失效,现在禁用躲猫猫模式')
const zbz = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '躲猫猫模式',
content: `输入抓捕者`,
confirmText: '确认',
});
zbznc = zbz;
while(1){
const result = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '躲猫猫模式',
content: `输入躲藏者昵称,输入@以结束添加`,
confirmText: '确认',
});
if(result!=`@`){
dcz.push(result);
entity.player.directMessage(`添加成功,${result}`)
dmmrenshu+=1;
}
else{
break;
}
}
const a = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '躲猫猫模式',
content: `输入躲藏时间,单位秒,不可包含小数`,
confirmText: '确认',
});
dctime = parseInt(a)*16
const b = await entity.player.dialog({
type: GameDialogType.INPUT,
title: '躲猫猫模式',
content: `输入抓捕时间,单位秒,不可包含小数`,
confirmText: '确认',
});
zbtime = parseInt(b)*16;
if(dmm==false){
dmm = true;
world.say(`管理员 ${entity.player.name} 开启了躲猫猫模式`)
dialog(`提示`,`已开启躲猫猫模式`,entity)
}
else{
dialog(`提示`,`错误:\n已经有另外一个管理员开启了躲猫猫模式`,entity)
}
}
else if(result.value='穿戴配件'){
chuandaipeijian(entity)
}
}
}
}
else if(button=='action3'){
entity.player.cameraEntity=entity
}
})
// 模型运动
const lotus_leaf = world.querySelector('#荷叶-2') //获取实体
lotus_leaf.fixed = true//不受外力影响
lotus_leaf.collides = true//允许碰撞
const startPos_lotus_leaf = [63.7, 3.1, 3.7]//初始位置
const endPos_lotus_leaf = [75, 3.1, 3.7]
const ani_lotus_leaf = lotus_leaf.animate([
{ position: startPos_lotus_leaf, duration: 0 },
{ position: startPos_lotus_leaf, duration: 2 },
{ position: endPos_lotus_leaf, duration: 0 },
{ position: endPos_lotus_leaf, duration: 2 },
{ position: startPos_lotus_leaf, duration: 0 },
], {
duration: 16 * 4, //一个循环共用时
iterations: 1,//只播放1次
direction: GameAnimationDirection.WRAP,//让实体从终点回到起点
})
world.onPlayerJoin(({entity}) => {
ani_lotus_leaf.play({
duration: 16 * 4, //播放一个循环共用时20秒(每秒16帧),
iterations: Infinity,//动画无限次循环播放
direction: GameAnimationDirection.WRAP,//让动画实体从终点回到起点
})
})
// gui
// const { GameEasyGUI } = require("./GameEasyGUI.js"); //导入GameEasyGUI.js
// world.onPlayerJoin(async ({ entity }) => {
// var mygui = new GameEasyGUI("myGUI", entity);
// entity.gui = mygui; //创建一个gui对象
// var dom = mygui.document;
// var msg1 = dom.createXml("label", {
// height: 20,
// width: 200,
// color: "#fff",
// fontSize: 18,
// x: 10,
// y: 70,
// id:"msg1"
// });
// var group = dom.createXml("group", {
// width: 240,
// height: 160,
// borderColor: "rgba(0,0,0,0)",
// backgroundColor: "rgba(0,0,0,0.45)",
// right:20,
// top:50
// }).appendChild(dom.createXml("label", {
// height: 20,
// width: 100,
// color: "#fff",
// fontSize: 20,
// x: 10,
// y: 10,
// text: "聊天消息"
// })).appendChild(msg1); //将创建好的元素插入group中
// dom.appendChild(group); //将元素插入document中
// mygui.render(); //渲染gui
// var button = dom.createXml("button",{
// text:"戳我发消息(防禁言)",
// x:10,
// y:120,
// percentWidth:90,
// height:30,
// color:"#fa0"
// });
// button.addEventListener("click",async function({entity}){
// const result = await entity.player.dialog({
// type: GameDialogType.INPUT,
// title: '发言',
// content: `你想要说啥`,
// confirmText: '确定发送,反悔请点X',
// });
// if(!result || result === null){
// return;
// }
// else {
// world.say(entity.player.name+':'+result)
// msglist[0]=entity.player.name+':'+result
// }
// })
// group.appendChild(button);
// mygui.reload(); //刷新
// });
// //循环显示信息
// world.onTick(()=>{
// world.querySelectorAll('player').forEach((e)=>{
// if(e.gui){
// let dom = e.gui.document;
// let msg1 = dom.getElementById("msg1");
// msg1.setAttribute("text",msglist[0]);
// }
// })
// })
world.onPlayerJoin(({entity})=>{
world.onTick(({tick})=>{
if(dmm==true&&entity.dmmshoudao==false){
if(zbznc==entity.player.name){
entity.player.directMessage(`你是抓捕者`);
entity.player.color=new GameRGBColor(1,0,0);
entity.dmmzy='抓捕';
dialog(`操作说明`,`碰到躲藏者(黑色的人)即可抓获`,entity)
entity.dmmshoudao=true;
entity.position.set(2,6,10);
entity.player.canFly=true;
}
else if(dcz.includes(entity.player.name)){
entity.player.directMessage(`你是躲藏者,快开始躲藏吧!`);
entity.dmmzy='躲藏';
dialog(`操作说明`,`不要被红色昵称的抓捕者碰到!`,entity)
entity.player.color=new GameRGBColor(0,0,0);
entity.dmmshoudao=true;
entity.player.canFly=true;
}
}
if(dmm==true){
if(dctime==0){
if(dctime==0&&entity.dmmzy=='抓捕'){
entity.player.forceRespawn()
// dctime-=16;
}
}
}
})
})
world.onTick(async({tick})=>{
if(dmm==true){
if(dctime>=0){
if(tick%16==0){
dctime-=16;
world.say(`躲猫猫-躲藏时间还剩${dctime/16}秒`)
world.clearCollisionFilters()
// entity.dmmshoudao=true
}
}
else if(zbtime!=0){
if(tick%16==0){
zbtime-=16;
world.say(`躲猫猫-抓捕时间还剩${zbtime/16}秒`)
}
}
else{
dmm=false;
world.say(`躲猫猫结束,如3s后服务器未自行重启,请管理员输入\$while(1){} 进行重启`)
await sleep(3000)
while(1){}
}
}
})
world.onEntityContact(({entity,other})=>{
if(entity.dmmzy=='抓捕'){
if(other.dmmzy=='躲藏'&&beizhuadao.includes(entity.player.name)==false){
beizhuadao.push(other.player.name);
world.say(`抓捕者抓到了${other.player.name}`)
entity.player.directMessage(`恭喜抓到人了!经验+10`);
entity.exp+=10;
savePlayer(entity)
other.player.directMessage(`被抓到了了!经验+5`);
other.exp+=5;
savePlayer(other)
other.player.color=new GameRGBColor(1,1,1);
}
}
})
//挂机检测
// world.onPlayerJoin(({entity})=>{
// entity.xcundang= 0
// entity.ycundang= 0
// entity.zcundang= 0
// entity.i=0
// world.onTick(async({tick})=>{
// if(tick%16==0){
// if(entity.xcundang==entity.position.x&&entity.ycundang==entity.position.y&&entity.zcundang==entity.position.z){
// entity.i+=1
// console.log('挂机',entity.i)
// }
// else{
// entity.i=0
// entity.xcundang=entity.position.x
// entity.ycundang=entity.position.y
// entity.zcundang=entity.position.z
// }
// if(entity.i==130&&entity.cankick==true){
// entity.player.cancelDialogs()
// dialog('系统','你已在当前位置停留了5min,若继续停留,10s后将踢出游戏!\n挂机会导致服务器变卡,甚至崩服,为了服务器的健康,现在禁止挂机',entity)
// }
// else if(entity.i>=140&&entity.cankick==true){
// entity.i=0
// entity.player.kick()
// }
// }
// })
// })
world.onTick(({tick})=>{
if(tick%960==0){
const date = new Date(Date.now());
const minute = date.getMinutes()
if(minute==0){
world.say('整点福利:全体玩家经验+10')
world.querySelectorAll('player').forEach((e)=>{
e.exp+=10
savePlayer(e)
})
}
}
})
// 服务端、客户端信息交流/gameUi控制
world.onTick(({tick})=>{
remoteChannel.sendClientEvent(world.querySelectorAll('player'), {
type:'世界信息',
args:{
message: msglist[0]
}
})
world.querySelectorAll('player').forEach((e)=>{
remoteChannel.sendClientEvent(e, {
type:'玩家信息1',
args:{
avatar:e.player.avatar,
name:e.player.name,
player_title:e.player_title
}
})
remoteChannel.sendClientEvent(e, {
type:'玩家信息2',
args:{
wintimes: e.wintimes,
exp: e.exp,
x: e.position.x,
y: e.position.y,
z: e.position.z
}
})
})
})
console.clear()
const mscale = 1 / 16
const Quat = new GameQuaternion(0, 0, 0, 1)
function buddyFollow(entity, mesh, y) {
const buddy = world.createEntity({
mesh,
position: entity.position,
meshScale: [mscale, mscale, mscale],
gravity: false, //不受重力影响
fixed: false, //可推移
collides: false, //不可碰撞
friction: 0, //无摩擦力
mass: 0.01, //非常轻
})
const tgPos = entity.position
const budPos = buddy.position
const facing = entity.player.facingDirection//玩家的朝向
const ratio = 0.1//追随的灵敏度, 最好设在0.5左右, 1.0表示立即移到玩家位置
const dist = 2 //与玩家保持的距离
const yOffset = y //y轴位移, 保持僚机在头顶或脚下
const ticker = world.onTick(() => {
//要让小精灵跟在玩家背后, 需要计算xz轴的位移: 玩家朝向的反方向
const xOffset = -facing.x * dist
const zOffset = -facing.z * dist
//当前位置与目标位置在xyz轴的差距
const xDiff = tgPos.x - budPos.x
const yDiff = tgPos.y - budPos.y
const zDiff = tgPos.z - budPos.z
//计算xyz方向上 当前位置向目标位置靠拢的速度
const vx = (xDiff + xOffset) * ratio
const vy = (yDiff + yOffset) * ratio
const vz = (zDiff + zOffset) * ratio
buddy.velocity.set(vx, vy, vz)//设置僚机速度
if (buddy.velocity.sqrMag() > 0.005) {//速度要足够大, 才触发转向, 防止抖动
buddy.meshOrientation = Quat.rotateY(Math.atan2(zDiff, xDiff)) //让小精灵一直面向玩家
}
})
return () => {
ticker.cancel() //关掉tick循环
buddy.destroy() //移除实体
}
}
world.onPlayerJoin(({ entity }) => {
entity.setPet = buddyFollow(entity, 'mesh/皮卡丘.vb', -1) //给玩家增加宠物
})
world.onPlayerLeave(({ entity }) => {
//玩家离开地图时, 切记一定要关掉tick循环以及销毁小精灵实体, 否则随着人数增加, 服务器积累到一定程度就会崩溃
entity.setPet() //干掉宠物
})
world.onPlayerJoin(({entity})=>{
world.onTick(({tick})=>{
if(entity.position.x<0){
entity.velocity.x=1;
entity.player.directMessage('别想不开啊,跳虚空干啥?')
}
else if(entity.position.x>127){
entity.velocity.x=-1;
entity.player.directMessage('别想不开啊,跳虚空干啥?')
}
if(entity.position.z<0){
entity.velocity.z=1;
entity.player.directMessage('别想不开啊,跳虚空干啥?')
}
else if(entity.position.z>127){
entity.velocity.z=-1;
entity.player.directMessage('别想不开啊,跳虚空干啥?')
}
})
})
9d407ff9fa37673dc2906501a380cf67ec57f121