Files
Main/Assets/Code/Logic/_Required/Entity/Character/Monster/Monster.cs
2025-01-25 04:38:09 +08:00

680 lines
23 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 UnityEngine;
using Thousandto.Core.Base;
using Thousandto.Core.Asset;
using Thousandto.Cfg.Data;
using Thousandto.Code.Center;
using Thousandto.Code.Global;
using Thousandto.Core.PostEffect;
using System.Collections.Generic;
namespace Thousandto.Code.Logic
{
/// <summary>
/// 怪物逻辑类
/// </summary>
public class Monster : Character
{
#region//私有变量
//怪物属性模块
private MonsterProperty _propMoudleEx = null;
//角色震动模块,用于受击震动
private CharacherShaker _shaker = null;
//移动状态true为跑flase为走
private bool _isRunning = true;
//是否播放出生动作
private bool _isPlayBornAnum = false;
//是否已经播放了死亡特写
private bool _isPlayDeadFeature = false;
//护甲特效
private FGameObjectVFX _armorVfx = null;
//角色闪烁模块,用于受击闪烁
private HitBlinker _blinker = null;
//怪物出生时间,在此时间内不能被攻击
private float _bornTimer = 0f;
//是否正在播放镜头死亡特写
private bool _isPlayCameraDeadFeature = false;
private float _cameraOriDis = 0f;
private float _cameraOriYaw = 0f;
private float _cameraOriPitch = 0f;
private float _cameraFeatureTimer = 0f;
//是否锁定学历
private bool _isLockHP = false;
//是否使用缓存的假伤害
private bool _useCacaheDamage = false;
//缓存伤害用于1血怪的表现
private ulong _cacheDamage = 0;
//缓存的当前血量用于1血怪表现
private ulong _cacheCurHP = 0;
//存储当前攻击者数量,每一秒清理一次
private Dictionary<ulong, bool> _cacheAtker = new Dictionary<ulong, bool>();
#endregion
#region//静态变量
#endregion
#region
public new MonsterProperty PropMoudle
{
get
{
if (_propMoudleEx == null)
{
_propMoudleEx = base.PropMoudle as MonsterProperty;
}
return _propMoudleEx;
}
}
//移动状态true为跑flase为走
public bool IsRunning
{
get
{
return _isRunning;
}
set
{
_isRunning = value;
}
}
//掉落的金币数量
public int DropGoldCount { get; set; }
//是否显示选中框
public override bool CanShowSelectUI
{
get
{
return true;
}
}
//是否可以被选择
public override bool CanBeSelect
{
get
{
if (PropMoudle.Cfg.CanBeSelect == 0)
return false;
return true;
}
}
public bool IsBoss
{
get;
private set;
}
//境界等级
public int RealmLevel
{
get
{
return PropMoudle.Cfg.StateLevel;
}
}
//是否加载完成
public bool IsLoadFinish
{
get;
private set;
}
//是否正在出生
public override bool IsBorning
{
get
{
return _bornTimer > 0f;
}
}
//角色闪烁模块,用于受击闪烁
public HitBlinker Blinker
{
get
{
return _blinker;
}
}
//当前血量
public override ulong CurHP
{
get
{
return PropMoudle.CurHP;
}
set
{
if(_useCacaheDamage)
{
if(value <= PropMoudle.CurHP)
{
//扣血
_cacheDamage += (PropMoudle.CurHP - value);
}
else
{
//回血
_cacheDamage = 0;
_cacheCurHP = value;
}
}
if (!_isLockHP && PropMoudle.CurHP != value)
{
PropMoudle.CurHP = value;
}
}
}
//血量百分比
public override float HpPercent
{
get
{
if(_useCacaheDamage)
{
if(IsDead())
{
_cacheCurHP = 0;
}
return (float)((double)_cacheCurHP / (double)PropMoudle.MaxHP);
}
return base.HpPercent;
}
}
//锁定血量
public bool LockCurHP
{
get
{
return _isLockHP;
}
set
{
_isLockHP = value;
}
}
#endregion
#region//怪物的效果设置接口 比如:出生的效果,被攻击效果,死亡效果
//接受到被击时的处理
public override void OnBeAttackedResponse(Character attacker, HitEffectInfo hitInfo, SkillHitType hitType, MSG_Fight.HitEffectInfo msgInfo)
{
//判断是否死亡
if (IsDead())
{
if(!string.IsNullOrEmpty(PropMoudle.Cfg.DeadSpeech))
{
AudioPlayer.PlaySpeech(Skin.RootGameObject, PropMoudle.Cfg.DeadSpeech);
}
if (GameCenter.GameSetting.IsEnabled(GameSettingKeyCode.EnablePostEffect) && !_isPlayDeadFeature && PropMoudle.Cfg.DeadFeature != 0)
{
//播放死亡特写
GameCenter.GameSceneSystem.DoTimeScale(0.3f, 3f);
//PostEffectManager.Instance.PlayRadiaBlur(0f, 1f, 0.6f);
_isPlayDeadFeature = true;
var cameraControl = Scene.CameraManager.SceneCameraControl;
if (cameraControl != null && !cameraControl.IsPlayAnim)
{
_isPlayCameraDeadFeature = true;
_cameraFeatureTimer = 0f;
cameraControl.FreeMode = true;
_cameraOriDis = cameraControl.CurDis;
_cameraOriYaw = cameraControl.CurYaw;
_cameraOriPitch = cameraControl.CurPitch;
}
}
}
if (IsXState(EntityStateID.Dead))
return;
if(_useCacaheDamage && _cacheDamage > 0)
{
if(attacker != null)
{
_cacheAtker[attacker.ID] = true;
}
var caCount = _cacheAtker.Count;
if(caCount <= 0)
{
caCount = 0;
}
if (IsDead())
{
_cacheDamage = 0;
_cacheCurHP = 0;
}
else
{
if(CombatUtil.IsMultipleAtk(msgInfo.effect))
{
//直接掉80%
var damageHp = (ulong)(_cacheDamage * 0.8f);
if (damageHp <= 0)
{
damageHp = 1;
}
_cacheDamage -= damageHp;
_cacheCurHP -= damageHp;
}
else
{
var damageHp = _cacheDamage / ((ulong)caCount * 5);
if (damageHp <= 0)
{
damageHp = 1;
}
_cacheDamage -= damageHp;
_cacheCurHP -= damageHp;
}
}
}
//震动效果
var shakeDir = GetFacingDirection();
if (attacker != null)
{
shakeDir = Position - attacker.Position;
}
if(PropMoudle.Cfg.HitShakePower > 0)
{
_shaker.StartShake(shakeDir, PropMoudle.Cfg.HitShakePower / 100f, 0.2f);
}
base.OnBeAttackedResponse(attacker, hitInfo, hitType, msgInfo);
if (PropMoudle.Cfg.MonsterType >= 3 && PropMoudle.Cfg.ArmorIf == 0 && PropMoudle.CurArmor > 0)
{
if (_armorVfx == null)
{
var pos = GetModelCenterPos();
_armorVfx = new FGameObjectVFX(ModelTypeCode.OtherVFX, 29);
_armorVfx.SetPosition(pos);
_armorVfx.IsFinishDestroy = false;
_armorVfx.StopIsDeactive = true;
_armorVfx.Play();
}
else
{
var pos = GetModelCenterPos();
_armorVfx.SetPosition(pos);
_armorVfx.Stop();
_armorVfx.Play();
}
}
if (!GameCenter.GameSetting.IsEnabled(GameSettingKeyCode.TPSkillBlink))
{
var setValue = GameCenter.GameSetting.GetSetting(GameSettingKeyCode.HitBlink);
if (setValue == 2 || (setValue == 1 && attacker.IsLocalPlayer()))
{
//开始闪烁
_blinker.Start(hitInfo.BlinkTime, hitInfo.BlinkPower, hitInfo.BlinkColor, hitInfo.BlinkCurve, Skin);
}
}
//只有主角或者主角宠物攻击的怪物才会显示血条
if (attacker != null && (attacker.IsLocalPlayer() || attacker.IsLocalPet() || attacker.IsLocalFlySword()))
{
if (Scene.Cfg.ShowMonsterHud != 0)
{
ShowHUD(false);
//显示血量
GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_HUD_SHOWMONSTER_HP, this);
}
}
if(attacker.IsLocalPlayer())
{
var lp = attacker as LocalPlayer;
lp.SetCurSelectBoss(this);
}
}
//设置溶解时间
public bool SetDissolvingTime(float time)
{
if (Skin.SkinStatus == FSkinStatusCode.Dead)
{
Skin.SetFloat(FSkinPartCode.Body, ShaderPropertyIDDefine.Timeline, time);
return true;
}
return false;
}
#endregion
#region//初始化,卸载,加载Skin等处理
//加载Skin
protected override FSkinBase OnSetupSkin()
{
IsLoadFinish = false;
FSkinModel skin = GameCenter.LuaSystem.Adaptor.CreateFSkinModel(FSkinTypeCode.Monster);
skin.SetLayer(LayerUtils.Monster);
skin.SetMipmapLevel(0.5f);
skin.SetActiveChangedCallBack(OnActiveChanged);
skin.SetOnSkinPartChangedHandler((x, y) =>
{
if(y == FSkinPartCode.Body)
{
IsLoadFinish = true;
//重新挂载buff特效
GameCenter.BuffSystem.ReAddAllBuffVfx(this);
if(_propMoudleEx.Cfg.PlayerModel != 0)
{
//怪物使用玩家模型,武器始终拿在手上
var body = Skin.GetSkinPart(FSkinPartCode.Body) as FGameObjectBody;
if (body != null && body.BrightWeapon)
{
body.BrightWeapon = true;
}
}
}
});
return skin;
}
//初始化之前
protected override bool OnSetupFSMBefore()
{
ResetDirection();
return base.OnSetupFSMBefore();
}
//安装设置FSM状态机
protected override bool OnSetupFSM()
{
Fsm = new EntityFSM(this);
Fsm.AddState(new Idle());
Fsm.AddState(new MonsterFSM.PathMove());
Fsm.AddState(new MonsterFSM.Dead());
Fsm.AddState(new BeHit());
Fsm.AddState(new BeHitBack());
Fsm.AddState(new BeHitFly());
Fsm.AddState(new BeHitGrab());
Fsm.AddState(new SkillMove());
Fsm.SetDefaultStateId(EntityStateID.Idle);
Fsm.Init(this);
return true;
}
//初始化
protected override bool OnInitializeAfter(EntityInitInfo baseInfo)
{
var initInfo = baseInfo as MonsterInitInfo;
base.OnInitializeAfter(baseInfo);
_shaker = new CharacherShaker(this);
_blinker = new HitBlinker();
SyncInfo(initInfo);
if (Scene.Cfg.ShowMonsterHud != 0)
{
if(!string.IsNullOrEmpty(initInfo.Cfg.Dialog))
{
//没有对话泡泡的时候不在一创建就显示
ShowHUD();
}
if (initInfo.IsBoss && _bornTimer <= 0f)
{
ShowHUD(false);
//显示血量
GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_HUD_SHOWMONSTER_HP, this);
}
}
GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_ON_MONSTER_BORN, this);
return true;
}
//卸载处理
protected override void OnUninitializeBefore()
{
HideHUD();
if (_armorVfx != null)
{
_armorVfx.Destroy();
_armorVfx = null;
}
GameCenter.DropAscriptionSystem.UpdateMonsterDropOwners(ID, null);
base.OnUninitializeBefore();
}
//初始化信息刷新
public void SyncInfo(MonsterInitInfo initInfo)
{
_useCacaheDamage = initInfo.Cfg.UseSmoothDamage != 0;
GameCenter.BuffSystem.ReAddAllBuffVfx(this);
DeadDetail = null;
_propMoudle = _propMoudleEx = new MonsterProperty(this, initInfo.Cfg);
_propMoudleEx.CurHP = (ulong)initInfo.CurHp;
_propMoudleEx.CurArmor = initInfo.CurArmor;
_propMoudleEx.SetBattleProp(AllBattleProp.MaxHP, (long)initInfo.MaxHp);
_propMoudleEx.SetBattleProp(AllBattleProp.AttackSpeed, initInfo.AttackSpeedFinal);
_propMoudleEx.SetBattleProp(AllBattleProp.MoveSpeed, initInfo.MoveSpeedFinal);
_propMoudleEx.SceneCampID = initInfo.Camp;
_cacheCurHP = _propMoudleEx.CurHP;
//Debug.Log(":::::" + _propMoudleEx.CurHP+","+ (long)initInfo.MaxHp);
if (initInfo.Cfg.Level < 0)
{
_propMoudleEx.Level = (uint)GameCenter.GameSceneSystem.GetLocalPlayerLevel();
}
else if(initInfo.Cfg.Level == 0)
{
_propMoudleEx.Level = (uint)GameCenter.LuaSystem.Adaptor.GetCurWorldLevel();
}
else
{
_propMoudleEx.Level = (uint)initInfo.Cfg.Level;
}
InitStartPose(initInfo.X, initInfo.Z, ref initInfo.PosList);
SetDirection2d(initInfo.Dir, false, true);
//设置状态
_stateManager.SetStateData(initInfo.State);
_isRunning = initInfo.IsRunning;
_isPlayBornAnum = initInfo.IsBorn;
IsBoss = initInfo.IsBoss;
if (_propMoudleEx.Cfg.PlayerModel != 0 && !String.IsNullOrEmpty(_propMoudleEx.Cfg.PlayerModelRes))
{
Skin.SkinTypeCode = FSkinTypeCode.Player;
String[] modelsparam = _propMoudleEx.Cfg.PlayerModelRes.Split('_');
int body = 0;
int weaponHead = 0;
int weaponBody = 0;
int weaponVFX = 0;
int cloak = 0;
if (modelsparam.Length > 0)
{
int.TryParse(modelsparam[0], out body);
}
if (modelsparam.Length > 1)
{
int.TryParse(modelsparam[1], out weaponHead);
}
if (modelsparam.Length > 2)
{
int.TryParse(modelsparam[2], out weaponBody);
}
if (modelsparam.Length > 3)
{
int.TryParse(modelsparam[3], out weaponVFX);
}
if (modelsparam.Length > 4)
{
int.TryParse(modelsparam[4], out cloak);
}
Skin.SetSkinPartFromCfgID(FSkinPartCode.Body, body, null, true);
Skin.SetSkinPartFromCfgID(FSkinPartCode.GodWeaponHead, weaponHead);
//Skin.SetSkinPartFromCfgID(FSkinPartCode.GodWeaponBody, weaponBody);
//Skin.SetSkinPartFromCfgID(FSkinPartCode.GodWeaponVfx, weaponVFX);
Skin.SetSkinPartFromCfgID(FSkinPartCode.Wing, cloak);
}
else
{
Skin.SkinTypeCode = FSkinTypeCode.Monster;
Skin.SetSkinPartFromCfgID(FSkinPartCode.Body, initInfo.Cfg.Res);
}
_bornTimer = 0f;
//判断是否出生
if (_isPlayBornAnum)
{
_bornTimer = PropMoudle.Cfg.BrithProtect / 1000f;
if (GameCenter.GameSetting.IsEnabled(GameSettingKeyCode.EnableMonsterGrownEffect))
{
//播放出生特效
if (PropMoudle != null && PropMoudle.Cfg != null && PropMoudle.Cfg.BrithVfx > 0)
{
Skin.PlayVFX(ModelTypeCode.OtherVFX, PropMoudle.Cfg.BrithVfx, SlotNameDefine.Origin, FSkinPartCode.Body, true, 1f,
true, false, ()=>
{
GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_ONMONSTER_BRITHVFX_PLAYED, PropMoudle.CfgID);
});
}
}
PlayAnim(AnimClipNameDefine.Born, AnimationPartType.AllBody, WrapMode.Once);
if(PropMoudle.Cfg.BrithFowardPlayer != 0)
{
var lp = GameCenter.GameSceneSystem.GetLocalPlayer();
if(lp != null)
{
SetDirection2d(lp.Position2d - Position2d, false, false);
}
}
if(!string.IsNullOrEmpty(PropMoudle.Cfg.BirthSpeech))
{
//播放出生音效
AudioPlayer.PlaySpeech(Skin.RootGameObject, PropMoudle.Cfg.BirthSpeech);
}
}
//这里如果是Boss的话,就让动作播放设置为一直播放.
//if (initInfo.IsBoss)
//{
// Skin.CullingType = AnimatorCullingMode.CullCompletely;
//}
BodyScale = PropMoudle.Cfg.SizeScale / 100f;
DropGoldCount = 0;
IsShowModel = GameObjectLimit.IsCanShow(this);
}
#endregion
#region //继承Character ,死亡等处理
public override void OnDead()
{
HideHUD();
base.OnDead();
}
#endregion
#region//是否被选择的处理
//选择
protected override void OnSelect()
{
Skin.SetSkinPart(FSkinPartCode.SelectedVfx, ModelTypeCode.OtherVFX, 920, false, null, null, null, SlotNameDefine.Origin);
//设置选择圈的大小
Skin.GetSkinPart(FSkinPartCode.SelectedVfx).SetLocalScale(new Vector3(PropMoudle.LogicBodyRadius / BodyScale, 1, PropMoudle.LogicBodyRadius / BodyScale));
if (Scene.Cfg.ShowMonsterHud != 0)
{
ShowHUD(false);
//显示血量
GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_HUD_SHOWMONSTER_HP, this);
}
}
//取消选择
protected override void OnDeselect()
{
Skin.RemoveSkinPart(FSkinPartCode.SelectedVfx);
//满血的情况下
if (!IsDead() && HpPercent >= 1.0f && !IsBoss)
{
//隐藏血量
GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_HUD_HIDEMONSTER_HP, this);
}
}
#endregion
#region//心跳处理
//心跳处理
protected override void OnUpdate(float elapsedTime)
{
if(Time.frameCount % 30 == 0)
{
_cacheAtker.Clear();
}
if(_bornTimer > 0)
{
_bornTimer -= elapsedTime;
if(IsBoss && _bornTimer <= 0f)
{
ShowHUD(false);
//显示血量
GameCenter.PushFixEvent(LogicEventDefine.EID_EVENT_HUD_SHOWMONSTER_HP, this);
}
}
//闪烁
_blinker.Update(elapsedTime);
//震动
_shaker.Update(elapsedTime);
if(_isPlayCameraDeadFeature)
{
_cameraFeatureTimer += elapsedTime / Time.timeScale;
var cameraControl = Scene.CameraManager.SceneCameraControl;
if(_cameraFeatureTimer > 4f)
{
_isPlayCameraDeadFeature = false;
cameraControl.FreeMode = false;
}
else
{
if(_cameraFeatureTimer <= 0.5f)
{
cameraControl.CurDis = Mathf.Lerp(_cameraOriDis, 15f, _cameraFeatureTimer / 0.5f);
cameraControl.CurYaw = Mathf.Lerp(_cameraOriYaw, _cameraOriYaw + 20f, _cameraFeatureTimer / 0.5f);
cameraControl.CurPitch = Mathf.Lerp(_cameraOriPitch, 10f, _cameraFeatureTimer / 0.5f);
}
else if(_cameraFeatureTimer <= 3f)
{
}
else
{
cameraControl.CurDis = Mathf.Lerp(15f, _cameraOriDis, (_cameraFeatureTimer - 3f) / 1f);
cameraControl.CurYaw = Mathf.Lerp(_cameraOriYaw + 20f, _cameraOriYaw, (_cameraFeatureTimer - 3f) / 1f);
cameraControl.CurPitch = Mathf.Lerp(10f, _cameraOriPitch, (_cameraFeatureTimer - 3f) / 1f);
}
}
}
base.OnUpdate(elapsedTime);
}
#endregion
#region//重新实现设置方向函数,用以实现某些怪物不能转向
public override void SetDirection(Vector3 direction, bool smooth = true, bool normalized = false)
{
if(PropMoudle.Cfg.IsLockDir != 0)
{
SetEulerAngle(new Vector3(0, PropMoudle.Cfg.LockDir, 0));
}
else
{
base.SetDirection(direction, smooth, normalized);
}
}
#endregion
}
}