Files
JJBB/Assets/Project/Script/Scene/SceneLogic/IndependentEffectManager.cs

448 lines
17 KiB
C#
Raw Normal View History

2024-08-23 15:49:34 +08:00
using System;
using System.Collections.Generic;
using Games.GlobeDefine;
using Games.LogicObj;
using GCGame.Table;
using Module.Log;
using UnityEngine;
/// <summary>
/// 独立特效管理器
/// </summary>
// 负责处理不依赖于任何角色的特效类型,例如子弹爆炸等
public sealed class IndependentEffectManager : BaseEffectLogic
{
// 最大缓存镜像数目
private List<CharacterCloneReference> _activeCloneList;
private List<MyTuple<Delay, float>> _delayParticleList;
// private List<CharacterCloneReference> _inactiveCloneList;
// 锁链类型Impact的Id
//public const int chainImpactLogicId = 16;
public static IndependentEffectManager Instance { get; private set; }
// public CentralEffectPool EffectPool { get; private set; }
private void Awake()
{
Init();
_delayParticleList = new List<MyTuple<Delay, float>>();
_activeCloneList = new List<CharacterCloneReference>();
}
protected override void OnEnable()
{
base.OnEnable();
if (Instance == null)
Instance = this;
#if UNITY_EDITOR
else
LogModule.ErrorLog("独立特效管理器试图播放两个!");
#endif
}
protected override void OnDisable()
{
base.OnDisable();
Instance = null;
}
private void Update()
{
for (var i = _delayParticleList.Count - 1; i >= 0; i--)
if (_delayParticleList[i].second <= Time.time)
{
// 有其他系统外的操作,可能造成特效物体被意外摧毁,因此增加一个检查
if (_delayParticleList[i].first != null)
_delayParticleList[i].first.DelayActive();
_delayParticleList.RemoveAt(i);
}
}
/// <summary>
/// 注册粒子延迟激活效果
/// </summary>
public static void AddParticleDelay(Delay delay)
{
if (Instance != null)
{
var record = Instance._delayParticleList.Find(a => a.first == delay);
if (record == null)
{
record = new MyTuple<Delay, float>(delay, default(float));
Instance._delayParticleList.Add(record);
}
record.second = Time.time + delay.delayTime;
record.first.gameObject.SetActive(false);
}
else
{
LogModule.ErrorLog("试图在IndependentEffectManager不存在的时候使用粒子Delay组件");
}
}
/// <summary>
/// 移除粒子延迟激活效果,是否激活由调用者自行决定
/// </summary>
public static void RemoveParticleDelay(Delay delay)
{
if (Instance != null)
{
var index = Instance._delayParticleList.FindIndex(a => a.first == delay);
if (index >= 0)
Instance._delayParticleList.RemoveAt(index);
}
}
public static void PushEffect(Tab_Effect data, Transform effect)
{
GameManager.gameManager.effectPool.PushEffect(data, effect);
}
public static void PushEffect(BaseEffectReference effectReference)
{
effectReference.EndEffect();
PushEffect(effectReference.data, effectReference.effect);
}
public static void CleanEffectLogic(BaseEffectLogic effectLogic)
{
if (GameManager.gameManager != null)
GameManager.gameManager.effectPool.CleanEffectLogic(effectLogic);
}
public static void CancelLoad(Predicate<EffectLoadData> predicate)
{
GameManager.gameManager.effectPool.RemoveLoadTask(predicate);
}
public static void CancelLoadByHandleId(int handleId)
{
GameManager.gameManager.effectPool.CancelLoadByHandleId(handleId);
}
public static void PullEffectItem(EffectLoadData loadData)
{
GameManager.gameManager.effectPool.PullEffect(loadData);
}
public void PreloadEffect(int effectId)
{
var tableData = TableManager.GetEffectByID(effectId, 0);
if (tableData == null)
LogModule.ErrorLog(string.Format("无法找到Id = {0}的特效!", effectId));
else
GameManager.gameManager.effectPool.PreloadEffect(tableData);
}
public void ShowEffect(int effectId, int layer, GameDefine_Globe.OBJ_TYPE objType, Vector3 position, Quaternion rotation, float duration = -1f,
PlayEffectDelegate playCallback = null, object playParameter = null, int? serverHandle = null)
{
var tableData = TableManager.GetEffectByID(effectId, 0);
if (tableData == null)
LogModule.ErrorLog(string.Format("无法找到Id = {0}的特效!", effectId));
else
ShowEffect(tableData, layer, objType, position, rotation, duration, playCallback, playParameter, serverHandle);
}
public void ShowEffect(Tab_Effect tableData, int layer, GameDefine_Globe.OBJ_TYPE objType, Vector3 position, Quaternion rotation, float duration = -1f,
PlayEffectDelegate playCallback = null, object playParameter = null, int? serverHandle = null)
{
if (ValidEffectByCount(tableData, objType))
{
var customData = new NormalEffectCustomData(position, rotation, duration);
var loadData =
new EffectLoadData(this, layer, tableData, serverHandle, playCallback, playParameter, customData);
GameManager.gameManager.effectPool.PullEffect(loadData);
}
}
public void ShowBullet(int bulletId, int sourceId, int targetId, int layer, GameDefine_Globe.OBJ_TYPE objType, PlayEffectDelegate playCallback = null,
object playParameter = null, int? serverHandle = null)
{
Tab_Effect effectData;
Tab_Bullet bulletData;
if (bulletId > 0 && GetBulletData(bulletId, out effectData, out bulletData) && ValidEffectByCount(effectData, objType))
{
var customData = new BulletCustomData(bulletData, sourceId, targetId);
var loadData = new EffectLoadData(this, layer, effectData, serverHandle, playCallback, playParameter,
customData);
GameManager.gameManager.effectPool.PullEffect(loadData);
}
}
public void ShowBulletToPos(int bulletId, Vector3 startPos, Vector3 endPos, int layer, GameDefine_Globe.OBJ_TYPE objType, PlayEffectDelegate playCallback = null,
object playParameter = null, int? serverHandle = null)
{
Tab_Effect effectData;
Tab_Bullet bulletData;
if (bulletId > 0 && GetBulletData(bulletId, out effectData, out bulletData) && ValidEffectByCount(effectData, objType))
{
var offset = new Vector3(bulletData.StartPosX, bulletData.StartPosY, bulletData.StartPosZ);
startPos += offset;
endPos += offset;
var customData = new BulletToPosData(bulletData, startPos, endPos);
var loadData = new EffectLoadData(this, layer, effectData, serverHandle, playCallback, playParameter,
customData);
GameManager.gameManager.effectPool.PullEffect(loadData);
}
}
// 注:特殊处理锁链 - 锁链句柄相同时,会重置而不是重新生成,因此需要传入两个句柄以保证客户端句柄正确执行
public void ShowChain(int effectId, int layer, GameDefine_Globe.OBJ_TYPE objType, ChainCustomData chainData, PlayEffectDelegate playCallback = null,
object playParameter = null, int? serverHandle = null)
{
var tableData = TableManager.GetEffectByID(effectId, 0);
if (tableData == null)
LogModule.ErrorLog(string.Format("无法找到Id = {0}的特效!", effectId));
else
ShowChain(tableData, layer, objType, chainData, playCallback, playParameter, serverHandle);
}
public void ShowChain(Tab_Effect tableData, int layer, GameDefine_Globe.OBJ_TYPE objType, ChainCustomData chainData,
PlayEffectDelegate playCallback = null, object playParameter = null, int? serverHandle = null)
{
var create = true;
if (serverHandle != null)
{
var activeChain = GetReferenceByHandle(serverHandle) as ChainEffectReference;
if (activeChain != null)
{
create = false;
activeChain.ResetParameters(chainData);
}
else
{
var delayChain = GetDelayByHandle(serverHandle);
if (delayChain != null)
{
create = false;
delayChain.loadData.customData = chainData;
}
else
{
CancelLoadByHandleId(serverHandle.Value);
}
}
}
if (create && ValidEffectByCount(tableData, objType))
{
var loadData = new EffectLoadData(this, layer, tableData, serverHandle, playCallback, playParameter,
chainData);
GameManager.gameManager.effectPool.PullEffect(loadData);
}
}
// 用于Boss特殊效果不执行数量屏蔽
public void ShowMeteor(int effectId, Vector2 holdPos,GameDefine_Globe.OBJ_TYPE objType, Vector2 fallPos, Vector2 rollPos, float fallTime,
float rollTime, int? serverHandle)
{
var effectData = CommonUtility.TryGetTable(effectId, a => TableManager.GetEffectByID(a, 0));
if (effectData != null)
{
var meteorData =
new MeteorEffectData(effectData.OffsetY, 0f, fallTime, rollTime, holdPos, fallPos, rollPos);
var loadData = new EffectLoadData(this, gameObject.layer, effectData, serverHandle, null, null, meteorData);
GameManager.gameManager.effectPool.PullEffect(loadData);
var glowId = effectData.GetParamValuebyIndex(0);
if (glowId >= 0)
{
var z = meteorData.fallPosition - meteorData.holdPosition;
var x = Vector3.Cross(Vector3.up, z);
var y = Vector3.Cross(z, x);
var rotation = y == Vector3.zero ? Quaternion.identity : Quaternion.LookRotation(z, y);
ShowEffect(glowId, gameObject.layer, objType, meteorData.fallPosition, rotation);
}
}
}
private bool GetBulletData(int bulletId, out Tab_Effect effectData, out Tab_Bullet bulletData)
{
var result = false;
bulletData = TableManager.GetBulletByID(bulletId, 0);
if (bulletData == null)
{
LogModule.ErrorLog("无法找到子弹数据表id={0}", bulletId);
effectData = null;
}
else
{
effectData = TableManager.GetEffectByID(bulletData.EffectId, 0);
if (effectData == null)
LogModule.ErrorLog("无法找到特效数据表id={0}", bulletData.EffectId);
else
result = true;
}
return result;
}
public CharacterCloneReference ShowCharacterClone(int serverId, Vector2 serverPos, Quaternion rotation,
Obj_Character_Clone_Init_Data initData)
{
// // 特殊处理如果服务器id同某个激活状态的影子一致直接替换影子状态
// // 服务器id一致或者重用模型参数一致的
// var index = _inactiveCloneList.FindIndex(a => a.cloneObj.Profession == initData.m_nProfession
// && a.cloneObj.ModelVisualID == initData.m_ModelVisualID
// && a.cloneObj.WeaponDataID == initData.m_WeaponDataID);
var reference = new CharacterCloneReference(serverId, initData, serverPos, rotation);
// if (index < 0)
// {
// reference
// }
// else
// {
// reference = _inactiveCloneList[index];
// _inactiveCloneList.RemoveAt(index);
// reference.cloneObj.gameObject.SetActive(true);
// reference.SetCloneInfo(serverId, initData, serverPos, rotation);
// }
_activeCloneList.Add(reference);
return reference;
}
public void RemoveCharacterClone(int serverId)
{
CharacterCloneReference clone = null;
for (var i = _activeCloneList.Count - 1; i >= 0; i--)
{
if (_activeCloneList[i].ServerId == serverId)
{
clone = _activeCloneList[i];
_activeCloneList.RemoveAt(i);
break;
}
}
if (clone != null)
{
clone.cloneObj.DestroyObj();
Destroy(clone.cloneObj.gameObject);
}
}
// 服务器没有提供唯一句柄,暂时使用这种策略做一个临时句柄
// 有低概率和服务器特效句柄重复,出现率应该不高,也不会引发其他逻辑混乱
private int CreateWuChangHandle(int effectId, int sourceId, int targetId)
{
return Animator.StringToHash(effectId + "_" + sourceId + "_" + targetId);
}
// 用于Boss特殊效果不执行数量屏蔽
public void CreateWuChangLink(int effectId, int sourceId, int targetId)
{
var handle = CreateWuChangHandle(effectId, sourceId, targetId);
if (CheckCreateByHandle(handle))
{
var effectData = CommonUtility.TryGetTable(effectId, a => TableManager.GetEffectByID(a, 0));
if (effectData != null)
{
var customData = new WuChangLinkData(sourceId, targetId);
var loadData = new EffectLoadData(this, gameObject.layer, effectData, handle, null, null, customData);
GameManager.gameManager.effectPool.PullEffect(loadData);
}
}
}
public void BreakWuChangLink(int effectId, int sourceId, int targetId)
{
var handle = CreateWuChangHandle(effectId, sourceId, targetId);
var effectReference = ActiveList.Find(a => a.effectHandle == handle) as WuChangLinkReference;
// 未激活时,可能处于加载或者等待状态
if (effectReference == null)
RemoveEffectByHandle(handle);
else
effectReference.BreakLink();
}
// 用于Boss特殊效果不执行数量屏蔽
public void AddWuChangAirport(int effectId, int sourceId, int count)
{
// 已知问题sourceId低概率同其他特效id重叠不过万年难遇
var handle = CreateGhostAirportHandle(sourceId);
if (CheckCreateByHandle(handle))
{
var effectData = CommonUtility.TryGetTable(effectId, a => TableManager.GetEffectByID(a, 0));
if (effectData != null)
{
var airportData = new WuChangAirportData(sourceId, count);
var loadData = new EffectLoadData(this, gameObject.layer, effectData, handle, null, null, airportData);
GameManager.gameManager.effectPool.PullEffect(loadData);
}
}
}
public void RemoveWuChangAirport(int sourceId)
{
// 已知问题sourceId低概率同其他特效id重叠不过万年难遇
var handle = CreateGhostAirportHandle(sourceId);
RemoveEffectByHandle(handle);
}
public void AttackFromWuChangAirport(int sourceId, Obj_Character target, float delay)
{
// 已知问题sourceId低概率同其他特效id重叠不过万年难遇
var handle = CreateGhostAirportHandle(sourceId);
var effectReference = ActiveList.Find(a => a.effectHandle == handle) as WuChangAirportReference;
if (effectReference != null)
{
var targetPoint = target.ObjEffectLogic == null
? target.ObjTransform
: target.ObjEffectLogic.GetBindPoint(EffectLogic.centerName);
effectReference.AttackTarget(targetPoint, Vector3.zero, delay);
}
}
private int CreateGhostAirportHandle(int id)
{
return Animator.StringToHash(id + "_GhostAirport");
}
private bool CheckCreateByHandle(int handle)
{
var create = true;
var effectReference = ActiveList.Find(a => a.effectHandle == handle);
if (effectReference != null)
create = false;
else
{
var delayChain = GetDelayByHandle(handle);
if (delayChain != null)
create = false;
else
CancelLoadByHandleId(handle);
}
return create;
}
/// <summary>
/// 角色克隆镜像的数据
/// </summary>
// 注:同一般特效不同,这个玩意是创建然后加载,而不是加载完成创建。
// 由于特效机制底层会走加载创建的逻辑,使用新的类型来处理这个
public class CharacterCloneReference
{
public const string shadowNameFormat = "CharacterClone_{0}";
public readonly Obj_CharacterClone cloneObj;
public CharacterCloneReference(int serverId, Obj_Character_Clone_Init_Data initData, Vector3 position,
Quaternion rotation)
{
var gameObject = new GameObject();
cloneObj = gameObject.AddComponent<Obj_CharacterClone>();
SetCloneInfo(serverId, initData, position, rotation);
}
public int ServerId { get; private set; }
public void SetCloneInfo(int serverId, Obj_Character_Clone_Init_Data initData, Vector2 position,
Quaternion rotation)
{
ServerId = serverId;
cloneObj.gameObject.name = string.Format(shadowNameFormat, serverId);
cloneObj.Init(initData);
cloneObj.SyncSetPos(position);
cloneObj.ObjTransform.localRotation = rotation;
}
}
}