EscapeShooter/My project/Assets/Project Files/Game/Scripts/Enemy/Boss/BossBomberBehaviour.cs

347 lines
11 KiB
C#

using UnityEngine;
using Watermelon.LevelSystem;
namespace Watermelon.SquadShooter
{
public class BossBomberBehaviour : BaseEnemyBehavior
{
protected static readonly int PARTICLE_BOSS_EAT_HASH = "Boss Eat".GetHashCode();
private readonly int PARTICLE_STEP_HASH = "Boss Step".GetHashCode();
private readonly int PARTICLE_DEATH_FALL_HASH = "Boss Death Fall".GetHashCode();
private readonly int PARTICLE_ENTER_FALL_HASH = "Boss Enter Fall".GetHashCode();
private readonly int PARTICLE_KICK_HASH = "Boss Kick".GetHashCode();
private readonly int ANIMATOR_ATTACK_HASH = Animator.StringToHash("Attack");
private readonly int ANIMATOR_DIE_HASH = Animator.StringToHash("Death");
private readonly int ANIMATOR_ENTER_HASH = Animator.StringToHash("Enter");
private readonly int ANIMATOR_SHOOTING_HASH = Animator.StringToHash("Shooting");
private readonly int ANIMATOR_KICK_HASH = Animator.StringToHash("Kick");
[SerializeField] GameObject graphicsObject;
[Header("Fighting")]
[SerializeField] GameObject bulletPrefab;
[SerializeField] float bulletSpeed;
[SerializeField] int shotsPerAttempt;
[SerializeField] float attackDistanceMin;
[SerializeField] float attackDistanceMax;
[SerializeField] float kickDistance;
[SerializeField] DuoInt damage;
[SerializeField] float hitCooldown;
[SerializeField] LayerMask targetLayer;
[SerializeField] AnimationCurve yBombMovementCurve;
public float KickDistance => kickDistance;
public float AttackDistanceMin => attackDistanceMin;
public float AttackDistanceMax => attackDistanceMax;
public float HitCooldown => hitCooldown;
[Space]
[SerializeField] float bombDamageMin;
[SerializeField] float bombDamageMax;
[SerializeField] float bombExplosionDuration;
[SerializeField] float bombExplosionRadius;
[SerializeField] float bombShakeDurationMin;
[SerializeField] float bombShakeDurationMax;
[SerializeField] float bombShakeDistance;
[Header("Weapon")]
[SerializeField] Transform weaponHolderTransform;
[SerializeField] Transform weaponTransform;
[SerializeField] Transform shootPointTransform;
[SerializeField] ParticleSystem shootParticleSystem;
[Header("Boss")]
[SerializeField] Transform leftFootTransform;
[SerializeField] Transform rightFootTransform;
[SerializeField] Transform backTransform;
[Space]
[SerializeField] Collider bossCollider;
[SerializeField] WeaponRigBehavior weaponRigBehavior;
private float sqrSpeed;
private Vector3 bombPoint;
private int shotsAmount;
private VirtualCamera gameCameraCase;
public event SimpleCallback OnEntered;
protected override void Awake()
{
base.Awake();
bossCollider.enabled = false;
}
public override void Init()
{
base.Init();
sqrSpeed = stats.MoveSpeed * stats.MoveSpeed;
// Reset weapon position
weaponTransform.SetParent(weaponHolderTransform);
weaponTransform.ResetLocal();
weaponTransform.gameObject.SetActive(true);
isDead = true;
gameCameraCase = CameraController.GetCamera(CameraType.Gameplay);
// Disable graphics
graphicsObject.SetActive(false);
healthbarBehaviour.HealthBarTransform.gameObject.SetActive(false);
weaponRigBehavior.enabled = true;
weaponTransform.gameObject.SetActive(false);
}
public void PerformHit()
{
navMeshAgent.SetDestination(transform.position);
navMeshAgent.isStopped = true;
animatorRef.SetBool(ANIMATOR_RUN_HASH, false);
transform.LookAt(target);
navMeshAgent.isStopped = true;
shotsAmount = shotsPerAttempt;
animatorRef.SetBool(ANIMATOR_RUN_HASH, false);
animatorRef.SetBool(ANIMATOR_SHOOTING_HASH, true);
animatorRef.SetTrigger(ANIMATOR_ATTACK_HASH);
bombPoint = target.position;
}
public void PerformKick()
{
transform.LookAt(target);
navMeshAgent.isStopped = true;
animatorRef.SetBool(ANIMATOR_RUN_HASH, false);
animatorRef.SetBool(ANIMATOR_SHOOTING_HASH, false);
animatorRef.SetTrigger(ANIMATOR_KICK_HASH);
Tween.DelayedCall(0.3f, () =>
{
AudioController.PlaySound(AudioController.GetClip("punch1"));
});
}
public void ChasePlayer()
{
navMeshAgent.SetDestination(target.position);
navMeshAgent.isStopped = false;
animatorRef.SetBool(ANIMATOR_RUN_HASH, true);
}
public void Idle()
{
navMeshAgent.SetDestination(transform.position);
navMeshAgent.isStopped = true;
animatorRef.SetBool(ANIMATOR_RUN_HASH, false);
}
protected override void FixedUpdate()
{
base.FixedUpdate();
if (!LevelController.IsGameplayActive)
return;
if (isDead)
return;
if (navMeshAgent.isStopped)
{
var targetRotation = Quaternion.LookRotation(target.position - transform.position);
// Smoothly rotate towards the target point.
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 50);
}
healthbarBehaviour.FollowUpdate();
animatorRef.SetFloat(ANIMATOR_SPEED_HASH, navMeshAgent.velocity.sqrMagnitude / sqrSpeed);
}
public override void TakeDamage(float damage, Vector3 projectilePosition, Vector3 projectileDirection)
{
if (isDead)
return;
base.TakeDamage(damage, projectilePosition, projectileDirection);
if (hitAnimationTime < Time.time)
HitAnimation(Random.Range(0, 2));
}
protected override void OnDeath()
{
if (isDead)
return;
isDead = true;
StateMachine.StopMachine();
navMeshAgent.enabled = false;
// Disable healthbar
healthbarBehaviour.DisableBar();
animatorRef.Play(ANIMATOR_DIE_HASH, -1, 0);
AudioController.PlaySound(AudioController.GetClip("boss_scream"), 0.6f);
DropResources();
LevelController.OnEnemyKilled(this);
OnDiedEvent?.Invoke(this);
weaponRigBehavior.enabled = false;
ActivateRagdollOnDeath();
}
public void OnBombExploded(BossBombBehaviour bossBombBehaviour, bool playerHitted)
{
if (playerHitted)
{
gameCameraCase.Shake(0.04f, 0.04f, bombShakeDurationMax, 1.4f);
return;
}
float distanceMultiplier = 1.0f - Mathf.InverseLerp(0, bombShakeDistance, Vector3.Distance(characterBehaviour.transform.position, bossBombBehaviour.transform.position));
if (distanceMultiplier != 0.0f)
gameCameraCase.Shake(0.04f, 0.04f, Mathf.Lerp(bombShakeDurationMin, bombShakeDurationMax, distanceMultiplier), 1.4f);
}
public override void OnAnimatorCallback(EnemyCallbackType enemyCallbackType)
{
switch (enemyCallbackType)
{
case EnemyCallbackType.Hit:
OnBossHit();
break;
case EnemyCallbackType.BossKick:
if (Vector3.Distance(transform.position, target.position) <= kickDistance)
{
ParticlesController.PlayParticle(PARTICLE_KICK_HASH).SetPosition(leftFootTransform.position);
characterBehaviour.TakeDamage(characterBehaviour.MaxHealth * 0.5f);
}
break;
case EnemyCallbackType.BossLeftStep:
ParticlesController.PlayParticle(PARTICLE_STEP_HASH).SetPosition(leftFootTransform.position);
break;
case EnemyCallbackType.BossRightStep:
ParticlesController.PlayParticle(PARTICLE_STEP_HASH).SetPosition(rightFootTransform.position);
break;
case EnemyCallbackType.BossEnterFall:
OnBossEnterFall();
break;
case EnemyCallbackType.BossEnterFallFinished:
OnEntered?.Invoke();
CharacterBehaviour.GetBehaviour().TryAddClosestEnemy(this);
break;
case EnemyCallbackType.BossDeathFall:
ParticlesController.PlayParticle(PARTICLE_DEATH_FALL_HASH).SetPosition(backTransform.position);
gameCameraCase.Shake(0.04f, 0.04f, 0.3f, 1.4f);
break;
}
}
private void OnBossHit()
{
shootParticleSystem.Play();
GameObject bombObject = Instantiate(bulletPrefab);
bombObject.transform.position = shootPointTransform.position;
bombObject.transform.LookAt(bombPoint);
BossBombBehaviour bossBombBehaviour = bombObject.GetComponent<BossBombBehaviour>();
bossBombBehaviour.Init(this, bombExplosionDuration, Random.Range(bombDamageMin, bombDamageMax), bombExplosionRadius);
bossBombBehaviour.transform.DOMoveXZ(bombPoint.x, bombPoint.z, 1.0f);
bossBombBehaviour.transform.DOMoveY(bombPoint.y, 1.0f).SetCurveEasing(yBombMovementCurve).OnComplete(delegate
{
bossBombBehaviour.OnPlaced();
});
shotsAmount--;
// Recalculate bomb point
bombPoint = target.position + new Vector3(Random.Range(-4, 4), 0, Random.Range(-4, 4));
if (shotsAmount <= 0)
{
// move closer to the player
navMeshAgent.SetDestination(target.position);
navMeshAgent.isStopped = false;
animatorRef.SetBool(ANIMATOR_SHOOTING_HASH, false);
animatorRef.SetBool(ANIMATOR_RUN_HASH, true);
}
AudioController.PlaySound(AudioController.GetClip("shoot2"), 0.3f);
}
private void OnBossEnterFall()
{
isDead = false;
healthbarBehaviour.HealthBarTransform.gameObject.SetActive(true);
ParticlesController.PlayParticle(PARTICLE_ENTER_FALL_HASH).SetPosition(transform.position);
gameCameraCase.Shake(0.04f, 0.04f, 0.3f, 1.4f);
AudioController.PlaySound(AudioController.GetClip("jump_landing"));
CharacterBehaviour.GetBehaviour().TryAddClosestEnemy(this);
weaponTransform.gameObject.SetActive(true);
Tween.DelayedCall(0.4f, () =>
{
AudioController.PlaySound(AudioController.GetClip("boss_scream"), 0.6f);
});
}
public void Enter()
{
// Enable graphics
graphicsObject.SetActive(true);
healthbarBehaviour.HealthBarTransform.gameObject.SetActive(true);
animatorRef.Play(ANIMATOR_ENTER_HASH, -1, 0);
}
public override void Attack()
{
}
}
}