"PropName": "梦境楼梯", "AssetPath": "/Game/Props/SceneProps/Items/BP_Steps.BP_Steps", 定义场景A与场景B,A=>B。 1. 创建一个和A或者B相同的场景道具。使用LevelInstance。 2. 制作渐变效果,在A或者B溶解完成后,进行一次切换区域。 1. 或者使用一个其他模型做过度。 3. 物理问题可以使用 Ignore Component Transform 来解决。 manager.LayerManager.EnterLevelArea(this.preset.LevelAreaPreset.UUID, manager.LevelSwitchType); # 角色会隐藏问题解决 1. TsIdolControllerActor.ts中绑定了若干事件 ```typescript RegisterEventListener(): void { this.ListenerWrapper_SwitchLiveArea = (liveAreaUUID: UE.Guid) => { this.SwitchToLiveArea(liveAreaUUID) } this.ListenerWrapper_OnFinishCreateTmpArea = (liveAreaUUID: UE.Guid) => { this.RequireSwitchToLiveArea(liveAreaUUID) } this.ListenerWrapper_SceneChanged = (levelName:string)=>{this.OnSceneChanged() }; this.ListenerWrapper_BeforeSceneChanged = (levelName:string)=>{this.BeforeSceneChanged() }; DirectorEventSystem.RegisterEventListener(this, DirectorEvent.OnFinishSwitchLiveAreaLocal, this.ListenerWrapper_SwitchLiveArea) DirectorEventSystem.RegisterEventListener(this, DirectorEvent.OnFinishSwitchSubLevelLocal,this.ListenerWrapper_SceneChanged) DirectorEventSystem.RegisterEventListener(this, DirectorEvent.BeforeSwitchLevel,this.ListenerWrapper_BeforeSceneChanged) DirectorEventSystem.RegisterEventListener(this, DirectorEvent.OnFinishCreateTmpLiveAreaLocal,this.ListenerWrapper_OnFinishCreateTmpArea) } ``` - ListenerWrapper_SwitchLiveArea:角色移动到其他LiveArea的核心逻辑。 - ListenerWrapper_OnFinishCreateTmpArea:无逻辑。 - ListenerWrapper_SceneChanged:卸载所有道具?this.PropComp.OnSceneChanged() - ListenerWrapper_BeforeSceneChanged:将角色与衣服从LiveAreaDetach? this.DressModel.K2_DetachFromActor() ## ListenerWrapper_SwitchLiveArea ```c++ SwitchToLiveArea(TargetLiveAreaGUID: UE.Guid): void { console.warn(this.Identity.RootTag.TagName.toString() + ' switch to live area ' + TargetLiveAreaGUID.ToString()) this.LiveAreaGIUD = TargetLiveAreaGUID this.SetTransformToLiveArea() if (this.PropComp.DressModel && this.PropComp.DressModel.MovementComp&&this.PropComp.DressModel.MovementComp.ManulMovement) { console.warn(this.PropComp.DressModel.GetName() + ' is in free move mode, will not teleport to new area!') return } var liveAreaMgr = LiveAreaUtils.GetLievAreaManagerInstance(this) if (liveAreaMgr && liveAreaMgr.IsTmpLiveArea(TargetLiveAreaGUID)) { // teleport to the target live area without fx this.PropComp.Teleport(TargetLiveAreaGUID) } else { this.PropComp.DressModelTeleport(TargetLiveAreaGUID) } } ``` ## 相关事件 - BeforeSwitchArea_Multicast ## 笔记 - SwitchToLiveArea() - 设置Idol的位置。 - this.OnSwitchLiveArea.Broadcast(oriUUID, uuid);         - DirectorEventSystem.Emit(this, DirectorEvent.OnFinishSwitchLiveAreaLocal, this.CurrentLiveAreaUUID) TsDirectorCamManagerActor.ts         - console.log('切换直播区域,area=[' + (liveArea as UE.LiveAreaActor).Title + ']')         - DirectorCamUtil.EnsureWorkShopReady(this, placement.UUID, () => { this.SwitchWorkShopInAreaServer(0) }) ***TsDirectorCamManagerActor.ts***         - SwitchWorkShopInAreaServer         - this.HandlePreviewTaskDataMulticast(newPreviewTaskData);         - this.RequestPVWTaskServer(newPVWTaskData); ```ts     //推流     E_StartCut(progress: number): void {         this.camManagerCache = DirectorCamUtil.PushStreamOnServerAsync(this, UE.EPushStreamMethod.Cut, false, this.camManagerCache)     } function PushStreamOnServerAsync(context:UE.Object, method:UE.EPushStreamMethod,bForce:boolean, camManagerCache? : TsDirectorCamManagerActor):TsDirectorCamManagerActor{ let camManager = GetCamManager(context, camManagerCache) if(camManager){ camManager.PushStreamOnServerAsync(method, bForce) } return camManager } // Server端判断是否可以推流。(存在网络延迟�? @ufunction.ufunction(ufunction.Reliable, ufunction.ServerAPI) PushStreamOnServerAsync(method:UE.EPushStreamMethod, bForce : boolean):void{ let newPGMTaskData = DirectorCamUtil.CopyTaskData(this.prestreamTaskData) this.RequestPGMTaskServer(newPGMTaskData, method, bForce) } ``` ## TsMovableLiveAreaComponent - TsMovableLiveAreaComponent ## ```ts /** 使用cmd进入区域,跳过加载等待, 其他方法不可调用 */ @ufunction.ufunction(ufunction.ServerAPI, ufunction.Reliable) EnterAreaByCMD(areaUUIDStr: string): void { let areaManager = this.GetLevelAreaManager(); if (!areaManager) { return; } let area: UE.LiveAreaActor = null; if (areaUUIDStr != null || areaUUIDStr != "") { let uuid = new UE.Guid(); if (UE.Guid.Parse(areaUUIDStr, $ref(uuid))) { area = areaManager.GetLiveArea(uuid); } } if (area == null) { area = areaManager.GetAllLiveAreas().GetRef(0) } if (area == null) { console.error("no area") return } if (area.UUID.op_Equality(areaManager.CurrentLiveAreaUUID)) { return } let bHasData = false; let presetId:UE.Guid; let manager = this.GetManager() for (let index = 0; index < manager.Config.AreaPresets.Num(); index++) { const element = manager.Config.AreaPresets.GetRef(index); if (element.AreaGuid.op_Equality(area.UUID)) { presetId = element.UUID; bHasData = true; break; } } let levelName = UE.GameplayStatics.GetCurrentLevelName(this, true); if (!bHasData) { manager.AddAreaPreset( levelName, area.UUID, area.Title) for (let index = 0; index < manager.Config.AreaPresets.Num(); index++) { const element = manager.Config.AreaPresets.GetRef(index); if (element.AreaGuid.op_Equality(area.UUID)) { presetId = element.UUID; break; } } } let viewTarget = areaManager.GetViewTarget(area.UUID) if (!viewTarget) { this.AddViewTarget(area.UUID, area.Title); } manager.AddConfigLevelSetting(levelName); this.BeforeSwitchArea_Multicast(manager.CurPresetId); manager.CurPresetId = presetId; areaManager.SwitchToLiveArea(area.UUID); } } ```