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

563 lines
22 KiB
C#
Raw Normal View History

2024-08-23 15:49:34 +08:00
/********************************************************************************
* EffectLogic.cs
* \Script\LogicCore\EffectLogic.cs
*
* 2013-11-21
*
*
*
*********************************************************************************/
using System;
using System.Collections.Generic;
using Games.GlobeDefine;
using Games.LogicObj;
using GCGame.Table;
using Module.Log;
using UnityEngine;
public class EffectLogic : BaseEffectLogic
{
public enum EffectType
{
TYPE_NORMAL = 0,
TYPE_CHANGEMODEL = 1,
TYPE_CHANGMATPRO = 2, //材质属性
TYPE_BLIND = 3, //致盲
TYPE_CHANGEMODELMAT = 4, //改变模型材质
TYPE_CHANGESHADER = 5, //该变模型Shder
TYPE_SCREENUIEFFECT = 6, //将一下UI当作特效显示
TYPE_CHAOS = 7, //混乱的效果逻辑
TYPE_ADDMAT = 8, // 增加材质
TYPE_CLIENTNPC = 9, //客户端NPC
TYPE_CLONE = 10, //角色模型复制
TYPE_SCREEN = 11, //显示在屏幕的特效
TYPE_CIRCLE = 12, // 圆形指示器
TYPE_RECTANGLE = 13, // 矩形指示器
TYPE_SECTOR = 14, // 扇形指示器
TYPE_MATPROBYHEALTH = 15, // 颜色随生命值改变
TYPE_AVATAR = 16, // 背后幻象效果,跟随角色并且使用监听角色动画
TYPE_SCALE = 17 // 修改模型尺寸
}
// 通用节点名称记录
public const string centerName = "CenterPoint";
public const string headName = "HeadPoint";
public const string leftHandName = "LHandPoint";
public const string rightHandName = "RHandPoint";
public const string leftFootName = "LFootPoint";
public const string rightFootName = "RFootPoint";
public const string leftWeaponName = "Weapon_L";
public const string rightWeaponName = "Weapon_R";
public const string namePointName = "NamePoint"; // 节点头顶位置
public const string normalPointName = "EffectPoint"; //通用点
private readonly Dictionary<string, Transform> _effectBindPointCache = new Dictionary<string, Transform>(); // 绑定点缓存
private readonly List<EffectAddPoint> _effectpointInfo = new List<EffectAddPoint>(); // 额外绑定点缓存
private Obj _effectObj;
private ImpactEffectMgr _impactEffectMgr;
private Tab_CharModel _modelData;
public bool hideAllEffect { get; private set; }
/// <summary>
/// 获得绑定位置节点Transform
/// </summary>
public Transform GetBindPoint(string pointName)
{
Transform result;
if (!_effectBindPointCache.TryGetValue(pointName, out result))
for (var i = _effectpointInfo.Count - 1; i >= 0; i--)
// 原规则中自修复列表的功能
if (_effectpointInfo[i] == null)
_effectpointInfo.RemoveAt(i);
else if (string.Equals(_effectpointInfo[i].pointName, pointName,
StringComparison.CurrentCultureIgnoreCase))
result = _effectpointInfo[i].transform;
// 自修复逻辑,某些不存在或者挂点命名不规范的物体,使用控制器所在节点
if (result == null)
result = _effectObj.effectPoint;
return result;
}
public override Obj_Character GetOwnerCharacter()
{
var result = _effectObj as Obj_Character;
if (result == null)
LogModule.ErrorLog("EffectLogic拥有者不是一个角色不应该使用角色独有的特效类型");
return result;
}
/// <summary>
/// 获得绑定位置节点Transform和相对偏移数值
/// </summary>
public override Transform GetBindPoint(string pointName, out Vector3 offset)
{
offset = GetBindPointOffset(pointName);
return GetBindPoint(pointName);
}
public bool IsHaveBindPoint(string pointName)
{
return GetBindPoint(pointName) != null;
}
public void SetHideAllEffect(bool isHideAll)
{
if (hideAllEffect != isHideAll)
{
hideAllEffect = isHideAll;
if (hideAllEffect)
{
CleanEffect();
CleanImpacts();
}
}
}
/// <summary>
/// 角色模型析构时,移除特效绑定点
/// </summary>
public void RemoveBindPoints()
{
_effectBindPointCache.Clear();
if (_effectObj != null)
{
var normalPoint = _effectObj.effectPoint;
_effectBindPointCache.Add(normalPointName, normalPoint);
for (var i = 0; i < ActiveList.Count; i++)
if (ActiveList[i].effect != null)
ActiveList[i].effect.SetParent(normalPoint, false);
}
}
//上坐骑的时候修改一下默认特效节点位置
public void ResetNormalEffectPoint()
{
var move = false;
var newParent = _effectObj.effectPoint;
Transform oldParent;
if (_effectBindPointCache.TryGetValue(normalPointName, out oldParent))
{
if (oldParent != newParent)
{
move = true;
_effectBindPointCache[normalPointName] = newParent;
}
}
else
{
// 未初始化时,使用根节点作为实际位置
// 注实际应该是使用ModelNode的模型节点作为根节点但是由于早期特效都不继承模型缩放继续使用根节点
oldParent = _effectObj.ObjTransform;
if (oldParent != newParent)
{
move = true;
_effectBindPointCache.Add(normalPointName, newParent);
}
}
if (move)
for (var i = 0; i < ActiveList.Count; i++)
if (ActiveList[i].effect != null && ActiveList[i].effect.parent == oldParent)
ActiveList[i].effect.SetParent(newParent, false);
}
/// <summary>
/// 获得绑定位置的偏移数值
/// </summary>
private Vector3 GetBindPointOffset(string pointName)
{
var result = Vector3.zero;
if (_modelData == null)
_modelData = TableManager.GetCharModelByID(_effectObj.ModelID);
if (_modelData != null)
if (pointName == headName)
{
if (_modelData.ModelType == (int) GameDefine_Globe.MODELTYPE.ANIMAL)
result = new Vector3(0.0f, -0.8f, 0f);
else if (_modelData.ModelType == (int) GameDefine_Globe.MODELTYPE.HUMAN ||
_modelData.ModelType == (int) GameDefine_Globe.MODELTYPE.HUMAN_FAT ||
_modelData.ModelType == (int) GameDefine_Globe.MODELTYPE.HUMAN_DYQ)
result = new Vector3(-0.5f, 0f, 0f);
else if (_modelData.ModelType == -1)
result = new Vector3(0.0f, _modelData.HeadInfoHeight * 0.5f + 0.5f, 0f);
}
else if (pointName == centerName)
{
if (_modelData.ModelType == -1)
result = new Vector3(0.0f, _modelData.HeadInfoHeight * 0.25f, 0f);
}
else if (pointName == leftHandName || pointName == rightHandName)
{
if (_modelData.ModelType == (int) GameDefine_Globe.MODELTYPE.HUMAN ||
_modelData.ModelType == (int) GameDefine_Globe.MODELTYPE.HUMAN_FAT ||
_modelData.ModelType == (int) GameDefine_Globe.MODELTYPE.HUMAN_DYQ)
result = new Vector3(-0.03f, 0.035f, 0.01f);
}
else if (pointName == namePointName)
{
// 需要移除Transform缩放的影响
result = Vector3.up * _modelData.HeadInfoHeight / _effectObj.Scale.y;
}
return result;
}
/// <summary>
/// 获得绑定节点当前的世界坐标位置
/// </summary>
public Vector3 GetBindPointPosition(string pointName)
{
Vector3 offset;
var bindPoint = GetBindPoint(pointName, out offset);
// 无效节点校正到物体本身位置
if (bindPoint == null)
bindPoint = gameObject.transform;
return bindPoint.position + bindPoint.rotation * offset;
}
public void InitEffect(Obj effGameObj, GameObject modelRoot)
{
// 如果已经初始化过只需要更新_effectObj
if (!IsInited)
{
Init();
_impactEffectMgr = new ImpactEffectMgr();
}
_effectObj = effGameObj;
InitEffectPointInfo(modelRoot);
}
public void InitEffectPointInfo(GameObject modelRoot)
{
_effectBindPointCache.Clear();
_effectpointInfo.Clear();
// 绑定全部自定义节点
var points = _effectObj.GetComponentsInChildren<EffectAddPoint>();
for (var i = 0; i < points.Length; i++)
if (points[i].pointName == namePointName)
LogModule.ErrorLog(string.Format("{0}物体试图重新定义基础特效绑定点{1}", modelRoot.transform.GetHierarchyName(),
normalPointName));
else
_effectpointInfo.Add(points[i]);
// 绑定固定节点
if (_effectObj == null)
{
LogModule.ErrorLog(string.Format("物体{0}拥有EffectLogic但是未绑定m_EffectObj", gameObject.name));
}
else
{
_effectBindPointCache.Add(normalPointName, _effectObj.effectPoint);
var charModelInfo = TableManager.GetCharModelByID(_effectObj.ModelID);
if (charModelInfo != null && charModelInfo.ModelType != -1)
{
var effectPointInfo = TableManager.GetEffectPointByID(charModelInfo.ModelType);
if (effectPointInfo != null)
{
RegisterBindPoint(modelRoot, centerName, effectPointInfo.CenterPoint);
RegisterBindPoint(modelRoot, headName, effectPointInfo.HeadPoint);
RegisterBindPoint(modelRoot, leftHandName, effectPointInfo.LHandPoint);
RegisterBindPoint(modelRoot, rightHandName, effectPointInfo.RHandPoint);
RegisterBindPoint(modelRoot, leftFootName, effectPointInfo.LFootPoint);
RegisterBindPoint(modelRoot, rightFootName, effectPointInfo.RFootPoint);
RegisterBindPoint(modelRoot, leftWeaponName, effectPointInfo.WeaponL);
RegisterBindPoint(modelRoot, rightWeaponName, effectPointInfo.WeaponR);
// 头顶绑定点直接使用主要Transform
_effectBindPointCache.Add(namePointName, _effectObj.transform);
}
for (var i = 0; i < ActiveList.Count; i++)
{
var effect = ActiveList[i].effect;
var data = ActiveList[i].data;
if ((data != null) & (effect != null))
{
// 注Offset位置当前Offset不变
var parent = GetBindPoint(data.ParentName);
if (parent != effect.parent)
{
var offset = GetBindPointOffset(data.ParentName);
// 旋转和缩放维持原有参数
effect.SetParent(parent, false);
effect.localPosition = offset;
}
}
}
}
}
}
private void RegisterBindPoint(GameObject modelRoot, string pointName, string path)
{
path = Obj.TrimModelRoot(path);
var bindPoint = modelRoot.transform.Find(path);
if (bindPoint)
_effectBindPointCache.Add(pointName, bindPoint);
}
public void CleanImpacts()
{
if (_impactEffectMgr != null)
_impactEffectMgr.ClearEffect();
}
public void PlaySpecialEffect(Tab_Effect effectData, float overrideDuration = -1f)
{
if (effectData.Type == (int) EffectType.TYPE_SCREEN)
{
GlobalEffectMgr.PlayerNormalEffect(effectData.Path, Vector3.zero,
overrideDuration > 0f ? overrideDuration : effectData.Duration);
return;
}
if (_impactEffectMgr == null)
return;
_impactEffectMgr.StartImpactEffect(effectData, _effectObj, overrideDuration);
}
/// <summary>
/// 检查普通特效是否可以被播放
/// </summary>
private bool ValidEffectCondition(Tab_Effect effectInfo)
{
bool result;
if (string.IsNullOrEmpty(effectInfo.Path) || _effectObj == null || GameManager.gameManager.effectPool == null)
result = false;
else
result = ValidEffectByCount(effectInfo, _effectObj.ObjType);
return result;
}
protected override void AfterCameraMovement(object args)
{
base.AfterCameraMovement(args);
_impactEffectMgr.OnUpdate();
}
/// <summary>
/// 检查当前玩家状态是不是正常
/// </summary>
private bool ValidPlayer()
{
return !hideAllEffect && _effectObj != null && _effectObj.IsVisibleChar();
}
/// <summary>
/// 开始播放一个特效
/// </summary>
/// <param name="effectId">特效id</param>
/// <param name="delPlayEffect">特效播放回调</param>
/// <param name="param">额外参数</param>
/// <param name="delayModifier">延迟修正值,负数减少延迟,整数增加延迟</param>
/// <param name="handle">特效句柄</param>
public void PlayEffect(int effectId, PlayEffectDelegate delPlayEffect = null, object param = null,
float delayModifier = 0f, int? handle = null)
{
if (effectId <= 0 || !PlayerPreferenceData.SystemRoleEffectEnable)
return;
var effectInfo = TableManager.GetEffectByID(effectId);
if (effectInfo == null)
{
LogModule.ErrorLog(string.Format("无法找到id={0}的特效数据!", effectId));
if (null != delPlayEffect)
delPlayEffect(null, param);
return;
}
// 延迟跳过时间超过特效播放时间
if (effectInfo.Duration > 0 && -delayModifier > effectInfo.DelayTime + effectInfo.Duration)
return;
PlayEffect(effectInfo, delPlayEffect, param, delayModifier, handle);
}
/// <summary>
/// 开始播放一个特效
/// </summary>
/// <param name="effectInfo">特效数据表</param>
/// <param name="delPlayEffect">特效播放回调</param>
/// <param name="param">额外参数</param>
/// <param name="delayModifier">延迟修正值,负数减少延迟,整数增加延迟</param>
/// <param name="handle">特效句柄</param>
public void PlayEffect(Tab_Effect effectInfo, PlayEffectDelegate delPlayEffect = null, object param = null,
float delayModifier = 0f, int? handle = null)
{
if (!PlayerPreferenceData.SystemRoleEffectEnable)
return;
if (ValidPlayer() && (effectInfo.Profession < 0 || effectInfo.Profession == _effectObj.Profession))
{
var effectType = (EffectType) effectInfo.Type;
if (IsImpact(effectType))
{
PlaySpecialEffect(effectInfo);
}
else if (effectType == EffectType.TYPE_AVATAR)
{
var loadData = new EffectLoadData(this, gameObject.layer, effectInfo, handle, delPlayEffect,
param, new AvatarEffectData(), delayModifier);
IndependentEffectManager.PullEffectItem(loadData);
}
else
{
if (!effectInfo.IsFellowOwner)
{
Vector3 offset;
var bindPoint = GetBindPoint(effectInfo.ParentName, out offset);
var rotation = bindPoint.rotation;
var position = CommonUtility.RootOffsetPosition(bindPoint,
offset + new Vector3(effectInfo.OffsetX, effectInfo.OffsetY, effectInfo.OffsetZ));
IndependentEffectManager.Instance.ShowEffect(effectInfo, gameObject.layer, _effectObj.ObjType,
position, rotation,
-1f,
delPlayEffect, param, handle);
}
// 跟随主角的特效,仍然使用原来方式绑定到骨骼节点上
else if (ValidEffectCondition(effectInfo))
{
var loadData = new EffectLoadData(this, gameObject.layer, effectInfo, handle, delPlayEffect,
param, new BoundCustomData(), delayModifier);
IndependentEffectManager.PullEffectItem(loadData);
}
}
}
}
public void SetStampEffect(Tab_Effect effectInfo, int count)
{
if (count > 0)
{
var stampData = GetReferenceByEffectId(effectInfo.EffectID) as StampEffectReference;
if (stampData != null)
{
stampData.SetCurrentCount(count);
}
else
{
// 防止稀有情况,第一层印记未加载完成,立刻来第二层的需求
IndependentEffectManager.CancelLoad(a => a.data.EffectID == effectInfo.EffectID);
var loadData = new EffectLoadData(this, gameObject.layer, effectInfo, null, null, null,
new StampCustomData(count));
IndependentEffectManager.PullEffectItem(loadData);
}
}
else
{
// 仅仅移除当前加载 - 可能在上一个印记爆破期间叠加新的印记,因此仅仅在有激活中的印记时,才停止当前印记
IndependentEffectManager.CancelLoad(a => a.data.EffectID == effectInfo.EffectID);
var stampData = GetReferenceByEffectId(effectInfo.EffectID) as StampEffectReference;
if (stampData != null)
StopEffect(effectInfo.EffectID);
}
}
public void DetonateStamp(Tab_Effect effectInfo)
{
var stampData = GetReferenceByEffectId(effectInfo.EffectID) as StampEffectReference;
if (stampData != null)
stampData.Detonate();
else
// 防止稀有情况,印记未加载完成就爆炸了
IndependentEffectManager.CancelLoad(a => a.data.EffectID == effectInfo.EffectID);
}
// public int GetEffectCountById(int effectId)
// {
// var count = 0;
// if (ActiveList != null && DelayList != null)
// {
// for (var i = 0; i < ActiveList.Count; i++)
// if (ActiveList[i].data.EffectID == effectId)
// count++;
// for (var i = 0; i < DelayList.Count; i++)
// if (DelayList[i].loadData.data.EffectID == effectId)
// count++;
// }
//
// return count;
// }
///// <summary>
///// 停止NPC所有特效
///// </summary>
//public void NpcStopEffect()
//{
// if (_effectObj == null || _effectObj.ObjType != GameDefine_Globe.OBJ_TYPE.OBJ_NPC)
// return;
// _impactEffectMgr.ClearEffect();
// CleanEffect();
//}
/// <summary>
/// 停止其他玩家特效
/// </summary>
public void Other_PlayerStopEffect()
{
if (_effectObj == null || _effectObj.ObjType != GameDefine_Globe.OBJ_TYPE.OBJ_OTHER_PLAYER)
return;
_impactEffectMgr.ClearEffect();
CleanEffect();
}
public void StopEffect(int effectId, bool bStopAll = true)
{
if (effectId > 0)
{
var effectTable = TableManager.GetEffectByID(effectId);
if (effectTable == null)
LogModule.ErrorLog(string.Format("无法找到id={0}的特效数据!", effectId));
else
StopEffect(effectTable, bStopAll);
}
}
public void StopEffect(Tab_Effect effectTable, bool bStopAll = true)
{
if (IsImpact((EffectType) effectTable.Type))
{
if ((EffectType) effectTable.Type == EffectType.TYPE_SCREEN)
{
GlobalEffectMgr.StopNormalEffect(effectTable.Path);
return;
}
_impactEffectMgr.RemoveImpactEffect(effectTable, bStopAll);
}
else
{
var effectFound = false;
// 试图从已经激活的任务中移除
for (var i = 0; i < ActiveList.Count; i++)
if (ActiveList[i].data.EffectID == effectTable.EffectID)
if (!ActiveList[i].DelayRecovery)
{
effectFound = !bStopAll;
if (!ActiveList[i].CheckDelayRecovery())
RemoveEffectAt(i);
break;
}
if (!effectFound)
for (var i = 0; i < DelayList.Count; i++)
if (DelayList[i].loadData.data.EffectID == effectTable.EffectID)
{
effectFound = !bStopAll;
RemoveDelayAt(i);
break;
}
if (!effectFound)
IndependentEffectManager.CancelLoad(a => a.data.EffectID == effectTable.EffectID);
}
}
private bool IsImpact(EffectType effectType)
{
return effectType != EffectType.TYPE_NORMAL &&
effectType != EffectType.TYPE_CIRCLE &&
effectType != EffectType.TYPE_RECTANGLE &&
effectType != EffectType.TYPE_SECTOR &&
effectType != EffectType.TYPE_AVATAR;
}
}