Files
JJBB/Assets/Project/Script/Scene/SceneLogic/IndependentEffectManager.cs
2024-08-23 15:49:34 +08:00

448 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}