Skip to content
V0.22.0.0 Release Note

V0.22.0.0 Release Note

注意事项

1、预制体重构项目升级教程及注意事项

2、23版本之前游泳区域存在边缘区域不生效的问题,所以部分游戏中的游泳区域设置的要比实际区域大,在023版本,游泳区域边缘不生效的问题将被修复,问题修复后会出现游戏场景中非游泳区域也在游泳的情况,因此需要大家看一下自己游戏中游泳区域的部分,并且在022游戏更新之前,写一个“根据版本,去走不同游泳区域大小”的兼容(022和022之前的版本走的是场景中设置的游泳区域大小,022之后版本走的是脚本中重新设置的游泳区域大小)

3、目前部分工程可能存在单端NPC下陷问题,后续会有需求修复此问题,目前可以通过修改NPC为双端来临时解决下陷问题

4、【兼容】针对目前的资源加载流程来说,判断本地资源是否存在对用户来说是没有意义,且asyncDownloadAsset自行判断本地资源不存在时,会进行下载并加载,未加载的资源本身就不存在同步加载的情况,022版本作了以下修改,两个版本后即024版本移除兼容 (1)移除资源是否存在接口(AssetUtil.isAssetExist)及资源同步加载接口(AssetUtil.loadAsset) (2)保留资源是否加载接口(AssetUtil.isAssetLoaded)及异步下载并加载接口( AssetUtil.asyncDownloadAsset),并修改isAssetLoaded为assetLoaded

新增功能

[新增] Prefab重构

目的

  • 解决了旧版prefab需要同时维护多份相同UI、脚本、材质的问题;同时简化了prefab结构

概述

  • 关键改动:以预制体代替原先预制体包的概念,与工程内容中的脚本、UI、材质是纯引用关系
  • 工程内容中修改原先预制体目录结构,去掉文件夹结构,只保留.prefab文件

022-1

主要功能点

工程内容相关修改

新版本的prefab支持在工程内容中进行常规操作,包括创建文件夹、拖动挂载等

预制体删除
删除预制体时,弹出二次确认弹窗
  1. 若该预制体在场景中存在引用对象
     1. ![022-2](https://arkimg.ark.online/022-2.PNG)

     2.  点击【删除引用对象】,将该预制体删除,该预制体在对象管理器中的所有**普通状态**引用对象同步删除,该预制体在对象管理器中的所有**实例状态**引用对象保存 
     3. 点击【解除引用关系】,将该预制体删除,该预制体在对象管理器中所有**普通状态**引用对象执行【解除预制体】操作,该预制体在对象管理器中的所有**实例状态**引用对象保存 
     4. 删除文件夹时,自动执行“删除引用对象”逻辑
  2. 若该预制体在场景中不存在引用对象
     1. ![022-3](https://arkimg.ark.online/022-3.PNG)

     2. 点击【确定】,将该预制体删除 
     3. 点击【取消】,关闭弹窗,取消本次操作 
导出相关修改
  1. 老版本导出:将该预制体包压缩后导出
  2. 新版本导出:将该预制体描述文件(.prefab文件)以及所有其引用的文件全部导出,并保证文件之间的相对路径不变
    1. 若脚本/UI中引用了其他脚本,多次引用的脚本及路径信息一并导出,保证相对路径不变
导入相关修改
  1. 导入时将恢复预制体描述文件
    1. 恢复预制体描述文件至工程内容预制体分类当前路径下
  2. 导入时将恢复所有引用文件
    1. 恢复预制体引用的脚本、UI、材质至工程内容对应分类下,恢复其原路径
  3. 导入时需要进行冲突校验,文件冲突判断逻辑如下:

022-4

  1. 当GUID相同但文件名或内容不同时,出现覆盖/重命名选项,此时的重命名的文件生成路径为导入的prefab中该文件的路径;覆盖时生成的路径为原工程中该相同GUID文件的路径
    1. 选择重命名时,由于GUID相同,导致新导入的prefab将自动引用到原工程中同GUID的文件,并且后续无法定位到问题,此处提示如下

    2. 022-5

    3. 选择覆盖时,生成的实际位置为原工程中相同GUID文件的位置,提示如下

    4. 022-6

    5. 显示不完时用省略号代替,hover文本时出现完整文本tips

  2. 当GUID相同且文件名与内容均相同时,不执行操作(忽略)
  3. 当GUID不同,但相同路径下存在同名文件时,提供重命名/覆盖操作
  4. 当GUID不同,且相同路径下不存在同名文件时,提示新增
  5. 显示该prefab所有文件结构及解决方式,标题为“xxx预制体导入”

022-7

  1. 文件路径置灰,只高亮叶子节点
  2. 存在两种不可操作的情况,分新增和忽略
    1. 新增:同路径下没有此重名文件;在导入面板显示new图标,不提供操作

    2. 022-8

    3. 忽略,同路径下存在完全相同的一份文件;仅显示其结构,不显示图标和操作

    4. 022-9

  3. 解决方式,以下拉菜单形式显示显示解决方式,包含以下两种选项
    1. 覆盖(默认)
      1. 选择覆盖,导入时将导入的文件覆盖导入;并在文件右侧显示覆盖图标

        022-10

      2. 选择覆盖时,弹窗顶部将显示警告文本,并会在点击导入后出现二次弹窗

        022-11

        022-12

    2. 重命名
      1. 选择重命名,导入时将导入的文件自动重命名导入

        1. 命名规则为文件名+“_1”,若重命名后的文件在原工程依然存在,则增加序号,直到原工程此路径下没有重名后的文件为止;此时再把名称显示至导入窗口

          022-13

      2. 对于脚本类型而言,若重命名修改的脚本正在被其他脚本引用,则树状结构中显示引用此脚本的脚本文件,并在此脚本后显示文本:“该脚本引用了xxx.ts,导入后请手动修改”

        022-14

        1. 此情况若与重名情况同时发生,则显示在操作说明后方

          022-15

  4. 导入位置
    1. 若从本地导入,生成至当前目录下
    2. 若从资源库导入,生成至当前目录下;若当前未进入预制体目录,则生成至预制体根目录下
解除预制体

022-16

  1. 新增“解除预制体”功能,右键预制体头结点可使用
  2. 功能:将此预制体引用对象逻辑改为普通对象
    1. 删除预制体头文件,对象均变为普通对象(紫色——白色)

[新增] 逻辑对象tips支持链接跳转

  • 鼠标悬浮至逻辑对象图标上时,tips会显示描述与官方文档
  • tips显示后,按住alt可固定tips;固定后点击“查看官方文档”蓝色文字即可打开官方文档地址

022-17

[新增] 菜单栏工程右键增加删除缓存功能

  • 功能:删除DBCache文件夹

022-18

[优化] 对象管理器筛选逻辑优化

  • 当前版本:筛选结果为满足任意一个筛选条件的所有对象(如筛选双端动态,则显示满足双端的对象+满足动态的对象)
  • 新版本:
    • 在同一类型内(如双端、客户端、服务端)筛选逻辑与老版本一致
    • 不同类型属性(如双端、动态、预制体)取同时满足全部所选条件的对象,即取交集

[优化] 音效播放以及手动下载相关逻辑优化

  1. 音效播放快捷键新增tips提示

022-19

  1. 资源下载逻辑优化
    1. 当前版本:鼠标点击时,执行下载
    2. 优化方案:选中后,执行下载
  2. 音效自动播放
    1. 在预览窗口打开的前提下,已下载的音效在选中时将进行自动播放,只播放一次
      1. 未下载的音效在选中时自动执行下载逻辑,并在下载完成后自动播放
    2. 切换音效时会终止上一个音效的播放,并开启当前选中的音效播放

[优化] 异步生成对象入参形式

通过该接口生成的对象是直接按照Transform的输入生成,避免先生成在原点,然后修改位置(旋转,缩放)。

新接口:

TypeScript
interface SpawnInfo {
    /** @description 资源guid或物体guid */
    guid?: string;
    /** @description 是否同步 */
    replicates?: boolean;
    /** @description transform */
    transform?: Transform;
}

/**
 * @description 异步构造一个 GameObject 资源不存在会先去下载资源再去创建
 * @effect 调用端生效
 * @param spawnInfo usage: 构建物体的信息
 * @returns 构造的GameObject
 */
static asyncSpawn<T extends GameObject>(spawnInfo: Type.SpawnInfo): Promise<T>;
interface SpawnInfo {
    /** @description 资源guid或物体guid */
    guid?: string;
    /** @description 是否同步 */
    replicates?: boolean;
    /** @description transform */
    transform?: Transform;
}

/**
 * @description 异步构造一个 GameObject 资源不存在会先去下载资源再去创建
 * @effect 调用端生效
 * @param spawnInfo usage: 构建物体的信息
 * @returns 构造的GameObject
 */
static asyncSpawn<T extends GameObject>(spawnInfo: Type.SpawnInfo): Promise<T>;

示例:

TypeScript
let obj = await Core.GameObject.asyncSpawn({guid: "7669", replicates: true, transform: Type.Transform.identity});
let obj = await Core.GameObject.asyncSpawn({guid: "7669", replicates: true, transform: Type.Transform.identity});

[新增] 角色编辑器开放手脚编辑项

  • 手掌缩放(设置范围为0-5)

  • 022-20022-21
    缩放值为1缩放值为5
  • 脚掌缩放(设置范围为0-5)

    • 022-22022-23
      缩放值为1缩放值为5

[新增] 捏人数据预览时新增默认装扮

若保存的角色文件中仅包含体型与姿态数据,则在预览窗口中进行预览时,新增默认装扮。

022-24

[UI] 新增UI组件-遮罩按钮

  • 遮罩按钮是一种遮挡、遮盖部分图像内容,并显示特定区域的图像内容的UI组件;可用于实现技能冷却按钮、特殊形状按钮的遮罩效果;也可以不作为按钮,而用于场景过度、图片切割等效果。

    • 注意:如果不作为按钮使用时,请将可见性修改为可见不可交互仅自身(SelfHitTestInvisible)

    • 具体使用方法详见产品手册UI 控件-遮罩按钮

    • 022-25022-26
    • 022-27

[UI] 进度条组件新增属性-条厚度

  • 进度条组件的可操作范围与图片大小分离为两个属性,允许渲染图形大小和可操作范围分别设置不同大小
    • 1.进度条的【变换】-【大小】是组件实际可以操作范围的大小,也就是下方动图中的蓝框,这个范围内都允许玩家点击和拖动,滑动值均为点击/拖动点作垂线到进度条上的值
      • 修改【变换】-【大小】时,只会改变进度条滑动填充图片和滑动背景图片渲染图形的长度,并不会改变其宽度
    • 2.进度条的【条厚度】为本次新增属性,用于修改进度条滑动填充图片和滑动背景图片渲染图形的宽度
    • 3.在【滑动按钮图片】-【图片大小】单独修改滑动按钮图片大小,与【变换】-【大小】或【条厚度】无关
022-28022-29022-30
【变换】-【大小】【滑动设置】-【条厚度】【样式】-【滑动按钮图片】-【图片大小】

022-31

  • 此外,也可以在脚本中修改【条厚度】这一属性

ProgressBar类新增Accessors

属性名称用法说明类型使用域
barThicknessget barThickness(): number;set barThickness(inputBarThickness: number);进度条厚度numberClient
  • 示例:
TypeScript
//找到对应的进度条
const slider = this.uiWidgetBase.findChildByPath('MWCanvas/ProgressBar_1') as UI.ProgressBar
//修改barThickness
slider.barThickness=50
//找到对应的进度条
const slider = this.uiWidgetBase.findChildByPath('MWCanvas/ProgressBar_1') as UI.ProgressBar
//修改barThickness
slider.barThickness=50

[UI] 进度条组件新增属性-进度条滑动方式

  • 此前,进度条组件的滑动方式为——点击并滑动才能改变进度条的值,本次新增了另一种滑动方式——点击就会立刻改变进度条的值,滑动也会正常改变
  • 可以在脚本中修改【进度条的滑动方式】这一属性,预计后者作为默认值能满足大多数使用场景,所以该属性暂未暴露到属性面板

ProgressBar类新增Accessors

属性名称用法说明类型使用域
slideMethodget slideMethod(): SlideMethod;set slideMethod(inSlideMethod: SlideMethod);进度条的滑动方式inSlideMethod: SlideMethodClient

新增枚举——SlideMethod

枚举类型数值说明
PressOrSlide(默认值)0点击到进度条的可交互范围内,就会立刻根据点击位置改变当前值,并且把滑动按钮移动到当前点击的位置,后续滑动也能正常改变当前值
Slide1点击并滑动才能改变进度条的值,仅点击时不会改变
  • 示例:
TypeScript
//找到对应的进度条
const slider = this.uiWidgetBase.findChildByPath('MWCanvas/ProgressBar_1') as UI.ProgressBar
//修改SlideMethod
slider.slideMethod=1
//找到对应的进度条
const slider = this.uiWidgetBase.findChildByPath('MWCanvas/ProgressBar_1') as UI.ProgressBar
//修改SlideMethod
slider.slideMethod=1

[UI] 摇杆组件控制摄像机时的手感优化

  • 此前,当摇杆的控制方式=摄像机控制时,会将摇杆当前的(x,y)值作为摄像机的横纵向速度,所以摇杆从(0,0)到(1,1)过程中速度由慢到快,有延迟感;而摇杆到(1,1)时,速度又太快;手指停止移动时,摇杆当前值如果不在(0,0)点,摄像机仍会移动难以瞄准,这些都使得摇杆控制摄像机的手感不佳

022-33

  • 因此,本次更新优化了摇杆控制摄像机时的逻辑,修改为:

    • 从按下摇杆开始计算,手指/鼠标移动时,摄像机方向就会移动;手指停下时,摄像机也停下。类似操控摄像机滑动区,摄像机旋转速度只与手指/鼠标移动速度有关,与摇杆当前的(x,y)值完全无关
    • 释放摇杆时,摄像机就停留在原方向,也于摄像机滑动区逻辑类似
      • 022-34
    • 手指移动单位距离所对应摄像机的旋转角度大小可以通过调整摇杆组件的灵敏度来调整,推荐将灵敏度比例设置为(0.15,0.15),后续版本会此为默认值
      • 022-35
  • 本次优化后,非常推荐大家使用摇杆制作射击游戏的开火键,下面是热武器prefab测试摇杆优化前后效果的示例项目:

优化后

优化前

移动端效果

  • 提示:如果需要为PC端提供控制方案,可以将开火摇杆的仅按下/抬起绑定在鼠标左键,这样,玩家可以按住鼠标右键拖动或者直接拖动鼠标(鼠标锁定时)来转动摄像机进行瞄准,并使用左键触发摇杆完成开火

022-39

[UI] Tips漏缺补充

  • 为了便于查阅各项属性和功能的用法,全面补充了UI编辑器内此前缺失的Tips;在022online版本,各UI组件的产品手册链接也将增加到Tips内
022-40022-41
022-42022-43

[UI] 按钮组件继承PanelWidget的getchild等功能

  • 为了给按钮组件的子级文本组件补充常用的组件获取方式,Button类调整为继承PanelWidget类,允许在TS中使用PanelWidget的getChildAt、addChild、removeChild来获取、添加、移除按钮组件的子级文本组件
  • 示例:
TypeScript
//找到对应的跳跃按钮
const JumpBtn = this.uiWidgetBase.findChildByPath('Canvas/Button_Jump') as UI.Button
//找到跳跃按钮的子级文本组件
let text =JumpBtn.getChildByName("text") as UI.TextBlock
//找到对应的跳跃按钮
const JumpBtn = this.uiWidgetBase.findChildByPath('Canvas/Button_Jump') as UI.Button
//找到跳跃按钮的子级文本组件
let text =JumpBtn.getChildByName("text") as UI.TextBlock

[UI] UI编辑器对象列表及设计器的一些易用性优化

  • 1.此前执行UI组件复制粘贴操作的要求过于严格,必须要选中容器才能完成粘贴操作;为了更符合使用习惯,我们将此复制粘贴逻辑优化为:选中不能挂子级的UI组件并且粘贴时,也要能粘贴创建组件,并且把新组件放在粘贴时所选中组件的同级

    • 举个例子,如果选中按钮组件后,粘贴一个图片组件,会允许粘贴并且把图片粘贴在按钮的同级

    • 无论是设计器和对象列表中,也无论是快捷键复制粘贴还是右键菜单,只要是复制粘贴创建组件都会遵循以下逻辑:

      • 粘贴时选中的组件A(粘贴时必须选中组件个数=1是才能粘贴成功,如果选中了多个组件,粘贴一个或者多个组件都会失败)所粘贴创建的组件B创建结果(新建的组件保持现有逻辑,放在父级下的对象列表最下方,也就是渲染在最顶层)粘贴创建多个组件BC的情况
        能挂任意子级的组件(目前只有容器/滚动框)任意UI组件/自定义UIB创建在A的子级BC创建在A的子级
        只能挂特定子级的组件(目前只有按钮)能挂的UI组件(对于按钮来说只有文本)B创建在A的子级如果BC都是能挂到A的UI组件,BC都创建在A的子级如果BC都是不能挂到A的UI组件,BC都创建在A的同级如果B能挂,C不能挂,那么B创建在A的子级,C创建失败
        不能挂的UI组件以及自定义UIB创建在A的同级
        不能挂子级的组件(图片等)任意UI组件/自定义UIB创建在A的同级BC创建在A的同级
  • 2.拖动UI组件在列表中到达列表的上下边缘时,列表会向上滑或者下滑

022-44

  • 3.为了提升使用效率,拖入到设计器进行UI组件创建时,把新创建的UI组件挂载到其所允许挂载的鼠标释放位置的最上层的PanelWidget组件(容器/滚动框/按钮)

022-45

  • 4.UI编辑器设计器标尺显示逻辑优化
    • 使用鼠标滚轮调整缩放时,网格大小的逻辑修改为:
      • +7~-3:一大格为100
      • -4~-5:一大格为200
      • -6~-9:一大格为400
      • -10~-12:一大格为800
    • 调整设计器顶部【微调】的值时,网格大小将不再改变

022-46

[优化]寻路功能的moveTo()接口,将角色和NPC使用方法统一

TypeScript
/*优化前
  角色需要在客户端(主控端)进行调用;
  NPC需要在服务端进行调用;
*/
@Core.Class
export default class Nav extends Core.Script {
    protected onStart(): void {
        let player = Gameplay.getCurrentPlayer();
        let NPC = this.gameObject as Gameplay.NPC;
        let targetLocation= new Type.Vector(1400, 600, 0);
        
        //角色寻路
        InputUtil.onKeyDown(Type.Keys.One, () => {
            Gameplay.moveTo(player.character, targetLocation);
        });
        
        //NPC寻路,只能在服务端进行调用
        InputUtil.onKeyDown(Type.Keys.One, () => {
             this.AImoveTO(NPC,targetLocation);
        });
    }

    @Core.Function(Core.Server)
    AImoveTO(NPC:Gameplay.NPC,loc:Type.Vector){
        Gameplay.moveTo(NPC,targetLocation);
    }
}

/*优化后
  角色和NPC的调用方法通一,都可以(主控端)进行调用;
*/
@Core.Class
export default class Nav extends Core.Script {
    protected onStart(): void {
        let NPC = this.gameObject as Gameplay.NPC;
        let player = Gameplay.getCurrentPlayer();
        let targetLocation= new Type.Vector(1400, 600, 0);

        //角色、NPC寻路
        InputUtil.onKeyDown(Type.Keys.One, () => {
            Gameplay.moveTo(player.character, targetLocation);
            Gameplay.moveTo(NPC,targetLocation);
        });
    }
}
/*优化前
  角色需要在客户端(主控端)进行调用;
  NPC需要在服务端进行调用;
*/
@Core.Class
export default class Nav extends Core.Script {
    protected onStart(): void {
        let player = Gameplay.getCurrentPlayer();
        let NPC = this.gameObject as Gameplay.NPC;
        let targetLocation= new Type.Vector(1400, 600, 0);
        
        //角色寻路
        InputUtil.onKeyDown(Type.Keys.One, () => {
            Gameplay.moveTo(player.character, targetLocation);
        });
        
        //NPC寻路,只能在服务端进行调用
        InputUtil.onKeyDown(Type.Keys.One, () => {
             this.AImoveTO(NPC,targetLocation);
        });
    }

    @Core.Function(Core.Server)
    AImoveTO(NPC:Gameplay.NPC,loc:Type.Vector){
        Gameplay.moveTo(NPC,targetLocation);
    }
}

/*优化后
  角色和NPC的调用方法通一,都可以(主控端)进行调用;
*/
@Core.Class
export default class Nav extends Core.Script {
    protected onStart(): void {
        let NPC = this.gameObject as Gameplay.NPC;
        let player = Gameplay.getCurrentPlayer();
        let targetLocation= new Type.Vector(1400, 600, 0);

        //角色、NPC寻路
        InputUtil.onKeyDown(Type.Keys.One, () => {
            Gameplay.moveTo(player.character, targetLocation);
            Gameplay.moveTo(NPC,targetLocation);
        });
    }
}

[优化]客户端人形对象可以使用寻路功能

优化前优化后
022-47优化前022-48优化后

[新增]通过asyncFindPathToLocation()获取两个位置点之间所有路径点的位置信息

TypeScript
@Core.Class
export default class Nav extends Core.Script {
    
    locPoint: Array<any>

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        let startLocation = new Type.Vector(-140, -240, 0); //设置一个起点位置
        let targetLocation = new Type.Vector(-270, 740, 0); //设置一个终点位置
        let player = Gameplay.getCurrentPlayer();

        //获取起点与终点之间的所有路径点
        this.locPoint = Gameplay.asyncFindPathToLocation(startLocation, targetLocation);

        Events.addLocalListener("FindPathToLocation",()=>{
            //给获取到的路径点上生成一个标识物
            this.locPoint.forEach(async (point) => {
                let pointFlag = await Core.GameObject.asyncSpawnGameObject("7667") as Gameplay.StaticMesh;
                pointFlag.setCollision(Type.CollisionStatus.Off)
                pointFlag.worldLocation = point;
            });
        })

        //角色开始寻路,验证路径点信息的正确性
        Events.addLocalListener("movetoPlayer",()=>{
            Gameplay.moveTo(player.character,targetLocation)
        });
    }
}
@Core.Class
export default class Nav extends Core.Script {
    
    locPoint: Array<any>

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        let startLocation = new Type.Vector(-140, -240, 0); //设置一个起点位置
        let targetLocation = new Type.Vector(-270, 740, 0); //设置一个终点位置
        let player = Gameplay.getCurrentPlayer();

        //获取起点与终点之间的所有路径点
        this.locPoint = Gameplay.asyncFindPathToLocation(startLocation, targetLocation);

        Events.addLocalListener("FindPathToLocation",()=>{
            //给获取到的路径点上生成一个标识物
            this.locPoint.forEach(async (point) => {
                let pointFlag = await Core.GameObject.asyncSpawnGameObject("7667") as Gameplay.StaticMesh;
                pointFlag.setCollision(Type.CollisionStatus.Off)
                pointFlag.worldLocation = point;
            });
        })

        //角色开始寻路,验证路径点信息的正确性
        Events.addLocalListener("movetoPlayer",()=>{
            Gameplay.moveTo(player.character,targetLocation)
        });
    }
}

[新增]寻路功能支持动态修改局部寻路数据,实现在运行时动态修改导航路线的效果

在编辑器菜单栏[设置]功能中增加了[寻路设置]属性,可以设置是否开启动态寻路功能。动态寻路开启后,可以通过脚本在游戏运行时动态设置寻路动态修饰区状态。

WARNING

关闭动态寻路后,寻路区域数据在项目发布时即构建完成,不会在游戏启动时消耗性能。

开启动态寻路后,会在游戏启动时对场景中的寻路区域进行构建,场景地图越大、地形越复杂,构建耗时越高。

以A57手机为例,构建100*100大小地形寻路数据,耗时约0.3秒;

WARNING

动态寻路使用方式

使用寻路动态修饰区来改变寻路数据时,只对寻路动态修饰区所在区域进行一次局部寻路数据重构,寻路动态修饰区越大、形状越复杂,构建耗时越高。

以A57手机为例,构建10*10大小的寻路动态修饰区,耗时约0.01秒;

1.在[世界设置]-[寻路设置]中打开动态寻路;

022-50

2.在场景中放置寻路动态修饰区对象做为路障;

022-51

3.将寻路动态修饰区属性设置为默认

022-52

4.创建一个脚本,来动态控制寻路动态修饰区

TypeScript
@Core.Class
export default class Nav extends Core.Script {
    
    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected async onStart(): Promise<void> {
        let player = Gameplay.getCurrentPlayer();
        let targetLocation = new Type.Vector(1940, -3400, 0);

        //找到寻路动态修饰区
        let navModifierVolume = await Core.GameObject.asyncFind("3C7B1C36") as Gameplay.ModifierVolume;
        
        //找到路障装饰对象
        let og = await Core.GameObject.asyncFind("1D40B15D") as Gameplay.StaticMesh;
        //生成路障
        
        //通过UI按钮创建路障
        Events.addLocalListener("spawnNAV",()=>{
            og.setVisibility(Type.PropertyStatus.On); //显示路障外形
            og.setCollision(Type.PropertyStatus.On); //显示开启路障对象碰撞
            navModifierVolume.areaClass = Gameplay.AreaClass.Null; //将寻路动态修饰区类型设为禁用
        });

        //角色开始寻路
        Events.addLocalListener("movetoPlayer",()=>{
            Gameplay.moveTo(player.character,targetLocation)
        });
    }
}
@Core.Class
export default class Nav extends Core.Script {
    
    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected async onStart(): Promise<void> {
        let player = Gameplay.getCurrentPlayer();
        let targetLocation = new Type.Vector(1940, -3400, 0);

        //找到寻路动态修饰区
        let navModifierVolume = await Core.GameObject.asyncFind("3C7B1C36") as Gameplay.ModifierVolume;
        
        //找到路障装饰对象
        let og = await Core.GameObject.asyncFind("1D40B15D") as Gameplay.StaticMesh;
        //生成路障
        
        //通过UI按钮创建路障
        Events.addLocalListener("spawnNAV",()=>{
            og.setVisibility(Type.PropertyStatus.On); //显示路障外形
            og.setCollision(Type.PropertyStatus.On); //显示开启路障对象碰撞
            navModifierVolume.areaClass = Gameplay.AreaClass.Null; //将寻路动态修饰区类型设为禁用
        });

        //角色开始寻路
        Events.addLocalListener("movetoPlayer",()=>{
            Gameplay.moveTo(player.character,targetLocation)
        });
    }
}

[新增]寻路区域参数,可在编辑阶段调整寻路计算结果

寻路区域对象在属性面板中新增寻路设置参数,可以通过调节参数来改变寻路区域计算结果。

设置参数以需要使用寻路功能的对象为参照,比如默认大小的角色或NPC使用寻路时,寻路参数可以直接使用默认值,以保证角色或NPC对象导航时不会被阻挡。如果是体形较大或较小的对象使用寻路,可以适当调整胶囊半径、高度等参数,使寻路区域计算更加精准。

*通过调整胶囊体半径属性,可以设置与碰撞对象接触边缘的间隙大小。

022-56022-57
022-58022-59

*通过调整不可跨越高度属性,可以设置进行寻路导航的对象能行走的坡度。

022-60022-61
022-62022-63

[新增] 新交互物(交互结点)

TIP

为避免老交互物废弃后后蓝军需要大量修改项目中场景内的老交互物,024版本准备提供一种兼容方式:缝合新老交互物。缝合后类名统一使用老交互物的类名。新交互物将自身API及属性迁移至老交互物内,同时,老交互物的原有API和属性标废弃处理。最终蓝军项目中场景对象无需修改,只需要在老交互物删除前将游戏代码中使用的接口和属性换为新交互物的即可。同时024版本后建议统一使用新交互物的属性和接口。022 - 024版本中如果使用了新交互物,则需要在024修改。

修复BUG

【UI编辑器】UI编辑器任意可设置图片资源的组件,选择重置资源图片然后执行撤回操作,编辑器概率崩溃
【角色换装接口】setColor接口使用后,再次进行setmesh,服装没有恢复默认颜色
Extension.GameObjPool.spawn()接口中传入的Guid格式为科学计数法的字符串,getScoureType()只会返回1
【Gameplay-音效】音量为0时开始播放音乐,等待音效播放结束后调节音量,此时音效会自动播放。
【WorldRun】多层级使用脚本销毁整个对象时,Update函数不会被销毁