Advertisement
Guest User

Untitled

a guest
Apr 24th, 2017
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.43 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. [RequireComponent (typeof (Animator))]
  5. [RequireComponent (typeof (NavMeshAgent))]
  6. [RequireComponent (typeof (CapsuleCollider))]
  7.  
  8. public class ZombieInstance : MonoBehaviour {
  9.  
  10. public float hp = 100.0f, damage = 20.25f, bodieRemovalTime = 10.0f, moveSpeed = 2.0f, fieldOfView = 45.0f, viewDistance = 5.0f, playerSearchInterval = 1.0f, minChase = 5.0f, maxChase = 10.0f, minWander = 5.0f, maxWander = 20.0f;
  11. /*
  12. * Health points of this zombie.
  13. * Damage of the attacks of this zombie.
  14. * Time to wait for deleting the dead bodie.
  15. * GLOBAL SPEED OF THE ZOMBIE I RECOMMEND 2 FOR WALKERS AND 7 FOR RUNNERS, DEPENDS ON YOUR GAME
  16. * FIELD OF VIEW OF THE ZOMBIE
  17. * VIEW DISTANCE OF THE ZOMBIE
  18. * INTERVAL USED TO CHECK IF THE ZOMBIE IS LOOKING AT THE PLAYER, JUST TO PREVENT OVERUSE OF RESOURCES
  19. SET 0 IF YOU DON'T CARE OR KEEP IT BETWEEN 1.0F AND 0.5F, RECOMMENDED
  20. *Min time to chase the player
  21. *Max time to chase the player (will be random between these 2 values)
  22. *Min time to wander around
  23. *Max time to wander around (works the same way)
  24. */
  25. public string playerTag = "Player", bodiesTag = "DeadPlayer";
  26. /*
  27. * SET HERE THE TAG TO IDENTIFY YOUR PLAYER
  28. * YOUR PLAYER DEAD BODIES
  29. */
  30. public bool canRun = false, eatBodies = false;
  31. /*
  32. * CAN YOUR ZOMBIE RUN?
  33. * WILL IT EAT THE DEAD PLAYER BODIES?
  34. */
  35. public Transform zombieHead = null;//Pivot point to use as reference, use it as if it were the eyes of the zombie.
  36. public LayerMask checkLayers;//Layers to check when searching for the player (after the check interval)
  37.  
  38. /*Zombie sounds AnimationStates
  39. * 0 = Sound on wandering, idle or whatever.
  40. * 1 = Sound for chasing player.
  41. * 2 = Sound for losing player or extras.
  42. * 3 = Sound while eating.
  43. * Length of 4.
  44. */
  45. public AudioClip[] audioClips = new AudioClip[4];
  46. /*
  47. * If you want to set a new clip, you must change the length of the array and edit the inspector script.
  48. * You can find the needed line by searching "AnimationStates", on the script ZombieUI.cs
  49. */
  50.  
  51. private bool playerChase = false, wandering = false, eatingBodie = false;
  52. /*
  53. * Will be true when the zombie is chasing the player, then the code will randomize when will stop doing it.
  54. */
  55. private float lastCheck = -10.0f, lastChaseInterval = -10.0f, lastWander = -10.0f;
  56. /*
  57. *Last time we checked the player's position.
  58. *Last or next time we chased the player before losing him.
  59. *Last time we set a wander position
  60. */
  61. private NavMeshAgent agent;//This zombie's nav mesh agent
  62. private Animator Anim;//This zombie's animator
  63. private Transform player = null, wanderManager = null;//Player position/transform
  64. private Vector3 lastKnownPos = Vector3.zero;//Last known player position
  65. private AudioSource SNDSource;//zombieHead should always have 2 audioSources
  66.  
  67. void Start () {
  68. //THIS IS USED TO GET THE LOCAL NAV MESH AGENT, wanderManager AND ANIMATOR OF THIS ZOMBIE
  69. agent = GetComponent<NavMeshAgent>();
  70. Anim = GetComponent<Animator>();
  71. SNDSource = zombieHead.GetComponent<AudioSource>();
  72. wanderManager = GameObject.FindWithTag("wanderManager").transform;
  73.  
  74. //SET THE MAIN VALUES
  75. agent.speed = moveSpeed;
  76. agent.acceleration = moveSpeed * 40;
  77. agent.angularSpeed = 999;
  78. resetZombie();
  79.  
  80. }
  81.  
  82. void Update(){
  83. /* IN CASE YOU CHANGE YOUR PLAYER GAMEOBJECT OR THE ZOMBIE IS SPAWNINg */
  84. if(Anim.GetCurrentAnimatorStateInfo(0).IsName("Spawn"))
  85. return;
  86.  
  87. if(player == null){
  88. if(eatingBodie)
  89. resetZombie();
  90. GameObject newPlayer = GameObject.FindWithTag(playerTag);
  91. GameObject bodySearch = GameObject.FindWithTag(bodiesTag);
  92. if(newPlayer != null && !newPlayer.name.Contains("Clone")){
  93. //There is a bug in unity that i couldn't fix, so i added the clone thing, so yeah...
  94. player = newPlayer.transform;
  95. }else if(eatBodies && bodySearch != null){
  96. player = bodySearch.transform;
  97. eatingBodie = true;
  98. followBodie();
  99. }else{
  100. doWanderFunctions();
  101.  
  102. if(newPlayer != null && newPlayer.name.Contains("Clone")){//Prevent that bug on the next search
  103. Destroy(newPlayer);
  104. }
  105.  
  106. return;//DON'T DO ANYTHING UNTIL WE HAVE THE PLAYER GAMEOBJECT, GO BACK, ABOOORRTTT!!!!
  107. }
  108. }
  109.  
  110. /* ACTUAL ZOMBIE CODE */
  111.  
  112. if(Time.time > lastCheck){//SEARCH FOR THE PLAYER AFTER INTERVAL
  113. checkView();
  114. lastCheck = Time.time + playerSearchInterval;
  115. }
  116.  
  117. if(!eatingBodie){
  118. /* PLAYER SEARCH ALGORITHMS */
  119. if(playerChase && Anim.GetBool("isChasing")){
  120. if(Time.time > lastChaseInterval){
  121. gotoLastKnown();
  122. }else{
  123. chasePlayer();
  124. }
  125. }
  126.  
  127. //SET THE ATTACK AND RESET IT
  128. AnimatorStateInfo state = Anim.GetCurrentAnimatorStateInfo(0);
  129. if(!state.IsName("Attack") && playerChase && reachedPathEnd()){//READY TO ATTACK!
  130. Anim.SetTrigger("doAttack");
  131. Anim.SetBool("isIdle", false);
  132. Anim.SetBool("isChasing", false);
  133. playerChase = false;
  134. }
  135. if(state.IsName("Attack") && state.normalizedTime > 0.90f){
  136. chasePlayer();
  137. Attack();//HERE WE CALL THE PLAYER'S DAMAGE
  138. }
  139. }else{
  140. /* EAT BODIE ALGORITHMS */
  141. if(reachedPathEnd()){//This means we are in the right position to eat the bodie.
  142. startEating();
  143. }else{
  144. followBodie();//In case or explosions or stuff like that.
  145. }
  146. }
  147.  
  148. //MAKE THE ZOMBIE WANDER AROUND THE MAP
  149. if(wandering){
  150. if(reachedPathEnd()){
  151. resetZombie();
  152. }
  153. if(Time.time > lastWander){//IF WE ARE READY TO CHOOSE A NEW POSITION
  154. wanderManager.SendMessage("getNewPos", this.gameObject, SendMessageOptions.RequireReceiver);
  155. }
  156. }
  157.  
  158. }
  159.  
  160. //Just to make this code prettier, simplify with functions...
  161. void checkView(){
  162. RaycastHit hit = new RaycastHit();
  163. Vector3 checkPosition = player.position - zombieHead.position;
  164. if(Vector3.Angle(checkPosition, zombieHead.forward) < fieldOfView){ //Check if player is inside the field of view
  165. if (Physics.Raycast(zombieHead.position, checkPosition, out hit, viewDistance, checkLayers)) {
  166. if(hit.collider.tag == playerTag){//do this..
  167. chasePlayer();
  168. lastChaseInterval = Time.time + Random.Range(minChase, maxChase);
  169. }
  170. }
  171. }else if(meleeDistance()){
  172. chasePlayer();
  173. lastChaseInterval = Time.time + Random.Range(minChase, maxChase);
  174. }
  175. }
  176.  
  177. void gotoLastKnown(){
  178. Anim.SetBool("isChasing", true);
  179.  
  180. if(canRun)
  181. Anim.SetBool("isRunning", true);
  182.  
  183. Anim.SetBool("isIdle", false);
  184. playerChase = true;
  185. agent.SetDestination(lastKnownPos);
  186. agent.Resume();
  187. wandering = true;
  188. eatingBodie = false;
  189. }
  190.  
  191. void chasePlayer(){
  192. Anim.SetBool("isChasing", true);
  193.  
  194. if(canRun)
  195. Anim.SetBool("isRunning", true);
  196.  
  197. Anim.SetBool("isIdle", false);
  198. playerChase = true;
  199. agent.SetDestination(player.position);
  200. lastKnownPos = player.position;
  201. agent.Resume();
  202. wandering = false;
  203. eatingBodie = false;
  204. playSound(audioClips[1], false, false, true, true);
  205. }
  206.  
  207. void stopChase(){
  208. Anim.SetBool("isChasing", false);
  209.  
  210. if(canRun)
  211. Anim.SetBool("isRunning", false);
  212.  
  213. Anim.SetBool("isIdle", true);
  214. playerChase = false;
  215. agent.Stop();
  216. wandering = false;
  217. eatingBodie = false;
  218. }
  219.  
  220. void resetZombie(){
  221. Anim.SetBool("isIdle", true);
  222. Anim.SetBool("isChasing", false);
  223. Anim.SetBool("isEating", false);
  224.  
  225. if(canRun)
  226. Anim.SetBool("isRunning", false);
  227.  
  228. playerChase = false;
  229. agent.Stop();
  230.  
  231. wandering = true;
  232. eatingBodie = false;
  233. playSound(audioClips[0], false, false, true, true);
  234. }
  235.  
  236. void startEating(){
  237. Anim.SetBool("isChasing", false);;
  238.  
  239. if(canRun)
  240. Anim.SetBool("isRunning", false);
  241.  
  242. Anim.SetBool("isIdle", false);
  243. Anim.SetBool("isEating", true);
  244.  
  245. playerChase = false;
  246. agent.SetDestination(player.position);//Just to keep track of it, ignore this.
  247. agent.Stop();//Won't actually follow the bodie, let's store that for later.
  248. wandering = false;
  249. eatingBodie = true;
  250. playSound(audioClips[3], true, true, false, true);
  251. }
  252.  
  253. void followBodie(){
  254. Anim.SetBool("isChasing", true);
  255.  
  256. if(canRun)
  257. Anim.SetBool("isRunning", true);
  258.  
  259. Anim.SetBool("isIdle", false);
  260. Anim.SetBool("isEating", false);
  261. playerChase = false;
  262. agent.SetDestination(player.position);//In this case "player" will be a dead bodie.
  263. agent.Resume();//Lets follow it, to prevent mistakes.
  264. wandering = false;
  265. eatingBodie = true;
  266. SNDSource.Stop();
  267. }
  268.  
  269. void setNewWanderPos(Vector3 targetPos){
  270. Anim.SetBool("isIdle", false);
  271. Anim.SetBool("isChasing", true);
  272.  
  273. if(canRun)
  274. Anim.SetBool("isRunning", true);
  275.  
  276. playerChase = false;
  277. agent.SetDestination(targetPos);
  278. agent.Resume();
  279. lastWander = Time.time + Random.Range(minWander, maxWander);
  280. playSound(audioClips[2], false, false, true, true);
  281. }
  282.  
  283. /* PARAMS:
  284. * Sound: Sound clip AudioClip
  285. * loop: boolean, to make the audio loop
  286. * randomStart: boolean, Start the clip at a random time
  287. * checkSameClip: boolean, prevent the replay of the audio if it is the same clip
  288. * isPlayingCheck: boolean, when preventing replay, should check if it's still playing while the same clip?
  289. */
  290. void playSound(AudioClip sound, bool loop, bool randomStart = false, bool checkSameClip = false, bool isPlayingCheck = false){
  291. if(checkSameClip && SNDSource.clip == sound && !SNDSource.isPlaying)
  292. return;
  293.  
  294. if(isPlayingCheck && SNDSource.clip == sound && SNDSource.isPlaying)
  295. return;
  296.  
  297. SNDSource.clip = sound;
  298. SNDSource.loop = loop;
  299.  
  300. if(randomStart)
  301. SNDSource.time = Random.Range(0.0f, sound.length);
  302.  
  303. SNDSource.Play();
  304. }
  305.  
  306. //ONLY WHEN THE PLAYER AND DEAD BODY VARIABLE ARE NULL
  307. void doWanderFunctions(){
  308. //MAKE THE ZOMBIE WANDER AROUND THE MAP EXACTLY LIKE THE UPDATE SYSTEM, JUST TO MAKE EVERYTHING EASIER
  309. if(wandering){
  310. if(reachedPathEnd()){
  311. resetZombie();
  312. }
  313. if(Time.time > lastWander){//IF WE ARE READY TO CHOOSE A NEW POSITION
  314. wanderManager.SendMessage("getNewPos", this.gameObject, SendMessageOptions.RequireReceiver);
  315. }
  316. }
  317. }
  318.  
  319. void Attack(){
  320. if(!meleeDistance())//DON'T DO ANYTHING IF WE ARE NOT AT A MELEE DISTANCE TO THE PLAYER
  321. return;
  322.  
  323. /*
  324. * HERE YOU SET DAMAGE TO PLAYER YOU MUST DO THE CODE BY YOURSELF
  325. * REMEMBER THE PLAYER VARIABLE IS ALREADY SET
  326. */
  327. agent.updateRotation = false;
  328. transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(agent.destination - transform.position, transform.up), 7.0f *Time.deltaTime);
  329. agent.updateRotation = true;
  330. player.SendMessage("Damage", damage, SendMessageOptions.RequireReceiver);
  331. }
  332.  
  333. void Damage(float dmg){
  334. /*HERE YOU CALL DAMAGE FOR ZOMBIE EXAMPLE:
  335. *zombieObject.SendMessage("ZombieDamage", float value, SendMessageOptions.RequireReceiver);
  336. */
  337. hp -= dmg;
  338.  
  339. if(player != null)
  340. chasePlayer();
  341.  
  342. if(hp < 0.0f || hp == 0.0f){//This zombie is freakin' dead!
  343. this.tag = "Untagged";
  344. BroadcastMessage("ActivateR", SendMessageOptions.RequireReceiver);//Activate ragdoll or spawn the dead bodie.
  345. Anim.enabled = false;//Deactivate things that might screw the ragdoll up.
  346. agent.enabled = false;
  347. GetComponent<Collider>().enabled = false;
  348. Destroy(gameObject, bodieRemovalTime);
  349. enabled = false;
  350. }
  351. }
  352.  
  353. //Check if agent reached the player
  354. bool reachedPathEnd (){
  355. if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance){
  356. if (!agent.hasPath || agent.velocity.sqrMagnitude == 0.0f){
  357. return true;
  358. }
  359. return true;
  360. }
  361. return false;
  362. }
  363.  
  364. bool meleeDistance(){
  365. if(Vector3.Distance(transform.position, player.position) < 2.0f){
  366. return true;
  367. }
  368.  
  369. return false;
  370. }
  371. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement