V0.33.0.0 Release Note
注意事项
资源库中的预制体使用时,改为网络资源引用的方式。
如果需要对预制体节点进行二次编辑或其他使用需求,可以手动将引用的网络预制体资源导入到工程内容库中:
对027遗留旧资源进行第二轮替换
在033上打开旧版本工程后,可能会弹出资源替换窗口,如:
若提示中存在需要修改的资源,可以按照版本更新手册 | 脚本资源替换,替换旧的资源。
新增功能
一、编辑器交互、资源管理、发版
[优化]属性面板去除“生存时间”
在之前的版本中,属性面板上存在失效的“生存时间”属性,为了防止其造成误解,在本次更新中我们将该属性去除。
033之前生存时间
033
[新增]网络预制体引用规则改进
由于之前版本中,从资源库拖动预制体到场景上时,会自动在工程内容中增添预制体文件,这可能在预览预制体时会造成工程内容的污染。所以在本次更新中,我们优化了网络预制体的引用规则。
创建预制体的改动:
- 优化前:从资源库中拖拽一个预制体到场景中时,会自动在工程内容中创建一份预制体资源,对象列表中引用的是工程内容中的预制体;
- 优化后:从资源库中拖拽一个预制体到入场景中时,对象列表将直接引用网络资源,不会在本地创建预制体文件;
预制体编辑的改动:
- 优化前:由于已经在工程内容中创建了预制体资源,所以可以直接对预制体的节点信息、属性进行编辑;
- 优化后:可以直接编辑引用的网络资源的属性,但如果需要编辑节点信息,需要先手动将预制体导入到本地工程。
二、UI编辑器功能新增及优化
[新增]安全区适配及机型预览功能
我们注意到,当前游戏项目在异形屏手机上运行时(尤其是 IPhone X 等 IOS 设备),UI可能会被刘海屏挡住,或者出现在无法进行点击交互的区域。为了解决这个问题,我们新增了以下功能:
在UI文件的 Root 层级(对应 UserWidget 类中的 safeAreaEnable 属性)中,我们新增了【适配安全区】属性。默认情况下,这个功能是关闭的。
勾选了【适配安全区】的UI文件在实例化为UI对象时,会自动读取玩家设备信息,并自动调整此UI文件中 RootCanvas 层级的尺寸和位置,将其收进异形屏设备的安全区范围内,从而避开 iPhone X 刘海屏、屏幕内部摄像头等无法显示/点击的区域,包括横屏翻转屏幕或者竖屏游戏的情况;同时不影响非异形屏设备的UI显示。
推荐用法:
- 需要适配的UI控件,仅需任意一级父级UI文件(UserWidget)开启【适配安全区】即可,不要重复开启;不需要适配的UI控件,要保证其任意一级父级UI文件(UserWidget)都没有开启【适配安全区】;
- 因此,推荐只将某个顶端父节点的全屏UI文件开启【适配安全区】,将需要做适配的UI都放在其内部,或者动态生成到其内部作为子级。或者仅给多个同级UI文件开启【适配安全区】。
控制是否开启【适配安全区】API:
属性名称 | 英文名称 | 类型 | 默认值 | 说明 | 读写 | 分组 |
---|---|---|---|---|---|---|
适配安全区 | safeAreaEnable | Boolean | false | 开启后,此UI文件的RootCanvas层级将自动适配到 iPhone X 等iOS和Android异形屏手机的安全区域大小,建议仅在全屏的UI中开启 | Read / Write | UI编辑器-Root-默认 |
- 主编辑器和UI编辑器的机型预览菜单新增了若干种预设机型,便于直接选择
主编辑器中选择预览某种机型后,主视口内的显示区域和运行时窗口的尺寸能调整为该机型的长宽比;
UI编辑器中选择预览某种机型后,能将该UI文件的设计尺寸自动调整为该机型的分辨率,同时应用DPI缩放,选择存在安全区配置的机型还能预览此UI文件的安全区适配情况;如果手动修改了设计尺寸,会结束机型预览状态,自动切换为主视口平铺状态。
- UI编辑器中新增预览聊天框的区域,与主视口的聊天框区域类似,建议UI摆放尽量空出这一区域
- 目前UI编辑器中聊天框区域的提示没有单独控制是否展示的开关,如果想要关掉,请取消勾选【主编辑器右上角——显示——聊天框区域】。
注意事项:
- 创建一个新的开启安全区适配的UI对象,会需要一帧的时间完成计算,会表现为UI闪烁一下后收进安全区,如果不希望有这个延迟,应将新建的UI对象挂在已经创建好的开启安全区适配的UI对象内作为其子级;
- 开启【适配安全区】后,RootCanvas层级会根据玩家设备的变化而变化。它的工作原理是在四周空出该机型上下左右的安全区边距。因此,即使此UI文件不会作为全屏UI使用,开启【适配安全区】时,在异形屏设备上也会留出空白。因此,当您制作背包等列表时,存放每个条目的非全屏UI文件不需要开启【适配安全区】
- 与上一条类似,在多个UI文件嵌套的情况下,如果将一个UI文件作为自定义控件挂载在另一个UI文件下作为子级时,且父级UI文件和子级UI文件同时开启了【适配安全区】,在父级UI文件适配的基础上,子级UI文件还会再进行一次适配,这会导致子级UI文件内部的控件“叠加两次适配”,空出了两倍的间距,要注意避免这种用法。;
- 即使是全屏UI也不意味着一定应该开启【适配安全区】,例如现在要制作一个加载等待界面,用一张全屏图片覆盖住屏幕,如果这张图片也受【适配安全区】影响,在异形屏手机上会表现为四周留出空白。因此不同情况的UI是否应该开启【适配安全区】需要由按照业务需求自行选择。
三、编辑器新增功能及API更新
[新增]实体建模工具
编辑器中的基础模型支持布尔运算,可以使用实体建模工具对两个及以上的物体进行并集、差集运算,通过组合一些基本的静态模型,如方块、球体和圆柱体等,来创建新的复杂模型,可以自由组合出符合项目和游戏需求的物件。
- 组合:将多个模型融合为一个模型。
- 镂空:将模型设置为镂空状态。
- 分离:将融合模型分离为原始状态。
实体建模工具仅适用于静态模型中的基础模型,可以使用工具栏中的模型工具快捷创建。
组合工具
基础模型可以使用组合工具(快捷键:Ctrl+Shift+U) 将多个模型融合为一个模型,若基础模型材质不同,则操作后的融合模型继承运算时首个输入模型的材质,如A+B再+C,则A+B+C的融合模型继承A模型的材质。
组合规则1:若选中的基础模型和融合模型都未产生交集,则组合时将所有选中对象组合为一个模型,镂空模型进行隐藏。
组合前
组合后
组合规则2:若产生交集的对象为实体对象+实体对象,则使用组合工具时,将选中的实体对象之间进行并集集合运算。
组合前
组合后
组合规则3:若产生交集的对象为镂空对象+镂空对象,则使用组合工具时,将选中的镂空对象之间进行并集集合运算。
组合前
组合后
组合规则4:若产生交集的对象为实体对象+镂空对象,则使用组合工具时,进行差集集合运算,从实体对象中减去与镂空对象重合的部分,镂空对象隐藏不可选中。
组合前
组合后
组合规则5:若选中对象中,同时存在以上情况,既包含未产生交集的对象,又包含产生交集的对象(实体+实体 / 镂空+镂空 / 实体+镂空),则使用组合工具时,将产生交集的基础模型按照上述规则进行分别计算。
组合前
组合后
镂空工具
基础模型可以使用镂空工具(快捷键:Ctrl+Shift+N)在实体状态和镂空状态之间切换。
镂空规则1:若选中对象皆为实体状态对象,则使用镂空工具时,所有实体状态的基础模型将切换为镂空状态。
镂空前
镂空后
镂空规则2:若选中对象皆为镂空状态对象,则使用镂空工具时,将所有镂空状态的基础模型切换为实体状态。
镂空前
镂空后
镂空规则3:若选中对象中同时包含实体状态和镂空状态对象,则使用镂空工具时,将所有基础模型切换为镂空状态,再次使用镂空工具,将所有基础模型切换回实体状态。
镂空前
镂空后
分离工具
融合模型可以使用分离工具(快捷键:Ctrl+Shift+S)将组合起来的各个模型还原。
若选中对象中包含融合模型,则使用分离工具时,按照组合顺序依次对融合模型进行分离。如A+B求并集后,再与C求并集,则分离时先将融合模型分离为Union(A+B)和C,再次分离时分离A和B。
分离前
分离后
保存为本地文件
在对象管理器中右键选中组合模型时,可以在右键菜单中将该模型保存为本地文件,存储在在工程内容-模型路径下,命名为对象管理器中的命名,若出现名称相同的情况,则自动在名称后面添加正序序号1/2/3...
模型列表中的文件支持拖入到场景和预制体中,生成一个新的融合模型,二者之间无引用关系。支持在主视口中还原为融合前的各个基础模型并支持继续对各个基础模型进行二次调整。
融合后的属性
实体模型和融合模型的属性与当前编辑器中基础模型的属性相同。
镂空模型的碰撞始终关闭,其它属性与当前编辑器中基础模型的属性相同。
融合模型自动生成复杂碰撞和简单碰撞。
[新增]死亡边界功能
为了防止玩家意外坠落到地图边界时,出现一直坠落的情况,我们提供了死亡边界功能。死亡边界开启后,角色在接触到死亡边界时,将会触发死亡状态,物体在接触到死亡边界时,触发删除功能。不启用时,死亡边界高度的属性将会被隐藏。
启用死亡边界和死亡边界高度需要在设置面板中设置:
可以在脚本中获取当前死亡边界的高度,但暂不支持在脚本中修改
EnvironmentSettings
类新增属性
属性名称 | 英文名称 | 类型 | 默认值 | 说明 | 读写 |
---|---|---|---|---|---|
死亡边界高度 | deathBoundaryHeight | number | -1000 | 角色超过死亡边界高度时,将会被重置至出生点。物体超过死亡边界高度时,将会直接被删除。 | Only Read |
死亡边界开关 | deathBoundaryEnabled | bool | false | 控制死亡边界的开启与关闭 | Only Read |
[优化] 脚本逻辑 & 生命周期梳理
在每帧tick期间,可以在代码多个入口写入业务逻辑。033版本将大部分脚本逻辑固定执行顺序,至此脚本的每一帧有一个比较清晰的帧生命周期和执行顺序。
注意
通过delegate注册监听的一些事件,如动画播放完成之类的,这些事件的业务逻辑在整个生命周期中的执行顺序无法控制,时序不定
[新增]支持TS监测当前触发层级是否为UI控件
<Class><ScreenUtil>
- 屏幕工具
方法
功能说明 | 方法名 | 返回类型 | 输入说明 | 输出说明 | 使用域 |
---|---|---|---|---|---|
检查屏幕坐标点处是否有UI控件 | checkWidgetAt(screenPosition: Vector2): boolean | boolean | screenPosition屏幕坐标 | 检查结果,如果屏幕坐标处存在UI控件返回true。 | 仅客户端 |
获取屏幕坐标点处的UI控件 | getWidgetAt(screenPosition: Vector2): Widget | Widget | screenPosition屏幕坐标 | UI控件,如果屏幕坐标处不存在UI控件返回null。 | 仅客户端 |
[新增]新增Touch回调事件,不受其他影响始终会在屏幕上响应
<Class><InputUtil>
功能说明 | 方法名 | 返回类型 |
---|---|---|
获取手指按下代理,不被UI影响的输入事件 | onRawTouchBegin | MulticastDelegate<(FingerIndex: number, Position: mw.Vector2) => void |
获取手指滑动代理,不被UI影响的输入事件 | onRawTouchMove | MulticastDelegate<(FingerIndex: number, Position: mw.Vector2) => void |
获取手指抬起代理,不被UI影响的输入事件 | onRawTouchEnd | MulticastDelegate<(FingerIndex: number) => void |
四、游戏功能对象新增功能及API更新
[优化]水体优化
- 水体功能我们进一步优化,完善了水体预设,并新增了屏幕空间反射效果。
- 画质分级为7、8、9时自动开启,暂不支持手动开启
- 详情请见产品手册:水体区域 | 产品手册
[新增]角色基础状态二期(角色推动/角色死亡/角色起身)
我们补充了角色基础状态,新增了角色推动状态、角色死亡状态、角色起身状态。
角色基础状态 | 枚举 | 说明 |
---|---|---|
推动状态 | Pushed | 角色在被其他角色推动的状态 |
死亡状态 | Dead | 角色在死亡时的状态。 |
起身状态 | GettingUp | 角色在触发布娃娃状态后的起身状态 |
推动状态
用法:通过调用setStateEnabled方法开启角色的推动状态开关
TypeScript
Player.asyncGetLocalPlayer().then((player) => {
this.character = player.character;
// 开启角色的推动状态
this.character.setStateEnabled(mw.CharacterStateType.Pushed, true)
// 监听状态改变
// prevState: mw.CharacterStateType, currentState: mw.CharacterStateType
this.character.onStateChanged.add((ps, cs)=>{
console.log("ps, cs ", ps, cs);
})
});
Player.asyncGetLocalPlayer().then((player) => {
this.character = player.character;
// 开启角色的推动状态
this.character.setStateEnabled(mw.CharacterStateType.Pushed, true)
// 监听状态改变
// prevState: mw.CharacterStateType, currentState: mw.CharacterStateType
this.character.onStateChanged.add((ps, cs)=>{
console.log("ps, cs ", ps, cs);
})
});
开启后的角色将能被其他角色推着走:
死亡状态
角色切换到死亡状态后会自动播放死亡动画,并在3秒后在离死亡地点最近的出生点复活,复活过程会从死亡状态切换回地面移动状态
起身状态
当角色在布娃娃状态时,可以使用changeState(CharacterStateType.GettingUp)让角色更为自然的恢复到地面状态,使用代码如下:
TypeScript
jumpBtn.onPressed.add(() => {
Player.asyncGetLocalPlayer().then((player) => {
this.character = player.character;
//使角色进入起身状态
this.character.changeState(CharacterStateType.GettingUp)
});
})
attackBtn.onPressed.add(() => {
Player.asyncGetLocalPlayer().then((player) => {
this.character = player.character;
//使角色进入布娃娃状态
this.character.changeState(CharacterStateType.Ragdoll)
});
})
jumpBtn.onPressed.add(() => {
Player.asyncGetLocalPlayer().then((player) => {
this.character = player.character;
//使角色进入起身状态
this.character.changeState(CharacterStateType.GettingUp)
});
})
attackBtn.onPressed.add(() => {
Player.asyncGetLocalPlayer().then((player) => {
this.character = player.character;
//使角色进入布娃娃状态
this.character.changeState(CharacterStateType.Ragdoll)
});
})
角色将根据布娃娃状态,自动播放起身动画:
- 详情请见产品手册:角色基础状态 | 产品手册
[新增]获取角色morph位置接口
- 我们提供了通过角色的MorphName实时获取顶点位置的接口,方便大家制作捏脸功能时绘制UI。
功能说明 | 方法名 | 返回类型 | 输入说明 | 输出说明 | 使用域 |
---|---|---|---|---|---|
通过头部模型MorphName实时获取所有对应的顶点位置 | getVertexArrayByMorphName(morphName: string): Array 【Vector】 | Array【Vector】 | MorphName | 获取morph对应所有顶点位置 | Server & Client |
通过头部模型MorphName实时获取中心顶点位置 | getCenterVertexByMorphName(morphName: string): Vector | Vector | MorphName | 获取中心顶点位置 | Server & Client |
[新增]提供角色mesh旋转参数
- 基于原来的mesh偏移我们进行调整和新增,将原来的meshOffset废弃,新增meshPositionOffset,用来控制角色mesh的相对坐标偏移。新增meshRotationOffset,用来控制角色的旋转偏移。(碰撞盒不变)
属性名称 | 英文名称 | 类型 | 说明 |
---|---|---|---|
角色模型的坐标偏移 | meshPositionOffset | vector | 用于设置角色mesh相对角色位置偏移 |
角色模型的旋转偏移 | meshRotationOffset | Rotation | 用于设置角色mesh相对角色旋转偏移 |
- meshPositionOffset应用场景 - 滑板模型在脚下,角色漂浮
- meshRotationOffset应用场景 - 直升机倾斜,角色跟着倾斜
修复BUG
[修复] 角色对象setVisibility,第二参数propagateToChildren = false不生效
以头顶UI为例(挂载在角色胶囊体上)
修复前:character.setVisibility(false, false),角色隐藏+头顶UI隐藏
修复后:character.setVisibility(false, false),角色隐藏+头顶UI显示
之前项目中如果使用propagateToChildren = false,但是期望挂载子对象一起隐藏,则需要进行下列改动:
TypeScript
// 第二个参数默认值为true
character.setVisibility(false);
// 指定propagateToChildren = true
character.setVisibility(false, true);
// 第二个参数默认值为true
character.setVisibility(false);
// 指定propagateToChildren = true
character.setVisibility(false, true);