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

Resolved IF/THEN Ranged Statements + Other script Interaction

Discussion in 'Scripting' started by Blckspawn92, Jul 20, 2023.

  1. Blckspawn92

    Blckspawn92

    Joined:
    Jul 19, 2023
    Posts:
    21
    I'm trying to make a Script that reads the Sum of another Script and adds text information based on value ranges.



    If the SUM of the other script (TMPro.TMP_Text Def_Total) is between the given ranges (Def. Total), then this script will output Classification, Base Movement, and Base AP to

    TMPro.TMP_Text Classification
    TMPro.TMP_Text Base_Movement
    TMPro.TMP_Text Base_AP

    Im not sure where to start on something like this. I'm thinking it would start with float, but I'm not sure.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    If you are contemplating rewriting a general purpose spreadsheet (as you intimated in your other post mentioning Excel), I think you want to slow down and get some more basic programming time, because such a project is deep into advanced coding territory. So deep that in the general sense, I would need perhaps a day to even begin to sketch the various subsystems involved in a generic spreadsheet creator.

    Otherwise, if you're just summing data off a bunch of lookup tables, such as what looks like the movement lookup tables for some kind of dice-based game, look into ScriptableObjects (there are bazillions of Youtube tutorials for them) for authoring and containing the data, and then those same ScriptableObjects, along with perhaps some utility classes and methods, will give you the perfect surface to construct tools such as summation and other aggregation.

    Here's the general purpose "how do I get at other scripts" blurb:

    Referencing variables, fields, methods (anything non-static) in other script instances:

    https://forum.unity.com/threads/hel...-vars-in-another-script.1076825/#post-6944639

    https://forum.unity.com/threads/accessing-a-gameobject-in-different-scene.1103239/

    It isn't always the best idea for everything to access everything else all over the place. For instance, it is BAD for the player to reach into an enemy and reduce his health.

    Instead there should be a function you call on the enemy to reduce his health. All the same rules apply for the above steps: the function must be public AND you need a reference to the class instance.

    That way the enemy (and only the enemy) has code to reduce his health and simultaneously do anything else, such as kill him or make him reel from the impact, and all that code is centralized in one place.
     
  3. Blckspawn92

    Blckspawn92

    Joined:
    Jul 19, 2023
    Posts:
    21
    Im just trying to sum up player input values from a datasheet to a tabletop game.

    Basically, the orange boxes will be the sum total of the orange lines.
    The green box is text information derived from the total defense SUM.
    All of the orange boxes will also be summed into the Blue Box.

    After reading through your links, I did decide that instead of making multiple scripts to do the calculations of each section, it might be better to make one large script to handle all of the calculations.
     
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    Make sure you categorize your data appropriately. If you're dealing with natural (discrete) numbers, use integers. If you're dealing with multipliers, percentage values/modifiers, use floating point. Never use strings to store and manipulate values, use strings only to present human readable text to player (or yourself through the development).

    In general, to transcribe a character sheet to a software model, it makes sense to leverage the benefits of the object-oriented paradigm. That way, each field can be made to do what it is expected to do, on its own. This requires you to break down the sheet into a tree-like structure, where you start from "The Sheet" and trickle down to its atomic leaf data through various intermediate boxes as shown in your picture.

    Once you have this tree-like representation, you can easily connect with lines what Deployment Cost needs and address such fields from the code.

    So if you care about how we would design and implement this, start from learning how object-oriented languages work, what are classes, properties and methods, and especially how to implement a tree-like data model.

    Ultimately you want that your actual game to query the model by doing (i.e.)
    Code (csharp):
    1. playerSheet.Inventory.AddWeapon(someWeapon);
    2. UI.Instance.InfoBox.DeploymentCostLabel.Text = playerSheet.DeploymentCost.ToString();
    That's what programming is all about. You build strong foundations, so that the logic you actually want to implement is very abstract and very light on code. Imagine building a sky rise.

    Of course, you can do it differently, but then you're just multiplying the ways of introducing errors, and it's likely it won't be as readable and maintainable in the long run, turning the final rendition of the game, or any subsequent changes into a slog.

    Because this is the curse of engineering, you get to decide which path is harder for you. Later you will learn whether this decision was good. This is why it is essential to get some prospect on how to proceed, gather as much information as possible, and then try making things one by one, while imagining them being used later. If you go through it all, regardless of how bad your prior decisions were, you will learn a lot. And if you're motivated enough, you can even fix some mistakes you made earlier.

    That's why many people will tell you to "just do do do" keep writing code and see what can be done differently/better.

    I personally always do it like I did above, I try to imagine what the end goal should be, code-wise, and then I try and architect systems that will get me there. I call this a two-way approach, where instead of only working bottom-up or top-down, you try to grasp both ends, and proceed with materializing the interface between them. This is essentially how tunnels are bored. And apparently how software is made as well.
     
  5. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    1,862
    I think the practical upshot of this good advice, for Blackspawn92, is to reorganize that "Def. Total" column into a "Min Def. Total" and "Max Def. Total" column so each column can have a simple integer, rather than the extra complexity of trying to parse strings with dashes and work it out from there.
     
    mopthrow and orionsyndrome like this.
  6. Blckspawn92

    Blckspawn92

    Joined:
    Jul 19, 2023
    Posts:
    21
    So would you suggest that I make separate scripts that to the required calculations for each section, then add it all together with another script or adding everything into a single script?
     
  7. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    524
    I believe the point is (and mine would be) to create a "class" (I don't think in terms of scripts) that is able to handle all the data aspects. There would be public properties and/or methods that aid you in constructing the model and that prevent bad data from getting in. Having all the related data in one place makes it far easier to understand and to test. Each data item is also given an appropriate unambiguous name. If you need another data point simply add it to that class.

    Speaking of testing you don't even need any real data to test. You can for instance simply set some values and then reference the with log outputs. You would expect to see your data appear in the console. If it doesn't then assigning them to text components isn't going to work.

    If the values need formatting (my suggestion) is to add formatted properties to that class or to create a second class that will handle the formatting. Do not do it 'inline" when assigning to you text fields. Again all formatting is centralized and testable. The "grid" should just reflect the model not decide how many decimal places or leading zeros and what not the output should have.
     
  8. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    @Blckspawn92
    As @tleylan points out, I'm not talking about scripting. Scripting as a term in Unity is about writing a "script", then adding it as a component to some object, which is exclusively a derivation of MonoBehaviour, at least in the standard form. C# programming is wider than that. You are free to write full on C# programs -- we call that pure C# -- which are then used by Unity scripts for greater effect.

    When I mention the sheet model, I talk about writing a pure C# object-oriented program that models the behavior of the character sheet; tabular data and spreadsheets are the textbook example of why we have the object-oriented paradigm in the first place.

    Quite frankly, if you're not on a level that you can easily make this in an afternoon, you really should invest some time in good programming courses and books. There is no "trick" we can share with you, it's a long talk and a topic of holistic knowledge, which isn't particularly complicated but we can talk about it forever.
     
    Kurt-Dekker likes this.
  9. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,917
    The standard idea is to call the first range (0-75 in your case), "range 0", the next "range 1" and so on. Somehow find that range index. Then you can use it to look up the other values from an array.

    There are standard ways of converting breakpoints into range indexes. Yours happen to be every 75. That's fairly common. Just divide:
    rangeIndex=(defTotal-1)/75
    . The -1 is so that 75 counts as 0, 150 counts as 1, and so on.

    When ranges are different odd sizes, a loop is common. Store the ranges in an array and look at breakpoints from the bottom until you find one larger:
    for(int i=0;i<R.Length;i++) { if(R[i]>=defTotal) { rangeIndex=i; break; }}
    . It's what a human would do -- if defTotal is 156 you go "75? nope, 150? nope, 225? Yes -- I'm in the 3rd range".

    Then, as mentioned, put the values in a simple class:
    class DefStats { int move; int baseAP; inf topOfRange; }
    . I only used one value for AP since you always add a d8, so the total is always X+d8. If you sometimes add 2 D6's you'd use two more fields, for example
    int dieSize; int DieAmt;
    . I added the topOfRange only in case you need method #2, since you have to write them down somewhere. And you don't need the Classification field since it's always the index+1.