563 lines
22 KiB
C#
563 lines
22 KiB
C#
/********************************************************************************
|
||
* 文件名: 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;
|
||
}
|
||
} |