Search Unity

[UNITY 5 FPS Tutorials] GTGD S3 - Advanced First Person Shooter

Discussion in 'Community Learning & Teaching' started by GTGD, Oct 9, 2015.

  1. PiterQ70

    PiterQ70

    Joined:
    Mar 3, 2015
    Posts:
    59
    Hello I added to the script sneaking. Maybe for someone be useful :] It works so that if enemy detect player is executed animation sneaking to given radius and then enemy walk.

    You need add new animation sneak and make transition bool "isSneaking" to Idle like Walk transiton.



    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. namespace AvA
    5. {
    6.     public class Enemy_Animation : MonoBehaviour
    7.     {
    8.  
    9.         private Enemy_Master enemyMaster;
    10.         private Animator myAnimator;  
    11.  
    12.         void OnEnable()
    13.         {
    14.             SetInitialReferences();
    15.             enemyMaster.EventEnemyDie += SetAnimationToDie;
    16.             enemyMaster.EventEnemyWalking += SetAnimationToWalk;
    17.             enemyMaster.EventEnemySneak += SetAnimationToSneak;
    18.             //enemyMaster.EventEnemyRuning += SetAnimationToRuning; //running animation
    19.             enemyMaster.EventEnemyReachedNavTarget += SetAnimationToIdle;
    20.             enemyMaster.EventEnemyAttack += SetAnimationToAttack;
    21.             enemyMaster.EventEnemyDeductHealth += SetAnimationToGetHit;
    22.  
    23.         }
    24.  
    25.         void OnDisable()
    26.         {
    27.             enemyMaster.EventEnemyDie -= SetAnimationToDie;
    28.             enemyMaster.EventEnemyWalking -= SetAnimationToWalk;
    29.             enemyMaster.EventEnemySneak -= SetAnimationToSneak;
    30.             //enemyMaster.EventEnemyRuning -= SetAnimationToRuning; //running animation
    31.             enemyMaster.EventEnemyReachedNavTarget -= SetAnimationToIdle;
    32.             enemyMaster.EventEnemyAttack -= SetAnimationToAttack;
    33.             enemyMaster.EventEnemyDeductHealth -= SetAnimationToGetHit;
    34.         }
    35.  
    36.         void SetInitialReferences()
    37.         {
    38.             enemyMaster = GetComponent<Enemy_Master>();
    39.  
    40.             if (GetComponent<Animator>() != null)
    41.             {
    42.                 myAnimator = GetComponent<Animator>();
    43.             }
    44.                
    45.         }
    46.  
    47.         void SetAnimationToWalk()
    48.         {
    49.             if (myAnimator != null)
    50.             {
    51.                 if(myAnimator.enabled)
    52.                 {
    53.                     myAnimator.SetBool("isSneaking", false); //stop sneaking when walking
    54.                     myAnimator.SetBool("isPursuing", true);
    55.                 }
    56.             }
    57.         }
    58.  
    59.         void SetAnimationToSneak()
    60.         {
    61.             if (myAnimator != null)
    62.             {
    63.                 if(myAnimator.enabled)
    64.                 {
    65.                     myAnimator.SetBool ("isPursuing", false); //stop walking when sneaking
    66.                     myAnimator.SetBool("isSneaking", true);
    67.                 }
    68.             }
    69.         }
    70.  
    71.         //void SetAnimationToRuning()
    72.         //{
    73.         //    if (myAnimator != null)
    74.         //    {
    75.         //        if(myAnimator.enabled)
    76.         //        {
    77.         //            myAnimator.SetBool ("isRuning", true);
    78.         //        }
    79.         //    }
    80.         //}
    81.  
    82.         void SetAnimationToIdle()
    83.         {
    84.             if(myAnimator != null)
    85.             {
    86.                 if(myAnimator.enabled)
    87.                 {
    88.                     myAnimator.SetBool ("isPursuing", false);
    89.                     myAnimator.SetBool ("isSneaking", false); //stop sneaking when idle
    90.                     //myAnimator.SetBool ("isRuning", false); // stop running when idle
    91.                 }
    92.             }
    93.         }
    94.  
    95.         void SetAnimationToAttack()
    96.         {
    97.             if(myAnimator != null)
    98.             {
    99.                 if(myAnimator.enabled)
    100.                 {
    101.                     myAnimator.SetTrigger("isAttack");
    102.                 }
    103.             }
    104.         }
    105.  
    106.         void SetAnimationToGetHit(int dummy)
    107.         {
    108.             if(myAnimator != null)
    109.             {
    110.                 if(myAnimator.enabled)
    111.                 {
    112.                     myAnimator.SetTrigger("getHit");
    113.                 }
    114.             }
    115.         }
    116.  
    117.         void SetAnimationToDie()
    118.         {
    119.             if(myAnimator != null)
    120.             {
    121.                 if(myAnimator.enabled)
    122.                 {
    123.                     //myAnimator.SetTrigger("isDead");
    124.                     myAnimator.enabled = false;
    125.                 }
    126.                 //myAnimator.enabled = false;
    127.             }
    128.         }
    129.     }
    130. }
    131.  
    132.  
    133.  

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. namespace AvA
    5. {
    6.     public class Enemy_NavPursue : MonoBehaviour
    7.     {
    8.  
    9.         private Enemy_Master enemyMaster;
    10.         private NavMeshAgent myNavMeshAgent;
    11.         private float checkRate;
    12.         private float nextCheck;
    13.         public float sneakDistance = 50; //distance to stop sneak
    14.  
    15.         void OnEnable()
    16.         {
    17.             SetInitialReferences();
    18.             enemyMaster.EventEnemyDie += DisableThis;
    19.         }
    20.  
    21.         void OnDisable()
    22.         {
    23.             enemyMaster.EventEnemyDie -= DisableThis;
    24.         }
    25.  
    26.         void Update()
    27.         {
    28.             if (Time.time > nextCheck)
    29.             {
    30.                 nextCheck = Time.time + checkRate;
    31.                 TryToChaseTarget();
    32.             }
    33.         }
    34.  
    35.         void SetInitialReferences()
    36.         {
    37.             enemyMaster = GetComponent<Enemy_Master>();
    38.             if(GetComponent<NavMeshAgent>() != null)
    39.             {
    40.                 myNavMeshAgent = GetComponent<NavMeshAgent>();
    41.             }
    42.  
    43.             checkRate = Random.Range(0.1f, 0.2f);
    44.             Debug.Log(checkRate);
    45.         }
    46.  
    47.         void TryToChaseTarget()
    48.         {
    49.             if (enemyMaster.myTarget != null && myNavMeshAgent != null && !enemyMaster.isNavPaused)
    50.             {
    51.                
    52.                 myNavMeshAgent.SetDestination (enemyMaster.myTarget.position);
    53.  
    54.                 if (myNavMeshAgent.remainingDistance > myNavMeshAgent.stoppingDistance)
    55.                     {
    56.                     if (myNavMeshAgent.remainingDistance >= sneakDistance) {
    57.                         enemyMaster.CallEventEnemySneak ();
    58.                         enemyMaster.isOnRoute = true;
    59.                     } else if (myNavMeshAgent.remainingDistance <= sneakDistance) {
    60.                         enemyMaster.CallEventEnemyWalking ();
    61.                         enemyMaster.isOnRoute = true;
    62.                     }
    63.                     }
    64.             }
    65.         }
    66.  
    67.         void DisableThis()
    68.         {
    69.             if (myNavMeshAgent != null)
    70.             {
    71.                 myNavMeshAgent.enabled = false;
    72.             }
    73.  
    74.             this.enabled = false;
    75.         }
    76.     }
    77. }
     
  2. Demondarem

    Demondarem

    Joined:
    Aug 31, 2016
    Posts:
    2
    Thank you for making those videos
    this is my game Abandoned Hunter

    Download link is in the description
     
    Raf2756 likes this.
  3. GTGD

    GTGD

    Joined:
    Feb 7, 2012
    Posts:
    431
    Your solution looks fine. Once you get to chapter 9 you will implement a better AI system and hopefully you won't have the same inconvenience :)
     
  4. GTGD

    GTGD

    Joined:
    Feb 7, 2012
    Posts:
    431
    Definite A!
    Very good work for a first game project!
     
  5. GTGD

    GTGD

    Joined:
    Feb 7, 2012
    Posts:
    431
    After you complete chapter 9 you'll find that you are capturing the attacker in a variable called myAttacker. I'm going to extend that for another purpose in some upcoming videos. You'll be able to use the contents of that variable and I'm sure you'll be able to develop your own system for writing to a UI.
     
  6. Wambhse

    Wambhse

    Joined:
    Aug 11, 2015
    Posts:
    13
    When doing [176] Setup Ranged Ally 2 - How To Make A Game I ran into a problem. When adjusting the gun's position and the left and right hand targets like you did in your video. I noticed that when you "Played" the scene the gun (on Max Ranged Ally) stayed in the location you adjusted it to when the scene wasn't playing. However for me, after adjusting the position of the gun on Max and when I played the scene, the gun snapped into the floor. The Gun still moved and animated properly, it just moved along the floor of the scene instead of his hands like I placed it. After tracking down the problem I found that it was the animator that was causing it. The animator for the gun was originally created for the player, and the position of the gun was key framed for the player not Max. In order to get around this I created an empty game object and put it above the Assault Rifle of Max. I called the Empty Game object Weapon Offset. Then I adjusted the position of Weapon Offset and placed the Gun back into his hands after the idle animation moved the gun in the floor. My question was, what did I do wrong? You didn't seem to have this problem with your Max ally or the gun animator. Why did I? does this mean if people decided to change the idle animation then it wouldn't for other allies / enemies, or if different size allies / enemies were used then it wouldn't work either? I'm just trying to figure out what I might have done wrong, and fix it.

    Also one other thing I noticed just now is when My Max Ranged Ally dies, the item he drops does not drop where he dies but drops at the same location every time. No matter how far we travel. Or where he dies. The Gun drops in the same location every time. It only does that on the Ally, not the Golems. I have combed through all the scripts, I can't figure out why it's doing that.

    update 1: I did find out that when I put another item on max ally and he dies then the item drops where it is suppose to be.

    update 2: looks like it's because the animator is on when the item drops. I need to update the scripts so that the animator is turned off before the item is thrown. One problem down!.
     
    Last edited: Oct 17, 2016
  7. Saurabh-Saralaya

    Saurabh-Saralaya

    Joined:
    Apr 28, 2016
    Posts:
    23

    I had the same problem, along with the Max 's Ragdoll rotating violently once he died. I had to redo whole of the Max Ragdoll to get it working. Well I'll be doing the Ranged weapon again, l'll tell you about my progress soon.

    Edit: Well I have a new problem, The pivot point of Assault rifle is misplaced and it doesn't reset back to the geometry.

    Edit 2:I got mine working somehow.
     
    Last edited: Oct 16, 2016
  8. Saurabh-Saralaya

    Saurabh-Saralaya

    Joined:
    Apr 28, 2016
    Posts:
    23
    How do I turn Animations from Read-only state?

    I tried adding the other attack animation from the Golem to another model I created from it, and I couldn't add the Event for Attack in the Animation because it said 'read-only'.

    Edit: I added a Event from the model/Rig/Events/Event in the Inspector. Now it looks like I have Hard-coded the Event
     

    Attached Files:

    Last edited: Oct 19, 2016
  9. johnCordeiro

    johnCordeiro

    Joined:
    Mar 15, 2016
    Posts:
    6
    I have finished the 2 parts of the ammo and reloading videos, the gun fires fine and reloads correctly, the problem I am having is the gun fires when I press R and it will even go past 0 to -1 when I press R if the gun is not loaded. I checked all the references to EventPlayerInput and nothing is subscribed to it from any of the EventReloadRequest. Any ideas where to look for the problem?

    Doing some investigating and after disabling the Ammo and reset scripts my gun fires using the R key along with the fire button.

    UpDate: Solved it was the Input Manager.

    Thanks for the great tutorials.
     
    Last edited: Oct 21, 2016
  10. johnCordeiro

    johnCordeiro

    Joined:
    Mar 15, 2016
    Posts:
    6
    How would I make the crosshairs float a little either procedurally or using animations?
    Also how do I make the gun not so accurate?

    I also noticed that when the golem squats after getting hit the hitbox is still well over his head and shootable. Seems like it would be a simple fix, either disable the hitbox for the length of the hit animation or reduce its size during the animation.

    Thank you,
     
    Raf2756 likes this.
  11. Saurabh-Saralaya

    Saurabh-Saralaya

    Joined:
    Apr 28, 2016
    Posts:
    23
  12. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    13
    Hey guys, I bought this but unfortunately it's really laggy on my computer, so I had to return it :c
    It sucks because I was really hyped to learn

    But I'm still curious what are the stats for your PCs? Does the demo game that comes with this lag for you to?
     
  13. Raf2756

    Raf2756

    Joined:
    Jun 1, 2016
    Posts:
    13
    Hello,

    I want to ask how I would implement a directional damage indicator mechanic in the game, how would I use the vectors from the gun system to rotate a hitmarker UI on the players screen. This is a essential component in a FPS as the player is required to quickly turn to see where they are being shot from, or is it much too easy for an attacker to gun down the player as they cannot be seen.

    Example: https://encrypted-tbn3.gstatic.com/...DbgTzmmINMuDTQ7OGKW43Nb6RkuElVXJw47Zhx-oEzF7D

    Thank You.
     
  14. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    13
    I have hardly have enough experience in Unity to make a cube move, but I would think you could get the angle on the y axis between the player and the target, then use that angle difference and apply it to a red circle on the user's screen
     
  15. Raf2756

    Raf2756

    Joined:
    Jun 1, 2016
    Posts:
    13
    Thanks for the reply, I will see what I can do though I may have trouble capturing the angle using Vectors. As for your question, I don't have the demo, but it was most likely because of the 3d grass used in the scene and the mass amount of NPC's. I have a very old laptop and the game runs smoothly with about 20 NPC's. No lag is to be expected for the first 10 chapters, I guess its when you start making the map your using more resources, as long as your using efficient code you should be fine.
     
  16. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    13
    I'm glad I could help. Maybe you could get the dot product of both 3d vectors and use that to fill in this formula https://www.mathsisfun.com/algebra/trig-solving-sss-triangles.html, but even that confuses me so I'm sure Unity has something built in!

    Anyway, FRAPS says I get about 30 fps on the main demo game with the grass on lowest settings, but it feels like a lot less! What settings do you have it on and what is your fps?

    Thanks!
     
  17. Raf2756

    Raf2756

    Joined:
    Jun 1, 2016
    Posts:
    13
    Sorry but I don't have the game demo, I have a lot of other processes, systems and animations running in the background (which is not in the demo) but my game runs around 60fps, but the map is a flat plane, because im testing only the gameplay mechanics for now and will work on graphics later.
     
  18. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    13
    Oh, my bad! I thought you said the demo ran smoothly for you.

    With just a flat plane from the first 4 videos I get 60 fps. I'm sure it is the 3d grass and the large landscape in the demo that causes the lag.
     
  19. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    You got a refund on the tut and you're still using it and asking for support?
    You sound like a really honest guy :p

    GTGD, thank you for these tutorials, they have helped me a lot.
     
    Last edited: Nov 27, 2016
  20. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    13
    I bought it again because figured it's only $7 and if it doesn't work out, at least I tried.
     
  21. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    The lag you are seeing is due to the large terrain and SpeedTree combined with an abundance of grass. The grass alone on high quality with shadows will add an extra 600,000 tris and approximately 900 drawcalls.
    A Unity terrain can add a million tris and 1200 drawcalls, so what most of us do is create the terrain and export it as an obj, then import it into our modeling software and export it as an fbx, then that same terrain will only eat 17,000 tris and as little as 4 drawcalls, dependent on your textures. SpeedTree has always been buggy, so if you must, disable soft lod, and for the grass, windzones ignore static batching, so use a third party vegetation or mobile equivalent. Also check static batching and dynamic batching in build settings, add all your instantiated prefabs in the preloaded assets field. Oh yeah, and don't forget to build your ambient occlusion.
    I currently have 35 million tris and 7500 drawcalls in my test scene, with most of it going to one special building that falls down when a nuke hits it, but using ao I can run it on an old laptop without any lag.

     
    Last edited: Dec 10, 2016
    DRAmos97, GTGD, Raf2756 and 1 other person like this.
  22. Mad_Mark

    Mad_Mark

    Joined:
    Oct 30, 2014
    Posts:
    367
    Nice! I like that FallOut menu system. Good work.
     
    Goofy420 likes this.
  23. Raf2756

    Raf2756

    Joined:
    Jun 1, 2016
    Posts:
    13
    Are the save and load features functioning?, and maybe try animating your menu for a future update.
     
    Goofy420 likes this.
  24. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    Thank you for your interest.
    The save/load function saves transforms, last position, health, and mission data to a .dat file on the users documents/m-co folder, but nothing else atm.
    I think I need to play Fallout 4 to remember how the PDA was animated, but it's a good suggestion, thanks.
     
  25. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    Using code instead of animation for the crosshair. Here's the snippet since others have asked.

    Code (CSharp):
    1.    
    2. public bool dynamicCrosshair = true;
    3.     public float crosshairSpread = 0.2f;
    4.     public RectTransform m_Top;
    5.     public RectTransform m_Bottom;
    6.     public RectTransform m_Left;
    7.     public RectTransform m_Right;
    8.     public GameObject AmmoUI;
    9.     public GameObject CrosshairUI;
    10.  [Range(0, 1)]
    11.   public float m_Spread = 0;
    12.  
    13. void Update()
    14. {
    15. Crosshair();
    16. }
    17.  
    18. void Crosshair()
    19.     {
    20.         if (currentItem == null || GetComponentInChildren<mt_Shooter>() == null)
    21.         {
    22.             ToggleCrosshair(false);
    23.             ToggleAmmo(false);
    24.         }
    25.         else if (currentItem != null && !GetComponentInChildren<mt_Shooter>().isZooming)
    26.         {
    27.             ToggleCrosshair(true);
    28.             ToggleAmmo(true);
    29.         }
    30.  
    31.         if (dynamicCrosshair == false) return;
    32.  
    33.         float speed = GetComponent<CharacterController>().velocity.sqrMagnitude * crosshairSpread;
    34.         CrosshairSpread = speed;
    35.     }
    36.  
    37.     protected float m_Spread;
    38.     public float CrosshairSpread
    39.     {
    40.         get
    41.         {
    42.             return m_Spread;
    43.         }
    44.         set
    45.         {
    46.             m_Top.anchoredPosition = new Vector2(0, 15 + CrosshairSpread);
    47.             m_Bottom.anchoredPosition = new Vector2(0, -15 - CrosshairSpread);
    48.             m_Left.anchoredPosition = new Vector2(-15 - CrosshairSpread, 0);
    49.             m_Right.anchoredPosition = new Vector2(15 + CrosshairSpread, 0);
    50.             m_Spread = value;
    51.         }
    52.     }
    53.  
    54.     public void ToggleAmmo(bool enabled)
    55.     {
    56.         if (AmmoUI == null) return;
    57.         AmmoUI.SetActive(enabled);
    58.     }
    59.  
    60.     public void ToggleCrosshair(bool enabled)
    61.     {
    62.         if (CrosshairUI == null) return;
    63.         CrosshairUI.SetActive(enabled);
    64.     }
     
    Last edited: Nov 27, 2016
  26. Raf2756

    Raf2756

    Joined:
    Jun 1, 2016
    Posts:
    13
    Im considering making a new crosshair script as well, except there will be one crosshair for all weapons, so it will be much easier to control, might post the code when I've finished that.
     
  27. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    It's not close to being finished, but this is the gist of how the save/load function works.

    Edit: Updated version. Used uGUI and allows choosing which save to load, naming your save, and auto save
    Code (CSharp):
    1.  
    2. public class mt_SaveLoad : MonoBehaviour
    3. {
    4.   [Header("Apply All Weapons/Items Prefabs")]
    5.   public List<Transform> itemList;
    6.  
    7.   [Header("UI Elements")]
    8.   public Canvas saveUI;
    9.   public RectTransform saveContent;
    10.   public Button accept, delete, cancel;
    11.   public InputField nameInput;
    12.  
    13.   public enum DIRECTORY { PERSISTENTDATAPATH, DOCUMENTS, MYGAMES }
    14.   [Header("Save Path, DOCUMENTS and MYGAMES for Windows Only")]
    15.   public DIRECTORY directoryPath = DIRECTORY.PERSISTENTDATAPATH;
    16.  
    17.   [Header("Auto Save")]
    18.   public bool autoSave;
    19.   [Range(1, 1200)]
    20.   public float saveTime;
    21.   public int maxSaves = 3;
    22.  
    23.   float currentPositionX, currentPositionY, currentPositionZ, currentRotationX, currentRotationY, currentRotationZ;
    24.   float currentHealth;
    25.   int currentAmmo, currentItem;
    26.   [HideInInspector]
    27.   public List<string> ownedItems;
    28.   [HideInInspector]
    29.   public List<FileInfo> datList = new List<FileInfo>();
    30.   [HideInInspector]
    31.   public FileInfo selectedFile;
    32.   string fileName = "saveGame";
    33.   bool isSave = false;
    34.  
    35.   string directory;
    36.  
    37.   mt_Director m_Manager = null;
    38.   mt_Director gm
    39.   {
    40.   get
    41.   {
    42.   if (m_Manager == null) m_Manager = FindObjectOfType<mt_Director>();
    43.   return m_Manager;
    44.   }
    45.   }
    46.  
    47.   void Awake()
    48.   {
    49.   accept.onClick.AddListener(() =>
    50.   {
    51.   if (isSave)
    52.   {
    53.   Save(fileName + ".dat");
    54.   }
    55.  
    56.   else
    57.   {
    58.   Load(selectedFile.Name);
    59.   }
    60.   });
    61.  
    62.   delete.onClick.AddListener(() =>
    63.   {
    64.   File.Delete(selectedFile.FullName);
    65.   PopulateList();
    66.   });
    67.  
    68.   cancel.onClick.AddListener(() =>
    69.   {
    70.   saveUI.enabled = false;
    71.  
    72.   datList.Clear();
    73.   datList.TrimExcess();
    74.  
    75.   foreach (Transform child in saveContent)
    76.   {
    77.   Destroy(child.gameObject);
    78.   }
    79.   });
    80.  
    81.   nameInput.onValueChanged.AddListener(delegate { fileName = nameInput.text; });
    82.   }
    83.  
    84.   void Start()
    85.   {
    86.   if (directoryPath == DIRECTORY.PERSISTENTDATAPATH) directory = Application.persistentDataPath;
    87.   else if (directoryPath == DIRECTORY.DOCUMENTS) directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments).Replace("\\", "/") + Path.DirectorySeparatorChar + Application.companyName + Path.DirectorySeparatorChar + Application.productName;
    88.   else if (directoryPath == DIRECTORY.MYGAMES) directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments).Replace("\\", "/") + Path.DirectorySeparatorChar + "My Games" + Path.DirectorySeparatorChar + Application.companyName + Path.DirectorySeparatorChar + Application.productName;
    89.   if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
    90.  
    91.   if (autoSave) InvokeRepeating("AutoSave", saveTime * 60, saveTime * 60);
    92.   PopulateList();
    93.   }
    94.  
    95.   void Update()
    96.   {
    97.   if (isSave)
    98.   {
    99.   nameInput.gameObject.SetActive(true);
    100.   fileName = nameInput.text;
    101.  
    102.   List<string> names = new List<string>();
    103.   foreach (FileInfo f in datList)
    104.   {
    105.   names.Add(f.Name);
    106.   }
    107.   if (names.Contains(nameInput.text + ".dat")) accept.GetComponentInChildren<Text>().text = "OVERWRITE";
    108.   else accept.GetComponentInChildren<Text>().text = "SAVE";
    109.  
    110.   if (fileName == "" && isSave)
    111.   {
    112.   InputField b = nameInput;
    113.   ColorBlock cb = b.colors;
    114.   cb.normalColor = Color.red;
    115.   b.colors = cb;
    116.  
    117.   accept.interactable = false;
    118.   }
    119.   else
    120.   {
    121.   InputField b = nameInput;
    122.   ColorBlock cb = b.colors;
    123.   cb.normalColor = Color.white;
    124.   b.colors = cb;
    125.  
    126.   accept.interactable = true;
    127.   }
    128.   }
    129.   else nameInput.gameObject.SetActive(false);
    130.  
    131.   if (!gm.PauseUI.enabled) saveUI.enabled = false;
    132.   }
    133.  
    134.   int counter = 0;
    135.   void AutoSave()
    136.   {
    137.   Save("autoSave" + counter + ".dat");
    138.   counter++;
    139.   if (counter >= maxSaves) counter = 0;
    140.   }
    141.  
    142.   public void PopulateList()
    143.   {
    144.   datList.Clear();
    145.   datList.TrimExcess();
    146.  
    147.   DirectoryInfo dir = new DirectoryInfo(directory);
    148.   FileInfo[] info = dir.GetFiles("*.dat");
    149.   foreach (FileInfo f in info) datList.Add(f);
    150.   UpdateUI();
    151.   }
    152.  
    153.   void UpdateUI()
    154.   {
    155.   int counter = 0;
    156.   foreach (Transform child in saveContent)
    157.   {
    158.   Destroy(child.gameObject);
    159.   }
    160.  
    161.   foreach (FileInfo f in datList)
    162.   {
    163.   Button go = Instantiate(gm.UIButtonPrefab);
    164.   go.GetComponentInChildren<Text>().text = f.Name;
    165.   int index = counter;
    166.   go.onClick.AddListener(delegate
    167.   {
    168.   selectedFile = datList[index];
    169.   if (isSave)
    170.   {
    171.   nameInput.text = selectedFile.Name;
    172.   nameInput.text = nameInput.text.Replace(".dat", "");
    173.   }
    174.   });
    175.  
    176.   go.transform.SetParent(saveContent, false);
    177.   counter++;
    178.   }
    179.   }
    180.  
    181.   public void TrySave()
    182.   {
    183.   if (File.Exists(directory + Path.DirectorySeparatorChar + "saveGame.dat0"))
    184.   {
    185.   gm.MessageText("File Exists", Color.red);
    186.   ToggleUI(true);
    187.   return;
    188.   }
    189.   Save("saveGame.dat0");
    190.   }
    191.  
    192.   void Save(string fileName)
    193.   {
    194.   try
    195.   {
    196.   BinaryFormatter bf1 = new BinaryFormatter();
    197.   FileStream file1 = File.Open(directory + Path.DirectorySeparatorChar + fileName, FileMode.OpenOrCreate, FileAccess.Write);
    198.   GameData data1 = new GameData();
    199.  
    200.   currentHealth = gm.Player.Health;
    201.   currentItem = gm.Player.InventoryList.IndexOf(gm.Player.currentItem);
    202.   currentAmmo = gm.Player.weaponTypes[currentItem].currentAmmo;
    203.  
    204.   currentPositionX = gm.Player.transform.position.x;
    205.   currentPositionY = gm.Player.transform.position.y;
    206.   currentPositionZ = gm.Player.transform.position.z;
    207.   currentRotationX = gm.Player.transform.rotation.x;
    208.   currentRotationY = gm.Player.transform.rotation.y;
    209.   currentRotationZ = gm.Player.transform.rotation.z;
    210.  
    211.   foreach (Transform t in gm.Player.InventoryList)
    212.   {
    213.   if (!ownedItems.Contains(t.name)) ownedItems.Add(t.name);
    214.   }
    215.  
    216.   data1.currentHealth = currentHealth;
    217.   data1.currentItem = currentItem;
    218.   data1.currentAmmo = currentAmmo;
    219.   data1.ownedItems = ownedItems;
    220.  
    221.   data1.currentPositionX = currentPositionX;
    222.   data1.currentPositionY = currentPositionY;
    223.   data1.currentPositionZ = currentPositionZ;
    224.   data1.currentRotationX = currentRotationX;
    225.   data1.currentRotationY = currentRotationY;
    226.   data1.currentRotationZ = currentRotationZ;
    227.  
    228.   data1.autoSave = autoSave;
    229.   data1.saveTime = saveTime;
    230.  
    231.   bf1.Serialize(file1, data1);
    232.   file1.Close();
    233.   file1.Dispose();
    234.  
    235.   ToggleUI(false);
    236.   gm.ToggleMenu();
    237.   gm.MessageText("Saving " + fileName, Color.green);
    238.   }
    239.   catch (Exception ex)
    240.   {
    241.   Debug.LogError("Save Error: " + ex.Message);
    242.   }
    243.   }
    244.  
    245.   public void TryLoad()
    246.   {
    247.   if (!File.Exists(directory + Path.DirectorySeparatorChar + "saveGame.dat0"))
    248.   {
    249.   gm.MessageText("No Save Games...", Color.red);
    250.   return;
    251.   }
    252.   PopulateList();
    253.   ToggleUI(false);
    254.   }
    255.  
    256.   void Load(string fileName)
    257.   {
    258.   try
    259.   {
    260.   BinaryFormatter bf2 = new BinaryFormatter();
    261.   FileStream file2 = File.Open(directory + Path.DirectorySeparatorChar + fileName, FileMode.Open, FileAccess.Read);
    262.   GameData data2 = (GameData)bf2.Deserialize(file2);
    263.   file2.Close();
    264.   file2.Dispose();
    265.  
    266.   currentHealth = data2.currentHealth;
    267.   currentItem = data2.currentItem;
    268.   currentAmmo = data2.currentAmmo;
    269.   ownedItems = data2.ownedItems;
    270.  
    271.   currentPositionX = data2.currentPositionX;
    272.   currentPositionY = data2.currentPositionY;
    273.   currentPositionZ = data2.currentPositionZ;
    274.  
    275.   foreach (string s in ownedItems)
    276.   {
    277.   foreach (Transform t in itemList)
    278.   {
    279.   if (t.name == s)
    280.   {
    281.   Transform go = Instantiate(t);
    282.   go.name = go.name.Replace("(Clone)", "");
    283.   go.SetParent(gm.FPCam.transform);
    284.   go.transform.localPosition = Vector3.zero;
    285.   go.transform.localRotation = Quaternion.Euler(Vector3.zero);
    286.   go.transform.localScale = Vector3.one;
    287.  
    288.   go.GetComponent<mt_Item>().Initialize();
    289.   go.GetComponent<mt_Item>().SetLocal();
    290.  
    291.   }
    292.   }
    293.   }
    294.  
    295.   gm.Player.Health = currentHealth;
    296.   gm.Player.currentItem = itemList[currentItem];
    297.   gm.Player.weaponTypes[currentItem].currentAmmo = currentAmmo;
    298.  
    299.   gm.Player.transform.position = new Vector3(currentPositionX, currentPositionY, currentPositionZ);
    300.   gm.Player.transform.rotation = Quaternion.Euler(currentRotationX, currentRotationY, currentRotationZ);
    301.  
    302.   gm.Player.UpdateInventory();
    303.   gm.Player.ActivateItem(currentItem);
    304.  
    305.   autoSave = data2.autoSave;
    306.   saveTime = data2.saveTime;
    307.  
    308.   ToggleUI(false);
    309.   gm.ToggleMenu();
    310.   gm.MessageText("Loaded " + fileName, Color.green);
    311.   }
    312.   catch (Exception ex)
    313.   {
    314.   Debug.LogError("Load Error: " + ex.Message);
    315.   }
    316.   }
    317.  
    318.   void ToggleUI(bool save)
    319.   {
    320.   isSave = save;
    321.   if (save)
    322.   {
    323.   saveUI.enabled = !saveUI.enabled;
    324.   accept.GetComponentInChildren<Text>().text = "SAVE";
    325.   }
    326.   else
    327.   {
    328.   saveUI.enabled = !saveUI.enabled;
    329.   accept.GetComponentInChildren<Text>().text = "LOAD";
    330.   }
    331.   }
    332.  
    333.   [Serializable]
    334.   public class GameData
    335.   {
    336.   public float currentHealth;
    337.   public int currentAmmo;
    338.  
    339.   public int currentItem;
    340.   public List<string> ownedItems;
    341.  
    342.   public float currentPositionX;
    343.   public float currentPositionY;
    344.   public float currentPositionZ;
    345.  
    346.   public float currentRotationX;
    347.   public float currentRotationY;
    348.   public float currentRotationZ;
    349.  
    350.   public bool autoSave;
    351.   public float saveTime;
    352.   }
    353.  
    354. }
    355.  
    356. }
     
    Last edited: Nov 29, 2016
    Saurabh-Saralaya likes this.
  28. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    Weapon Bob/ Weapon Sway, just add this to your weapon script
    Code (CSharp):
    1. public bool weaponBob = true;
    2.     [SerializeField]
    3.     WeaponBob m_WeaponBob;
    4.     public bool weaponSway = true;
    5.     [SerializeField]
    6.     WeaponSway m_WeaponSway;
    7.  
    8. Vector3 originalWeaponPosition;
    9.     Quaternion originalWeaponRotation;
    10.     bool grounded;
    11.  
    12. void OnEnable()
    13. {
    14. originalWeaponPosition = transform.localPosition;
    15.         originalWeaponRotation = transform.localRotation;
    16.         m_WeaponBob.Setup(this, Manager.FPController.m_StepInterval);
    17.         m_WeaponSway.Setup(this, Manager.FPController.m_StepInterval);
    18. }
    19.  
    20. void Update()
    21. {
    22. if (!Controller.isGrounded && grounded) StartCoroutine(m_WeaponBob.JumpBob());
    23.         grounded = Controller.isGrounded;
    24. }
    25.  
    26. void FixedUpdate()
    27.     {
    28.         if (!transform.root.CompareTag("Player")) return;
    29.         UpdateBob(Manager.FPController.speed);
    30.         UpdateSway(Manager.FPController.speed);
    31.     }
    32.  
    33. protected void UpdateBob(float speed)
    34.     {
    35.         Vector3 newWeaponPosition;
    36.         if (!weaponBob)
    37.         {
    38.             return;
    39.         }
    40.  
    41.         newWeaponPosition = transform.localPosition;
    42.         if (Controller.velocity.magnitude > 0 && Controller.isGrounded)
    43.         {
    44.             transform.localPosition = m_WeaponBob.DoWeaponBob(this, Controller.velocity.magnitude + (speed * (Manager.FPController.m_IsWalking ? 1f : Manager.FPController.m_RunstepLenghten)));
    45.            
    46.             newWeaponPosition.y = transform.localPosition.y - Manager.FPController.m_JumpBob.Offset();
    47.         }
    48.         else if (!Controller.isGrounded && !grounded)
    49.         {
    50.             newWeaponPosition.y = originalWeaponPosition.y - m_WeaponBob.Offset();
    51.         }
    52.         else
    53.         {
    54.             newWeaponPosition.y = originalWeaponPosition.y - Manager.FPController.m_JumpBob.Offset();
    55.         }
    56.         transform.localPosition = newWeaponPosition;
    57.     }
    58.  
    59.     protected void UpdateSway(float speed)
    60.     {
    61.         Quaternion newWeaponRotation;
    62.         if (!weaponSway || m_WeaponBob.Offset() != 0) return;
    63.        
    64.         if (Controller.isGrounded)
    65.         {
    66.             transform.localRotation =
    67.                 m_WeaponSway.DoWeaponSway(this, Controller.velocity.magnitude +
    68.                                   (speed * (Manager.FPController.m_IsWalking ? 1f : Manager.FPController.m_RunstepLenghten)));
    69.             newWeaponRotation = transform.localRotation;
    70.             newWeaponRotation.y = transform.localRotation.y - Manager.FPController.m_JumpBob.Offset();
    71.         }
    72.         else
    73.         {
    74.             newWeaponRotation = transform.localRotation;
    75.             newWeaponRotation.y = originalWeaponRotation.y - Manager.FPController.m_JumpBob.Offset();
    76.         }
    77.         transform.localRotation = newWeaponRotation;
    78.     }
    79.  
    80.     [System.Serializable]
    81.     class WeaponBob
    82.     {
    83.         public float HorizontalBobRange = 0.15f;
    84.         public float VerticalBobRange = 0.15f;
    85.         public AnimationCurve Bobcurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(0.5f, 1f), new Keyframe(1f, 0f), new Keyframe(1.5f, -1f), new Keyframe(2f, 0f));
    86.  
    87.         protected float m_CyclePositionX;
    88.         protected float m_CyclePositionY;
    89.         protected float m_BobBaseInterval;
    90.         protected Vector3 originalWeaponPosition;
    91.         protected float m_Time;
    92.  
    93.         protected float m_Offset = 0f;
    94.         public float Offset()
    95.         {
    96.             return m_Offset;
    97.         }
    98.  
    99.         public IEnumerator JumpBob()
    100.         {
    101.             float t = 0f;
    102.             float duration = 0.7f;
    103.             float length = 0.2f;
    104.             while (t < duration)
    105.             {
    106.                 m_Offset = Mathf.Lerp(0f, length, t / duration);
    107.                 t += Time.deltaTime;
    108.                 yield return new WaitForFixedUpdate();
    109.             }
    110.  
    111.             // make it move back to neutral
    112.             t = 0f;
    113.             while (t < duration)
    114.             {
    115.                 m_Offset = Mathf.Lerp(length, 0f, t / duration);
    116.                 t += Time.deltaTime;
    117.                 yield return new WaitForFixedUpdate();
    118.             }
    119.             m_Offset = 0f;
    120.         }
    121.  
    122.         public void Setup(mt_Shooter weapon, float bobBaseInterval)
    123.         {
    124.             m_BobBaseInterval = bobBaseInterval;
    125.             originalWeaponPosition = weapon.transform.localPosition;
    126.             m_Time = Bobcurve[Bobcurve.length - 1].time;
    127.         }
    128.  
    129.         public Vector3 DoWeaponBob(mt_Shooter weapon, float speed)
    130.         {
    131.             float xPos = originalWeaponPosition.x + (Bobcurve.Evaluate(m_CyclePositionX) * HorizontalBobRange * 0.01f);
    132.             float yPos = originalWeaponPosition.y + (Bobcurve.Evaluate(m_CyclePositionY) * VerticalBobRange * 0.01f);
    133.  
    134.             m_CyclePositionX += (speed * Time.deltaTime) / m_BobBaseInterval;
    135.             m_CyclePositionY += ((speed * Time.deltaTime) / m_BobBaseInterval);
    136.  
    137.             if (m_CyclePositionX > m_Time)
    138.             {
    139.                 m_CyclePositionX = m_CyclePositionX - m_Time;
    140.             }
    141.             if (m_CyclePositionY > m_Time)
    142.             {
    143.                 m_CyclePositionY = m_CyclePositionY - m_Time;
    144.             }
    145.             return new Vector3(xPos, yPos, weapon.transform.localPosition.z);
    146.         }
    147.     }
    148.  
    149.     [System.Serializable]
    150.     class WeaponSway
    151.     {
    152.         public float HorizontalSwayRange = 0.15f;
    153.         public float VerticalSwayRange = 0.15f;
    154.         public AnimationCurve Swaycurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(0.5f, 1f), new Keyframe(1f, 0f), new Keyframe(1.5f, -1f), new Keyframe(2f, 0f));
    155.  
    156.         protected float m_CyclePositionX;
    157.         protected float m_CyclePositionY;
    158.         protected float m_SwayBaseInterval;
    159.         protected Quaternion originalWeaponRotation;
    160.         protected float m_Time;
    161.  
    162.         public void Setup(mt_Shooter weapon, float swayBaseInterval)
    163.         {
    164.             m_SwayBaseInterval = swayBaseInterval;
    165.             originalWeaponRotation = weapon.transform.localRotation;
    166.             m_Time = Swaycurve[Swaycurve.length - 1].time;
    167.         }
    168.  
    169.         public Quaternion DoWeaponSway(mt_Shooter weapon, float speed)
    170.         {
    171.             float xPos = originalWeaponRotation.x + (Swaycurve.Evaluate(m_CyclePositionX) * HorizontalSwayRange * 0.01f);
    172.             float yPos = originalWeaponRotation.y + (Swaycurve.Evaluate(m_CyclePositionY) * VerticalSwayRange * 0.01f);
    173.  
    174.             m_CyclePositionX += (speed * Time.deltaTime) / m_SwayBaseInterval;
    175.             m_CyclePositionY += ((speed * Time.deltaTime) / m_SwayBaseInterval);
    176.  
    177.             if (m_CyclePositionX > m_Time)
    178.             {
    179.                 m_CyclePositionX = m_CyclePositionX - m_Time;
    180.             }
    181.             if (m_CyclePositionY > m_Time)
    182.             {
    183.                 m_CyclePositionY = m_CyclePositionY - m_Time;
    184.             }
    185.             return new Quaternion(xPos, yPos, weapon.transform.localRotation.z, weapon.transform.localRotation.w);
    186.         }
    187.     }
     
  29. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    I use a different crosshair for each weapon. That way the pistol can have old school style and the shotgun can have a big circle, whereas my bazooka just has three horizontal lines similar to a mil dot with each line representing 10 meters of accuracy.
     
  30. Raf2756

    Raf2756

    Joined:
    Jun 1, 2016
    Posts:
    13
    Im hoping to implement a system where the the crosshair design will update when the gun is picked up, so it can vary to a classic crosshair system to a shotgun can have a different one, I'm using OnGui() so I don't have to mess around with canvas's. Just added changing the crosshair colour depending on the NPC the player is looking at, eg Ally -> Green // Enemy -> Red.
     
  31. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    13
    Hey guys, I just completed my first Unity game. I know the video quality isn't great, but the download link is in the description :)

     
    Goofy420 and Raf2756 like this.
  32. Mad_Mark

    Mad_Mark

    Joined:
    Oct 30, 2014
    Posts:
    367
    @GTGD I have posted on the Steam Discussion group, since that is where I bought this asset. To date, the author has not responded to questions.
    1) Is this where I should be posting for support?
    2) Does the author monitor this thread?
    3) Is there a better way to contact the author?
    4) Did I just throw away yet another 10 bucks on an unsupported asset?

    I am trying to use the purchased scripts, and have gone through the many, many videos. It all works very well with the included imported assets. I have tried to replicate the Kyle Robot asset for a melee only Enemy-NPC. I have attached every script found on Kyle to my model, given it the required Ragdoll, adjusted all of the public assignments in the editor, and it fails to operate as expected. No errors appear in the console.

    The model goes through all of the states, wanders about, detects the player, moves to the player, and launches a melee attack animation. It does this once, and only once, then goes into pursue state. No damage is passed to the player. It is right up against the player, so it doesn't actually move forward, just animates its walk animation. If I move the player back a few units, the model moves forward into the player's face, and again, attacks one time with no damage, then launches the pursuit state. If I shoot him, he takes damage, recovers, and attacks once, then back into pursuit.

    What am I missing, or need to modify to get this to work correctly?
    What do I need to do to have this character attack as long as he is within the attack range?
    Why does it not pass damage to the player?
     
  33. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    There's a slight bug in the NPC handler that could be causing that. When an NPC goes into the Alert State, then quickly switched between another state and alertState, the wantedPosition could be set to Vector3.zero before the NPC reaches the wantedState, but you can fix this by adding this to your NPC script.
    Code (csharp):
    1. void LateUpdate()
    2.   {
    3.   if (currentState == alertState && locationOfInterest == Vector3.zero) ActivatePatrolState();
    4.   }
    If the NPC is too far away from the player while attacking, then it can't ProcessDamage, and if that's the case, change the stoppingDistance in NavmeshAgent to a lower number, this will also work on the friendly NPC if he follows the player too closely or too far.
    If you have problems with NPC sliding after Stop() is called, add this in the StopWalking() methods just before myNavmeshagent.Stop()
    npc.myNavMeshAgent.velocity = Vector3.zero;

    If you want to see the state that the NPC is currently in during runtime, add this to your NPC script
    public string currentState;
    and add an identifier to every state method (in the abstract classes)
    npc.activeState = "Follow"; //added to FollowTarget()
    npc.activeState = "Alert " + npc.locationOfInterest; //added to GoToLocationOfInterest()

    Don't add a Debug.Log to these methods, or the garbage collector will eat up all your computers resources trying to display them in the console
     
    Last edited: Dec 4, 2016
  34. Mad_Mark

    Mad_Mark

    Joined:
    Oct 30, 2014
    Posts:
    367
    Thanks for replying, Goofy420. Is that LiveUpdate code snippet added to the NPC_Master script?
    I will add these bits, one at a time. Knowing the active state may be helpful. I'm gauging what he's in at the moment with the animator panel. It's kind of big and clunky to use for anything, really.
     
  35. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    I've manipulated my scripts to be more mobile and cpu friendly and easier to work with so I don't recall what the script was named; I think it was NPCStatePattern.cs
    LateUpdate is similar to Update, but it's called later and less often.
     
  36. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    The completed (mostly) Save/Load function. Now supports Binary, Json, and XML. I noticed that when saving over a million objects using Binary, it took over a minute to load. Although it's quicker to write using Binary, it's much slower to read. JSON only takes 7.3 seconds to load the same file, and XML splits the difference between load and save.
    Code (CSharp):
    1. public class mt_SaveLoad : MonoBehaviour
    2. {
    3.    
    4.  public enum STORAGETYPE { BINARY, JSON, XML }
    5.   [Header("Storage Method")]
    6.   public STORAGETYPE storageType = STORAGETYPE.BINARY;
    7.  
    8.   public enum DIRECTORY { PERSISTENTDATAPATH, DOCUMENTS, MYGAMES }
    9.   [Header("Save Path, DOCUMENTS and MYGAMES for Windows Only")]
    10.   public DIRECTORY directoryPath = DIRECTORY.PERSISTENTDATAPATH;
    11.  
    12.   [Header("Apply All Weapons/Items Prefabs")]
    13.   public List<Transform> itemList;
    14.  
    15.   [Header("UI Elements")]
    16.   public Canvas saveUI;
    17.   public RectTransform saveContent;
    18.   public Button accept, delete, cancel;
    19.   public InputField nameInput;
    20.  
    21.   [Header("Auto Save")]
    22.   public bool autoSave;
    23.   [Range(1, 1200)]
    24.   public float saveTime;
    25.   public int maxSaves = 3;
    26.  
    27.   //hidden
    28.   public float currentPositionX, currentPositionY, currentPositionZ, currentRotationX, currentRotationY, currentRotationZ, currentHealth;
    29.   public string directory, currentScene, fileName;
    30.   public List<int> currentAmmo;
    31.   public List<string> ownedItems;
    32.   public List<FileInfo> datList = new List<FileInfo>();
    33.   public FileInfo selectedFile;
    34.   public int currentItem;
    35.   public bool isSave = false;
    36.  
    37.   mt_Director m_Manager = null;
    38.   mt_Director gm
    39.   {
    40.   get
    41.   {
    42.   if (m_Manager == null) m_Manager = FindObjectOfType<mt_Director>();
    43.   return m_Manager;
    44.   }
    45.   }
    46.  
    47.   void Awake()
    48.   {
    49.   accept.onClick.AddListener(() =>
    50.   {
    51.   if (isSave)
    52.   {
    53.   Save(fileName + ".dat");
    54.   }
    55.  
    56.   else
    57.   {
    58.   Load(selectedFile.Name);
    59.   }
    60.   });
    61.  
    62.   delete.onClick.AddListener(() =>
    63.   {
    64.   File.Delete(selectedFile.FullName);
    65.   PopulateList();
    66.   });
    67.  
    68.   cancel.onClick.AddListener(() =>
    69.   {
    70.   saveUI.enabled = false;
    71.  
    72.   datList.Clear();
    73.   datList.TrimExcess();
    74.  
    75.   foreach (Transform child in saveContent)
    76.   {
    77.   Destroy(child.gameObject);
    78.   }
    79.   });
    80.  
    81.   nameInput.onValueChanged.AddListener(delegate { fileName = nameInput.text; });
    82.   }
    83.  
    84.   void Start()
    85.   {
    86.   if (directoryPath == DIRECTORY.PERSISTENTDATAPATH) directory = Application.persistentDataPath;
    87.   else if (directoryPath == DIRECTORY.DOCUMENTS) directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments).Replace("\\", "/") + Path.DirectorySeparatorChar + Application.companyName + Path.DirectorySeparatorChar + Application.productName;
    88.   else if (directoryPath == DIRECTORY.MYGAMES) directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments).Replace("\\", "/") + Path.DirectorySeparatorChar + "My Games" + Path.DirectorySeparatorChar + Application.companyName + Path.DirectorySeparatorChar + Application.productName;
    89.   if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
    90.  
    91.   if (autoSave) InvokeRepeating("AutoSave", saveTime * 60, saveTime * 60);
    92.   PopulateList();
    93.   }
    94.  
    95.   void Update()
    96.   {
    97.   if (selectedFile == null) accept.interactable = false;
    98.   else accept.interactable = true;
    99.  
    100.   if (isSave)
    101.   {
    102.   nameInput.gameObject.SetActive(true);
    103.   fileName = nameInput.text;
    104.  
    105.   List<string> names = new List<string>();
    106.   foreach (FileInfo f in datList)
    107.   {
    108.   names.Add(f.Name);
    109.   }
    110.   if (names.Contains(nameInput.text + ".dat")) accept.GetComponentInChildren<Text>().text = "OVERWRITE";
    111.   else accept.GetComponentInChildren<Text>().text = "SAVE";
    112.  
    113.   if (fileName == "")
    114.   {
    115.   InputField b = nameInput;
    116.   ColorBlock cb = b.colors;
    117.   cb.normalColor = Color.red;
    118.   b.colors = cb;
    119.  
    120.   accept.interactable = false;
    121.   }
    122.   else
    123.   {
    124.   InputField b = nameInput;
    125.   ColorBlock cb = b.colors;
    126.   cb.normalColor = Color.white;
    127.   b.colors = cb;
    128.  
    129.   accept.interactable = true;
    130.   }
    131.   }
    132.   else nameInput.gameObject.SetActive(false);
    133.  
    134.   if (!gm.PauseUI.enabled) saveUI.enabled = false;
    135.   }
    136.  
    137.   int counter = 0;
    138.   void AutoSave()
    139.   {
    140.   Save("autoSave" + counter + ".dat");
    141.   counter++;
    142.   if (counter >= maxSaves) counter = 0;
    143.   }
    144.  
    145.   public void PopulateList()
    146.   {
    147.   datList.Clear();
    148.   datList.TrimExcess();
    149.  
    150.   DirectoryInfo dir = new DirectoryInfo(directory);
    151.   FileInfo[] info = dir.GetFiles("*.dat");
    152.   foreach (FileInfo f in info) datList.Add(f);
    153.   UpdateUI();
    154.   }
    155.  
    156.   void UpdateUI()
    157.   {
    158.   int counter = 0;
    159.   foreach (Transform child in saveContent)
    160.   {
    161.   Destroy(child.gameObject);
    162.   }
    163.  
    164.   foreach (FileInfo f in datList)
    165.   {
    166.   Button go = Instantiate(gm.UIButtonPrefab);
    167.   go.GetComponentInChildren<Text>().text = f.Name;
    168.   int index = counter;
    169.   go.onClick.AddListener(delegate
    170.   {
    171.   selectedFile = datList[index];
    172.   if (isSave)
    173.   {
    174.   nameInput.text = selectedFile.Name;
    175.   nameInput.text = nameInput.text.Replace(".dat", "");
    176.   }
    177.   });
    178.  
    179.   go.transform.SetParent(saveContent, false);
    180.   counter++;
    181.   }
    182.   }
    183.  
    184.   public void TrySave()
    185.   {
    186.   if (File.Exists(directory + Path.DirectorySeparatorChar + "saveGame.dat0"))
    187.   {
    188.   ToggleUI(true);
    189.   return;
    190.   }
    191.   Save("saveGame.dat0");
    192.   }
    193.  
    194.   void Save(string filename)
    195.   {
    196.   SavePlayerData(filename);
    197.  
    198.   if (saveUI.enabled) ToggleUI(false);
    199.   if (gm.PauseUI.enabled) gm.ToggleMenu();
    200.   StartCoroutine(DisableInteractions(3));
    201.   gm.MessageText("Saving " + filename, Color.green, 3, 30, TextAnchor.UpperLeft);
    202.  
    203.   }
    204.  
    205.   void SavePlayerData(string filename)
    206.   {
    207.   PlayerData playerData = new PlayerData();
    208.  
    209.   currentScene = SceneManager.GetActiveScene().name;
    210.  
    211.   currentHealth = gm.Player.Health;
    212.   currentItem = gm.Player.InventoryList.IndexOf(gm.Player.currentItem);
    213.  
    214.   int index = 0;
    215.   currentAmmo.Clear();
    216.   currentAmmo.TrimExcess();
    217.   foreach (mt_Director.WeaponTypes i in gm.weaponTypes)
    218.   {
    219.   currentAmmo.Insert(index, i.currentAmmo);
    220.   index++;
    221.   }
    222.  
    223.   currentPositionX = gm.Player.transform.position.x;
    224.   currentPositionY = gm.Player.transform.position.y;
    225.   currentPositionZ = gm.Player.transform.position.z;
    226.   currentRotationX = gm.Player.transform.rotation.x;
    227.   currentRotationY = gm.Player.transform.rotation.y;
    228.   currentRotationZ = gm.Player.transform.rotation.z;
    229.  
    230.   ownedItems.Clear();
    231.   ownedItems.TrimExcess();
    232.   foreach (Transform t in gm.Player.InventoryList)
    233.   {
    234.   ownedItems.Add(t.name);
    235.   }
    236.  
    237.   playerData.currentScene = currentScene;
    238.  
    239.   playerData.currentHealth = currentHealth;
    240.   playerData.currentItem = currentItem;
    241.   playerData.currentAmmo = currentAmmo;
    242.   playerData.ownedItems = ownedItems;
    243.  
    244.   playerData.currentPositionX = currentPositionX;
    245.   playerData.currentPositionY = currentPositionY;
    246.   playerData.currentPositionZ = currentPositionZ;
    247.   playerData.currentRotationX = currentRotationX;
    248.   playerData.currentRotationY = currentRotationY;
    249.   playerData.currentRotationZ = currentRotationZ;
    250.  
    251.   playerData.autoSave = autoSave;
    252.   playerData.saveTime = saveTime;
    253.  
    254.   if (storageType == STORAGETYPE.BINARY)
    255.   {
    256.   BinaryFormatter binaryFormatter = new BinaryFormatter();
    257.   FileStream fileStream = File.Open(directory + Path.DirectorySeparatorChar + filename, FileMode.OpenOrCreate, FileAccess.Write);
    258.  
    259.   binaryFormatter.Serialize(fileStream, playerData);
    260.   fileStream.Close();
    261.   fileStream.Dispose();
    262.   }
    263.  
    264.   else if (storageType == STORAGETYPE.JSON)
    265.   {
    266.   string file = directory + Path.DirectorySeparatorChar + filename;
    267.   string data = JsonUtility.ToJson(playerData, true);
    268.   File.WriteAllText(file, data);
    269.   }
    270.  
    271.   else if (storageType == STORAGETYPE.XML)
    272.   {
    273.   string file = directory + Path.DirectorySeparatorChar + filename;
    274.   XmlSerializer data = new XmlSerializer(typeof(PlayerData));
    275.   using (FileStream fileStream = new FileStream(file, FileMode.Create, FileAccess.Write))
    276.   {
    277.   data.Serialize(fileStream, playerData);
    278.  
    279.   fileStream.Close();
    280.   fileStream.Dispose();
    281.   }
    282.   }
    283.   }
    284.  
    285.   /*
    286.   void SaveSceneBinary(string filename)
    287.   {
    288.   filename = filename.Replace(".dat", ".scn");
    289.   SceneData sceneData = new SceneData();
    290.   byte[] bytes = File.ReadAllBytes(SceneManager.GetActiveScene().path);
    291.   sceneData.sceneData = bytes;
    292.  
    293.   if (storageType == STORAGETYPE.BINARY)
    294.   {
    295.   BinaryFormatter binaryFormatter = new BinaryFormatter();
    296.   FileStream fileStream = File.Open(directory + Path.DirectorySeparatorChar + filename, FileMode.OpenOrCreate, FileAccess.Write);
    297.  
    298.   binaryFormatter.Serialize(fileStream, sceneData);
    299.   fileStream.Close();
    300.   fileStream.Dispose();
    301.   }
    302.  
    303.   else if (storageType == STORAGETYPE.JSON)
    304.   {
    305.   string file = directory + Path.DirectorySeparatorChar + filename;
    306.   string data = JsonUtility.ToJson(sceneData, true);
    307.   File.WriteAllText(file, data);
    308.   }
    309.  
    310.   else if (storageType == STORAGETYPE.XML)
    311.   {
    312.   string file = directory + Path.DirectorySeparatorChar + filename;
    313.   XmlSerializer data = new XmlSerializer(typeof(SceneData));
    314.   using (FileStream fileStream = new FileStream(file, FileMode.Create, FileAccess.Write))
    315.   {
    316.   data.Serialize(fileStream, sceneData);
    317.   fileStream.Close();
    318.   fileStream.Dispose();
    319.   }
    320.   }
    321.   }
    322.  
    323.   public List<Transform> sceneObjects;
    324.   void SaveSceneObjects(string filename)
    325.   {
    326.   filename = filename.Replace(".dat", ".obj");
    327.   SceneData sceneData = new SceneData();
    328.  
    329.   Transform[] allItems = FindObjectsOfType<Transform>();
    330.    
    331.   for (int i = 0; i < allItems.Length; i++)
    332.   {
    333.   if (!sceneObjects.Contains(allItems[i].root))
    334.   sceneObjects.Add(allItems[i].root);
    335.   }
    336.   for (int i = 0; i < sceneObjects.Count; i++)
    337.   {
    338.   sceneItems.Add(sceneObjects[i].name);
    339.   }
    340.   sceneData.sceneItems = sceneItems;
    341.  
    342.   if (storageType == STORAGETYPE.BINARY)
    343.   {
    344.   BinaryFormatter binaryFormatter = new BinaryFormatter();
    345.   FileStream fileStream = File.Open(directory + Path.DirectorySeparatorChar + filename, FileMode.OpenOrCreate, FileAccess.Write);
    346.  
    347.   binaryFormatter.Serialize(fileStream, sceneData);
    348.   fileStream.Close();
    349.   fileStream.Dispose();
    350.   }
    351.  
    352.   else if (storageType == STORAGETYPE.JSON)
    353.   {
    354.   string file = directory + Path.DirectorySeparatorChar + filename;
    355.   string data = JsonUtility.ToJson(sceneData, true);
    356.   File.WriteAllText(file, data);
    357.   }
    358.  
    359.   else if (storageType == STORAGETYPE.XML)
    360.   {
    361.   string file = directory + Path.DirectorySeparatorChar + filename;
    362.   XmlSerializer data = new XmlSerializer(typeof(SceneData));
    363.   using (FileStream fileStream = new FileStream(file, FileMode.Create, FileAccess.Write))
    364.   {
    365.   data.Serialize(fileStream, sceneData);
    366.   fileStream.Close();
    367.   fileStream.Dispose();
    368.   }
    369.   }
    370.   }
    371.   */
    372.  
    373.   IEnumerator DisableInteractions(float time)
    374.   {
    375.   accept.interactable = false;
    376.   yield return new WaitForSeconds(time);
    377.   accept.interactable = true;
    378.   }
    379.  
    380.   public void TryLoad()
    381.   {
    382.   if (!File.Exists(directory + Path.DirectorySeparatorChar + "saveGame.dat0"))
    383.   {
    384.   gm.MessageText("No Save Games...", Color.red, 3, 30, TextAnchor.UpperLeft);
    385.   return;
    386.   }
    387.  
    388.   PopulateList();
    389.   ToggleUI(false);
    390.   }
    391.  
    392.  
    393.   void Load(string fileName)
    394.   {
    395.   PlayerData data2 = new PlayerData();
    396.  
    397.   if (storageType == STORAGETYPE.BINARY)
    398.   {
    399.   BinaryFormatter bf2 = new BinaryFormatter();
    400.   FileStream file2 = File.Open(directory + Path.DirectorySeparatorChar + fileName, FileMode.Open, FileAccess.Read);
    401.   data2 = (PlayerData)bf2.Deserialize(file2);
    402.   file2.Close();
    403.   file2.Dispose();
    404.   }
    405.  
    406.   else if (storageType == STORAGETYPE.JSON)
    407.   {
    408.   string file = directory + Path.DirectorySeparatorChar + fileName;
    409.   string serializedData = File.ReadAllText(file);
    410.   data2 = JsonUtility.FromJson<PlayerData>(serializedData);
    411.   }
    412.  
    413.   else if (storageType == STORAGETYPE.XML)
    414.   {
    415.   string file = directory + Path.DirectorySeparatorChar + fileName;
    416.   using (FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
    417.   {
    418.   XmlSerializer serializer = new XmlSerializer(typeof(PlayerData));
    419.   data2 = (PlayerData)serializer.Deserialize(stream);
    420.  
    421.   stream.Close();
    422.   stream.Dispose();
    423.   }
    424.   }
    425.  
    426.   currentHealth = data2.currentHealth;
    427.   currentItem = data2.currentItem;
    428.   currentAmmo = data2.currentAmmo;
    429.   ownedItems = data2.ownedItems;
    430.  
    431.   currentPositionX = data2.currentPositionX;
    432.   currentPositionY = data2.currentPositionY;
    433.   currentPositionZ = data2.currentPositionZ;
    434.  
    435.   gm.Player.Health = currentHealth;
    436.  
    437.   gm.Player.transform.position = new Vector3(currentPositionX, currentPositionY, currentPositionZ);
    438.   gm.Player.transform.rotation = Quaternion.Euler(currentRotationX, currentRotationY, currentRotationZ);
    439.  
    440.   currentScene = data2.currentScene;//todo: dontdestroyonload or call load after loadscene
    441.   //  SceneManager.LoadScene(currentScene);
    442.  
    443.   foreach (Transform t in gm.FPCam.transform)
    444.   {
    445.   if (t.transform.CompareTag("Item"))
    446.   {
    447.   t.GetComponent<mt_Item>().Throw();
    448.   Destroy(t.gameObject, 0.1f);
    449.   }
    450.   }
    451.  
    452.   foreach (string s in ownedItems)
    453.   {
    454.   foreach (Transform t in itemList)
    455.   {
    456.   if (t.name == s)
    457.   {
    458.   Transform go = Instantiate(t);
    459.   go.name = go.name.Replace("(Clone)", "");
    460.   go.SetParent(gm.FPCam.transform);
    461.   go.transform.localPosition = Vector3.zero;
    462.   go.transform.localRotation = Quaternion.Euler(Vector3.zero);
    463.   go.transform.localScale = Vector3.one;
    464.  
    465.   go.GetComponent<mt_Item>().Initialize();
    466.   go.GetComponent<mt_Item>().SetLocal();
    467.   }
    468.   }
    469.   }
    470.  
    471.   for (int i = 0; i < gm.weaponTypes.Count; i++)
    472.   {
    473.   currentAmmo[i] = currentAmmo[i];
    474.   }
    475.  
    476.   gm.Player.currentItem = itemList[currentItem];
    477.   gm.Player.ActivateItem(currentItem);
    478.   gm.Player.UpdateInventory();
    479.  
    480.   autoSave = data2.autoSave;
    481.   saveTime = data2.saveTime;
    482.  
    483.   ToggleUI(false);
    484.   gm.ToggleMenu();
    485.   StartCoroutine(DisableInteractions(3));
    486.   gm.MessageText("Loaded " + fileName, Color.green, 3, 30, TextAnchor.UpperLeft);
    487.   }
    488.  
    489.   void ToggleUI(bool save)
    490.   {
    491.   isSave = save;
    492.   if (save)
    493.   {
    494.   saveUI.enabled = !saveUI.enabled;
    495.   accept.GetComponentInChildren<Text>().text = "SAVE";
    496.   }
    497.   else
    498.   {
    499.   saveUI.enabled = !saveUI.enabled;
    500.   accept.GetComponentInChildren<Text>().text = "LOAD";
    501.   }
    502.   }
    503.  
    504.   [Serializable]
    505.   public class PlayerData
    506.   {
    507.   public float currentHealth;
    508.   public List<int> currentAmmo;
    509.  
    510.   public int currentItem;
    511.   public List<string> ownedItems;
    512.  
    513.   public float currentPositionX;
    514.   public float currentPositionY;
    515.   public float currentPositionZ;
    516.  
    517.   public float currentRotationX;
    518.   public float currentRotationY;
    519.   public float currentRotationZ;
    520.  
    521.   public string currentScene;
    522.  
    523.   public bool autoSave;
    524.   public float saveTime;
    525.   }
    526.  
    527. }
     
    Last edited: Dec 10, 2016
  37. Oskang09

    Oskang09

    Joined:
    Nov 14, 2015
    Posts:
    1

    The Chapter 1 submission its ok? haha sorry if not good
    * New To Unity , also thanks to your tutorial.

    And i wanna ask about
    The Enemy Detecting in mine video it looks delay how i can make its not delaying
    after enemy dead and just declare it already 0 enemy and work all the event?
    *I haven't read about unity script just see your video in 2 day and done this assignment
     
    Last edited: Dec 8, 2016
    Goofy420 likes this.
  38. Gee85

    Gee85

    Joined:
    Feb 28, 2015
    Posts:
    9
    Hi guys! Here's my attempt at the Chapter 1 Assignment. I decided to take my time and challenge myself with this so please be critical. I drew the textures myself for the road, pavement and the entire building so im quite pleased with the outcome! I was going to develop it further but I am now moving on with the series. If anyone wants to play it you can downlaod from here: Treasure Hunter.

    (If anyone feels the desire to continue this project drop me a line and ill zip you the project folder)

     
    Goofy420 likes this.
  39. Gee85

    Gee85

    Joined:
    Feb 28, 2015
    Posts:
    9
    One way I could think of doing this, is in the GrenadeExplosion script, under the detection part:

    foreach(Collider hitCol in hitColliders)

    if(hitCol.CompareTag("Enemy"))
    {
    Destroy(hitCol, destroyTime);
    ADD enemyCountDisplayScript.enemyCount --;
    }

    Add a part that does "enemy count --" (-- subtracts 1) in whichever script you are using to put the enemy count into text so it will update immediately.
     
  40. Gee85

    Gee85

    Joined:
    Feb 28, 2015
    Posts:
    9
    For future reference, a "read only" animation means you cannot edit it in the unity animation window. A simple work around for this is to duplicate the animation and it becomes fully editable. :)
     
  41. GTGD

    GTGD

    Joined:
    Feb 7, 2012
    Posts:
    431
    So cool! Really nice work there! Thanks for sharing your knowledge as well
     
  42. Gee85

    Gee85

    Joined:
    Feb 28, 2015
    Posts:
    9
    How does one build ambient occlusion? I am currently toying with optimisation just to see how much faster I can get my project to run, any improvements are welcome =)

    *EDIT* I have exported my terrain but lose all the trees and texture. Any way to save this or do I have to repaint it in Blender and create tree prefabs? P.S It went from 1.4m Tris down to about 40k tris. Massive saving!
     
    Last edited: Dec 10, 2016
  43. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    Select all the animations clips you want to be write accessible, then hold down ctrl and click d, this will dupicate all the animations selected and allow them to be edited in Unity Legacy Animation panel. You can also select any Legacy animation, and in the top right corner of the Inspector, select Debug in the dropdown, uncheck legacy, and vice versa, you can set Mecanim animation to legacy.
     
  44. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    In the Window dropdown, select Occlusion, then in the Inspector area, you'll have a new Occlusion window. You can experiment with different settings, but the best way is to create manual occlusion areas. To start, select your terrain, and just click bake. You'll see a basic OA built, and then in your Camera, check Occusuion, then only non occluded areas will be drawn at runtime. So instead of drawing a 5000x5000 area constantly, it'll draw 1000x1000 or less depending on what your Cameras view range is set to.
     
  45. Gee85

    Gee85

    Joined:
    Feb 28, 2015
    Posts:
    9
    Ah! Thanks a bunch! Its amazing what a little extra time playing round can achieve on the performance side, even with such a basic project such as mine! Its all a good learning curve to take further down the line also!
     
  46. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    If you're not a very good artist, like myself, and can't afford to hire out every single model to an established artist, I found that using Daz3D models (may require a gamedev license for some of them) can create many unique models in the AAA quality reign. Using decimator can cut a 2.5 million poly model down to 12,000 without any real noticeable quality loss.
    This Gatling was originally 2.5 million, but imported into Unity at 12,000 and I can't tell the difference between the decimated and original file. The arms use some of the best textures I've seen (Mortum Vetus) and all I did was remove all the meshes except the arms but left the bones, so it can use humanoid animations on an FPS arm
    "]
     
    Last edited: Dec 10, 2016
  47. Gee85

    Gee85

    Joined:
    Feb 28, 2015
    Posts:
    9
    Sweet that! I like the counterstrike reload sound =) I am not fully sure about Daz3d not used it enough yet, how do you send it over to Unity etc? Might be something I toy around with again later!
     
  48. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    Daz has FBX export, which also supports BlendShapes. The morphs of the bipedal characters allow you to have infinitum of characters using the same mesh. Plus, you can purchase the Morphs++ and other morph packs like MS-Lycan and have a human character blend from human to werewolf in real time with a single line of code.
    GetComponent<SkinnedMeshRenderer>().SetBlendShapeWeight(0, 1); which would end up something like
    Code (CSharp):
    1. public int blendIndex = 0;
    2.     public float blendTime = 0.5f;
    3.     float blendValue;
    4.     public void Blend()
    5.     {
    6.         if (GetComponent<SkinnedMeshRenderer>().GetBlendShapeWeight(blendIndex) < 0.75f)
    7.         {
    8.             StartCoroutine(ToLycan());
    9.         }
    10.         else if (GetComponent<SkinnedMeshRenderer>().GetBlendShapeWeight(blendIndex) > 0.25f)
    11.         {
    12.             StartCoroutine(ToHuman());
    13.         }
    14. else
    15. {
    16. //still blending, so do nothing
    17. }
    18.     }
    19.     IEnumerator ToLycan()
    20.     {
    21.         GetComponent<SkinnedMeshRenderer>().SetBlendShapeWeight(blendIndex, blendValue);
    22.         yield return new WaitForSeconds(blendTime);
    23.         blendValue++;
    24.     }
    25.  
    26.     IEnumerator ToHuman()
    27.     {
    28.         GetComponent<SkinnedMeshRenderer>().SetBlendShapeWeight(blendIndex, blendValue);
    29.         yield return new WaitForSeconds(blendTime);
    30.         blendValue--;
    31.     }
    In Daz, you select the morphs in the fbx export panel, and they will be exported as blend shapes. You can also export animate animations the same way and they will be imported as Mecanim animations.
     
  49. mohlkert

    mohlkert

    Joined:
    Dec 16, 2015
    Posts:
    2
    hello.
    i followed your tutorial and everything seems to work just fine but i can not get the enemy to attack the player do u have any ideas on what it could be? best regards
     
  50. DRAmos97

    DRAmos97

    Joined:
    Jan 28, 2016
    Posts:
    1
    Thank you for the tutorials! Here is my project so far.