Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Need help with upgrade script please!

Discussion in 'Scripting' started by thorolfyggsson, May 25, 2023.

  1. thorolfyggsson

    thorolfyggsson

    Joined:
    May 25, 2023
    Posts:
    5
    I've recently completed Brackeys Tower Defense tutorial, and have decided to try my hand at adding some additional functionality, but I'm having some trouble. I'm sure my script is sloppy and there are better, more efficient ways to do what I'm attempting, but I have very little experience with scripting. I want my towers to upgrade sequentially, but if the player has the money, it's skipping straight to the highest upgrade and I can't figure out why! Sorry for posting so much script at once, but I don't know what might be relevant. There are also several other scripts, such as the BuildManager, and the NodeUI, but I don't think the problem is there. As best I can tell it's in the Upgrade function. Please Help!

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.EventSystems;
    3.  
    4. public class Node : MonoBehaviour
    5. {
    6.     public Color hoverColor;
    7.     public Color notEnoughMoneyColor;
    8.     public Vector3 positionOffset;
    9.  
    10.  
    11.  
    12.     [HideInInspector]
    13.     public GameObject turret;
    14.     [HideInInspector]
    15.     public TurretBlueprint turretBlueprint;
    16.  
    17.     public bool isUpgraded = false;
    18.  
    19.     public bool isUpgraded1 = false;
    20.  
    21.     public bool isUpgraded2 = false;
    22.  
    23.     private Renderer rend;
    24.     private Color startColor;
    25.  
    26.     BuildManager buildManager;
    27.  
    28.     void Start ()
    29.     {
    30.         rend = GetComponent<Renderer>();
    31.         startColor = rend.material.color;
    32.  
    33.         buildManager = BuildManager.instance;
    34.  
    35.         buildManager.nbTurretsBuilt = 0;
    36.     }
    37.  
    38.     public Vector3 GetBuildPosition ()
    39.     {
    40.         return transform.position + positionOffset;
    41.     }
    42.  
    43.     void OnMouseDown ()
    44.     {
    45.         if(EventSystem.current.IsPointerOverGameObject())
    46.             return;
    47.  
    48.         if (turret != null)
    49.         {
    50.             buildManager.SelectNode(this);
    51.             return;
    52.         }
    53.  
    54.         if (!buildManager.CanBuild)
    55.             return;
    56.  
    57.         BuildTurret(buildManager.GetTurretToBuild());
    58.     }
    59.  
    60.     void BuildTurret (TurretBlueprint blueprint)
    61.     {
    62.         if (PlayerStats.Money < blueprint.cost)
    63.         {
    64.             Debug.Log("Not enough Money to build that!");
    65.             return;
    66.         }
    67.  
    68.         if (buildManager.nbTurretsBuilt <= buildManager.MaxTurretsBuilt)
    69.         {
    70.             PlayerStats.Money -= blueprint.cost;
    71.  
    72.             GameObject _turret = (GameObject)Instantiate(blueprint.prefab, GetBuildPosition(), Quaternion.identity);
    73.             turret = _turret;
    74.  
    75.             turretBlueprint = blueprint;
    76.  
    77.             GameObject effect = (GameObject)Instantiate(buildManager.buildEffect, GetBuildPosition(), Quaternion.identity);
    78.             Destroy(effect, 5f);
    79.  
    80.             Debug.Log("Turret Built!");
    81.             buildManager.nbTurretsBuilt++;
    82.         }
    83.         else
    84.         {
    85.             Debug.Log("Maximum Number of Turrets Already Built!");
    86.             return;
    87.         }
    88.      
    89.     }
    90.  
    91.     public void UpgradeTurret()
    92.     {
    93.         if (PlayerStats.Money < turretBlueprint.upgradeCost)
    94.         {
    95.             Debug.Log("Not enough Money to upgrade that!");
    96.             return;
    97.         }
    98.  
    99.         if (!isUpgraded && PlayerStats.Money >= turretBlueprint.upgradeCost)
    100.         {
    101.  
    102.             PlayerStats.Money -= turretBlueprint.upgradeCost;
    103.  
    104.             //Get rid of old turret
    105.             Destroy(turret);
    106.             buildManager.nbTurretsBuilt--;
    107.  
    108.             //Build new turret
    109.             GameObject _turret = (GameObject)Instantiate(turretBlueprint.upgradedPrefab, GetBuildPosition(), Quaternion.identity);
    110.             turret = _turret;
    111.  
    112.             GameObject effect = (GameObject)Instantiate(buildManager.buildEffect, GetBuildPosition(), Quaternion.identity);
    113.             Destroy(effect, 5f);
    114.  
    115.             isUpgraded = true;
    116.  
    117.             Debug.Log("Turret Upgraded!");
    118.             buildManager.nbTurretsBuilt++;
    119.  
    120.         }
    121.         else
    122.         {
    123.             Debug.Log("Not Enough Money To Upgrade!");
    124.                 return;
    125.         }
    126.  
    127.         if (!isUpgraded1 && PlayerStats.Money >= turretBlueprint.upgradeCost1)
    128.         {
    129.             PlayerStats.Money -= turretBlueprint.upgradeCost1;
    130.  
    131.             //Get rid of old turret
    132.             Destroy(turret);
    133.             buildManager.nbTurretsBuilt--;
    134.  
    135.             //Build new turret
    136.             GameObject _turret1 = (GameObject)Instantiate(turretBlueprint.upgradedPrefab1, GetBuildPosition(), Quaternion.identity);
    137.             turret = _turret1;
    138.  
    139.             GameObject effect1 = (GameObject)Instantiate(buildManager.buildEffect, GetBuildPosition(), Quaternion.identity);
    140.             Destroy(effect1, 5f);
    141.  
    142.             isUpgraded1 = true;
    143.  
    144.             Debug.Log("Turret Upgraded!");
    145.             buildManager.nbTurretsBuilt++;
    146.  
    147.         }
    148.         else
    149.         {
    150.             Debug.Log("Not Enough Money To Upgrade!");
    151.                 return;
    152.         }
    153.  
    154.         if (isUpgraded1 && PlayerStats.Money >= turretBlueprint.upgradeCost2)
    155.         {
    156.             PlayerStats.Money -= turretBlueprint.upgradeCost2;
    157.  
    158.             //Get rid of old turret
    159.             Destroy(turret);
    160.             buildManager.nbTurretsBuilt--;
    161.  
    162.             //Build new turret
    163.             GameObject _turret2 = (GameObject)Instantiate(turretBlueprint.upgradedPrefab2, GetBuildPosition(), Quaternion.identity);
    164.             turret = _turret2;
    165.  
    166.             GameObject effect2 = (GameObject)Instantiate(buildManager.buildEffect, GetBuildPosition(), Quaternion.identity);
    167.             Destroy(effect2, 5f);
    168.  
    169.             isUpgraded2 = true;
    170.  
    171.             Debug.Log("Turret Upgraded!");
    172.             buildManager.nbTurretsBuilt++;
    173.         }
    174.         else
    175.         {
    176.             Debug.Log("Not Enough Money To Upgrade!");
    177.                 return;
    178.         }
    179.     }
     
    Last edited: May 26, 2023
  2. mopthrow

    mopthrow

    Joined:
    May 8, 2020
    Posts:
    341
    If you edit your post and use the forum's code tags (Instert Code button) your post will be more likely get a response. It makes things much easier to read ;)
     
    Last edited: May 26, 2023
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    If you post a code snippet, ALWAYS USE CODE TAGS:

    How to use code tags: https://forum.unity.com/threads/using-code-tags-properly.143875/

    Here's how to fix that!

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    "When in doubt, print it out!(tm)" - Kurt Dekker (and many others)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.

    ----------------------------

    Tutorials and example code are great, but keep this in mind to maximize your success and minimize your frustration:

    How to do tutorials properly, two (2) simple steps to success:

    Step 1. Follow the tutorial and do every single step of the tutorial 100% precisely the way it is shown. Even the slightest deviation (even a single character!) generally ends in disaster. That's how software engineering works. Every step must be taken, every single letter must be spelled, capitalized, punctuated and spaced (or not spaced) properly, literally NOTHING can be omitted or skipped.

    Fortunately this is the easiest part to get right: Be a robot. Don't make any mistakes.
    BE PERFECT IN EVERYTHING YOU DO HERE!!


    If you get any errors, learn how to read the error code and fix your error. Google is your friend here. Do NOT continue until you fix your error. Your error will probably be somewhere near the parenthesis numbers (line and character position) in the file. It is almost CERTAINLY your typo causing the error, so look again and fix it.

    Step 2. Go back and work through every part of the tutorial again, and this time explain it to your doggie. See how I am doing that in my avatar picture? If you have no dog, explain it to your house plant. If you are unable to explain any part of it, STOP. DO NOT PROCEED. Now go learn how that part works. Read the documentation on the functions involved. Go back to the tutorial and try to figure out WHY they did that. This is the part that takes a LOT of time when you are new. It might take days or weeks to work through a single 5-minute tutorial. Stick with it. You will learn.

    Step 2 is the part everybody seems to miss. Without Step 2 you are simply a code-typing monkey and outside of the specific tutorial you did, you will be completely lost. If you want to learn, you MUST do Step 2.

    Of course, all this presupposes no errors in the tutorial. For certain tutorial makers (like Unity, Brackeys, Imphenzia, Sebastian Lague) this is usually the case. For some other less-well-known content creators, this is less true. Read the comments on the video: did anyone have issues like you did? If there's an error, you will NEVER be the first guy to find it.

    Beyond that, Step 3, 4, 5 and 6 become easy because you already understand!

    Finally, when you have errors, don't post here... just go fix your errors! Here's how:

    Remember: NOBODY here memorizes error codes. That's not a thing. The error code is absolutely the least useful part of the error. It serves no purpose at all. Forget the error code. Put it out of your mind.

    The complete error message contains everything you need to know to fix the error yourself.

    The important parts of the error message are:

    - the description of the error itself (google this; you are NEVER the first one!)
    - the file it occurred in (critical!)
    - the line number and character position (the two numbers in parentheses)
    - also possibly useful is the stack trace (all the lines of text in the lower console window)

    Always start with the FIRST error in the console window, as sometimes that error causes or compounds some or all of the subsequent errors. Often the error will be immediately prior to the indicated line, so make sure to check there as well.

    Look in the documentation. Every API you attempt to use is probably documented somewhere. Are you using it correctly? Are you spelling it correctly?

    All of that information is in the actual error message and you must pay attention to it. Learn how to identify it instantly so you don't have to stop your progress and fiddle around with the forum.
     
    thorolfyggsson likes this.
  4. thorolfyggsson

    thorolfyggsson

    Joined:
    May 25, 2023
    Posts:
    5
    Thanks for the info! I'm old in age and new at programming. It's all a learning experience...
     
    mopthrow likes this.
  5. thorolfyggsson

    thorolfyggsson

    Joined:
    May 25, 2023
    Posts:
    5
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    I told you what to do: it is time to start debugging.

    We don't possess magical knowledge of how to fix your problem. That's not a thing.

    The basic process is that you use the debugging tips I posted above to find the problem.

    By "find the problem" I mean you come back saying "I expected variable XXX to be true at line ###, but it is actually false there when I print it out... why?!"

    That's the kind of "find" we expect in software engineering. Any less is pointless.

    Once you find the problem, you may be able to reason about how to fix it.

    Since you're going from a tutorial, you could also back up to that point of the tutorial and doublecheck your work.

    Either way, if you fail to do Step #2 of "How to do a tutorial" then you are just going to remain lost. It is axiomatic that if you are going to do something, you will need to make an effort to understand what you are doing, otherwise you're just a monkey hammering on a keyboard.

    I would consider "completed" to occur only once you can explain to me what each line does. Otherwise, did you really complete it?
     
  7. mopthrow

    mopthrow

    Joined:
    May 8, 2020
    Posts:
    341
    @Kurt-Dekker I think he's finished the tutorial, he's trying to extend it on his own :) Your debugging copy pasta stands though and would be good to read and try out op.

    @thorolfyggsson The way you have your if statements set up right now is they check one after another on the same frame.

    In your upgrade function, starting on 91;
    The first if on 99 runs, and does the upgrade (it checks to see if upgrade is NOT done, it isn't, so it does it)
    Then the next if on 127 runs, and does the upgrade (it checks if upgrade1 is NOT done, it isn't, so it does it)
    Then the next if on 154 runs, and does the upgrade (it checks if the upgrade1 IS done, it is, so it upgrades to 2)

    You just did all your upgrades in one frame, at least if the player has enough money for it.

    First thing I'd recommend, is changing the condition on 154 to read !isUpgraded2 instead of isUpdgraded1. Now each of your if statements are all checking the same way (checking to see whether they themselves are false), which makes things less confusing.

    1 The fastest way to fix the all upgrading at once problem is to put the return keyword at the end of each upgrade (119, 146 and the line after 172). That way, the next ifs won't run. It'll do whichever upgrade is valid and end the function.

    2 Alternative approach is to remove your elses, and change all your if's apart from the first one to else if. Stick that else not enough money back on at the end of it all. Then it'll only do the first valid upgrade and won't bother with the rest.

    This second option is probably the better choice because right now your elses run and say not enough money when that's not necessarily the case. Eg the first else containing the not enough money message may run if the first upgrade is already built. Option two will only display not enough money if that's the case.

    Best of luck.
     
    Last edited: May 26, 2023
    thorolfyggsson likes this.
  8. thorolfyggsson

    thorolfyggsson

    Joined:
    May 25, 2023
    Posts:
    5
    That is exactly what I needed to do, and it worked perfectly! I'm unfamiliar with else if statements, having never used them inside the Brackeys tutorial, and I thank you greatly for introducing me to them! I knew it would be something simple, I just couldn't figure out how to stop all the upgrades from running through in one frame. I'd already tried the return at the end of the lines, but it gave me an unreachable code error, so I'd either misplaced them or it wasn't going to work. But your second fix did the trick, and you have my undying gratitude, good Sir!
     
    mopthrow likes this.
  9. thorolfyggsson

    thorolfyggsson

    Joined:
    May 25, 2023
    Posts:
    5
    While you are certainly correct, and I do see your point, I have a very finite amount of time with access to my project, and am on a deadline. I wish I could afford to spend hours pouring over Unity and C# literature to learn every in and out, how and why, cause and effect, and learn everything there is to learn, I simply can't afford that sort of time expenditure right now. To some small extent, I'll just have to be a monkey hammering on a keyboard until I finish this project. But your debugging tips will always be on the forefront of my mind, and I thank you for your time and effort.