JeCodeLeSoir

=== Zombie ===

Feb 1st, 2023 (edited)
251
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 13.74 KB | None | 0 0
  1. using UnityEngine;
  2. using UnityEngine.AI;
  3. using UnityEngine.Events;
  4. using static UnityEngine.GraphicsBuffer;
  5.  
  6. [RequireComponent(typeof(NavMeshAgent))]
  7. [RequireComponent(typeof(Animator))]
  8. [RequireComponent(typeof(AudioSource))]
  9. public class ZombieJCLS : MonoBehaviour
  10. {
  11.     /*
  12.        === Animation ===
  13.  
  14.       Walk = bool
  15.       Dead = bool
  16.       Food = bool
  17.  
  18.       Hit = triger
  19.       Attack = triger
  20.       Detect = triger
  21.  
  22.     */
  23.  
  24.     [SerializeField] NavMeshAgent agent;
  25.     [SerializeField] Animator animator;
  26.     [SerializeField] GameObject player;
  27.     [SerializeField] AudioSource audioSource;
  28.  
  29.     [Header("=== Audio ===")]
  30.     public SAudioClip[] AudioClips = new SAudioClip[]
  31.     {
  32.          new SAudioClip() { name =  "Dead" },
  33.          new SAudioClip() { name =  "Hit" },
  34.          new SAudioClip() { name =  "Attack" },
  35.          new SAudioClip() { name =  "DetecPlayer" },
  36.          new SAudioClip() { name =  "RandomDestination" },
  37.          new SAudioClip() { name =  "UnAgro" },
  38.          new SAudioClip() { name =  "Food" },
  39.     };
  40.  
  41.     [Header("=== Life ===")]
  42.     [SerializeField] double HealPoint = 200;
  43.  
  44.     [Header("=== Range ===")]
  45.     [SerializeField] float DetectPlayerRange = 10;
  46.     [SerializeField] float AttackPlayerRange = 1;
  47.     [SerializeField] float RandomRadiusDestination = 3f;
  48.  
  49.     [Header("Delay Random Destination")]
  50.     [SerializeField] float RandomDestinationDelay = 3f;
  51.     float RandomRadiusDestinationPause;
  52.  
  53.     [Header("Delay Attack")]
  54.     [SerializeField] float AttackDelay = 0.5f;
  55.     float AttackPause;
  56.  
  57.     [Header("Hit Damage Zombie")]
  58.     public HitDmg[] HitProps = new HitDmg[]
  59.     {
  60.        new HitDmg() { name =  "Projectile", damage = 10 }
  61.     };
  62.  
  63.     bool IsHitDamage;
  64.  
  65.     [Header("Delay after Hit Damage")]
  66.     [SerializeField] float DelayAfterHit = 0.5f;
  67.     float DelayAfterPause;
  68.  
  69.     [Header("Delay after Detecte Player")]
  70.     [SerializeField] float DelayAfterDetecte = 2f;
  71.     float DetecteAfterPause;
  72.  
  73.     [SerializeField] float viewRadius = 100;
  74.     [SerializeField] float viewAngle = 90;
  75.  
  76.     [Header("Zombie Damage player")]
  77.     [SerializeField] float Damage = 20;
  78.  
  79.     [Header("Add function give damage player")]
  80.     public HitPlayerDamage AttackCallbackPlayer;
  81.  
  82.     [Header("Delay quand il mange")]
  83.     [SerializeField] float FoodDelay = 2f;
  84.     float FoodPause;
  85.     Transform FoodTarget;
  86.  
  87.     public LayerMask layerMaskCadravre;
  88.     bool IsTargetAManger;
  89.  
  90.     [Header("Animations")]
  91.     public AnimationNameKey[] AnimationNameKeys = new AnimationNameKey[]
  92.     {
  93.        new AnimationNameKey() { KeyName =  "Attack", AnimationName = "Zombie Attack" },
  94.        new AnimationNameKey() { KeyName =  "Detect", AnimationName = "Zombie Scream 0" }
  95.     };
  96.  
  97.     [System.Serializable]
  98.     public class HitPlayerDamage : UnityEvent<float> { }
  99.  
  100.     [System.Serializable]
  101.     public struct HitDmg
  102.     {
  103.         public string name;
  104.         public float damage;
  105.     }
  106.  
  107.     [System.Serializable]
  108.     public struct SAudioClip
  109.     {
  110.         public string name;
  111.         public AudioClip clip;
  112.     }
  113.  
  114.     [System.Serializable]
  115.     public struct AnimationNameKey
  116.     {
  117.         public string KeyName;
  118.         public string AnimationName;
  119.     }
  120.  
  121.     string lastAudioClip;
  122.  
  123.     public bool IsAgro { get; private set; }
  124.  
  125.     void PlayAudio(string name, bool spam = false)
  126.     {
  127.         if (lastAudioClip != name || spam)
  128.         {
  129.             if (!audioSource)
  130.                 return;
  131.  
  132.             lastAudioClip = name;
  133.  
  134.             if (spam is false)
  135.                 audioSource.Stop();
  136.  
  137.             if ((audioSource.isPlaying && spam is true) is false)
  138.                 foreach (SAudioClip clip in AudioClips)
  139.                 {
  140.                     if (clip.name == name)
  141.                     {
  142.                         audioSource.clip = clip.clip;
  143.                         audioSource.Play();
  144.                         return;
  145.                     }
  146.                 }
  147.         }
  148.     }
  149.  
  150.  
  151.     void Start()
  152.     {
  153.         agent = GetComponent<NavMeshAgent>();
  154.         animator = GetComponent<Animator>();
  155.         audioSource = GetComponent<AudioSource>();
  156.     }
  157.  
  158.     bool IsPointInTriangle(Vector3 a, Vector3 b, Vector3 c, Vector3 target)
  159.     {
  160.         float alpha = ((b.z - c.z) * (target.x - c.x) + (c.x - b.x) * (target.z - c.z)) /
  161.                       ((b.z - c.z) * (a.x - c.x) + (c.x - b.x) * (a.z - c.z));
  162.         float beta = ((c.z - a.z) * (target.x - c.x) + (a.x - c.x) * (target.z - c.z)) /
  163.                      ((b.z - c.z) * (a.x - c.x) + (c.x - b.x) * (a.z - c.z));
  164.  
  165.         float gamma = 1.0f - alpha - beta;
  166.  
  167.         return (alpha > 0) && (beta > 0) && (gamma > 0);
  168.     }
  169.    
  170.     bool IsInVision(Vector3 position)
  171.     {
  172.         Vector3 a = Quaternion.AngleAxis(-viewAngle / 2, transform.up) * transform.forward;
  173.         Vector3 b = Quaternion.AngleAxis(viewAngle / 2, transform.up) * transform.forward;
  174.  
  175.         Vector3 a1 = transform.position + (a * viewRadius);
  176.         Vector3 b1 = transform.position + (b * viewRadius);
  177.  
  178.         Debug.DrawLine(transform.position, a1, Color.green);
  179.         Debug.DrawLine(transform.position, b1, Color.green);
  180.  
  181.         return IsPointInTriangle(transform.position, a1, b1, position);
  182.     }
  183.  
  184.     void Update()
  185.     {
  186.         agent.stoppingDistance = AttackPlayerRange;
  187.  
  188.         if (!player)
  189.         {
  190.             Debug.LogError(this.name + " : Zombie à pas de player en ref !");
  191.             return;
  192.         }
  193.  
  194.         if (IsHitDamage)
  195.         {
  196.             if (DelayAfterPause >= DelayAfterHit)
  197.             {
  198.                 IsHitDamage = false;
  199.                 DelayAfterPause = 0;
  200.             }
  201.             DelayAfterPause += 1 * Time.deltaTime;
  202.             return;
  203.         }
  204.  
  205.         if (HealPoint <= 0)
  206.         {
  207.             PlayAudio("Dead");
  208.             animator.SetTrigger("Dead");
  209.             Destroy(this.gameObject, 5f);
  210.  
  211.             return;
  212.         }
  213.  
  214.         float velocity = agent.velocity.magnitude / agent.speed;
  215.         animator.SetBool("Walk", velocity > 0.3);
  216.  
  217.         float PlayerDistance = Vector3.Distance(transform.position, player.transform.position);
  218.  
  219.         bool isReachable = PathIsReachable(agent, player.transform.position);
  220.         bool isInVision = IsInVision(player.transform.position);
  221.        
  222.         bool IsDetectPlayer =
  223.                 (PlayerDistance < DetectPlayerRange)
  224.                 && isReachable && (IsAgro ? true : isInVision);
  225.        
  226.  
  227.         if ((IsDetectPlayer) is false )
  228.         {
  229.             // ==== à Perdu l'agro ====
  230.             if (IsAgro)
  231.             {
  232.                 PlayAudio("UnAgro");
  233.                 agent.SetDestination(this.transform.position);
  234.                 IsAgro = false;
  235.             }
  236.  
  237.             // ==== Cherche un truc a manger ====
  238.             if (IsTargetAManger is false)
  239.                 if (Physics.SphereCast(this.transform.position, 3,
  240.                     transform.forward, out RaycastHit hit, 10, layerMaskCadravre))
  241.                 {
  242.                     FoodTarget = hit.transform;
  243.                     agent.SetDestination(hit.transform.position);
  244.                     IsTargetAManger = true;
  245.                 }
  246.  
  247.             // ==== Je Ganbade ====
  248.             if (IsTargetAManger is false)
  249.             {
  250.                 //Debug.Log("Je Ganbade");
  251.                 RandomDestination();
  252.                 animator.SetBool("Food", false);
  253.             }
  254.  
  255.             // ==== J'ai a mangé ====
  256.             if (IsTargetAManger is true && IsAgro is false)
  257.             {
  258.                 if (FoodTarget)
  259.                 {
  260.                     float d = Vector3.Distance(FoodTarget.position, transform.position);
  261.                     if (d < (agent.stoppingDistance + 0.1f))
  262.                     {
  263.  
  264.                         PlayAudio("Food", true);
  265.  
  266.                         if (FoodPause >= FoodDelay)
  267.                         {
  268.                             //Destroy(FoodTarget.gameObject);
  269.  
  270.                             IsTargetAManger = false;
  271.                             FoodPause = 0;
  272.                         }
  273.  
  274.                         FoodPause += 1 * Time.deltaTime;
  275.  
  276.                         animator.SetBool("Food", true);
  277.                     }
  278.                 }
  279.                 else
  280.                 {
  281.                     IsTargetAManger = false;
  282.                     FoodPause = 0;
  283.                 }
  284.             }
  285.  
  286.             return;
  287.         }
  288.         else
  289.         {
  290.             bool IsAttackRange = PlayerDistance
  291.             < (agent.stoppingDistance) && isInVision;
  292.            
  293.             if (!IsAttackRange)
  294.             {
  295.                 if (IsAgro is false)
  296.                 {
  297.                     PlayAudio("DetecPlayer");
  298.                     animator.SetTrigger("Detect");
  299.                 }
  300.                
  301.                 IsAgro = true;
  302.  
  303.                 LookAt(player.transform.position, 2);
  304.  
  305.                 if (!animator.GetCurrentAnimatorStateInfo(0).IsName(GetAnimationName("Detect")))
  306.                 {
  307.                     AttackPause = 0;
  308.                     IsTargetAManger = false;
  309.                    
  310.                     if (
  311.                         agent.pathStatus == NavMeshPathStatus.PathComplete
  312.                         && PlayerDistance <= agent.stoppingDistance
  313.                     )
  314.                     {
  315.                         LookAt(player.transform.position, 2);
  316.                     }
  317.                     else
  318.                     {
  319.  
  320.                         if (DetecteAfterPause >= DelayAfterDetecte)
  321.                         {
  322.                             agent.SetDestination(player.transform.position);
  323.                             Debug.DrawLine(transform.position, player.transform.position, Color.yellow);
  324.                             DetecteAfterPause = 0;
  325.                         }
  326.  
  327.                         DetecteAfterPause += 1 * Time.deltaTime;
  328.                     }
  329.                 }
  330.             }
  331.             else
  332.             {
  333.                 if(isInVision)
  334.                     Attack();
  335.  
  336.                 DetecteAfterPause = 0;
  337.             }
  338.  
  339.             RandomRadiusDestinationPause = 0;
  340.         }
  341.     }
  342.  
  343.    
  344.     private void OnTriggerEnter(Collider other)
  345.     {
  346.         foreach (HitDmg hitprop in HitProps)
  347.         {
  348.             if (hitprop.name == other.tag)
  349.             {
  350.                 IsHitDamage = true;
  351.                 DelayAfterPause = 0;
  352.  
  353.                 this.HealPoint -= hitprop.damage;
  354.  
  355.                 animator.SetTrigger("Hit");
  356.  
  357.                 PlayAudio("Hit");
  358.  
  359.                 Destroy(other.gameObject);
  360.                 return;
  361.             }
  362.         }
  363.     }
  364.  
  365.     void RandomDestination()
  366.     {
  367.  
  368.         //========== RandomDestination ==========//
  369.  
  370.         if (RandomRadiusDestinationPause >= RandomDestinationDelay)
  371.         {
  372.             float randomAngle = Random.Range(0, 2 * Mathf.PI);
  373.             float randomRadius = Random.Range(agent.stoppingDistance + 1, RandomRadiusDestination);
  374.            
  375.             float x = randomRadius * Mathf.Cos(randomAngle);
  376.             float y = randomRadius * Mathf.Sin(randomAngle);
  377.  
  378.             Vector3 nextDestination = new Vector3(x, 0, y);
  379.  
  380.             nextDestination += transform.position;
  381.             debugPosition = nextDestination;
  382.  
  383.             if (NavMesh.SamplePosition(nextDestination,
  384.                 out NavMeshHit hit, RandomRadiusDestination, 1))
  385.                 agent.SetDestination(hit.position);
  386.  
  387.             PlayAudio("RandomDestination", true);
  388.  
  389.             if (
  390.                 (agent.pathStatus == NavMeshPathStatus.PathPartial
  391.                 || agent.pathStatus == NavMeshPathStatus.PathInvalid) is false
  392.             )
  393.                 RandomRadiusDestinationPause = 0;
  394.  
  395.         }
  396.  
  397.         RandomRadiusDestinationPause += 1 * Time.deltaTime;
  398.  
  399.         Debug.DrawLine(transform.position, agent.destination, Color.red);
  400.     }
  401.  
  402.     void LookAt(Vector3 target, float speed = 1)
  403.     {
  404.         Vector3 dir = target - transform.position;
  405.         dir.y = 0;
  406.         Quaternion rot = Quaternion.LookRotation(dir);
  407.         transform.rotation = Quaternion.Slerp(transform.rotation, rot, speed * Time.deltaTime);
  408.     }
  409.  
  410.     string GetAnimationName(string KeyName)
  411.     {
  412.        foreach(AnimationNameKey animationNameKey in AnimationNameKeys)
  413.        {
  414.             if (animationNameKey.KeyName == KeyName)
  415.                 return animationNameKey.AnimationName;
  416.        }
  417.        return null;
  418.     }
  419.  
  420.     void Attack()
  421.     {
  422.         if (AttackPause >= AttackDelay)
  423.         {
  424.             if (animator.GetCurrentAnimatorStateInfo(0).IsName(GetAnimationName("Attack")))
  425.                 return;
  426.            
  427.             //==========  Attack  ==========//
  428.  
  429.             animator.SetTrigger("Attack");
  430.             PlayAudio("Attack", true);
  431.  
  432.             if (AttackCallbackPlayer != null)
  433.                 AttackCallbackPlayer.Invoke(Damage);
  434.  
  435.             AttackPause = 0;
  436.         }
  437.  
  438.         AttackPause += 1 * Time.deltaTime;
  439.     }
  440.     bool PathIsReachable(NavMeshAgent agentNav, Vector3 position)
  441.     {
  442.         NavMeshPath navMeshPath = new NavMeshPath();
  443.         return agentNav.CalculatePath(position, navMeshPath)
  444.         && navMeshPath.status == NavMeshPathStatus.PathComplete;
  445.     }
  446.  
  447.     Vector3 debugPosition;
  448.     void OnDrawGizmos()
  449.     {
  450.         Gizmos.color = Color.green;
  451.         Gizmos.DrawWireSphere(transform.position, DetectPlayerRange);
  452.         Gizmos.color = Color.red;
  453.         Gizmos.DrawWireSphere(transform.position, agent.stoppingDistance);
  454.         Gizmos.color = Color.blue;
  455.         Gizmos.DrawWireSphere(debugPosition, 0.5f);
  456.     }
  457.    
  458.     public void Hurt()
  459.     {
  460.         Debug.Log("Hurt");
  461.  
  462.         if (IsAgro is false)
  463.         {
  464.             PlayAudio("DetecPlayer");
  465.             animator.SetTrigger("Detect");
  466.         }
  467.     }
  468. }
Advertisement
Add Comment
Please, Sign In to add comment