Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

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

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

  1. 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
  2. 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
  3. 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.
  4. Saurabh-Saralaya

    Saurabh-Saralaya

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

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    8
    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?
     
  6. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    8
    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
     
  7. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    8
    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!
     
  8. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    8
    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.
     
  9. 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
  10. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    8
    I bought it again because figured it's only $7 and if it doesn't work out, at least I tried.
     
  11. 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
  12. Mad_Mark

    Mad_Mark

    Joined:
    Oct 30, 2014
    Posts:
    484
    Nice! I like that FallOut menu system. Good work.
     
    Goofy420 likes this.
  13. 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.
     
  14. 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
  15. 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.
  16. 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.     }
     
  17. 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.
     
  18. Flame2057

    Flame2057

    Joined:
    Nov 26, 2016
    Posts:
    8
    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.
  19. Mad_Mark

    Mad_Mark

    Joined:
    Oct 30, 2014
    Posts:
    484
    @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?
     
  20. 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
  21. Mad_Mark

    Mad_Mark

    Joined:
    Oct 30, 2014
    Posts:
    484
    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.
     
  22. 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.
     
  23. 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
  24. 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.
  25. 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.
  26. 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.
     
  27. 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. :)
     
  28. GTGD

    GTGD

    Joined:
    Feb 7, 2012
    Posts:
    436
    So cool! Really nice work there! Thanks for sharing your knowledge as well
     
  29. 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
  30. 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.
     
  31. 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.
     
  32. 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!
     
  33. 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
  34. 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!
     
  35. 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.
     
  36. 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
     
  37. DARamos97

    DARamos97

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

    Fedora_Dev

    Joined:
    Oct 28, 2016
    Posts:
    35
    In regards to your script execution order issue in episode 68, I usually create a static reference to the game master script, since i know there will only be one. Then I use a property and define a specific get function that will check if the variable has been set yet, set it if not, then return it.

    Code (csharp):
    1. private static GameController gamecontroller;
    2.  
    3. public static GameController gameController
    4. {
    5.    get
    6.    {
    7.         if (gamecontroller == null)
    8.             gamecontroller = GameObject.FindGameObjectWithTag("GameController").GetComponent<GameController>();
    9.  
    10.         return gamecontroller;
    11.     }
    12. }
    This way, even if GameController's OnEnable hasn't run yet, the variable will be set. I also do this for the player variables that are stored in GameController.
     
  39. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    Code (CSharp):
    1. void CastARayToDetectItems()
    2.         {
    3.             if(Physics.SphereCast(RayTransformThePivot.position, DetectRadius, RayTransformThePivot.forward, out Hit, DetectTheRange, LayersToDetect))
    4.             {
    5.                 ItemsAvailableForPickUp = Hit.transform;
    6.                 ItemsInRange = true;
    7.             }
    8.             else
    9.             {
    10.                 ItemsInRange = true;
    11.             }
    12.         }
    13.  
    In your else statement, ItemsInRange = true; should be false;
     
    Last edited: Dec 23, 2016
  40. KyoSaya

    KyoSaya

    Joined:
    May 26, 2016
    Posts:
    4
    Oh my god, thank you so much, I try all days to fix it :)
    Sorry for being that dumb and careless.
     
  41. KyoSaya

    KyoSaya

    Joined:
    May 26, 2016
    Posts:
    4
    Here is another problem, Im in video 71 now and when I use navigation to bake the Navmesh the floor is not turning blue and I cannot bake it, and the havethe warning: Failed to create agent because there is no valid NavMesh. What sould I do now, I have been googled and had no idea what is going on.
     
  42. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    Select your terrain, then click bake.
     
  43. Kuba1412

    Kuba1412

    Joined:
    Feb 19, 2016
    Posts:
    3
    Hello, I have a weird problem. I'm on the 89 part in the tutorial and when the methods is moving from void OnEnable to void Start everything is ok but... when I picking the objects and I have these objects in inventory and I trying to throw these objects kinematic is OFF... this is weird. Sorry for my english :p Anyone can help me?
     
  44. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    It could be an issue with IsPlayer. You want to keep the method in OnEnable if the item doesn't start as a child of player or it could be missed between frames. Post the script so we can see if there's any discrepancies.

    Remember the execution order: Start will only be called on enabled scripts before the first frame update and OnEnable is only called on active gameobjects after the first scene load and beyond.

    Awake: This function is always called before any Start functions and also just after a prefab is instantiated. (If a GameObject is inactive during start up Awake is not called until it is made active.)

    OnEnable: (only called if the Object is active): This function is called just after the object is enabled. This happens when a MonoBehaviour instance is created, such as when a level is loaded or a GameObject with the script component is instantiated.

    Start: Start is called before the first frame update only if the script instance is enabled.
    For objects added to the scene, the Start function will be called on all scripts before Update, etc are called for any of them. Naturally, this cannot be enforced when an object is instantiated during gameplay
     
  45. Kuba1412

    Kuba1412

    Joined:
    Feb 19, 2016
    Posts:
    3
    Ok :)
    Item_SetPosition


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Item_SetPosition : MonoBehaviour {
    6.  
    7.     private Item_Master itemMaster;
    8.     public Vector3 itemLocalPosition;
    9.  
    10.     void Start ()
    11.     {
    12.         SetPositionOnPlayer ();
    13.     }
    14.  
    15.     void OnEnable ()
    16.     {
    17.         //SetPositionOnPlayer ();
    18.         SetInitialReferences ();
    19.         itemMaster.EventObjectPickup += SetPositionOnPlayer;
    20.     }
    21.  
    22.     void OnDisable ()
    23.     {
    24.         itemMaster.EventObjectPickup -= SetPositionOnPlayer;
    25.     }
    26.  
    27.     void SetInitialReferences ()
    28.     {
    29.         itemMaster = GetComponent<Item_Master> ();
    30.     }
    31.  
    32.     void SetPositionOnPlayer ()
    33.     {
    34.         if(transform.root.CompareTag(GameManager_References._playerTag))
    35.         {
    36.            transform.localPosition = itemLocalPosition;
    37.         }
    38.     }
    39.  
    40. [B]Item_SetLayer[/B]
    41.  
    42. }
    Item_SetLayer

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Item_SetLayer : MonoBehaviour {
    6.  
    7.     private Item_Master itemMaster;
    8.     public string itemThrowLayer;
    9.     public string itemPickupLayer;
    10.  
    11.     void Start()
    12.     {
    13.         SetLayerOnEnable ();
    14.     }
    15.  
    16.     void OnEnable ()
    17.     {
    18.         //SetLayerOnEnable ();
    19.         SetInitialReferences ();
    20.         itemMaster.EventObjectPickup += SetItemToPickupLayer;
    21.         itemMaster.EventObjectThrow += SetItemToThrowLayer;
    22.     }
    23.  
    24.     void OnDisable ()
    25.     {
    26.         itemMaster.EventObjectPickup -= SetItemToPickupLayer;
    27.         itemMaster.EventObjectThrow -= SetItemToThrowLayer;
    28.     }
    29.  
    30.     void SetInitialReferences ()
    31.     {
    32.         itemMaster = GetComponent<Item_Master> ();
    33.     }
    34.  
    35.     void SetItemToThrowLayer ()
    36.     {
    37.         SetLayer(transform, itemThrowLayer);
    38.     }
    39.  
    40.     void SetItemToPickupLayer ()
    41.     {
    42.         SetLayer(transform, itemPickupLayer);
    43.     }
    44.  
    45.     void SetLayerOnEnable ()
    46.     {
    47.         if (itemPickupLayer == "")
    48.         {
    49.             itemPickupLayer = "Item";
    50.         }
    51.  
    52.         if (itemThrowLayer == "")
    53.         {
    54.             itemThrowLayer = "Item";
    55.         }
    56.  
    57.         if (transform.root.CompareTag (GameManager_References._playerTag)) {
    58.             SetItemToPickupLayer ();
    59.         }
    60.         else
    61.         {
    62.             SetItemToThrowLayer ();
    63.         }
    64.     }
    65.  
    66.     void SetLayer (Transform tForm, string itemLayerName)
    67.     {
    68.         tForm.gameObject.layer = LayerMask.NameToLayer (itemLayerName);
    69.  
    70.         foreach (Transform child in tForm)
    71.         {
    72.             SetLayer (child, itemLayerName);
    73.         }
    74.     }
    75.  
    76. }
    Item_Rigidbodies

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Item_Rigidbodies : MonoBehaviour {
    6.  
    7.     private Item_Master itemMaster;
    8.     public Rigidbody[] rigidBodies;
    9.  
    10.     void Start()
    11.     {
    12.         CheckIfStartsInventory ();
    13.     }
    14.  
    15.     void OnEnable ()
    16.     {
    17.         //CheckIfStartsInventory ();
    18.         SetInitialReferences ();
    19.         itemMaster.EventObjectThrow += SetIsKinematicToFalse;
    20.         itemMaster.EventObjectPickup += SetIsKinematicToFalse;
    21.  
    22.     }
    23.  
    24.     void OnDisable ()
    25.     {
    26.         itemMaster.EventObjectThrow -= SetIsKinematicToFalse;
    27.         itemMaster.EventObjectPickup -= SetIsKinematicToFalse;
    28.     }
    29.  
    30.     void SetInitialReferences ()
    31.     {
    32.         itemMaster = GetComponent<Item_Master> ();
    33.     }
    34.  
    35.     void CheckIfStartsInventory ()
    36.     {
    37.         if(transform.root.CompareTag(GameManager_References._playerTag))
    38.             {
    39.                 SetIsKinematicToTrue ();
    40.             }
    41.     }
    42.  
    43.     void SetIsKinematicToTrue ()
    44.     {
    45.         if (rigidBodies.Length > 0)
    46.         {
    47.             foreach (Rigidbody rBody in rigidBodies)
    48.             {
    49.                 rBody.isKinematic = true;
    50.             }
    51.         }
    52.     }
    53.  
    54.     void SetIsKinematicToFalse ()
    55.     {
    56.         if (rigidBodies.Length > 0)
    57.         {
    58.             foreach (Rigidbody rBody in rigidBodies)
    59.             {
    60.                 rBody.isKinematic = false;
    61.             }
    62.         }
    63.     }
    64. }
    Item_Colliders

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Item_Colliders : MonoBehaviour {
    6.  
    7.     private Item_Master itemMaster;
    8.     public Collider[] colliders;
    9.     public PhysicMaterial myPhysicMaterial;
    10.  
    11.     void Start()
    12.     {
    13.         CheckIfStartsInInventory ();
    14.     }
    15.  
    16.     void OnEnable ()
    17.     {
    18.         //CheckIfStartsInInventory ();
    19.         SetInitialReferences ();
    20.         itemMaster.EventObjectThrow += EnableColliders;
    21.         itemMaster.EventObjectPickup += EnableColliders;
    22.     }
    23.  
    24.     void OnDisable ()
    25.     {
    26.         itemMaster.EventObjectThrow -= EnableColliders;
    27.         itemMaster.EventObjectPickup -= DisableColliders;
    28.     }
    29.  
    30.     void SetInitialReferences ()
    31.     {
    32.         itemMaster = GetComponent<Item_Master> ();
    33.         //colliders = GetComponentsInChildren<Collider> ();
    34.     }
    35.  
    36.     void CheckIfStartsInInventory ()
    37.     {
    38.         if(transform.root.CompareTag(GameManager_References._playerTag))
    39.             {
    40.                 DisableColliders();
    41.             }
    42.     }
    43.  
    44.     void EnableColliders ()
    45.     {
    46.         if (colliders.Length > 0)
    47.         {
    48.             foreach (Collider col in colliders)
    49.             {
    50.                 col.enabled = true;
    51.  
    52.                 if (myPhysicMaterial != null)
    53.                 {
    54.                     col.material = myPhysicMaterial;      
    55.                 }
    56.             }
    57.         }
    58.     }
    59.  
    60.     void DisableColliders ()
    61.     {
    62.                 if (colliders.Length > 0)
    63.                 {
    64.                     foreach (Collider col in colliders)
    65.                     {
    66.                         col.enabled = false;
    67.                     }
    68.                 }
    69.     }
    70.  
    71. }
     
  46. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    If you want to check for Player between frames or before the frame updates while enabling a script or go, you should add a dynamic bool that will be called each time you check for player. This would be similar to calling the Event each time you CheckForPlayer and is faster and more reliable than accessing it from Event while only using resources when you need it.
    Code (CSharp):
    1.  
    2. public Vector3 itemLocalPosition;
    3. private Item_Master itemMaster
    4. bool isPlayer()//whenevr this is called, it's checking for the root of the item being Player
    5.     {
    6.         if (!transform.root.CompareTag("Player")) return false;
    7.         return true;
    8.     }
    then when you call CheckForPlayer() this way will failsafe and always check immediately
    Code (CSharp):
    1. void SetPositionOnPlayer ()
    2.     {
    3.         if(isPlayer)//this calls the isPlayer bool dynamically, each time this method is run
    4.         {
    5.            transform.localPosition = itemLocalPosition;//since we know without a doubt whether or not the root isPlayer, we can call this function
    6.         }
    7.     }
    this can be used in Start(), OnEnable(), and even Awake() when Awake() is called on an inactive object or script and when using CompareTag will never result in null

    Why do you need to move the checks from OnEnable to Start? That might help in deciding the best way to fix this issue.
     
    Kuba1412 likes this.
  47. Kuba1412

    Kuba1412

    Joined:
    Feb 19, 2016
    Posts:
    3
    thank you very much!
     
  48. KemJer

    KemJer

    Joined:
    Jan 29, 2017
    Posts:
    2
    Hey,
    Im having a problem with the NPC_TakeDamage and NPC_Master scripts. I dont know what the real problem is since none of my debug logs are updating into unity. But I would like to figure this out now, since it jacks up my CPU Main to 870ms and also lowers my frames from 308 fps to 1.1 fps, so its says StackOverflowException. And this only happens when I shoot the NPC. Here is a Picture of the Error...



    I checked my code from the NPC_Master Script to the Gun_ApplyDamage Script since it just started happening in part 173. I checked GTGDs scripts and mine, back to back, over and over, but couldn't find any problems. here is my code for both NPC_Master and NPC_TakeDamage.

    Code (NPC_TakeDamage):
    1.         private NPC_Master npcMaster;
    2.         public int damageMultiplier = 1;
    3.         public bool shouldRemoveCollider;
    4.  
    5.         void OnEnable()
    6.         {
    7.             SetIntialReferences();
    8.             npcMaster.EventNpcDie += RemoveThis;
    9.             npcMaster.EventNpcDeductHealth += ProcessDamage;
    10.         }
    11.  
    12.         void OnDisable()
    13.         {
    14.             npcMaster.EventNpcDie -= RemoveThis;
    15.             npcMaster.EventNpcDeductHealth -= ProcessDamage;
    16.  
    17.         }
    18.  
    19.         void SetIntialReferences()
    20.         {
    21.             npcMaster = transform.root.GetComponent<NPC_Master>();
    22.         }
    23.  
    24.         public void ProcessDamage(int damage)
    25.         {
    26.             int damageToApply = damage * damageMultiplier;
    27.             npcMaster.CallEventNpcDeductHealth(damageToApply);
    28.         }
    29.  
    30.         void RemoveThis()
    31.         {
    32.             if (shouldRemoveCollider)
    33.             {
    34.                 if (GetComponent<Collider>() != null)
    35.                 {
    36.                     Destroy(GetComponent<Collider>());
    37.                 }
    38.  
    39.                 if (GetComponent<Rigidbody>() != null)
    40.                 {
    41.                     Destroy(GetComponent<Rigidbody>());
    42.                 }
    43.             }
    44.            
    45.             gameObject.layer = LayerMask.NameToLayer("Default");//So Ai doesn't keep detecting
    46.  
    47.             Destroy(this);
    48.         }
    49.     }
    50. }
    Code (NPC_Master Events):
    1.  
    2.         public delegate void GeneralEventHandler();
    3.         public event GeneralEventHandler EventNpcDie;
    4.         public event GeneralEventHandler EventNpcLowHealth;
    5.         public event GeneralEventHandler EventNpcHealthRecovered;
    6.         public event GeneralEventHandler EventNpcWalkAnim;
    7.         public event GeneralEventHandler EventNpcStruckAnim;
    8.         public event GeneralEventHandler EventNpcAttackAnim;
    9.         public event GeneralEventHandler EventNpcRecoveredAnim;
    10.         public event GeneralEventHandler EventNpcIdleAnim;
    11.  
    12.         public delegate void HealthEventHandler(int health);
    13.         public event HealthEventHandler EventNpcDeductHealth;
    14.         public event HealthEventHandler EventNpcIncreaseHealth;
    15.  

    Code (NPC_Master Deduct and Increase Health):
    1.  
    2.         public void CallEventNpcDeductHealth(int health)
    3.         {
    4.             if (EventNpcDeductHealth != null)
    5.             {
    6.                 EventNpcDeductHealth(health);
    7.             }
    8.         }
    9.  
    10.         public void CallEventNpcIncreaseHealth(int health)
    11.         {
    12.             if (EventNpcIncreaseHealth != null)
    13.             {
    14.                 EventNpcIncreaseHealth(health);
    15.             }
    16.         }
    17.     }
    18. }
     

    Attached Files:

  49. Goofy420

    Goofy420

    Joined:
    Apr 27, 2013
    Posts:
    248
    Once you start using the scripts from the NPC folder, remove the scripts of the Enemy folder. NPC are the updated Enemy functions.
    What's line 36 from NPC_TakeDamage and line 98 from NPC_Master?
    If your debug isn't displaying to console, see if you have the Warnings selection on the upper right of the console disabled.
     
  50. KemJer

    KemJer

    Joined:
    Jan 29, 2017
    Posts:
    2
    the warning selection isn't disabled but the few times that I rearranged the code to have the debug go through the code first, it froze unity and then crashed. The NPC works a little, like everything works in shooting and tracking, just that the gun placement is in the ground and the health is one shot one kill, even though the health is 140 and the damage is 34 and multiplier is 1. I dont know what causes the NPC health to do this, and the NPC only fires like 3 shots then stops in place as pursuing. Here are those two methods with the line.

    Take Damage Script
    33 public void ProcessDamage(int damage)
    34 {
    35 int damageToApply = damage * damageMultiplier;
    36 npcMaster.CallEventNpcDeductHealth(damageToApply);
    35 }

    NPC Master Script

    94 public void CallEventNpcDeductHealth(int health)
    95 {
    96 if (EventNpcDeductHealth != null)
    97 {
    98 EventNpcDeductHealth(health);
    99 }
    100 }