private void OnTriggerEnter(Collider other) { if (other.gameObject.layer == Layer_Wall) { print("EL colisionador choco con algo... " + other.gameObject.name); if (other.gameObject == self) { return; } IKilleable killeable = other.gameObject.GetComponent <IKilleable>(); if (killeable != null) { if (killeable.IsAlive && !killeable.invulnerable) { #if UNITY_EDITOR if (DebugMessages) { print("EL colisionador choco con algo KILLEABLE: " + other.gameObject.name); } #endif OnCollide(); return; } } #if UNITY_EDITOR if (DebugMessages) { print("EL colisionador choco con algo que no es KILLEABLE: " + other.gameObject.name); } #endif OnCollide(); } }
//============================= Colisiones ================================================ private void OnCollisionEnter(Collision collision) { //Detectamos collisiones con otros cuerpos. if (collision.gameObject.tag == "Player") { if (!charging) { return; } IKilleable killeable = collision.gameObject.GetComponent <IKilleable>(); if (killeable != null && killeable.IsAlive && !killeable.invulnerable) { print("EL colisionador choco con algo KILLEABLE: " + collision.gameObject.name); sm.Feed(BossStates.think); var Target = collision.gameObject.GetComponent <IDamageable <HitData, HitResult> >(); HitData data = new HitData() { Damage = ChargeDamage, BreakDefence = false }; Target.Hit(data); collision.rigidbody.AddForce(_chargeDir * ChargeCollisionForce, ForceMode.Impulse); return; } } if (collision.gameObject.layer == Layer_walls) { if (charging) { sm.Feed(BossStates.think); } print("EL colisionador choco con algo que no es KILLEABLE: " + collision.gameObject.name); } }
//========================================================================================= protected override void Awake() { base.Awake(); //Vulnerabilidad. //Si interrumpo el ataque... voy a stunned. FRitmo.OnComboSuccesfullyStart += () => _sm.Feed(ShieldEnemyStates.stunned); FRitmo.OnComboCompleted += () => { Health -= ComboCompleteDamage; }; FRitmo.TimeEnded += () => { _sm.Feed(ShieldEnemyStates.think); }; FRitmo.OnComboFailed += () => { _sm.Feed(ShieldEnemyStates.think); }; //Primera vulnerabilidad. Tuple <int, Inputs>[] data = new Tuple <int, Inputs> [3]; data[0] = Tuple.Create(1, Inputs.light); data[1] = Tuple.Create(3, Inputs.light); data[2] = Tuple.Create(7, Inputs.light); FRitmo.AddVulnerability(0, data); //Segunda vulnerabilidad Tuple <int, Inputs>[] data2 = new Tuple <int, Inputs> [3]; data2[0] = Tuple.Create(2, Inputs.strong); data2[1] = Tuple.Create(5, Inputs.light); data[2] = Tuple.Create(9, Inputs.light); FRitmo.AddVulnerability(1, data2); #region State Machine. var idle = new State <ShieldEnemyStates>("Idle"); var alerted = new State <ShieldEnemyStates>("Alerted"); var pursue = new State <ShieldEnemyStates>("pursue"); var blocking = new State <ShieldEnemyStates>("Bloquing"); var vulnerable = new State <ShieldEnemyStates>("Vulnerable"); var reposition = new State <ShieldEnemyStates>("Repositioning"); var parry = new State <ShieldEnemyStates>("Parrying"); var attack = new State <ShieldEnemyStates>("Attacking"); var think = new State <ShieldEnemyStates>("Thinking"); var dead = new State <ShieldEnemyStates>("Dead"); /* * anims.SetBool("Dead", true); * anims.SetTrigger("getDamage"); * anims.SetFloat("Moving", 1f); * anims.SetInteger("Attack", 1); * anims.SetBool("Blocking", true); * anims.SetTrigger("BlockBreak"); * anims.SetBool("Parrying"); */ #region Transitions idle.AddTransition(ShieldEnemyStates.alerted, alerted) .AddTransition(ShieldEnemyStates.dead, dead); alerted.AddTransition(ShieldEnemyStates.think, think) .AddTransition(ShieldEnemyStates.dead, dead); pursue.AddTransition(ShieldEnemyStates.pursue, pursue) .AddTransition(ShieldEnemyStates.think, think) .AddTransition(ShieldEnemyStates.dead, dead); reposition.AddTransition(ShieldEnemyStates.dead, dead) .AddTransition(ShieldEnemyStates.think, think); blocking.AddTransition(ShieldEnemyStates.parry, parry) .AddTransition(ShieldEnemyStates.attack, attack) .AddTransition(ShieldEnemyStates.vulnerable, vulnerable) .AddTransition(ShieldEnemyStates.think, think) .AddTransition(ShieldEnemyStates.dead, dead); vulnerable.AddTransition(ShieldEnemyStates.think, think) .AddTransition(ShieldEnemyStates.dead, dead); parry.AddTransition(ShieldEnemyStates.think, think) .AddTransition(ShieldEnemyStates.dead, dead); attack.AddTransition(ShieldEnemyStates.dead, dead) .AddTransition(ShieldEnemyStates.think, think); think.AddTransition(ShieldEnemyStates.dead, dead) .AddTransition(ShieldEnemyStates.block, blocking) .AddTransition(ShieldEnemyStates.parry, parry) .AddTransition(ShieldEnemyStates.vulnerable, vulnerable) .AddTransition(ShieldEnemyStates.reposition, reposition) .AddTransition(ShieldEnemyStates.attack, attack) .AddTransition(ShieldEnemyStates.pursue, pursue) .AddTransition(ShieldEnemyStates.idle, idle); #endregion #region Estados idle.OnEnter += (previousState) => { anims.SetFloat("Moving", 0f); }; idle.OnUpdate += () => { var toDamage = sight.target.GetComponent <IKilleable>(); if (!toDamage.IsAlive) { return; } if (sight.IsInSight() || sight.distanceToTarget < minDetectionRange) { _targetDetected = true; } if (_targetDetected) { _sm.Feed(ShieldEnemyStates.alerted); } }; alerted.OnEnter += (previousState) => { _alertedTimeRemaining = AlertedTime; }; alerted.OnUpdate += () => { if (_alertedTimeRemaining >= 0) { _alertedTimeRemaining -= Time.deltaTime; transform.forward = Vector3.Slerp(transform.forward, sight.dirToTarget, _rotationLerpSpeed); } else { _sm.Feed(ShieldEnemyStates.think); } }; alerted.OnExit += (nextState) => { }; blocking.OnEnter += (previousState) => { anims.SetBool("Blocking", true); anims.SetFloat("Moving", 0f); LookTowardsPlayer = true; _originalRotLerpSpeed = _rotationLerpSpeed; _rotationLerpSpeed = BlockLerpSpeed; _blocking = true; //recievedHits = 0; FRitmo.SetCurrentVulnerabilityCombo(1); FRitmo.ShowVulnerability(); }; blocking.OnUpdate += () => { if (sight.distanceToTarget > BlockRange) { _sm.Feed(ShieldEnemyStates.think); } }; blocking.OnExit += (nextState) => { if (nextState == ShieldEnemyStates.vulnerable) { Debug.LogWarning("Voy a vulnerable"); } anims.SetBool("Blocking", false); _rotationLerpSpeed = _originalRotLerpSpeed; _blocking = false; }; vulnerable.OnEnter += (previousState) => { _blocking = false; Disarmed = true; _currentDisarmedTime = DisarmedTime; //SetVulnerabity(true, 1); anims.SetBool("Disarmed", true); }; //vulnerable.OnUpdate += () => { }; vulnerable.OnExit += (nextState) => { anims.SetBool("Disarmed", false); }; parry.OnEnter += (previousState) => { //_parrying = true; //recievedHits = 0; anims.SetTrigger("Parrying"); ShieldSparks.Play(); }; //parry.OnExit += (nextState) => { _parrying = false; }; pursue.OnEnter += (previousState) => { anims.SetFloat("Moving", 1f); //recievedHits = 0; }; pursue.OnUpdate += () => { //Correr como si no hubiera un mañana (? transform.forward = Vector3.Slerp(transform.forward, sight.dirToTarget, _rotationLerpSpeed); if (sight.distanceToTarget > AttackRange) { agent.Move(sight.dirToTarget * MovementSpeed * Time.deltaTime); } if (sight.distanceToTarget <= AttackRange) { _sm.Feed(ShieldEnemyStates.think); } }; //pursue.OnExit += (nextState) => { }; reposition.OnEnter += (previousState) => { LookTowardsPlayer = true; _originalRotLerpSpeed = _rotationLerpSpeed; _rotationLerpSpeed = repositionLerpSpeed; }; reposition.OnUpdate += () => { if (sight.angleToTarget < 45) { _sm.Feed(ShieldEnemyStates.think); } }; reposition.OnExit += (nextState) => { LookTowardsPlayer = false; _rotationLerpSpeed = _originalRotLerpSpeed; }; attack.OnEnter += (previousState) => { //_attacking = true; agent.isStopped = true; rb.velocity = Vector3.zero; anims.SetInteger("Attack", 1); //recievedHits = 0; }; //attack.OnUpdate += () => { }; attack.OnExit += (nextState) => { //_attacking = false; agent.isStopped = false; }; think.OnEnter += (previousState) => { if (ThinkTime > 0) { remainingThinkTime = ThinkTime; } }; think.OnUpdate += () => { if (remainingThinkTime > 0) { remainingThinkTime -= Time.deltaTime; } else { remainingThinkTime = 0; IKilleable target = Target.GetComponent <IKilleable>(); if (sight.angleToTarget > 45f) { _sm.Feed(ShieldEnemyStates.reposition); return; } if (target.IsAlive) { //Tomo una desición. float blockImportance = (1 - (Health / MaxHP)) * 10; float pursueImportance = ((Health / MaxHP) * 10); float AttackImportance = 10f - (blockImportance * 0.8f); //print(string.Format("BlockImp: {0} / PursueImp: {1} / AttackImportance: {2}", // blockImportance, pursueImportance, AttackImportance)); //Desiciones posibles: //Perseguir --> se realiza siempre que el enemigo esté más lejos de cierta distancia. //Atacar --> Su importancia se mantiene. //Bloquear --> Cuando la vida se va reduciendo su imporancia es mayor. if (sight.distanceToTarget > AttackRange) { int decition = RoulleteSelection.Roll(new float[2] { pursueImportance, blockImportance }); //print("Distance is bigger than the AttackRange.\nDecition was: " + (decition == 0 ? "pursue" : "block")); if (decition == 0) { _sm.Feed(ShieldEnemyStates.pursue); } if (decition == 1) { _sm.Feed(ShieldEnemyStates.block); } } if (sight.distanceToTarget < AttackRange) { int decition = RoulleteSelection.Roll(new float[2] { AttackImportance, blockImportance }); //print("Distance is smaller than the AttackRange.\nDecition was: " + (decition == 0 ? "Attack" : "block")); if (decition == 0) { _sm.Feed(ShieldEnemyStates.attack); } if (decition == 1) { _sm.Feed(ShieldEnemyStates.block); } } } } }; think.OnExit += (nextState) => { //print(string.Format("Exiting from Thinking, next State will be {0}", nextState.ToString())); }; dead.OnEnter += (previousState) => { anims.SetBool("Dead", true); Die(); }; #endregion _sm = new GenericFSM <ShieldEnemyStates>(idle); #endregion }