Search Unity

Am I dumb or is it difficult to keep best practices while using Unity?

Discussion in 'General Discussion' started by evan_ohara, Jul 20, 2019.

  1. evan_ohara

    evan_ohara

    Joined:
    Oct 28, 2016
    Posts:
    35
    My brain wonders why we have so many ways to do the same things.

    Tags collide with me wanting to use interfaces, and often times I just use whatever one occurs to me first.

    Things like GetComponent/FindComponent offer me cheap ways to solve problems when I don't want to back out into the editor. But in the end I don't like when I've done the same thing 5 different ways.

    Is it simply things like tags are there for more novice programmers? I just kinda doubt the way i'm structuring things is correct all the time because it's so difficult to be consistent. (At least for a semi-nub like me.)

    Thoughts?
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Available options allows you to select best tools for the job.
    But which tools, that only comes with an experience, as you learn pros and cons of each.
     
  3. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    I dunno about these specific tools you mention, but usually everything is there for a reason. Sometimes there may be some legacy thats not super relevant, but still has use for some people so it's left in. Usually the more work you do, the more problems you find, then you understand which tools are good for one job or another.
     
  4. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,190
    I almost always use a component as a way of tagging an object rather than an actual tag. There are legitimate uses for it but you're restricted to just one per object whereas you can stack as many components onto an object as you want. Or even better you could make a component that behaves as a collection of "tags" which are all indexed by your game.
     
  5. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    6,023
    Do you want Unity to restrict you to doing things 1 way?

    The fact is that there are many people using Unity with many different skill levels. For my space combat kit, I stopped using a lot of interfaces because (amongst other reasons) many people weren't familiar with them. For me they are easy to use, but I have some experience as a programmer. But that doesn't prevent someone from using interfaces if they want to.

    I think the problem is that you're assuming that if something exists you have some obligation to use it. I stopped using tags a long time ago, because I prefer to use direct references. Apart from 'MainCamera' which is really a static reference (Camera.Main) they don't even really exist to me.

    Do things however you like. Nobody can judge a game that runs well and is fun to play, so use that to measure how well you're doing and develop whatever practices take you there.
     
  6. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    11,792
    Because there are no best practices actually.
     
  7. Zarconis

    Zarconis

    Joined:
    Jun 5, 2018
    Posts:
    234
    Exactly.

    1) Does it work without bugs?
    2) Is it performant?
    3) Could I read it three weeks later?

    Done, move on...
     
  8. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    I would previously use tags to mark multiple different prefab types, but it became cumbersome when trying to compare objects using them, especially when it involved comparing physics layers as well, because then it just added an extra thing to compare, and it just felt like I was doing something wrong.

    Recently, I've started using tags & layers as the equivalent of HTML ids & classes respectively, and I feel that improved my workflow a lot. I now use a tag (id) for marking one unique object in each scene, and if I need multiple of this object or functionally similar types of objects, then it should probably be on a layer (class) instead.
     
  9. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Stay away from tags, I would go as far as calling it a antipattern. Use components to tag gameobjets for a certain behaviour
     
    taptpci and angrypenguin like this.
  10. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    Please let us know why, so we understand why you have this opinion.

    What problems did you run into when using tags?
    What issues solve the Components approach?
    What problems does the Components approach perhaps have?
    What are the pros and cons of either approach?
     
    Martin_H and Antypodish like this.
  11. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    I have never used tags. They are prone to bugs because no compile time support. Relying on strings like this is never a good idea.
     
    RecursiveFrog likes this.
  12. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    A lot depends on if you are more of a programmer or more of a generalist. Programmers will lean more toward managing as much through the IDE as possible because the tools and support are better. Generalists will probably lean more towards in editor tools because its 'quick and easy'.

    Over time, I've started to reduce the number of components attached to a given game object for example. Instead a component will add all the sub components it needs at runtime. This is far easier to manage IMO, at least as a programmer.
     
    Socrates and GarBenjamin like this.
  13. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    Sort of. When Unity was made, tags were already standard. I doubt that the Unity team took even 3 seconds to think about it -- their customers were game designers wanting a nicer engine, and Unity had to provide all of the standard features.

    I say sort of, since back then games were programmed with a simpler language with more built-in commands. Traditional game designers knew enough coding to work those languages, and knew they had no interest in learning C++. They aren't novice programmers -- they know raycasting and more, but not int vs. float. You could think of them as novice coders, the same way most adults are novice race-car drivers.
     
  14. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Added one in there for you.
     
    NotaNaN, Martin_H, frosted and 3 others like this.
  15. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    • As has been pointed out, you can only have one tag per GameObject where you can attach as many Components as you want. This immediately increases flexibility.
    • You can search for Components at least as well as you can search for tags. If lookup performance is important, you can easily add your own case-specific search.
    • As has been pointed out, the compiler generally won't let you refer to invalid classes, so marker Components are less error prone.
    • Often when you're marking something for a particular use (ie: "tagging it"), you will later need to attach some related data. Eg: my enemies now all need a faction. If you used a Component you have a logical place to do that, and it is trivially easy. If you used a tag now you have either some refactoring or some spaghetti... or both.
    Basically, it's both more flexible and less error prone. Honestly, I don't really understand* why Unity has tags considering that the GameObject/Component system is so fundamental to the engine and already ticks the same boxes.

    It's just a matter of using "other.GetComponent<X> != null" instead of "other.tag == x".

    * My guess is that it provides a way to do certain things without writing code.
     
    NotaNaN, Peter77 and Ryiah like this.
  16. XCPU

    XCPU

    Joined:
    Nov 5, 2017
    Posts:
    145
    Maybe I'm not understanding this but, I used tags in my pathfinding.
    Most Objects of any type aren't tagged but some I tagged FreePass, so that's the first thing checked.
    If its tagged, let it do what it wants, no cost, no other checking required, other Objects will need
    a few things to be checked about it before allow it it or not.
    Pretty easy to add new special ones later as I dream them up without messing with the checking code.
    Always just seen it as a way to group different types, just one more tool to solve something. Glad it's there.
     
  17. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    This is why seperation of concerns are so important. It boils down to that good old low coupling high cohesion
     
  18. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    That's why tags were invented (not by Unity) and it works great most of the time. But suppose you had freeness for woods creatures, plains creatures, or both. You'd need tags FreeW, FreeP, and FreeWP. That's not too bad. Also, you'd probably have a different NavMesh for each type anyway. But suppose not and you had 5 types of creatures, that's 31 tags for every combination. Suppose everything also had a 1-10 muddiness rating. A small script, on each node, could hold that:
    Code (CSharp):
    1. class NavData_t {
    2.   // freeness checkboxes:
    3.   public bool fWood, fPlain, fWater, fSwamp, fWind;
    4.  
    5.   public int muddiness;
    6. }
    Now you can easily check-off the ones that apply to each space, and no longer need a tag. A custom editor could make it look even nicer. But real games aren't going to need this: FortFight isn't that complicated and probably uses tags. Collectable hero games have simple fights. Farming games don't have difficult programming. Only if you're making Dwarven Fortress, are tags a bad idea.
     
    angrypenguin and AndersMalmgren like this.
  19. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    We use same method to tag our world colliders for ballistics material config. Probably needless of similar use cases were components are better than tags
     
  20. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    I like enums for that sort of thing. I know most people frown on things like enums, but in actual practice, I've never regretted making something an enum in a game.
     
  21. Zarconis

    Zarconis

    Joined:
    Jun 5, 2018
    Posts:
    234
    It's standard practice in other engines, don't worry bout it.
     
  22. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    I think its standard practice in game dev in general, but in enterprise land, these sorts of non extensible things are frowned upon. I remember seeing heavy use of enums in blizzard games though and that was good enough for me.
     
    Martin_H likes this.
  23. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Enums are used all the time in the enterprise world to mark entities to a certain type etc.

    I also use it for our game, in fact above mentioned material config component today only holds a enum were you can select material type like Metal, Wood, etc. In the future it will contain some more things like configure if the instance has a skin thickness instead of using actual raycasted thickness. Etc
     
  24. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    I know enterprise devs (even skilled ones) who really frown on enums (usually preferring an object with readonly members or some other more OO approach). But I'm glad to hear its not pervasive cuz enums are really nice, and with extension methods you can add a lot of convenience.
     
    Martin_H likes this.
  25. RecursiveFrog

    RecursiveFrog

    Joined:
    Mar 7, 2011
    Posts:
    350
    The thought of using layers in this way gives me great pause for several reasons

    1. Layers are a limited resource
    2. Layers are already overladen in their responsibilities, both tasked with roles pertenint to rendering and physics
    3. 3rd Party dependencies May already have used layers irresponsibly, in ways that conflict with your own, limiting their utility and interoperability.

    In my experience, layers are not to be used frivolously, as the consequences of doing so can be far reaching and non obvious. I’ve never regretted taking the time to ask myself if a problem can be solved without creating a new layer.
     
    frosted likes this.
  26. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Just use them for what they were ment for to flag entities for certain behaviour.
     
  27. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    I should've clarified that I only do this when physics and/or rendering are applied (which, by the way, I'm wondering why these are not separated into their own layer systems).

    Say for example, I had a garden with flowers and trees, and I wanted to add a feature where I can detect either all trees or all flowers within a certain radius.

    Previously, I would give each tree and flower their own "tree" and "flower" tags, then when performing a
    Physics.OverlapSphere()
    , for instance, I would've had to loop through and compare all objects in the radius and filter them by the desired tag name. Instead, I can just separate trees and flowers onto their own layer, and use the overloaded version of
    Physics.OverlapSphere()
    containing the Layermask parameter to pass in the desired layer instead, and wouldn't need to filter the results since they all are the kinds of objects I'm looking for already.
     
  28. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Main problem with using layers is really if you need to exclude stuff from lighting. The old "only 4 layers can be excluded" thing is really annoying when you want to create a special light for a specific effect.

    Having layers interact w/ both lighting and physics is just soooo annoying.
     
    Zarconis, joshcamas, Ryiah and 4 others like this.
  29. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,278
    I personally hate tags and don't use them at all. Far too limiting (one tag per object, what?) and tied to the editor, and there's really no reason to use them instead of components in my eyes - components can essentially be a tag, but also have more complex logic attached. (And multiple)

    Absolutely agree 100% oof. Layers interact with lighting, rendering, and physics. Who thought that was a good idea, I have no idea.
     
    RecursiveFrog likes this.
  30. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    I'm pretty sure every game engine before Unity. It's a quick, cheap bit mask that worked well in practice. That's really the neat thing about Unity. All they really did was copy the standard features, put them all together and make it all more generic.
     
    Peter77, Ryiah and Joe-Censored like this.
  31. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,278
    Well, that's not an excuse imo. Combining light + rendering bitmasks makes sense, but cramming physics bitmask in there just doesn't make sense, and results in a lot of issues and complications for larger projects. (For example, in my project, I'm having to do a lot of tricks with adding more gameobjects and such). In other words, not generic nor quick and cheap.

    Godot, for example, has two bitmasks - one for rendering, one for physics.
     
  32. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    was discussed multiple time over the years. Yeah, I think was bad approach, and should be resolved much earlier.
    But I am happy now, that ECS / DOTS now deals with that matter on its own. Sure, us not for everyone, but at least is an option.

    I assume, it will eventually get there, as default part of Unity editor utility.
     
  33. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    That sounds about right. Modellers like to use empties for grouping and roots. Is that what you mean by "a lot of tricks"? In my little Unity projects I've learned that even a box should be an empty with one child for the mesh, another for the collider(s) (I'm not an old-time game designer. I assume they all knew this already). I often only set the layer for the collider gameObject -- it's for physics, so having it only there seems clearer. That leaves a spot on the mesh gameObject to set a lighting layer (I don't even know what lighting layers are, but assume they're for meshes).

    If you can do the math yourself, using empties seems wasteful, but I've tried it both ways and extra objects is easier, and doesn't seem any slower.
     
  34. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    Usually I regret making something an enum. Just yesterday I wanted to print an enum's name, but I was limited to using itself.ToString(). If I had used an object I could have given it a proper name and any other data. I've been using ScriptableObjects for types of inventory item and it works great, and I can give each type a name/description/tooltip/etc.

    On the topic of tags, they seem almost useless unless it's a one-way interaction where the thing finding the tag will be doing the work. If you find something via a tag, how do you do anything with it? Probably by using a GetComponent call anyway. So, just do that to begin with.
     
    dadude123 likes this.
  35. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Just for the record, you can do a lot of that by using an extension methods to add functionality to it or evolve into using the enum into a key if you really need a lot more data.
     
  36. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,190
    You could have the extraneous information stored in a custom attribute. Below is an example where I needed to have a language code associated with a language enum.

    Code (csharp):
    1. public enum Language
    2. {
    3.     [LanguageCode("en-US")]
    4.     English,
    5.     [LanguageCode("ja-JP")]
    6.     Japanese
    7. }
     
    Martin_H likes this.
  37. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Alternatively using dictionary, with enum value as key and class / object etc. as value.
     
    Ryiah likes this.
  38. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,190
    Since enums are technically classes you can create extension methods too. I'm getting the distinct feeling that I'm starting to abuse the language and its framework at this point. :p

    https://docs.microsoft.com/en-us/do...how-to-create-a-new-method-for-an-enumeration
    Code (csharp):
    1. public static class Extensions
    2. {
    3.     public static string GetLanguageCode(this Language language)
    4.     {
    5.         if (language == Language.English) return "en-US";
    6.     }
    7. }
    8.  
    9. public enum Language { English };
     
    Ony and Antypodish like this.
  39. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Ah this is interesting.
    Go use and abuse, as long does the job for you :)

    I only suspect, that once extension values are hardcoded, they can not be changed at runtime, or can they?
    Like changing English to French i.e?
     
  40. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Abuse or not, I love this.

    This is the simple example:
    Code (csharp):
    1.  
    2.   public static String GetShortDisplayName( this Stat stat )
    3.   {
    4.     switch( stat )
    5.     {
    6.       case Stat.MovementPointsMax:
    7.         return "Movement";
    8.       case Stat.SightRange:
    9.         return "Sight";
    10.       ...
    11.     }
    12.   }
    13.  
    But it can get much more elaborate. You can do keying from the enum like so:

    Code (csharp):
    1.  
    2.       Units.Townsguard.Create( new UnitDefinition()
    3.       {
    4.         UnitCategory = UnitCategory.HeavyInfantry,
    5.         StrengthMax = 15,
    6.         SightRange = 2,
    7.         ...
    8.         UpgradesIntoIDs = new[]
    9.         {
    10.           Units.Poleaxemen, ...
    11.         },
    12.         PerkIDsPerLevel = new[]
    13.         {
    14.           new[] {PerkTypes.HardToShoot, PerkTypes.Highlander, PerkTypes.ThickClothes},
    15.           ...
    16.           new[] {PerkTypes.LightEquipment,}
    17.         }
    18.       } );
    19.  
    This is an extension method off an enum that creates and registers the unit type with the enum as a key.

    Abuse? Eh.
     
    Last edited: Jul 26, 2019
    Ryiah likes this.
  41. Extending the enums is absolutely standard, no abuse. You wouldn't find examples in the MS documentation if it wasn't recommended.
     
    Antypodish and Ryiah like this.
  42. JohnnyA

    JohnnyA

    Joined:
    Apr 9, 2010
    Posts:
    5,041
    I've often found working with enums and mecanim (for tasks like frame accurate animation syncing) was burning a lot of heap with ToString(), so I use a pattern like this quite a bit:

    Code (csharp):
    1.  
    2.     /// <summary>
    3.     /// Static extensions for Animation State
    4.     /// </summary>
    5.     public static class AnimationStateExtensions
    6.     {
    7.         /// <summary>
    8.         /// Dictionary of the states as strings.
    9.         /// </summary>
    10.         static Dictionary<int, string> animationStatesAsStrings;
    11.  
    12.         /// <summary>
    13.         /// Initialises the dictionary.
    14.         /// </summary>
    15.         static AnimationStateExtensions()
    16.         {
    17.             animationStatesAsStrings = new Dictionary<int, string>();
    18.             foreach (AnimationState value in System.Enum.GetValues(typeof(AnimationState)))
    19.             {
    20.                 animationStatesAsStrings.Add ((int)value, System.Enum.GetName(typeof(AnimationState), value));
    21.             }
    22.         }
    23.  
    24.         ///<summary
    25.         /// AsString() is a ToString() like method that doesn't allocate heap space.
    26.         /// </summary>
    27.         public static string AsString(this AnimationState state)
    28.         {
    29.             return animationStatesAsStrings[(int)state];
    30.         }
    31.     }
    32.  
    I guess this is digressing from the topic though ... :)
     
    frosted and Martin_H like this.
  43. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    I think it's mostly a case of C# saying it can fake anything Java can do. In Java enums are also classes, but can have everything else (private variables, member functions, constructors). One of C#'s things is "hey, Java coders, we got you covered".
     
  44. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Isnt java style enum just a regular class w a bunch of static final members? I think I remember them adding an enum keyword but it was just sugar.
     
  45. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Yeah, it's surprising how much garbage strings can make. I made this little util to just wrap that exact process.

    Code (csharp):
    1.  
    2.   public class StringCache<T>
    3.   {
    4.     private Dictionary< T, String > m_Cache = new Dictionary< T, string >();
    5.     private Func< T, String > m_Conversion;
    6.  
    7.     public StringCache( Func<T,String> conversion )
    8.     {
    9.       m_Conversion = conversion;
    10.     }
    11.     public String GetText( T argument )
    12.     {
    13.       String value;
    14.       if( ! m_Cache.TryGetValue( argument, out value ) )
    15.         value = m_Cache[argument] = m_Conversion(argument);
    16.       return value;
    17.     }
    18.   }
    19.  
    You generally want to use it if you need to do some basic string concat like:
     String.Format( "There are {0} items", count );
    so you check if the dictionary has stored "count" and if not, save the result for next time.
     
  46. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    When using TextMesh Pro, you can use:
    .SetText("Score {0}", score)

    rather than:
    .text = string.Format("Score {0}", score)

    to format strings in a garbage-free manner.

    There are multiple overloads that accept different arguments:
    https://docs.unity3d.com/Packages/c...TMP_Text_SetText_System_String_System_Single_

    The old scripting documentation also contains this note:
    http://digitalnativestudios.com/textmeshpro/docs/ScriptReference/TextMeshPro-SetText.html
     
  47. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Hey, that's super handy! Didn't know it was there and will definitely be using that in the future.
     
    Peter77 likes this.
  48. Zarconis

    Zarconis

    Joined:
    Jun 5, 2018
    Posts:
    234
    Y'know switching between C++ and C# is always interesting, in UE you have UObjects (30 sec spin GC (configurable), weak PTR alt known as FWeakObjectPointer ( a reference that gets nulled if GC'd), TSharedRef (usual ref counter based memory de-alloc when no references are found).

    So you still have to be very much aware of what you're doing even if there is a type of GC "type" setup and chances are if you're doing anything fancy you're stuck with good ol C++ 11. In Unity I don't really seem to care all that much, until one day a GC alloc kicks in that sends the frame rate through the gutter (usually because I've done something daft in the 500K+ lines of code and forgot about it).

    Then I start looking at all the principles to circumvent issues, avoid string manipulation where possible, local variables, proper use of math helpers like square mag instead of vec dist (or calculate it myself), caching components (GetComp etc.) and of course recycling heap objects making sure the GC never even kicks in.

    Still, I'll never actively try any of this (and more) unless it becomes an actual issue. I have to admit 95% of all my problems stem from shader complexity, lighting, shadows, art, special effects (including volumetrics, VFX etc.). But these issues are very specific to certain projects, you're not going to have the same issues as me when developing a 2D mobile game.

    Improving shader performance written by a team that most likely knows a ton more than you is always a PITA.! Shaders are complicated by default (far more than programming in general IMO). On a side note I had a quick go at a Vulkan implementation just to display basic shapes, NEVER again.
     
  49. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    This is also a feature built into C# itself, or rather two features:
    The
    String.Format
    method can be used in the above way...
    Code (CSharp):
    1. string name = "Fred";
    2.  
    3. string.Format("Hello, my name is, {0}.", name);
    4.  
    5. //Result:
    6. //     Hello, my name is, Fred.
    ...but it also has some more complex ways of displaying values in a specific format, such as limiting a decimal value to two decimal places, for instance:
    Code (CSharp):
    1. string name = "Fred";
    2. float number = 241.82651f;
    3.  
    4. string.Format("Hello, my name is, {0}, and my favourite number is, {1:0.##}.", name, number);
    5.  
    6. //Result:
    7. //     Hello, my name is, Fred, and and my favourite number is 241.83.
    8.  
    9. //In this sequence: {1:0.##}
    10. //     '1' indicates the placeholder to insert the second parameter in the string.
    11. //     ':' indicates the start of a formatting sequence
    12. //     '0' indicates a mandatory numerical value to display
    13. //     '.' is simply just the decimal place.
    14. //     '##' indicates up to two maximum optional numbers that can be displayed (more hashes = more decimal places and vice-versa)
    If you're just looking to insert variables into strings without any additional formatting though, then the string interpolation method would be more ideal; it's easier to both write and read.
    The string must have a dollar sign preceding it, and any variables can be inserted within curly braces:
    Code (CSharp):
    1. int num1 = 4;
    2. int num2 = 8;
    3.  
    4. string result = $"The sum of {num1} and {num2} is: {num1 + num2}.";
    5.  
    6. //Result:
    7. //      The sum of 4 and 8 is: 12.
    Also worth mentioning that in both the
    String.Format
    and string interpolation methods, if you want to insert a curly brace character in the string, you can escape the sequence it by typing it twice in a row:
    Code (CSharp):
    1. int num1 = 4;
    2. int num2 = 8;
    3.  
    4. string result = $"The }}sum of {num1} {{and {num2} is: {{{num1 + num2}}}.";
    5.  
    6. //Result:
    7. //      The }sum of 4 {and 8 is: {12}.
     
    Last edited: Jul 27, 2019
  50. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    String.Format is also copied from Java (sort of. Java had it 10 years earlier, but everyone knew about it before that from C, C++, and Fortran). The inline variable expansion, "Eat {amount} carrots", is from the '70's with sh and bash, and has long been a common feature of "scripting" languages.