Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Weapon stats

Discussion in 'Scripting' started by NotBabyYugo1243, Mar 22, 2024.

  1. NotBabyYugo1243

    NotBabyYugo1243

    Joined:
    Mar 22, 2024
    Posts:
    5
    In Unity C#, I’m trying to make this gun customization system that’s really advanced and unique.

    when you attach mods to the gun like suppressors, optics, foregrips, etc. it’ll change the stats for damage, accuracy, recoil, etc. all perfectly fine.

    however; I’m trying to add a new feature where you can preview or see the stats of the attachment you’re hovering your mouse over. how I have it setup is, I have a float assigned to a slider value, if a button is pressed to assign the attachment, it’ll equip the attachment, and change the stats accordingly.

    the main issue I’m having with this is that when I take my mouse cursor off the button to preview the stats of an attachment, it just gives me a completely wrong value to revert the value of the stats back to what it originally was before previewing the stats of the new attachment.
     
  2. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    574
    You will need to show some code (please use code tags on the forums to submit code, no screenshots or simple text), because you clearly are doing something wrong there, but we can't guess what since we aren't familiar with your code.
     
  3. NotBabyYugo1243

    NotBabyYugo1243

    Joined:
    Mar 22, 2024
    Posts:
    5
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using TMPro;
    5. using UnityEngine.UI;
    6. using UnityEngine.UIElements;
    7. using UnityEditor.Build.Content;
    8. using static UnityEngine.Rendering.DebugUI;
    9. using Image = UnityEngine.UI.Image;
    10.  
    11. public class MK18stats : MonoBehaviour
    12. {
    13.     //Scripts
    14.     public MK18 MainMK18Script;
    15.  
    16.     //Stats
    17.     public float DamageValue;
    18.     public UnityEngine.UI.Slider DamageStatSlider;
    19.     public TextMeshProUGUI DamageStatValueText;
    20.     public GameObject DamageSliderBackground;
    21.  
    22.     // Start is called before the first frame update
    23.     void Start()
    24.     {
    25.         //Stats
    26.         DamageValue = 22.30f;
    27.         DamageStatValueText.text = DamageValue.ToString();
    28.         DamageStatSlider.value = (float)DamageValue;
    29.     }
    30.  
    31.     // Update is called once per frame
    32.     void Update()
    33.     {
    34.         //Stats
    35.         DamageStatValueText.text = DamageValue.ToString();
    36.         DamageStatSlider.value = (float)DamageValue;
    37.         if (DamageValue < 22.3)
    38.         {
    39.             DamageSliderBackground.SetActive(true);
    40.         }
    41.         else
    42.         {
    43.             DamageSliderBackground.SetActive(false);
    44.         }
    45.     }
    46.  
    47.     public void AttachSurefireSOCOMRC2stats()
    48.     {
    49.         DamageValue -= 2.40f;
    50.     }
    51.  
    52.     public void AttachAACRANGER5stats()
    53.     {
    54.         DamageValue -= 2.25f;
    55.     }
    56.  
    57.     public void UnequipMuzzleStats()
    58.     {
    59.         if (MainMK18Script.isSUREFIRESOCOMRC2active)
    60.         {
    61.             DamageValue += 2.40f;
    62.             MainMK18Script.isSUREFIRESOCOMRC2active = false;
    63.         }
    64.         if (MainMK18Script.isAACRANGER5active)
    65.         {
    66.             DamageValue += 2.25f;
    67.             MainMK18Script.isAACRANGER5active = false;
    68.         }
    69.     }
    70. }
    Code (CSharp):
    1. public class MK18 : MonoBehaviour
    2. {
    3.     //Scripts
    4.     public MK18stats MK18statsScript;
    5.  
    6.     //Arrays
    7.     public GameObject[] suppressors;
    8.     public GameObject[] toggles;
    9.  
    10.     //Suppressors
    11.     #region
    12.     public GameObject AACRANGER5;
    13.     public GameObject DEADAIRSIERRA5;
    14.     public GameObject ENERGETICARMAMENTARX;
    15.     public GameObject GEMTECHHALOGMT;
    16.     public GameObject HUXWRXFLOW556K;
    17.     public GameObject RUGGEDRAZOR556;
    18.     public GameObject SILENCERCOVELOSLBP;
    19.     public GameObject SOUNDGUARDSG556;
    20.     public GameObject SUREFIRESOCOMRC2;
    21.  
    22.     public GameObject AACRANGER5Toggle;
    23.     public GameObject DEADAIRSIERRA5Toggle;
    24.     public GameObject ENERGETICARMAMENTARXToggle;
    25.     public GameObject GEMTECHHALOGMTToggle;
    26.     public GameObject HUXWRXFLOW556KToggle;
    27.     public GameObject RUGGEDRAZOR556Toggle;
    28.     public GameObject SILENCERCOVELOSLBPToggle;
    29.     public GameObject SOUNDGUARDSG556Toggle;
    30.     public GameObject SUREFIRESOCOMRC2Toggle;
    31.     #endregion
    32.  
    33.     //Booleans
    34.     #region
    35.     public bool isSUREFIRESOCOMRC2active;
    36.     public bool isAACRANGER5active;
    37.     #endregion
    38.  
    39.     private void Start()
    40.     {
    41.         //Script
    42.         MK18statsScript = GameObject.FindObjectOfType<MK18stats>();
    43.  
    44.         //Arrays
    45.         suppressors = new GameObject[] { AACRANGER5, DEADAIRSIERRA5, ENERGETICARMAMENTARX, GEMTECHHALOGMT,
    46.                                      HUXWRXFLOW556K, RUGGEDRAZOR556, SILENCERCOVELOSLBP, SOUNDGUARDSG556,
    47.                                      SUREFIRESOCOMRC2 };
    48.  
    49.         // Initialize toggle array
    50.         toggles = new GameObject[] { AACRANGER5Toggle, DEADAIRSIERRA5Toggle, ENERGETICARMAMENTARXToggle, GEMTECHHALOGMTToggle,
    51.                                  HUXWRXFLOW556KToggle, RUGGEDRAZOR556Toggle, SILENCERCOVELOSLBPToggle, SOUNDGUARDSG556Toggle,
    52.                                  SUREFIRESOCOMRC2Toggle };
    53.     }
    54.  
    55.     public void Update()
    56.     {
    57.         isSUREFIRESOCOMRC2active = SUREFIRESOCOMRC2.activeSelf;
    58.         isAACRANGER5active = AACRANGER5.activeSelf;
    59.     }
    60.  
    61.     #region
    62.     // Method to deactivate all suppressors except the one being activated
    63.     void DeactivateAllSuppressorsExcept(GameObject suppressorToActivate)
    64.     {
    65.         foreach (GameObject suppressor in suppressors)
    66.         {
    67.             if (suppressor != null && suppressor != suppressorToActivate)
    68.             {
    69.                 suppressor.SetActive(false);
    70.             }
    71.         }
    72.     }
    73.  
    74.     // Method to deactivate all toggles except the one being toggled
    75.     void DeactivateAllTogglesExcept(GameObject toggleToActivate)
    76.     {
    77.         foreach (GameObject toggle in toggles)
    78.         {
    79.             if (toggle != null && toggle != toggleToActivate)
    80.             {
    81.                 toggle.SetActive(false);
    82.             }
    83.         }
    84.     }
    85.  
    86.     // Method to deactivate all suppressors at once
    87.     void DeactivateAllSuppressors()
    88.     {
    89.         foreach (GameObject suppressor in suppressors)
    90.         {
    91.             if (suppressor != null)
    92.             {
    93.                 suppressor.SetActive(false);
    94.             }
    95.         }
    96.     }
    97.     public void DeactivateAllToggles()
    98.     {
    99.         foreach (GameObject toggle in toggles)
    100.         {
    101.             if (toggle != null)
    102.             {
    103.                 toggle.SetActive(false);
    104.             }
    105.         }
    106.     }
    107.     #endregion
    108.  
    109.     public void AttachSUREFIRESOCOMRC2()
    110.     {
    111.         UnequipAttachedMuzzle();
    112.  
    113.         if (!isSUREFIRESOCOMRC2active)
    114.         {
    115.             if (SUREFIRESOCOMRC2 != null)
    116.             {
    117.                 MK18statsScript.AttachSurefireSOCOMRC2stats();
    118.  
    119.                 SUREFIRESOCOMRC2.SetActive(true);
    120.                 SUREFIRESOCOMRC2Toggle.SetActive(true);
    121.                 DeactivateAllSuppressorsExcept(SUREFIRESOCOMRC2);
    122.                 DeactivateAllTogglesExcept(SUREFIRESOCOMRC2Toggle);
    123.             }
    124.         }
    125.     }
    126.     public void AttachAACRANGER5()
    127.     {
    128.         UnequipAttachedMuzzle();
    129.  
    130.         if (!isAACRANGER5active)
    131.         {
    132.             if (AACRANGER5 != null)
    133.             {
    134.                 MK18statsScript.AttachAACRANGER5stats();
    135.  
    136.                 AACRANGER5.SetActive(true);
    137.                 AACRANGER5Toggle.SetActive(true);
    138.                 DeactivateAllSuppressorsExcept(AACRANGER5);
    139.                 DeactivateAllTogglesExcept(AACRANGER5Toggle);
    140.             }
    141.         }
    142.     }
    143.  
    144.     public void UnequipAttachedMuzzle()
    145.     {
    146.         MK18statsScript.UnequipMuzzleStats();
    147.  
    148.         DeactivateAllSuppressors();
    149.         DeactivateAllToggles();
    150.     }
    151.  
    152. }
     
  4. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    574
    I don't see handling any kind of hover here. No cursor of any kind. You said the Equip is ok, the hover and the subsequent leave is problematic, but maybe I misunderstood something?
     
  5. NotBabyYugo1243

    NotBabyYugo1243

    Joined:
    Mar 22, 2024
    Posts:
    5
    This is just the script before I tried making the functions. So the goal here is that I make a public void for an event trigger on a button to just alter the stats to as if the attachment is actually attached, and then a void to revert the stats back before. I don’t know if event triggers are even good in the first place but that’s how I do it. So when i tried to do it, hovering my mouse over a button would decrease the damage by 2.4 of course, and off the button would increase by 2.4, but when I have an attachment actually attached, and then I go on to hover the button of another attachment I want to see the stats change of, it properly shows it, and when I take the mouse off it would just give me completely faulty numbers that didn’t even make sense like it would be a dozen or a thousand numbers higher.
     
  6. NotBabyYugo1243

    NotBabyYugo1243

    Joined:
    Mar 22, 2024
    Posts:
    5

    the first 30 seconds of this video is a really good example of what I’m looking to make, this guy has it so that when he hovers his mouse over a button, it just changes the stats of the gun so that you get an idea of what the changes will be like. And then he takes his mouse off, it just reverts it back to what it originally was.
     
  7. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    574
    It is possible (and often made) mistake to subscribe to an event but never unsubscribe and then just subscribe over and over multiple times (sometimes between runs in the editor) so some calculations can be thrown off with this.
    But this is just blind guess, I don't even understand why you're lowering the damage stat when you equip an item and adding to it when unequip. :D
     
  8. NotBabyYugo1243

    NotBabyYugo1243

    Joined:
    Mar 22, 2024
    Posts:
    5
    game logic lol, suppressor = lower damage
    I’ll just try to figure out a way but I’ve been at it for the past 2 days
     
    Lurking-Ninja likes this.
  9. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 5, 2024
    Posts:
    574
    Anyway, I also recommend to refactor this whole thing into data-driven architecture. Make some ScriptabeObjects for some equipment and drive it by its data. There are great tutorials both on Youtube and on the Learn site if you aren't familiar with the SO-driven architectures. The main point is that you should not have kilometer long exact class member variables and magic numbers in your code.
     
  10. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,652
    One thing I noticed, OP, is that you're using MonoBehaviors for storing state. MonoBehaviors are things that are attached to in-game objects and exist in world space .Weapon Stats certainly do not sound like that.

    It would be better idea to make them C# classes or ScriptableObjects. ScriptableObjects are supported by inspector and can be stored as in-project assets.
     
    Chubzdoomer likes this.
  11. Reedex

    Reedex

    Joined:
    Sep 20, 2016
    Posts:
    389
    i would go for Scriptable object for each weapon like so. M16 could have:
    int Damage 15;
    List<Attachment> Attachments;
    then another scriptable objects for Attachments
    and it would be calculated like so
    Silencer example
    DamageMult 0.9;

    finally take Damage and loop through attachments * their damage mult.
    thats the point, but you would need to calculate it the way you want it. For example multiplicative or additive and so on.

    and of course function GetDamage in the Weapon scriptable object so you don't overwrite all SO weapon data.

    (15 + 10 * 0.2) * 1.25 * 1.05 * 0.6848 = 369 ( 368.5 ) <- this kind of craziness in the end, each number representing multiplication to base damage 15. ( got this from totally unrelated thing, but it shows what i mean)
     
  12. Nad_B

    Nad_B

    Joined:
    Aug 1, 2021
    Posts:
    730
    It's not that difficult with SOs and some basic clean architecture:

    Code (CSharp):
    1. public enum AttachmentModifierType
    2. {
    3.     Damage,
    4.     Range,
    5.     Silence
    6. }
    7.  
    8. // Attachments data SO, 1 per attachment
    9. // It contains a list of "Modifiers" to apply/remove when attached/detached
    10. [CreateAssetMenu())
    11. public class AttachmentDataSO : ScriptableObject
    12. {
    13.     public string Name;
    14.     public string Description;
    15.     public Sprite Icon;
    16.     public List<AttachmentModifier> Modifiers;
    17. }
    18.  
    19. [Serializable]
    20. public class AttachmentModifier
    21. {
    22.     public AttachmentModifierType ModifierType;
    23.     public float Amount;
    24. }
    25.  
    26. // Attachment script, attach to each attachment GO
    27. // and set its AttachmentData
    28. public class WeaponAttachment : MonoBehaviour
    29. {
    30.     public AttachmentDataSO AttachmentData;
    31.     public Transform AttachmentPoint;
    32.  
    33.     private void Awake()
    34.     {
    35.         if (!AttachmentData)
    36.             Debug.LogWarning("This Attachment has no AttachmentData assigned!", this);
    37.  
    38.         if (!AttachmentPoint)
    39.             AttachmentPoint = transform;
    40.     }
    41. }
    42.  
    43. // Weapon script
    44. public class Weapon : MonoBehaviour
    45. {
    46.     private readonly List<WeaponAttachment> _attachments = new();
    47.     private readonly Dictionary<AttachmentModifierType, float> _attachmentModifiers = Enum.GetValues<AttachmentModifierType>().ToDictionary(x => x, x => 0f);
    48.  
    49.     public void AddAttachment(WeaponAttachment attachment)
    50.     {
    51.         if (_attachments.Contains(attachment))
    52.             return;
    53.  
    54.         _attachments.Add(attachment);
    55.  
    56.         attachment.Transform.parent = this;
    57.         attachment.Transform.localPosition = attachment.AttachmentPoint.localPosition;
    58.  
    59.         AddAttachmentStats(attachment);
    60.     }
    61.  
    62.     public void RemoveAttachment(WeaponAttachment attachment)
    63.     {
    64.         if (!_attachments.Remove(attachment))
    65.             return;
    66.  
    67.         RemoveAttachmentStats(attachment);
    68.  
    69.         Destroy(attachment.gameObject);
    70.     }
    71.  
    72.     public void Fire()
    73.     {
    74.         // Fire your weapon, take into consideration _attachmentModifiers values...
    75.     }
    76.  
    77.     private AddAttachmentStats(WeaponAttachment attachment)
    78.     {
    79.         foreach (var modifier in attachment.AttachmentData.Modifiers)
    80.         {
    81.             _attachmentModifiers[modifier.StatType] += modifier.Amount;
    82.         }
    83.  
    84.     private RemoveAttachmentStats(WeaponAttachment attachment)
    85.     {
    86.         foreach (var modifier in attachment.AttachmentData.Modifiers)
    87.         {
    88.             _attachmentModifiers[modifier.StatType] -= modifier.Amount;
    89.         }
    90.     }
     
    Last edited: Mar 22, 2024