// *********************************************************************** // Assembly : Unity // Author : Kimch // Created : 2018-2-29 // Description : 游戏小兵 // Last Modified By : // Last Modified On : // *********************************************************************** // // // *********************************************************************** using System.Collections; using UnityEngine; namespace G { /// /// /// public sealed class EntityMinion : EntityEnemy { #region Field public const float ATTACK_DELAY = 2F; /// /// 子弹 /// private Transform _bullet => _enemyInfo.ef_weapon; /// /// /// private Transform _cloneBullet; private AudioClip _moveSound; private AudioClip _attackSound => _enemyInfo.snd_attack; public Transform _directionArrow => _enemyInfo.direction_arrow; /// /// 预警 /// private Transform _warning => _enemyInfo.line; private bool _lastMon; private Transform _targetOnlyone; /// /// /// private float _hpBarHeight; /// /// /// private bool _grabed; private int _grabStyle; /// /// /// private bool _spawning; /// /// 撞击 /// private bool _impact; /// /// /// private Quaternion _lookRotation; /// /// /// private bool _attackStart; /// /// /// private float _attackDelay = ATTACK_DELAY; /// /// 范围 /// private float _attackRange = 5f; /// /// /// private float _idleAnimSpeed; /// /// 游戏 /// private int _playKind; /// /// /// private ItemMinion _item; private EnemyInfo _enemyInfo; #endregion #region Property /// /// /// public override EntityType entityType { get { return EntityType.Minion; } } /// /// /// private int _kind { get { return _item.kind; } } private bool _useTargetPosition => _enemyInfo.useTargetPosition; /// /// /// private int _sizeKind { get { return _item.sizeKind; } } /// /// /// private int _dash { get { return _item.dash; } } /// /// /// private bool _attachWeaponEf { get { return _item.attach_ef != 0; } } /// /// /// private float _movingAtk { get { return _item.moving_attack; } } /// /// 开火 /// private float _fireRange { get { return _item.fireRange; } } /// /// /// public float attackCd => ATTACK_DELAY; ///// ///// ///// //public BehaviorTree behaviorTree //{ // get; // private set; //} #endregion #region Method /// /// 初始化 /// /// /// public override bool Init(EntityInfo info) { if (info != null) { _item = ItemProxy.Instance.GetStaticItem(info.itemId); SetLevel(info.factorA, info.factorB, 0, true); InitRigbody(_item.mass); _scriptCha = EntityMainPlayer.Instance; _cha1 = _scriptCha.transform; _target = _cha1; if (EntityCart.Instance) { _target = EntityCart.Instance.transform; } moveState = 0; } return base.Init(info); } /// /// /// protected override void OnViewInitCompleted() { base.OnViewInitCompleted(); var viewGO = entityView.gameObject; _enemyInfo = viewGO.GetComponent(); var orb = viewGO.GetComponent(); Destroy(orb); //if (enemy.aiBT) //{ // behaviorTree = this.gameObject.AddComponent(); // behaviorTree.ExternalBehavior = enemy.aiBT; // var s = behaviorTree.GetVariable("attackCD") as SharedFloat; // s.SetValue(5f); // s = behaviorTree.GetVariable("attackRange") as SharedFloat; // s.SetValue(0.15f); // s = behaviorTree.GetVariable("loseTargetRange") as SharedFloat; // s.SetValue(1f); //} //var osc = view.GetComponent(); //var sc = gameObject.AddComponent(); //sc.isTrigger = osc.isTrigger; //sc.center = osc.center; //sc.radius = osc.radius; //Destroy(osc); SetModel(viewGO); SetFloat(Hash_Speed_Move, _item.speed_move); SetFloat(Hash_Speed_Attack1, _item.speed_attack); SetFloat(Hash_Speed_Attack1_I, _item.speed_attack_i); _idleAnimSpeed = _item.speed_idle - 0.05f; SetFloat(Hash_Speed_Idle, _idleAnimSpeed); //_moveSound = Monster_efs.Instance.snd_move[Random.Range(0, 3)]; CreateHpBar(); SetShadowVisible(true); SummonStart(); StartAI(); } public override void CreateHpBar() { _hpBarHeight = 0.09f + _sizeKind * 0.007f; _blood = BoardManager.Instance.CreateBloodBoard("BloodBoard2"); _blood.SetTarget(this.transform, Vector3.up * _hpBarHeight); _blood.HideSlider(); } public override void SetHpBar(int cur, int max, float height, int index) { base.SetHpBar(cur, max, _hpBarHeight, index); } /// /// /// /// /// /// /// public void SetLevel(float[] a, float[] b, int playkind, bool isSummon) { _playKind = playkind; level = 1; attack = (int)(_item.power * 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); isLife = true; } /// /// /// /// public void SetMoveSpeed(float speedRate) { moveSpeed = _item.runSpeed * speedRate; SetFloat(Hash_Speed_Move, speedRate); } /// /// /// /// public override void Dead(int kind) { moveState = -4; _lastMon = false; curHp = 0; GameLevel.Instance.MinionKill(this.itemId); switch (kind) { case 2: _behitDirection.y = 0f; EnemyHelper.Instance.SoundOn(4); EnemyHelper.Instance.EnemyDead(_kind, transform.position, this.transform.localScale, _behitDirection, _mainRender.material.mainTexture); break; case 1: //Destroy(gameObject, 2f); //bekicked.wrapMode = WrapMode.ClampForever; EnemyHelper.Instance.EnemyDead(0, transform.position, Vector3.zero, Vector3.zero, null); SetShadowVisible(false); break; case 0: EnemyHelper.Instance.SoundOn(4); EnemyHelper.Instance.EnemyDead(1, transform.position, Vector3.zero, Vector3.zero, null); break; case 3: EnemyHelper.Instance.SoundOn(4); EnemyHelper.Instance.EnemyDead(3, transform.position, transform.localScale, Vector3.zero, _mainRender.material.mainTexture); break; } //_script_cha.GainExp(haveExp); if (_cloneBullet) { Destroy(_cloneBullet.gameObject); _cloneBullet = null; } base.Dead(kind); } 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 override void Grabed() { if (_attributeStatus <= 0 && !_grabed) { var myPos = transform.position; myPos.y = 0f; var chaPos = _cha1.position; chaPos.y = 0f; _behitDirection = Vector3.Normalize(myPos - chaPos); this.transform.forward = -_behitDirection; _grabStyle = Random.Range(0, 2); if (_sizeKind == 20) { _grabStyle += 3; } else if (_kind != 2) { _grabStyle = 6; } _collider.enabled = false; switch (_grabStyle) { case 1: PlayAnimation(Hash_Begrab1); break; case 2: PlayAnimation(Hash_Begrab2); break; case 3: PlayAnimation(Hash_Begrab3); break; case 4: PlayAnimation(Hash_Begrab4); break; case 5: PlayAnimation(Hash_Begrab5); break; default: PlayAnimation(Hash_Begrab); break; } AddForce(_behitDirection * EnemyHelper.Instance.GetGrabForce(_grabStyle)); _scriptCha.Grab(_grabStyle, transform.position); _grabed = true; _poisonDelay = -1f; } } public void CountDown() { if (isLife) { _cloneArrow = Instantiate(_directionArrow, _cha1.position, Quaternion.identity); _showArrow = true; _lastMon = true; } } /// /// /// public void SummonStart() { float time = 1.5f; if (_kind == 2) { } else { time = 0.4f; } _spawning = true; this.transform.rotation = Quaternion.Euler(0f, GlobalUtils.RndAngle, 0f); PlayAnimation(Hash_Summon); Invoke(nameof(SummonFinish), time); } /// /// /// public void SummonFinish() { _spawning = false; } public override void OnDamage(AllyDamage allyDamage, int damageLayer) { if (!isLife || _grabed) return; var sourceCha = allyDamage.source; var myPosition = this.position; _behitDirection = myPosition - sourceCha.position; _behitDirection.y = 0f; _behitDirection = Vector3.Normalize(_behitDirection); bool downHigh = sourceCha.attackRising; float damage = 0f; float addDamage = sourceCha.伤害加深百分比 * 0.01f; float realDefence = (defence - sourceCha.忽视防御固定值) * (100 - sourceCha.忽视防御百分比) * 0.01f; float damageForce = 0f; bool pierce = false; switch (damageLayer) { case GameLayer.NormalAttack: { damageForce = 40f; int sourceHitRate = sourceCha.sourceTotalHitRate; int blockRate = (int)((block - sourceHitRate) * 1000f / Mathf.Max(block, sourceHitRate, 1) + 50); //Debug.Log($"({block} - {sourceHitRate}) *100 /max({block},{sourceHitRate},1)+5 = " + blockRate); if (moveState >= 0 && GlobalUtils.RndThousand < blockRate) { _scriptCha.Blocked(myPosition); AddForce(_behitDirection * 10f); return; } damage = sourceCha.damage; _target = _cha1; GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood(myPosition, _behitDirection); break; } case GameLayer.PowerAttack: { damageForce = 30f; downHigh = true; realDefence *= 0.5f; damage = sourceCha.damage; _target = _cha1; GameCamera.Instance.Hitcam2(1f); EnemyHelper.Instance.CreateBlood_Only(myPosition, _behitDirection); break; } case GameLayer.SkillAttack: { damageForce = 10f; downHigh = true; damage = allyDamage.physicsDamage; _target = _cha1; //GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood_Only(myPosition, _behitDirection); break; } case GameLayer.PoisonAttack: { damageForce = 10f; damage = allyDamage.physicsDamage; if (damage == 0.1f) { damage = 0; _poison = true; _poisonDamage = sourceCha.damage * 0.2f; _poisonDelay = 4f; downHigh = false; _target = _cha1; return; } _poison = true; _poisonDamage = damage; damage *= 50f; _poisonDelay = 5f; downHigh = true; _target = _cha1; GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood_Only(myPosition, _behitDirection); break; } case GameLayer.DeathAttack: { damageForce = 0f; var petrifyRate = (int)allyDamage.physicsDamage; Petrify(petrifyRate); _target = _cha1; AddForce(_behitDirection * -100); GameCamera.Instance.Hitcam(); break; } case GameLayer.GeneralAttack: { damageForce = 60f; downHigh = false; damage = sourceCha.damage * EntityPet.Instance.bulletDamage; _target = _cha1; EnemyHelper.Instance.CreateBlood_Only(myPosition, _behitDirection); break; } case GameLayer.PierceAttack: { damageForce = 0f; pierce = true; damage = allyDamage.physicsDamage; Pierced((int)damage, _behitDirection); curHp -= (int)damage; _target = _cha1; SetHpBar(0, maxHp, 9f, 0); EnemyHelper.Instance.CreateBlood_Only(myPosition, _behitDirection); break; } case GameLayer.CrowdAttack: { damageForce = 10f; damage = allyDamage.physicsDamage; _target = sourceCha.transform; _resetTarget = true; EnemyHelper.Instance.CreateBlood_Only(myPosition, _behitDirection); break; } case GameLayer.PushAttack: { damageForce = 40f; damage = sourceCha.damage; _target = _cha1; GameCamera.Instance.Hitcam(); EnemyHelper.Instance.CreateBlood(myPosition, _behitDirection); break; } case GameLayer.BurnAttack: { damageForce = 40f; damage = sourceCha.damage; if (sourceCha.IsMainPlayer()) { GameCamera.Instance.Hitcam(); } _target = _cha1; if (Burn((int)damage)) EnemyHelper.Instance.CreateBlood(myPosition, _behitDirection); break; } case GameLayer.ColdAttack: { damageForce = 40f; downHigh = false; damage = sourceCha.damage; if (sourceCha.IsMainPlayer()) { GameCamera.Instance.Hitcam(); } _target = _cha1; var si = _animator.GetCurrentAnimatorStateInfo(0); if (si.shortNameHash != Hash_Down_High) { if (Freeze((int)damage)) EnemyHelper.Instance.CreateBlood(myPosition, _behitDirection); } break; } case GameLayer.StunAttack: { damageForce = -10f; damage = 0f; _target = _cha1; Stun((int)damage); break; } case GameLayer.ShockAttack: { damageForce = 40f; damage = sourceCha.damage; if (sourceCha.IsMainPlayer()) { GameCamera.Instance.Hitcam(); } _target = _cha1; if (Shock((int)damage)) { EnemyHelper.Instance.CreateBlood(myPosition, _behitDirection); } break; } case GameLayer.DarkAttack: { damageForce = 40f; damage = sourceCha.damage; if (sourceCha.IsMainPlayer()) { GameCamera.Instance.Hitcam(); } _target = _cha1; if (Darken((int)damage)) { EnemyHelper.Instance.CreateBlood(myPosition, _behitDirection); } break; } case GameLayer.RiseupAttack2: { damageForce = 0f; damage = sourceCha.damage * 0.4f; if (_risedrop) { _riseFactor = 0.6f; } else { transform.rotation = Random.rotation; _riseFactor = 3.4f; } _risedrop = true; _target = _cha1; EnemyHelper.Instance.CreateBlood_Only(myPosition, _behitDirection); break; } case GameLayer.RiseupAttack: { damageForce = 0f; damage = sourceCha.damage * 0.4f; GameCamera.Instance.Hitcam2(0.08f); if (_risedrop) { _riseFactor = 0.6f; } else { transform.rotation = Random.rotation; _riseFactor = 1.2f; } _risedrop = true; _target = _cha1; EnemyHelper.Instance.CreateBlood(myPosition, _behitDirection); break; } } damage -= realDefence; damage += damage * addDamage; damage = Mathf.Max(1f, damage); SetMoveSpeed(0f); EnemyHelper.Instance.SoundOn(1); if (!isLife) { if (pierce) { PlayAnimation(Hash_Pierced); } else { _animator.enabled = false; StopAnimation(); } } else { if (downHigh) { transform.Rotate(0f, Random.Range(0, 360), 0f); PlayAnimation(Hash_Down_High); } else { PlayAnimation(Hash_Down, 0f); } if (damageForce > 0f) this.AddForce(_behitDirection * damageForce); if (_direction == Vector3.zero) { _direction = -Vector3.forward; } if (damage > 0) { curHp -= (int)damage; SetDamageNumber(transform.position, (int)damage, _behitDirection, _scriptCha.critDamage); SetHpBar(curHp, maxHp, -1); } //if (Random.Range(0, 5) == 0) //{ // PlaySound(EnemyHelper.Instance.ScreamSFX()); //} } if (curHp <= 0 && isLife) { if (!_risedrop) { Dead(2); } } else if (_fixedTarget) { _target = _targetOnlyone; } if (EntityCart.Instance) { _target = EntityCart.Instance.transform; } } /// /// /// public override void UpdateState() { if (!entityView.initSuccess) { return; } if (!isLife) { return; } base.UpdateState(); // UpdateRiseDrop(); _behaviourDelay -= deltaTime; var currentStateInfo = _animator.GetCurrentAnimatorStateInfo(0); int currStateNameHash = currentStateInfo.shortNameHash; int currStateTagHash = currentStateInfo.tagHash; if (_grabed) { if (currStateTagHash == Hash_Begrab) { _scriptCha.Grabfinish(transform.position, transform.forward); moveState = -2; transform.position = _cha1.position; } else if (currStateTagHash == Hash_Bethrust) { _scriptCha.Grabfinish(transform.position, transform.forward); if (moveState != -3) { curHp = 0; SetHpBar(0); var transform2 = _scriptCha.scriptWeapon.main_hand;// GameObject.Find("weapon_dummy"); if (transform2) { Quaternion dir = Quaternion.LookRotation(-transform2.forward, new Vector3(0f, -1.3f, 1f)); EnemyHelper.Instance.CreateGrabBlood(transform2.position + transform2.forward * 0.01f, dir); } GameCamera.Instance.Hitcam2(1f); EnemyHelper.Instance.SoundOn(3); } moveState = -3; } else if (currStateTagHash == Hash_Bekicked) { if (moveState != -4) { AddForwardForce(EnemyHelper.Instance.GetKickForce(_grabStyle)); GameCamera.Instance.Hitcam2(1f); EnemyHelper.Instance.SoundOn(2); if (curHp <= 0) { Dead(1); } else { //if (_grabStyle != 6) //{ // myanimation.AddClip(script_monEf.getup[_grabStyle], "getup"); //} //var getup = myanimation.PlayQueued("getup"); //getup.speed = script_monEf.speed_getup[_grabStyle]; } } moveState = -4; _grabed = false; } } else if (currStateTagHash == Hash_Getup) { moveState = 0; } else if (currStateNameHash == Hash_Summon) { moveState = 0; } else if (currStateNameHash == Hash_Down_High) { moveState = -1; } else if (currStateNameHash == Hash_Down) { moveState = -1; } else if (currStateNameHash == Hash_Attack1) { _impact = false; moveState = 11; var _lookRotation = Quaternion.LookRotation(_attackStartDirection); transform.rotation = Quaternion.Lerp(transform.rotation, _lookRotation, deltaTime * 6f); transform.position += _attackStartDirection * (deltaTime * _movingAtk); } else if (currStateNameHash == Hash_Attack1_I) { moveState = 12; if (!_impact) { _impact = true; if (_dash > 0) { AddForce(_attackStartDirection * _dash); } Vector3 bulletPosition = _attackStartPosition; if (!_useTargetPosition) bulletPosition = transform.TransformPoint(_bullet.localPosition); if (_cloneBullet == null) { _cloneBullet = Instantiate(_bullet, bulletPosition, transform.rotation); _cloneBullet.GetComponent().PressDamage(this.attack); if (_attachWeaponEf) { _cloneBullet.parent = transform; } } else { _cloneBullet.SetPositionAndRotation(bulletPosition, transform.rotation); _cloneBullet.gameObject.SetActive(true); } PlaySound(_attackSound); Vector3 pos = transform.position; pos.y = 0f; transform.position = pos; } } else if (currStateNameHash == Hash_Idle || currStateNameHash == Hash_Move) { _attackDelay -= deltaTime; if (_attackDelay <= 0f) _attackStart = false; _grabed = false; moveState = 1; } else { moveState = 1; } if (moveState == 1) { this.transform.position += _direction * (moveSpeed * deltaTime); if (_animator.enabled) { this.transform.rotation = Quaternion.Lerp(transform.rotation, _lookRotation, deltaTime * 3f); } } // UpdateArrow(); //du UpdatePoison(); } /// /// /// private void UpdateRiseDrop() { if (_risedrop) { Vector3 position = this.transform.position; position += Vector3.up * (_riseFactor * deltaTime); _riseFactor -= deltaTime * 5f; if (position.y >= 0f) { this.transform.position = position; return; } position.y = 0f; this.transform.position = position; PlayAnimation(Hash_Down); _risedrop = false; _riseFactor = 0f; var damage = _scriptCha.damage; curHp -= damage; if (curHp <= 0) { Dead(3); } else if (_behitDirection != Vector3.zero) { transform.rotation = Quaternion.LookRotation(_behitDirection); } else { transform.rotation = Quaternion.identity; } } } /// /// /// private void UpdatePoison() { //中毒 if (_poison) { _poisonDelay -= deltaTime; if (_poisonDelay < 0f) { _poison = false; SetHpBar(curHp, maxHp, 0); } else if ((int)_poisonDelay != _lastPoisonDelay) { curHp -= (int)_poisonDamage; SetDamageNumber(transform.position, (int)_poisonDamage, _behitDirection); SetHpBar(curHp, maxHp, 1); _lastPoisonDelay = (int)_poisonDelay; if (curHp <= 0) { Dead(0); } } } } #endregion #region ForAI /// /// /// public void SimpleAI() { if (!isLife || _spawning) { return; } if (_target == null) { _target = GetDefaultTarget(); } switch (_attributeStatus) { //dark case 4: _attackRange = 2f; _direction = transform.position - _target.position; _direction.y = 0f; _direction = Vector3.Normalize(_direction); break; //shock case 3: _direction = -transform.forward; _attackRange = 2f; break; //freeze case 2: _direction = Vector3.zero; _attackRange = 2f; break; default: _direction = _target.position - transform.position; _attackRange = _direction.magnitude; _direction.y = 0f; _direction = Vector3.Normalize(_direction); break; } if (_direction != Vector3.zero) { _lookRotation = Quaternion.LookRotation(_direction); } //几种行为 if (_behaviourDelay < 0f) { _behaviour = Random.Range(0, 6); if (_behaviour == 0) { if (_moveSound) PlaySound(_moveSound); } _behaviourDelay = 2f; } if (_attackRange < _fireRange) { if (!_attackStart && moveState >= 0 && _scriptCha.CanSelectAsTarget()) { PlayAnimation(Hash_Attack1); _attackStart = true; _attackDelay = attackCd; _attackStartDirection = _direction; _attackStartPosition = _target.position; //开始攻击 if (_warning) { var clone_line = Instantiate(_warning, _useTargetPosition ? _attackStartPosition : transform.position, Quaternion.LookRotation(_attackStartDirection)); Destroy(clone_line.gameObject, 1f); } if (_resetTarget) { _target = _cha1; _resetTarget = false; } } else { moveSpeed = _item.backSpeed; SetFloat(Hash_Speed_Idle, _idleAnimSpeed * -0.5f); _behaviour = -1; _behaviourDelay = 1f; } } else if (_mainRender.isVisible) { if (_behaviour != -1) { if (_behaviour >= 3) { SetFloat(Hash_Speed_Idle, _idleAnimSpeed); SetMoveSpeed(0.4f); } else { SetMoveSpeed(1f); } } if (_lastMon) { ShowArrow(false); } } else { SetMoveSpeed(Random.Range(0.7f, 1f)); if (_direction != Vector3.zero) { transform.rotation = Quaternion.LookRotation(_direction); } if (_lastMon) { ShowArrow(true); } } } public override void StartAI() { //if (behaviorTree) // StartCoroutine(nameof(AICoroutine)); //else InvokeRepeating(nameof(SimpleAI), 0.1f, 0.5f); } public override void EndAI(bool pause) { CancelInvoke(nameof(SimpleAI)); //StopCoroutine(nameof(AICoroutine)); } private IEnumerator AICoroutine() { yield return new WaitForSeconds(0.1f); while (true) { UpdateAI(); yield return new WaitForSeconds(0.5f); } } private void UpdateAI() { if (!isLife | _spawning) { return; } if (_target == null) { _target = _cha1; } switch (_attributeStatus) { case 4: _attackRange = 2f; _direction = transform.position - _target.position; _direction.y = 0f; _direction = Vector3.Normalize(_direction); break; case 3: _direction = -transform.forward; _attackRange = 2f; break; case 2: _direction = Vector3.zero; _attackRange = 2f; break; default: _attackRange = Vector3.Distance(transform.position, _target.position); _direction = _target.position - transform.position; _direction.y = 0f; _direction = Vector3.Normalize(_direction); break; } } #endregion } }