2024-03-18 17:33:19 +08:00
using cfg.ShowCfg ;
using Cysharp.Threading.Tasks ;
using Framework ;
using Gameplay ;
using PhxhSDK ;
using Sirenix.OdinInspector ;
2024-03-29 16:57:35 +08:00
using Sirenix.Utilities ;
2024-03-18 17:33:19 +08:00
using SRF ;
using System ;
using System.Collections.Generic ;
2024-04-13 13:58:59 +08:00
using Gameplay.Emoji ;
2024-03-18 17:33:19 +08:00
using UnityEngine ;
using UnityEngine.Playables ;
using UnityEngine.Timeline ;
using static ShowComponent ;
2024-04-13 13:58:59 +08:00
using Constants = Framework . Constants ;
2024-03-18 17:33:19 +08:00
using Object = UnityEngine . Object ;
2024-04-26 15:35:22 +08:00
using System.Linq ;
2024-05-13 14:25:57 +08:00
using Random = UnityEngine . Random ;
2024-03-18 17:33:19 +08:00
/// <summary>
/// 演出组件
/// </summary>
2024-04-19 19:32:11 +08:00
public class ShowComponent : MonoBehaviour , IShow
2024-03-18 17:33:19 +08:00
{
/// <summary>
/// 当前状态
/// </summary>
2024-04-19 19:32:11 +08:00
protected enum E_CurState
2024-03-18 17:33:19 +08:00
{
None = 0 ,
/// <summary>
/// 加载角色
/// </summary>
LoadingCharacters ,
/// <summary>
/// 当前
/// </summary>
Present ,
}
/// <summary>
/// 被弃用的原因
/// </summary>
public enum E_DisposeReason
{
None ,
/// <summary>
/// 演出点重复
/// </summary>
[LabelText("演出点重复")]
ShowPointRepeat ,
/// <summary>
/// 组内人数不满
/// </summary>
[LabelText("组内人数不满")]
CharacterCountNotFull ,
/// <summary>
/// 固定角色不存在
/// </summary>
[LabelText("固定角色不存在")]
FixedCharacterNotExist ,
}
#region 外部序列化字段
/// <summary>
/// 演出场景类型
/// </summary>
[LabelText("演出场景类型")]
[SerializeField]
private E_ShowSceneType showSceneType ;
/// <summary>
/// 角色根节点
/// </summary>
[LabelText("角色根节点")]
[SerializeField]
private Transform tsCharacterRoot ;
2024-04-26 14:48:47 +08:00
/// <summary>
/// 道具根节点
/// </summary>
[LabelText("道具根节点")]
[SerializeField]
private Transform tsItemRoot ;
2024-03-18 17:33:19 +08:00
/// <summary>
2024-04-01 17:51:56 +08:00
/// 收集演出点根节点
2024-03-18 17:33:19 +08:00
/// </summary>
2024-04-01 17:51:56 +08:00
[LabelText("收集演出点的根节点")]
2024-03-18 17:33:19 +08:00
[SerializeField]
2024-04-01 17:51:56 +08:00
private Transform tsCollectRoot ;
/// <summary>
/// 角色演出点根节点
/// </summary>
[LabelText("角色演出点根节点")]
[SerializeField]
private Transform tsCharacterShowPointRoot ;
/// <summary>
/// 道具演出点根节点
/// </summary>
[LabelText("道具演出点根节点")]
[SerializeField]
private Transform tsItemShowPointRoot ;
2024-03-18 17:33:19 +08:00
/// <summary>
/// 最大抽取角色数量
/// </summary>
[LabelText("最大抽取角色数")]
[SerializeField]
private int characterMaxCount = 20 ;
/// <summary>
/// 是否忽略看板娘
/// </summary>
[LabelText("是否忽略看板娘")]
[SerializeField]
private bool IsIgnoreKanbanban ;
2024-04-11 14:10:46 +08:00
/// <summary>
2024-05-29 19:16:38 +08:00
/// 相机Timeline
2024-04-11 14:10:46 +08:00
/// </summary>
2024-05-29 19:16:38 +08:00
[LabelText("相机PlayableDirector")]
2024-04-11 14:10:46 +08:00
[SerializeField]
2024-05-29 19:16:38 +08:00
private PlayableDirector cameraPlayable ;
2024-04-11 14:10:46 +08:00
2024-03-18 17:33:19 +08:00
/// <summary>
/// 抽取记录
/// </summary>
[ReadOnly]
[LabelText("抽取记录")]
[SerializeField]
[ShowIf("@listExtractRecord.Count > 0")]
private List < ExtractRecord > listExtractRecord = new ( ) ;
# endregion
2024-04-26 14:48:47 +08:00
/// <summary>
/// 演出Timeline路径
/// </summary>
private const string SHOW_TIMELINE_PATH = "Assets/Art/Show/" ;
/// <summary>
/// 道具Timeline上角色轨道名
/// </summary>
private const string ITEM_TIMELINE_TRACK_NAME = "Character" ;
2024-05-21 18:53:53 +08:00
/// <summary>
/// 角色Activation轨道名
/// </summary>
private const string CHARACTER_ACTIVATION_TRACK_NAME = "characterActivationTrack" ;
2024-04-26 14:48:47 +08:00
2024-03-18 17:33:19 +08:00
/// <summary>
2024-04-26 15:35:22 +08:00
/// 当前场景所有角色演出点
2024-03-18 17:33:19 +08:00
/// </summary>
2024-04-26 15:35:22 +08:00
private List < Transform > listCharacterShowPoint ;
/// <summary>
/// 当前场景所有道具演出点
/// </summary>
private List < Transform > listItemShowPoint ;
2024-03-18 17:33:19 +08:00
/// <summary>
/// 当前场景所有演出组字典 key:组id value:演出组数据
/// </summary>
private readonly Dictionary < int , ShowGroupData > dicShowGroup = new ( ) ;
/// <summary>
/// 最终的演出点数据
/// </summary>
private readonly List < ShowPointResult > listShowPointResult = new ( ) ;
/// <summary>
/// Timeline资源字典
/// </summary>
2024-03-29 16:57:35 +08:00
private readonly Dictionary < string , TimelineAsset > dicTimeLineAsset = new ( ) ;
2024-03-18 17:33:19 +08:00
/// <summary>
2024-04-26 14:48:47 +08:00
/// 道具字典, 部分Timeline挂载到道具上, 优先使用道具上的Timeline
2024-03-18 17:33:19 +08:00
/// </summary>
2024-04-26 14:48:47 +08:00
private readonly Dictionary < string , Stack < GameObject > > dicItemModel = new ( ) ;
2024-03-18 17:33:19 +08:00
/// <summary>
/// 角色模型字典
/// </summary>
private readonly Dictionary < int , GameObject > dicCharacterModel = new ( ) ;
2024-04-26 14:48:47 +08:00
/// <summary>
/// 道具相对于角色的相对位置
/// </summary>
private readonly Dictionary < int , Vector3 > dicItemOffset = new ( ) ;
/// <summary>
/// 缓存的表情
/// </summary>
private readonly List < UnitEmojiManager > listCacheEmoji = new ( ) ;
/// <summary>
/// 已经加载的资源集合
/// </summary>
private readonly HashSet < string > setAssetToUnload = new ( ) ;
2024-03-18 17:33:19 +08:00
/// <summary>
/// 当前状态
/// </summary>
2024-04-19 19:32:11 +08:00
protected E_CurState currState = E_CurState . None ;
2024-03-18 17:33:19 +08:00
2024-05-29 19:16:38 +08:00
/// <summary>
/// 相机动画回调
/// </summary>
private Action cameraAction ;
2024-03-18 17:33:19 +08:00
#region (刷新数据,抽取)过程临时变量
/// <summary>
/// 可以抽取的演出组数据(排序用)
/// </summary>
private readonly List < ShowGroupData > listRemindShowGroup = new ( ) ;
/// <summary>
/// 可以抽取演出的角色数据(排序用)
/// </summary>
private readonly List < CharacterDataInfo > listRemindCharacter = new ( ) ;
/// <summary>
/// 随机抽取的演出组链表
/// </summary>
private LinkedList < ShowGroupData > linkShowGroup ;
/// <summary>
/// 随机抽取的角色链表
/// </summary>
private LinkedList < CharacterDataInfo > linkCharacter ;
/// <summary>
/// 已经抽取的演出点索引集合
/// </summary>
private readonly HashSet < int > setUseShowPointIndex = new ( ) ;
/// <summary>
/// 已经抽取的角色id
/// </summary>
private readonly HashSet < int > setUseCharactrtId = new ( ) ;
2024-04-13 13:58:59 +08:00
2024-03-18 17:33:19 +08:00
# endregion
/// <summary>
/// 可以抽取的角色最大数量
/// </summary>
public int CharacterMaxCount
{
2024-04-26 15:35:22 +08:00
get { return Mathf . Min ( listRemindCharacter . Count , characterMaxCount , listCharacterShowPoint . Count ) ; }
2024-03-18 17:33:19 +08:00
}
public E_ShowSceneType ShowSceneTyp
{
get { return showSceneType ; }
}
#if UNITY_EDITOR
/// <summary>
2024-04-26 15:35:22 +08:00
/// 角色演出点根节点
2024-03-18 17:33:19 +08:00
/// </summary>
2024-04-01 17:51:56 +08:00
public Transform TsShowPointRoot
2024-03-18 17:33:19 +08:00
{
2024-04-01 17:51:56 +08:00
get { return tsCharacterShowPointRoot ; }
2024-03-18 17:33:19 +08:00
}
2024-04-26 15:35:22 +08:00
/// <summary>
/// 道具演出点根节点
/// </summary>
public Transform TsItemShowPointRoot
{
get { return tsItemShowPointRoot ; }
}
2024-03-18 17:33:19 +08:00
# endif
private void Awake ( )
{
if ( ! CommonUtils . IsInGame ( ) )
return ;
2024-03-18 17:41:46 +08:00
ShowManager . Instance . Add ( this ) ;
2024-03-18 17:33:19 +08:00
currState = E_CurState . None ;
#region 初始化数据
2024-04-26 15:35:22 +08:00
#region 获取角色演出点
2024-04-01 17:51:56 +08:00
if ( tsCharacterShowPointRoot = = null )
2024-04-26 15:35:22 +08:00
listCharacterShowPoint = new ( ) ;
2024-03-18 17:33:19 +08:00
else
{
2024-04-26 15:35:22 +08:00
listCharacterShowPoint = new ( tsCharacterShowPointRoot . childCount ) ;
2024-04-01 17:51:56 +08:00
for ( int i = 0 ; i < tsCharacterShowPointRoot . childCount ; + + i )
2024-03-18 17:33:19 +08:00
{
2024-04-26 15:35:22 +08:00
listCharacterShowPoint . Add ( tsCharacterShowPointRoot . GetChild ( i ) ) ;
}
}
# endregion
#region 获取道具演出点
if ( tsItemShowPointRoot = = null )
listItemShowPoint = new ( ) ;
else
{
listItemShowPoint = new ( tsItemShowPointRoot . childCount ) ;
for ( int i = 0 ; i < tsItemShowPointRoot . childCount ; + + i )
{
listItemShowPoint . Add ( tsItemShowPointRoot . GetChild ( i ) ) ;
2024-03-18 17:33:19 +08:00
}
}
# endregion
#region 获取演出组配置
List < DataShowConfig > listShowConfig = TableManager . Instance . Tables . ShowConfig . DataList ;
foreach ( DataShowConfig showConfig in listShowConfig )
{
if ( showSceneType ! = showConfig . ShowSceneType )
continue ;
int groupID = showConfig . GroupID ;
if ( ! dicShowGroup . TryGetValue ( groupID , out ShowGroupData group ) )
{
group = new ( groupID ) ;
dicShowGroup . Add ( groupID , group ) ;
}
group . Add ( showConfig ) ;
}
foreach ( ShowGroupData group in dicShowGroup . Values )
{
group . Shuffle ( ) ;
}
# endregion
# endregion
}
private void OnDestroy ( )
{
2024-04-26 14:48:47 +08:00
dicTimeLineAsset . Clear ( ) ;
dicCharacterModel . Clear ( ) ;
dicItemModel . Clear ( ) ;
dicItemOffset . Clear ( ) ;
2024-03-18 17:33:19 +08:00
foreach ( string path in setAssetToUnload )
{
AssetManager . Instance . Unload ( path ) ;
}
2024-04-13 13:58:59 +08:00
2024-04-26 14:48:47 +08:00
foreach ( var unitEmojiManager in listCacheEmoji )
2024-04-13 13:58:59 +08:00
{
unitEmojiManager . Dispose ( ) ;
}
2024-03-18 17:33:19 +08:00
}
/// <summary>
/// 刷新演出
/// </summary>
2024-04-19 19:32:11 +08:00
public virtual async UniTask RefreshShow ( object data = null )
2024-03-18 17:33:19 +08:00
{
currState = E_CurState . LoadingCharacters ;
RefreshShowData ( ) ;
ExtractShowCharacter ( ) ;
await ExecuteShowResult ( ) ;
currState = E_CurState . Present ;
}
/// <summary>
/// 刷新演出数据
/// </summary>
private void RefreshShowData ( )
{
listRemindShowGroup . Clear ( ) ;
listRemindCharacter . Clear ( ) ;
listRemindShowGroup . AddRange ( dicShowGroup . Values ) ;
#region 获取看板娘id
int kanbanbanId = 0 ;
if ( IsIgnoreKanbanban )
{
MainPanelSceneStoreData storeData = StorageMgr . Instance . GetStorage < MainPanelSceneStoreData > ( "MainPanelSceneStoreData" ) ;
if ( storeData = = null )
DebugUtil . LogError ( "没有看板娘数据" ) ;
else
2024-03-20 16:25:29 +08:00
kanbanbanId = storeData . PosterID ;
2024-03-18 17:33:19 +08:00
}
# endregion
foreach ( CharacterDataInfo characterDataInfo in CharacterDataInfoManager . Instance . DataList )
{
2024-04-01 17:51:56 +08:00
if ( IsIgnoreKanbanban & & characterDataInfo . Cfg . RoleID = = kanbanbanId )
2024-03-18 17:33:19 +08:00
continue ; // TODO 看板娘不加进可以演出的抽取列表
listRemindCharacter . Add ( characterDataInfo ) ;
}
CommonUtils . Shuffle ( listRemindShowGroup ) ;
CommonUtils . Shuffle ( listRemindCharacter ) ;
linkShowGroup = new ( listRemindShowGroup ) ;
linkCharacter = new ( listRemindCharacter ) ;
#region 隐藏之前的角色模型
foreach ( GameObject go in dicCharacterModel . Values )
{
go . SetActive ( false ) ;
}
# endregion
}
/// <summary>
/// 抽取演出角色
/// </summary>
private void ExtractShowCharacter ( )
{
listExtractRecord . Clear ( ) ;
listShowPointResult . Clear ( ) ;
List < ShowPointResult > listTempResult = new ( ) ; // 临时存放抽取的结果
while ( linkShowGroup . First ! = null )
{
ShowGroupData groupData = linkShowGroup . First . Value ;
linkShowGroup . RemoveFirst ( ) ;
// 如果组里的演出点和当前已经使用的演出点重复,则踢出该组
if ( IsShowPointExist ( groupData ) )
{
listExtractRecord . Add ( new ExtractRecord ( groupData . GroupID , E_DisposeReason . ShowPointRepeat ) ) ;
continue ;
}
// 如果是固定角色的组的角色已经被使用,则踢出该组
if ( ! IsCanUseFixCharacter ( groupData ) )
{
listExtractRecord . Add ( new ExtractRecord ( groupData . GroupID , E_DisposeReason . FixedCharacterNotExist ) ) ;
continue ;
}
listTempResult . Clear ( ) ;
ExtractRecord extractRecord = new ( groupData . GroupID , E_DisposeReason . None ) ;
foreach ( DataShowConfig dataShowConfig in groupData . ListConfig )
{
// 如果当前没有剩余的演员,则直接跳出抽取
if ( linkCharacter . First = = null )
break ;
2024-04-26 15:35:22 +08:00
#region 抽取timeline
2024-03-29 16:57:35 +08:00
string timelineName = CommonUtils . GetRandomItem ( dataShowConfig . TimelineNames ) ;
2024-03-18 17:33:19 +08:00
ExtractRecord . SinglePointRecord singlePointRecord = new ( )
{
2024-03-29 16:57:35 +08:00
timelineName = timelineName
2024-03-18 17:33:19 +08:00
} ;
extractRecord . Add ( singlePointRecord ) ;
2024-03-29 16:57:35 +08:00
if ( timelineName = = "0" | | timelineName . IsNullOrWhitespace ( ) ) // 说明不站人
2024-03-18 17:33:19 +08:00
continue ;
2024-04-26 15:35:22 +08:00
# endregion
2024-03-18 17:33:19 +08:00
#region 角色抽取
CharacterDataInfo characterDataInfo = null ;
if ( ValueValidator . IsIdValid ( dataShowConfig . CharacterID ) ) // 抽取指定演员
{
foreach ( CharacterDataInfo character in linkCharacter )
{
if ( ( int ) character . ID = = dataShowConfig . CharacterID )
{
characterDataInfo = character ;
break ;
}
}
if ( characterDataInfo = = null )
continue ;
else
linkCharacter . Remove ( characterDataInfo ) ;
}
else
{
characterDataInfo = linkCharacter . First . Value ;
linkCharacter . RemoveFirst ( ) ;
}
# endregion
2024-04-26 15:35:22 +08:00
ShowPointResult result ;
// 道具抽取
if ( dataShowConfig . ItemNames . Count ( ) > 0 )
{
string itemName = CommonUtils . GetRandomItem ( dataShowConfig . ItemNames ) ;
result = new ( groupData . GroupID ,
dataShowConfig . PointID ,
timelineName ,
characterDataInfo ,
dataShowConfig . ItemPointId ,
itemName ) ;
}
else
{
result = new ( groupData . GroupID ,
dataShowConfig . PointID ,
timelineName ,
characterDataInfo ,
dataShowConfig . ItemPointId ,
string . Empty ) ;
}
2024-03-18 17:33:19 +08:00
singlePointRecord . showPoint = dataShowConfig . PointID ;
singlePointRecord . characterID = characterDataInfo . ID ;
listTempResult . Add ( result ) ;
}
if ( groupData . IsMustHasCharacter & & listTempResult . Count < groupData . ListConfig . Count )
{
// 如果该组必须满员但没满员
// 取出来的CharacterDataInfo归还
foreach ( ShowPointResult result in listTempResult )
{
listRemindCharacter . Add ( result . CharacterData ) ;
}
listExtractRecord . Add ( new ExtractRecord ( groupData . GroupID , E_DisposeReason . CharacterCountNotFull ) ) ;
}
else // 添加到最后的result列表中
{
foreach ( ShowPointResult result in listTempResult )
{
listShowPointResult . Add ( result ) ;
setUseCharactrtId . Add ( ( int ) result . CharacterData . ID ) ;
setUseShowPointIndex . Add ( result . ShowPointIndex ) ;
}
}
}
setUseShowPointIndex . Clear ( ) ;
setUseCharactrtId . Clear ( ) ;
}
/// <summary>
/// 执行演出结果
/// </summary>
2024-04-19 19:32:11 +08:00
protected virtual async UniTask ExecuteShowResult ( )
2024-03-18 17:33:19 +08:00
{
if ( listShowPointResult . Count = = 0 )
return ;
2024-04-26 14:48:47 +08:00
Dictionary < string , Stack < GameObject > > dicTempGoItem = new ( ) ; // 临时道具字典
2024-03-18 17:33:19 +08:00
foreach ( ShowPointResult result in listShowPointResult )
{
2024-04-26 15:35:22 +08:00
#region 获取角色演出点
2024-03-18 17:33:19 +08:00
int showPointIndex = result . ShowPointIndex ;
2024-04-26 15:35:22 +08:00
if ( showPointIndex < 0 | | showPointIndex > = listCharacterShowPoint . Count | | listCharacterShowPoint [ showPointIndex ] = = null )
2024-03-18 17:33:19 +08:00
{
DebugUtil . LogError ( $"找不到演出点!演出点索引:{showPointIndex}" ) ;
continue ;
}
2024-04-26 15:35:22 +08:00
Transform tsShowPoint = listCharacterShowPoint [ showPointIndex ] . transform ;
# endregion
int itemShowPointIndex = result . ItemPointIndex ;
if ( itemShowPointIndex > = 0 & & itemShowPointIndex < listItemShowPoint . Count & & listItemShowPoint [ itemShowPointIndex ] ! = null )
{
2024-04-28 17:55:51 +08:00
Transform tsItemShowPoint = listItemShowPoint [ itemShowPointIndex ] . transform ; // 获取道具演出点,有道具演出
2024-04-28 19:01:20 +08:00
GameObject goFixItemModel = await GetItemModel ( result . ItemName ) ; // 加载固定道具
2024-04-28 17:55:51 +08:00
if ( goFixItemModel ! = null )
goFixItemModel . transform . SetPositionAndRotation ( tsItemShowPoint . position , tsItemShowPoint . rotation ) ;
2024-04-26 15:35:22 +08:00
}
2024-03-18 17:33:19 +08:00
2024-04-26 14:48:47 +08:00
GameObject goCharacterModel = await GetCharacterModel ( result . CharacterData ) ;
if ( goCharacterModel = = null )
2024-03-18 17:33:19 +08:00
continue ;
2024-04-26 14:48:47 +08:00
goCharacterModel . SetActive ( true ) ;
goCharacterModel . transform . SetPositionAndRotation ( tsShowPoint . position , tsShowPoint . rotation ) ;
2024-03-18 17:33:19 +08:00
2024-04-26 14:48:47 +08:00
GameObject goItemModel = await GetItemModel ( result . TimelineName ) ; // 优先使用道具上的Timeline
if ( goItemModel = = null ) // 没有道具,直接加载Timeline
{
TimelineAsset timelineAsset = await GetTimeLineAsset ( result . TimelineName ) ;
if ( timelineAsset = = null )
continue ;
2024-03-18 17:33:19 +08:00
2024-04-26 14:48:47 +08:00
PlayableDirector playableDirector = goCharacterModel . GetComponentOrAdd < PlayableDirector > ( ) ;
playableDirector . playableAsset = timelineAsset ;
playableDirector . extrapolationMode = DirectorWrapMode . Loop ;
foreach ( PlayableBinding playableBinding in timelineAsset . outputs )
{
playableDirector . SetGenericBinding ( playableBinding . sourceObject , goCharacterModel . GetComponentInChildren < Animator > ( ) ) ;
}
2024-05-21 18:53:53 +08:00
foreach ( TrackAsset trackAsset in timelineAsset . GetOutputTracks ( ) )
{
if ( trackAsset . name . Equals ( CHARACTER_ACTIVATION_TRACK_NAME ) )
playableDirector . SetGenericBinding ( trackAsset , goCharacterModel . transform . GetChild ( 0 ) ? . gameObject ) ;
}
2024-04-26 14:48:47 +08:00
playableDirector . enabled = true ;
2024-05-13 14:25:57 +08:00
playableDirector . time = Random . Range ( 0f , ( float ) playableDirector . duration ) ;
2024-04-26 14:48:47 +08:00
playableDirector . Play ( ) ;
}
else // 有道具,不加载Timeline
2024-03-18 17:33:19 +08:00
{
2024-04-26 14:48:47 +08:00
#region 临时记录使用过的道具GameObject,方便后续归还给池子
if ( ! dicTempGoItem . TryGetValue ( result . TimelineName , out Stack < GameObject > goStack ) )
{
goStack = new ( ) ;
dicTempGoItem [ result . TimelineName ] = goStack ;
}
goStack . Push ( goItemModel ) ;
# endregion
PlayableDirector playableDirector = goItemModel . GetComponentOrAdd < PlayableDirector > ( ) ;
TimelineAsset timelineAsset = playableDirector . playableAsset as TimelineAsset ;
if ( timelineAsset = = null )
{
DebugUtil . LogError ( $"{goItemModel.name} 没有TimelineAsset" ) ;
continue ;
}
if ( dicItemOffset . TryGetValue ( goItemModel . GetInstanceID ( ) , out Vector3 offset ) )
goItemModel . transform . SetPositionAndRotation ( goCharacterModel . transform . position + offset , Quaternion . identity ) ;
else
goItemModel . transform . SetPositionAndRotation ( goCharacterModel . transform . position , Quaternion . identity ) ;
goItemModel . transform . RotateAround ( goCharacterModel . transform . position , Vector3 . up , goCharacterModel . transform . localEulerAngles . y ) ;
PlayableDirector cPlayableDirector = goCharacterModel . GetComponentOrAdd < PlayableDirector > ( ) ;
cPlayableDirector . enabled = false ;
foreach ( TrackAsset trackAsset in timelineAsset . GetOutputTracks ( ) )
{
if ( trackAsset . name . Equals ( ITEM_TIMELINE_TRACK_NAME ) )
playableDirector . SetGenericBinding ( trackAsset , goCharacterModel . GetComponentInChildren < Animator > ( ) ) ;
2024-05-21 18:53:53 +08:00
if ( trackAsset . name . Equals ( CHARACTER_ACTIVATION_TRACK_NAME ) )
2024-09-05 18:43:40 +08:00
{
Transform tsGo = goCharacterModel . transform . GetChild ( 0 ) ;
if ( null = = tsGo )
DebugUtil . LogError ( "赋值空的角色到Timeline轨道上" ) ;
else
playableDirector . SetGenericBinding ( trackAsset , tsGo . gameObject ) ;
}
2024-04-26 14:48:47 +08:00
}
2024-05-13 14:25:57 +08:00
playableDirector . time = Random . Range ( 0f , ( float ) playableDirector . duration ) ;
2024-04-26 14:48:47 +08:00
playableDirector . Play ( ) ;
2024-03-18 17:33:19 +08:00
}
2024-04-26 14:48:47 +08:00
}
2024-04-26 15:35:22 +08:00
#region 放回道具
2024-04-26 14:48:47 +08:00
foreach ( var kv in dicTempGoItem )
{
if ( ! dicItemModel . TryGetValue ( kv . Key , out Stack < GameObject > stack ) )
continue ;
2024-03-18 17:33:19 +08:00
2024-04-26 14:48:47 +08:00
stack ? ? = new ( ) ;
while ( kv . Value . Count > 0 )
2024-03-18 17:33:19 +08:00
{
2024-04-26 14:48:47 +08:00
stack . Push ( kv . Value . Pop ( ) ) ;
2024-03-18 17:33:19 +08:00
}
}
2024-04-26 14:48:47 +08:00
dicTempGoItem . Clear ( ) ;
2024-04-26 15:35:22 +08:00
# endregion
2024-03-18 17:33:19 +08:00
}
2024-04-26 14:48:47 +08:00
/// <summary>
/// 初始化emoji
/// </summary>
/// <param name="cObj"></param>
/// <param name="dataInfo"></param>
/// <returns></returns>
private UnitEmojiManager InitEmoji ( GameObject cObj , CharacterDataInfo dataInfo )
2024-04-13 13:58:59 +08:00
{
var config = dataInfo . Cfg ;
var skinID = dataInfo . SkinID > 0 ? ( int ) dataInfo . SkinID : Constants . DEFULT_SKINID ;
var skinData = TableManager . Instance . Tables . SkinCfg . Get ( skinID , dataInfo . Cfg . RoleID ) ;
if ( skinData = = null )
{
DebugUtil . LogError ( $"找不到皮肤数据, skinID:{skinID}, roleID:{dataInfo.Cfg.RoleID}" ) ;
return null ;
}
var eyebowsType = string . IsNullOrEmpty ( config . EmojiEyeBowsType ) ? "1" : config . EmojiEyeBowsType ;
var eyesColor = string . IsNullOrEmpty ( config . EmojiEyesColor ) ? "#ff0000" : config . EmojiEyesColor ;
var eyebowsColor = string . IsNullOrEmpty ( config . EmojiEyeBowsColor ) ? "#ff0000" : config . EmojiEyeBowsColor ;
2024-06-18 16:52:21 +08:00
var unitEmojiManager = new UnitEmojiManager ( cObj , eyesColor , eyebowsType , eyebowsColor ) ;
2024-04-24 15:06:37 +08:00
unitEmojiManager . SwitchEmoji ( config . DefaultDisplayEmojiId ) ;
2024-04-13 13:58:59 +08:00
return unitEmojiManager ;
}
2024-03-18 17:33:19 +08:00
/// <summary>
2024-04-11 14:10:46 +08:00
/// 播放相机动画
/// </summary>
/// <exception cref="NotImplementedException"></exception>
2024-06-19 13:59:31 +08:00
public void PlayeCameraAnim ( Action callbackAction , params string [ ] args )
2024-04-11 14:10:46 +08:00
{
2024-05-29 19:16:38 +08:00
if ( null = = cameraPlayable )
2024-04-11 14:10:46 +08:00
{
2024-05-29 19:16:38 +08:00
DebugUtil . LogError ( "相机Playable未赋值" ) ;
2024-04-11 14:10:46 +08:00
return ;
}
2024-05-29 19:16:38 +08:00
cameraAction = callbackAction ;
2024-04-11 14:10:46 +08:00
2024-05-29 19:16:38 +08:00
cameraPlayable . Play ( ) ;
}
2024-04-11 14:10:46 +08:00
2024-05-29 19:16:38 +08:00
/// <summary>
/// 相机动画播放完成
/// </summary>
public void OnPlayCameraAnimStop ( )
{
cameraAction ? . Invoke ( ) ;
cameraAction = null ;
2024-04-11 14:10:46 +08:00
}
/// <summary>
2024-03-18 17:33:19 +08:00
/// 异步加载资源
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="path"></param>
/// <returns></returns>
private async UniTask < T > LoadAssetAsync < T > ( string path ) where T : Object
{
T res = await AssetManager . Instance . LoadAssetAsync < T > ( path ) ;
if ( res ! = null )
setAssetToUnload . Add ( path ) ;
return res ;
}
/// <summary>
/// 获取角色模型
/// </summary>
/// <param name="characterDataInfo"></param>
/// <returns></returns>
2024-04-26 14:48:47 +08:00
private async UniTask < GameObject > GetCharacterModel ( CharacterDataInfo characterDataInfo )
2024-03-18 17:33:19 +08:00
{
if ( ! dicCharacterModel . TryGetValue ( characterDataInfo . Cfg . RoleID , out GameObject goModel ) )
{
string prefabPath = characterDataInfo . PrefabPath ;
goModel = await LoadAssetAsync < GameObject > ( prefabPath ) ;
if ( goModel = = null )
{
DebugUtil . LogError ( $"找不到模型, path:{prefabPath}" ) ;
return null ;
}
goModel = Instantiate ( goModel , tsCharacterRoot ) ;
2024-04-26 14:48:47 +08:00
goModel . SetLayerEx ( Constants . Layer . UIVIEW ) ;
HideCharacterWeapon ( goModel ) ;
UnitEmojiManager unitEmojiManager = InitEmoji ( goModel , characterDataInfo ) ;
2024-04-13 13:58:59 +08:00
if ( unitEmojiManager ! = null )
{
// 缓存起来
2024-04-26 14:48:47 +08:00
listCacheEmoji . Add ( unitEmojiManager ) ;
2024-04-13 13:58:59 +08:00
}
2024-03-18 17:33:19 +08:00
dicCharacterModel . Add ( characterDataInfo . Cfg . RoleID , goModel ) ;
}
return goModel ;
}
2024-04-26 14:48:47 +08:00
/// <summary>
/// 获取道具模型
/// </summary>
/// <param name="characterDataInfo"></param>
/// <returns></returns>
private async UniTask < GameObject > GetItemModel ( string name )
{
if ( ! dicItemModel . TryGetValue ( name , out Stack < GameObject > stackItem ) | | stackItem . Count < = 0 )
{
2024-04-28 19:01:20 +08:00
string itemPath = $"{SHOW_TIMELINE_PATH}{showSceneType}/{name}.prefab" ;
2024-04-26 14:48:47 +08:00
if ( ! AssetManager . Instance . CanLocateAsset < GameObject > ( itemPath ) )
return null ;
stackItem ? ? = new ( ) ;
GameObject goItem = await LoadAssetAsync < GameObject > ( itemPath ) ;
if ( goItem = = null )
return null ;
goItem = Instantiate ( goItem , tsItemRoot ) ;
goItem . SetLayerEx ( Constants . Layer . UIVIEW ) ;
dicItemModel [ name ] = stackItem ;
dicItemOffset [ goItem . GetInstanceID ( ) ] = goItem . transform . position ;
return goItem ;
}
return stackItem . Pop ( ) ;
}
2024-04-03 19:11:09 +08:00
/// <summary>
/// 隐藏角色武器
/// </summary>
private void HideCharacterWeapon ( GameObject goCharacter )
{
if ( goCharacter . transform . childCount < 1 )
{
2024-08-29 15:24:20 +08:00
DebugUtil . LogError ( "角色节点错误:" + goCharacter . name ) ;
2024-04-03 19:11:09 +08:00
return ;
}
// TODO 临时隐藏武器方式
Transform tsRoot = goCharacter . transform . GetChild ( 0 ) . Find ( "Root" ) ;
2024-08-16 13:55:00 +08:00
if ( null = = tsRoot )
return ;
2024-04-03 19:11:09 +08:00
Transform tsWeaponRoot = tsRoot . Find ( "Bip001/Bip001 Spine/Bip001 Spine1/Bip001 R Clavicle/Bip001 R UpperArm/Bip001 R Forearm/Bip001 R Hand/Grip_point01" ) ;
if ( tsWeaponRoot ! = null )
tsWeaponRoot . gameObject . SetActive ( false ) ;
}
2024-03-18 17:33:19 +08:00
/// <summary>
/// 获取Timeline资源
/// </summary>
2024-03-29 16:57:35 +08:00
/// <param name="timelineName"></param>
2024-03-18 17:33:19 +08:00
/// <returns></returns>
2024-03-29 16:57:35 +08:00
private async UniTask < TimelineAsset > GetTimeLineAsset ( string timelineName )
2024-03-18 17:33:19 +08:00
{
2024-03-29 16:57:35 +08:00
if ( ! dicTimeLineAsset . TryGetValue ( timelineName , out TimelineAsset timelineAsset ) )
2024-03-18 17:33:19 +08:00
{
2024-04-28 19:35:49 +08:00
string timelinePath = $"{SHOW_TIMELINE_PATH}{showSceneType}/{timelineName}.playable" ;
2024-03-18 17:33:19 +08:00
if ( string . IsNullOrWhiteSpace ( timelinePath ) )
{
2024-03-29 19:47:34 +08:00
DebugUtil . LogError ( $"找不到timelinePath,{nameof(timelineName)}:{timelineName}" ) ;
2024-03-18 17:33:19 +08:00
return null ;
}
timelineAsset = await LoadAssetAsync < TimelineAsset > ( timelinePath ) ;
if ( timelineAsset = = null )
{
2024-03-29 19:47:34 +08:00
DebugUtil . LogError ( $"找不到TimelineAsset, {nameof(timelineName)}:{timelineName} path:{timelinePath}" ) ;
2024-03-18 17:33:19 +08:00
return null ;
}
2024-03-29 16:57:35 +08:00
dicTimeLineAsset . Add ( timelineName , timelineAsset ) ;
2024-03-18 17:33:19 +08:00
}
return timelineAsset ;
}
/// <summary>
/// 演出点是否重复
/// </summary>
/// <param name="group"></param>
/// <returns></returns>
private bool IsShowPointExist ( ShowGroupData group )
{
foreach ( DataShowConfig showConfig in group . ListConfig )
{
if ( setUseShowPointIndex . Contains ( showConfig . PointID ) )
return true ;
}
return false ;
}
/// <summary>
/// 是否可以使用限定角色
/// </summary>
/// <param name="group"></param>
/// <returns></returns>
private bool IsCanUseFixCharacter ( ShowGroupData group )
{
2024-04-01 17:51:56 +08:00
foreach ( DataShowConfig showConfig in group . ListConfig )
2024-03-18 17:33:19 +08:00
{
if ( ! ValueValidator . IsIdValid ( showConfig . CharacterID ) & & ! IsCanUseCharacter ( showConfig . CharacterID ) )
return false ;
}
return true ;
}
/// <summary>
/// 角色是否可用
/// </summary>
/// <param name="characterId"></param>
/// <returns></returns>
private bool IsCanUseCharacter ( int characterId )
{
return ! setUseCharactrtId . Contains ( characterId ) ;
}
/// <summary>
/// 获取进度
/// </summary>
/// <returns>0f-1f</returns>
public float GetRefreshProcess ( )
{
return currState switch
{
E_CurState . None = > 0f ,
E_CurState . LoadingCharacters = > ( float ) listShowPointResult . Count / CharacterMaxCount ,
E_CurState . Present = > 1f ,
_ = > 0f ,
} ;
}
2024-04-01 17:51:56 +08:00
/// <summary>
/// 收集演出点
/// </summary>
[Button("收集演出点")]
public void CollectShowPoint ( )
{
if ( tsCharacterShowPointRoot = = null )
{
Debug . LogError ( "角色演出点为空" ) ;
return ;
}
if ( tsItemShowPointRoot = = null )
{
Debug . LogError ( "道具演出点为空" ) ;
return ;
}
#region 先清除原有演出点
Transform [ ] tsShowPoints = tsCharacterShowPointRoot . GetComponentsInChildren < Transform > ( ) ;
foreach ( Transform ts in tsShowPoints )
{
if ( ts = = tsCharacterShowPointRoot )
continue ;
DestroyImmediate ( ts . gameObject ) ;
}
tsShowPoints = tsItemShowPointRoot . GetComponentsInChildren < Transform > ( ) ;
foreach ( Transform ts in tsShowPoints )
{
if ( ts = = tsItemShowPointRoot )
continue ;
DestroyImmediate ( ts . gameObject ) ;
}
# endregion
ShowPoint [ ] showPoints = tsCollectRoot . GetComponentsInChildren < ShowPoint > ( ) ;
2024-04-01 18:24:46 +08:00
int characterIndex = 0 ;
int itemIndex = 0 ;
2024-04-01 17:51:56 +08:00
foreach ( ShowPoint showPoint in showPoints )
{
switch ( showPoint . ShowPointType )
{
case E_ShowPointType . Character :
{
2024-04-03 19:11:09 +08:00
GameObject go = new ( $"{characterIndex++:D3}_{showPoint.Name}" ) ;
2024-04-01 18:24:46 +08:00
go . transform . SetPositionAndRotation ( showPoint . gameObject . transform . position , showPoint . gameObject . transform . rotation ) ;
2024-04-01 17:51:56 +08:00
go . transform . parent = tsCharacterShowPointRoot ;
}
break ;
case E_ShowPointType . Item :
{
2024-04-03 19:11:09 +08:00
GameObject go = new ( $"{itemIndex++:D3}_{showPoint.Name}" ) ;
2024-04-01 18:24:46 +08:00
go . transform . SetPositionAndRotation ( showPoint . gameObject . transform . position , showPoint . gameObject . transform . rotation ) ;
2024-04-01 17:51:56 +08:00
go . transform . parent = tsItemShowPointRoot ;
}
break ;
default :
{
Debug . LogError ( "未处理类型" ) ;
}
break ;
}
}
}
2024-03-18 17:33:19 +08:00
}
/// <summary>
/// 抽取流程的记录
/// </summary>
[Serializable]
2024-04-26 14:48:47 +08:00
public class ExtractRecord
2024-03-18 17:33:19 +08:00
{
/// <summary>
/// 单个演出点记录
/// </summary>
[Serializable]
public struct SinglePointRecord
{
[LabelText("演出点ID")]
public int showPoint ;
2024-03-29 16:57:35 +08:00
public string timelineName ;
2024-03-18 17:33:19 +08:00
public uint characterID ;
}
[LabelText("组ID")]
private int groupID ;
[LabelText("抛弃原因")]
[ShowIf("isDispose")]
private E_DisposeReason disposeReason ;
[LabelText("角色记录")]
private List < SinglePointRecord > listRecord ;
public ExtractRecord ( int groupID , E_DisposeReason disposeReason )
{
this . groupID = groupID ;
this . disposeReason = disposeReason ;
listRecord = new ( ) ;
}
2024-04-26 14:48:47 +08:00
public void Add ( SinglePointRecord singlePointRecord )
2024-03-18 17:33:19 +08:00
{
listRecord . Add ( singlePointRecord ) ;
}
}
/// <summary>
/// 演出组数据
/// </summary>
public struct ShowGroupData
{
/// <summary>
/// 演出组id
/// </summary>
private readonly int groupId ;
/// <summary>
/// 是否必须有角色
/// </summary>
private bool isMustHasCharacter ;
/// <summary>
/// 该组演出点配置数据
/// </summary>
private readonly List < DataShowConfig > listConfig ;
/// <summary>
/// 演出组id
/// </summary>
public readonly int GroupID
{
get { return groupId ; }
}
/// <summary>
/// 是否必须有角色
/// </summary>
public readonly bool IsMustHasCharacter { get { return isMustHasCharacter ; } }
/// <summary>
/// 该组演出点配置数据
/// </summary>
public readonly List < DataShowConfig > ListConfig
{
get { return listConfig ; }
}
public ShowGroupData ( int groupId )
{
this . groupId = groupId ;
isMustHasCharacter = false ;
listConfig = new ( ) ;
}
public void Add ( DataShowConfig dataShowConfig )
{
isMustHasCharacter | = dataShowConfig . HasCharacter ;
listConfig . Add ( dataShowConfig ) ;
}
/// <summary>
/// 打乱顺序
/// </summary>
public readonly void Shuffle ( )
{
CommonUtils . Shuffle ( listConfig ) ;
}
}
/// <summary>
/// 演出点结果
/// </summary>
public readonly struct ShowPointResult
{
/// <summary>
/// 演出组id
/// </summary>
private readonly int groupID ;
/// <summary>
/// 演出点索引
/// </summary>
private readonly int showPointIndex ;
/// <summary>
2024-04-26 15:35:22 +08:00
/// 道具演出点索引
/// </summary>
private readonly int itemPointIndex ;
/// <summary>
2024-03-29 16:57:35 +08:00
/// Timeline名
2024-03-18 17:33:19 +08:00
/// </summary>
2024-03-29 16:57:35 +08:00
private readonly string timelineName ;
2024-03-18 17:33:19 +08:00
/// <summary>
2024-04-26 15:35:22 +08:00
/// 道具名
/// </summary>
private readonly string itemName ;
/// <summary>
2024-03-18 17:33:19 +08:00
/// 角色数据
/// </summary>
private readonly CharacterDataInfo characterData ;
2024-04-26 15:35:22 +08:00
#region 属性
2024-03-18 17:33:19 +08:00
public int GroupID
{
get { return groupID ; }
}
public int ShowPointIndex
{
get { return showPointIndex ; }
}
2024-03-29 16:57:35 +08:00
public string TimelineName
2024-03-18 17:33:19 +08:00
{
2024-03-29 16:57:35 +08:00
get { return timelineName ; }
2024-03-18 17:33:19 +08:00
}
2024-04-26 15:35:22 +08:00
public int ItemPointIndex
{
get { return itemPointIndex ; }
}
public string ItemName
{
get { return itemName ; }
}
2024-03-18 17:33:19 +08:00
public CharacterDataInfo CharacterData
{
get { return characterData ; }
}
2024-04-26 15:35:22 +08:00
# endregion
2024-03-18 17:33:19 +08:00
2024-04-26 15:35:22 +08:00
public ShowPointResult ( int groupID ,
int showPointIndex ,
string timelineName ,
CharacterDataInfo characterData ,
int itemPointIndex ,
string itemName )
2024-03-18 17:33:19 +08:00
{
this . groupID = groupID ;
this . showPointIndex = showPointIndex ;
2024-03-29 16:57:35 +08:00
this . timelineName = timelineName ;
2024-03-18 17:33:19 +08:00
this . characterData = characterData ;
2024-04-26 15:35:22 +08:00
this . itemPointIndex = itemPointIndex ;
this . itemName = itemName ;
2024-03-18 17:33:19 +08:00
}
}