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 { /// /// 怪物逻辑类 /// 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 _cacheAtker = new Dictionary(); #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 } }