// *********************************************************************** // Assembly : Unity // Author : Kimch // Created : 2018-2-29 // Description : 游戏Boss // Last Modified By : // Last Modified On : // *********************************************************************** // // // *********************************************************************** using System.Collections; using UnityEngine; namespace G { /// /// 游戏Boss /// public sealed class EntityBoss : EntityEnemy { private const int MAX_SKILL_COUNT = 3; class SkillWrapper { /// /// /// public BossInfo.SkillInfo skillInfo; /// /// /// public int power; /// /// /// public float fireRange; /// /// /// public Vector2 movingAttack; /// /// /// public Transform skillClone; } #region Field private bool _attackStart; private float _attackDelay; private int _attackKind; private bool _setAttackKind; private Transform _transform; private bool _bossCutin; /// /// /// private float _movingAttackDelay; private bool _jump; private ItemBoss _item; private BossInfo _bossInfo; /// /// /// private readonly SkillWrapper[] _skillWrappers = new SkillWrapper[MAX_SKILL_COUNT]; #endregion #region Property /// /// /// public override EntityType entityType { get { return EntityType.Boss; } } private Transform _secondSkill => _bossInfo.weapon_ef; #endregion #region Method public override bool Init(EntityInfo info) { if (info != null) { _item = ItemProxy.Instance.GetStaticItem(info.itemId); for (int i = 0; i < _skillWrappers.Length; i++) { _skillWrappers[i] = new SkillWrapper(); _skillWrappers[i].movingAttack = GlobalUtils.GetVector2(_item.moving_attack[i]); _skillWrappers[i].fireRange = _item.fireRange[i]; } SetLevel(info.factorA, info.factorB); _scriptCha = EntityMainPlayer.Instance; _cha1 = _scriptCha.transform; _target = _cha1; InitRigbody(_item.mass); moveState = 0; } return base.Init(info); } protected override void OnViewInitCompleted() { base.OnViewInitCompleted(); var viewGO = entityView.gameObject; _bossInfo = viewGO.GetComponent(); var orb = viewGO.GetComponent(); Destroy(orb); _transform = this.transform; EnemyHelper.Instance.CreateShadow(_transform, 2.2f); SetModel(viewGO); SetFloat(Hash_Speed_Attack1, _item.speed_attack[0]); SetFloat(Hash_Speed_Attack1_I, _item.speed_attack_i[0]); SetFloat(Hash_Speed_Attack2, _item.speed_attack[1]); SetFloat(Hash_Speed_Attack2_I, _item.speed_attack_i[1]); SetFloat(Hash_Speed_Attack3, _item.speed_attack[2]); SetFloat(Hash_Speed_Attack3_I, _item.speed_attack_i[2]); // CreateHpBar(); // _cloneArrow = Object.Instantiate(_bossInfo.direction_arrow); _cloneArrow.gameObject.SetActive(false); StartAI(); UI_Ingame.Instance.ShowEffect("UI_fx_Boss01"); //GlobalNotifier.PostNotification(GlobalDefine.EVENT_SHOW_EFFECT, "21539_", ""); } public override void CreateHpBar() { _blood = BoardManager.Instance.CreateBloodBoard("BloodBoard1"); _blood.SetFixedPosition(); _blood.SetName(_item.name); SetHpBar(); } public override void DestroyHpBar() { if (_blood) { _blood.ReleaseWaitFinish(); _blood = null; } } public override void SetHpBar(int cur, int max, float height, int index) { _blood.SetMultiHp(cur, max, 100); } /// /// /// /// public override void Dead(int kind) { moveState = -4; EnemyHelper.Instance.SoundOn(4); if (_bossInfo.weapon) { var dropWeapon = Object.Instantiate(_bossInfo.weapon); dropWeapon.parent = null; dropWeapon.GetComponent().Drop(true); } for (int i = 0; i < _skillWrappers.Length; i++) { if (_skillWrappers[i].skillClone) Object.Destroy(_skillWrappers[i].skillClone.gameObject); } if (_secondSkill != null) { Object.Destroy(_secondSkill.gameObject); } EnemyHelper.Instance.EnemyDead(kind, transform.position, Vector3.one * 2.5f, -_transform.forward, _originTex); GameLevel.Instance.BossKill(itemId); base.Dead(kind); } /// /// /// /// public void SetMoveSpeed(float speedRate) { moveSpeed = _item.runSpeed * speedRate; SetFloat(Hash_Speed_Move, speedRate); } /// /// /// public override void DropItems() { var dropBox = BoxProxy.Instance.GetBoxInfo(_item.boxDrop); if (dropBox != null) { int dropCount = dropBox.item.typeArgs[0]; for (int i = 0; i < dropCount; i++) { Vector3 a = Random.onUnitSphere * Random.Range(0.18f, 0.26f); var dropItem = dropBox.GetRndItem(); EnemyHelper.Instance.CreateBox(dropItem.id, dropItem.count, transform.position + a); } } base.DropItems(); } /// /// 设置等级 /// /// /// public void SetLevel(float[] a, float[] b) { for (int i = 0; i < _skillWrappers.Length; i++) { _skillWrappers[i].power = (int)(_item.power[i] * a[0] + b[0]); } defence = (int)(_item.defence * a[1] + b[1]); maxHp = (int)(_item.hp * a[2] + b[2]); curHp = maxHp; block = (int)((_item.block * a[3] + b[3]) * 0.01f); } /// /// /// /// /// public float GetFireRange(int index) { return _skillWrappers[index].fireRange; } /// /// /// /// /// public int GetDamage(int index) { return _skillWrappers[index].power; } /// /// /// /// /// public Vector2 GetMovingAttack(int index) { return _skillWrappers[index].movingAttack; } /// /// 撞击 /// public void Impact() { _secondSkill?.GetComponent()?.PressDamage(GetDamage(_attackKind)); _secondSkill?.gameObject.SetActive(true); } /// /// 撞击 /// public void Impact2() { _secondSkill?.GetComponent()?.PressDamage(GetDamage(_attackKind)); _secondSkill?.gameObject.SetActive(true); GameCamera.Instance.Hitcam(); } /// /// /// private void TurnNormal() { this.invincible = false; InvokeRepeating(nameof(SimpleAI), 0.3f, 0.5f); } /// /// 显示预警 /// /// public void ShowSkillWarningIndex(int index) { var skillInfo = _bossInfo.skillInfos[index]; //显示预警 if (skillInfo.warning != null) { var clone_decal = Instantiate(skillInfo.warning).transform; var ef_tr = skillInfo.skill; if (skillInfo.useTargetPosition) { clone_decal.position = _attackStartPosition; clone_decal.rotation = Quaternion.LookRotation(_attackStartDirection); } else { Quaternion oldRotation = _transform.rotation; _transform.rotation = Quaternion.LookRotation(_attackStartDirection); clone_decal.parent = _transform; var ef_position = ef_tr.transform.localPosition; ef_position.y = 0f; clone_decal.localPosition = ef_position; clone_decal.localRotation = Quaternion.identity; clone_decal.parent = null; _transform.rotation = oldRotation; } var ef_col = ef_tr.GetComponent(); //Vector3 atk_mov = Vector3.zero; //if (_movingAttack[_attackKind] != Vector2.zero) //{ // atk_mov = _attackStartDirection * _movingAttack[_attackKind].x * _movingAttack[_attackKind].y; //} //clone_decal.forward = _attackDirection; if (ef_col is SphereCollider sc) { clone_decal.localScale = Vector3.one * sc.radius; } else if (ef_col is BoxCollider bc) { clone_decal.localScale = bc.size;// new Vector3(bc.size.x, 1f, bc.size.z); } Destroy(clone_decal.gameObject, 1f); } } /// /// 发动技能 /// /// public void LaunchSkill(int index) { var skillInfo = _bossInfo.skillInfos[index]; var ef_position = skillInfo.skill.transform.localPosition; var ef_rotation = Quaternion.LookRotation(_attackStartDirection); if (skillInfo.useTargetPosition) { ef_position += _attackStartPosition; } else { ef_position = _transform.TransformPoint(ef_position); } var skillWrapper = _skillWrappers[_attackKind]; if (!skillWrapper.skillClone) { if (!skillInfo.instance) { var skillClone = Instantiate(skillInfo.skill, ef_position, ef_rotation); skillClone.SetActive(true); skillWrapper.skillClone = skillClone.transform; var attach_weaponEf = _item.attach_ef; if (attach_weaponEf != null && attach_weaponEf[_attackKind] >= 1) { skillWrapper.skillClone.parent = _transform; if (_secondSkill && attach_weaponEf[_attackKind] == 2) { Impact(); } } } else { var skillClone = skillInfo.skill; skillClone.SetActive(true); skillWrapper.skillClone = skillClone.transform; } var mainDamageComp = skillWrapper.skillClone.GetComponent(); if (mainDamageComp) mainDamageComp.SetDamage(GetDamage(_attackKind), 50); else Debug.Log("mainDamageComp = null" + this.itemId); } else { skillWrapper.skillClone.position = ef_position; skillWrapper.skillClone.rotation = ef_rotation; skillWrapper.skillClone.gameObject.SetActive(true); } } /// /// /// /// /// public override void OnDamage(AllyDamage allyDamage, int damageLayer) { if (this.invincible) { return; } var sourceCha = allyDamage.source; var myPosition = this.position; _setAttackKind = true; float damage = 0f; float addDamage = sourceCha.伤害加深百分比 * 0.01f; float realDefence = (defence - sourceCha.忽视防御固定值) * (100 - sourceCha.忽视防御百分比) * 0.01f; float damageForce = 0f; var damageDir = Vector3.zero; if (damageLayer == GameLayer.PushAttack) { damageDir = myPosition - sourceCha.position; damageDir.y = 0f; damageDir = Vector3.Normalize(damageDir); } else { damageDir = myPosition - allyDamage.transform.position; damageDir.y = 0f; damageDir = Vector3.Normalize(damageDir); } if (damageDir == Vector3.zero) { damageDir = -Vector3.forward; } switch (damageLayer) { case GameLayer.NormalAttack: //other.transform.root.GetComponent().AddForce(-_attackDirection * 80f); GameCamera.Instance.Hitcam(); damageForce = 60f; var sourceHitRate = sourceCha.sourceTotalHitRate; int blockRate = (int)((block - sourceHitRate) * 1000f / Mathf.Max(block, sourceHitRate, 1) + 100); if (moveState >= 0 && GlobalUtils.RndThousand < blockRate) { this.AddForce(damageDir * 10f); sourceCha.Blocked(myPosition); return; } damage = sourceCha.damage; _target = _cha1; EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; case GameLayer.PowerAttack: damageForce = 100f; realDefence *= 0.5f; damage = sourceCha.damage; _target = _cha1; GameCamera.Instance.Hitcam2(1f); EnemyHelper.Instance.CreateBlood_Only(myPosition, damageDir); break; case GameLayer.SkillAttack: GameCamera.Instance.Hitcam(); damageForce = 50f; damage = allyDamage.physicsDamage; _target = _cha1; EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; case GameLayer.PoisonAttack: { damage = allyDamage.physicsDamage; if (damage == 0.1f) { damage = 0f; _poison = true; _poisonDamage = sourceCha.damage * 0.6f; _poisonDelay = 4f; _target = _cha1; return; } damageForce = 100f; _poisonDamage = damage; _poison = true; _poisonDelay = 12f; damage *= 2f; _target = _cha1; GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; } case GameLayer.DeathAttack: damageForce = 100f; //var petrifyRate = (int)(allyDamage.physicsDamage * 0.01f); Petrify(0); _target = _cha1; GameCamera.Instance.Hitcam(); break; case GameLayer.GeneralAttack: damageForce = 60f; damage = sourceCha.damage * EntityPet.Instance.bulletDamage; _target = _cha1; EnemyHelper.Instance.CreateBlood_Only(myPosition, damageDir); break; case GameLayer.PierceAttack: damageForce = 10f; damage = allyDamage.physicsDamage; curHp -= (int)damage; SetHpBar(0, maxHp); _target = _cha1; EnemyHelper.Instance.CreateBlood_Only(myPosition, damageDir); PlayAnimation(Hash_Down, 0f); break; case GameLayer.PushAttack:// damageForce = 100f; damage = sourceCha.damage; _target = _cha1; GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; case GameLayer.RiseupAttack2: damageForce = 50f; damage = sourceCha.damage * 0.4f; _target = _cha1; EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; case GameLayer.BurnAttack: damageForce = 100f; damage = sourceCha.damage; _target = _cha1; GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; case GameLayer.ColdAttack: damageForce = 100f; damage = sourceCha.damage; _target = _cha1; GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; case GameLayer.StunAttack: damageForce = -50f; damage = 0f; _target = _cha1; Stun((int)damage); break; case GameLayer.RiseupAttack: damageForce = 40f; damage = allyDamage.physicsDamage; _target = _cha1; GameCamera.Instance.Hitcam2(0.2f); EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; case GameLayer.ShockAttack: damageForce = 100f; damage = sourceCha.damage; _target = _cha1; GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; case GameLayer.DarkAttack: damageForce = 100f; damage = sourceCha.damage; _target = _cha1; GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood(myPosition, damageDir); break; } if (!isLife) { EnemyHelper.Instance.SoundOn(1); //myanimation.Stop(); return; } EnemyHelper.Instance.SoundOn(1); damage -= realDefence; damage += damage * addDamage; damage = Mathf.Max(1, damage); int num = Mathf.Max(1, (int)(maxHp * 0.3f)); int num2 = curHp / num; if (curHp == maxHp) { num2--; } curHp -= (int)damage; SetDamageNumber(_transform.position, (int)damage, damageDir, _scriptCha.critDamage); SetHpBar(); if (curHp <= 0 && isLife) { Dead(2); } else if (curHp < num * num2) { GameLevel.Instance.Summon(4, transform.position); damageForce = 300f; PlayAnimation(Hash_Down); var skillWrapper = _skillWrappers[_attackKind]; if (skillWrapper.skillClone) { skillWrapper.skillClone.gameObject.SetActive(false); skillWrapper.skillClone.position = Vector3.one * 8f; } if (_secondSkill != null) { _secondSkill.gameObject.SetActive(false); } PlaySound(_bossInfo.snd_scream); } AddForce(damageDir * damageForce); } /// /// /// public override void UpdateState() { if (!entityView.initSuccess) { return; } if (!isLife) { return; } base.UpdateState(); _behaviourDelay -= deltaTime; UpdateAnim(); //显示箭头 UpdateArrow(); //中毒 UpdatePoison(); //限制范围 UpdateRestrictArea(); } private bool _isSkilling = false; /// /// /// private void UpdateAnim() { if (_isSkilling) { var skillWrapper = _skillWrappers[_attackKind]; var director = skillWrapper.skillClone.GetComponent(); if (director.state != UnityEngine.Playables.PlayState.Playing) { _isSkilling = false; _attackDelay = _item.attackCd; skillWrapper.skillClone.gameObject.SetActive(false); } return; } var currentStateInfo = _animator.GetCurrentAnimatorStateInfo(0); int stateNameHash = currentStateInfo.shortNameHash; int stateTagHash = currentStateInfo.tagHash; if (stateNameHash == Hash_Idle) { _attackDelay -= deltaTime; if (_attackDelay < 0f) { _attackStart = false; } moveState = 1; _transform.position += _direction * (deltaTime * moveSpeed); if (_direction != Vector3.zero) { var lookrotation = Quaternion.LookRotation(_direction); _transform.rotation = Quaternion.Lerp(_transform.rotation, lookrotation, deltaTime * 5f); } } else if (stateTagHash == Hash_Attack) { if (_attackStartDirection != Vector3.zero) { var lookrotation = Quaternion.LookRotation(_attackStartDirection); _transform.rotation = Quaternion.Lerp(_transform.rotation, lookrotation, deltaTime * _item.turnSpeed); } if (moveState != 11) { if (_item.colliderOff[_attackKind] != 0 && !_jump) { SetColliderEnabled(false); _jump = true; } if (_secondSkill && _item.attach_ef[_attackKind] == 2) { _secondSkill.gameObject.SetActive(true); } ShowSkillWarningIndex(_attackKind); } //攻击动作带位移 var movingAttack = GetMovingAttack(_attackKind); if (movingAttack != Vector2.zero) { if (_movingAttackDelay > movingAttack.x) { _transform.position += _direction * (deltaTime * movingAttack.y); } else { _movingAttackDelay += deltaTime; } } moveState = 11; } else if (stateTagHash == Hash_Attack_I) { //冲击 if (moveState == 11) { if (_attackStartDirection != Vector3.zero) { var lookrotation = Quaternion.LookRotation(_attackStartDirection); _transform.rotation = lookrotation; } if (_jump) { SetColliderEnabled(true); _jump = false; } this.AddForwardForce(_item.dash[_attackKind]); LaunchSkill(_attackKind); _movingAttackDelay = 0f; var position = _transform.position; position.y = 0f; _transform.position = position; _attackDelay = _item.attackCd; } moveState = 12; } else if (stateNameHash == Hash_Down) { moveState = -1; } else { moveState = 1; _attackDelay -= deltaTime; if (_attackDelay < 0f) { _attackStart = false; } if (_direction != Vector3.zero) { var lookrotation = Quaternion.LookRotation(_direction); _transform.rotation = Quaternion.Lerp(_transform.rotation, lookrotation, deltaTime * 5f); } } } /// /// /// private void UpdatePoison() { //中毒 if (_poison) { _poisonDelay -= deltaTime; if (_poisonDelay < 0f) { _poison = false; SetHpBar(); } else if ((int)_poisonDelay != _lastPoisonDelay) { curHp -= (int)_poisonDamage; SetHpBar(); _lastPoisonDelay = (int)_poisonDelay; if (curHp <= 0) { Dead(1); } } } } /// /// /// private void UpdateRestrictArea() { //if (Vector3.SqrMagnitude(transform.position) > _restrictArea) //{ // AddForce(-transform.position * 20f); //} } #endregion #region For AI /// /// /// public void SimpleAI() { if (!isLife) { return; } if (!_target) { _target = _cha1; } if (_bossCutin) { if (_behaviourDelay < 0f) { _behaviour = Random.Range(0, 6); if (_behaviour == 0) { PlaySound(_bossInfo.snd_move); } _behaviourDelay = 1f; } } else { GameLevel.Instance.BossCutin(itemId - 1); _bossCutin = true; _attackDelay = 2f; _attackStart = true; //_scriptCam.LookTarget(mytransform, 30, 0f); } // Vector3 targetPosition = _target.position; if (targetPosition.y > 2f) { //更换目标 _target = _cha1; } Vector3 myselfPosition = _transform.position; var distance = 0f; // if (_attributeStatus == 2) { _direction = Vector3.zero; distance = 2f; } else { _direction = targetPosition - myselfPosition; distance = _direction.magnitude; _direction.y = 0f; _direction = Vector3.Normalize(_direction); } if (distance < GetFireRange(2)) { ShowArrow(false); if (_attackStart) { return; } if (moveState >= 0 && _scriptCha.moveState < MoveState.state50) { if (_setAttackKind) { _attackKind = Random.Range(0, _bossInfo.skillInfos.Length); _setAttackKind = false; } var skillInfo = _bossInfo.skillInfos[_attackKind]; if (distance < GetFireRange(_attackKind)) { if (!skillInfo.instance) { if (_attackKind == 0) { PlayAnimation(Hash_Attack1); } else if (_attackKind == 1) { PlayAnimation(Hash_Attack2); } else { PlayAnimation(Hash_Attack3); } } else { _isSkilling = true; LaunchSkill(_attackKind); } _attackStartDirection = _direction; _attackStartPosition = targetPosition; _setAttackKind = true; _attackStart = true; } else { //move SetMoveSpeed(1f); //PlayAnim(Hash_Boss_Move); } } else if (!_attackStart) { //PlayAnim(Hash_Boss_Idle); SetMoveSpeed(0f); _behaviour = 4; _behaviourDelay = 1f; } } else if (!_attackStart) { SetMoveSpeed(_behaviour < 5 ? 1f : 0f); ShowArrow(true); } } public override void StartAI() { //if (behaviorTree) // StartCoroutine(nameof(AICoroutine)); //else InvokeRepeating(nameof(SimpleAI), 0.3f, 0.5f); } public override void EndAI(bool pause) { CancelInvoke(nameof(SimpleAI)); //StopCoroutine(nameof(AICoroutine)); } #endregion } }