Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

C#, my code snippets (and other things I want to remember)

Discussion in 'Community Learning & Teaching' started by APSchmidt, Aug 12, 2016.

  1. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    This thread is not intended to be a tutorial per se but it could function like one; which is why I created it here, in the "Community Learning and Teaching" section of the forums. What I'd like to do here is posting what I've learnt so far while working on my personal projects, mainly how to do stuff with C#.

    Looking for answers to questions about how to do stuff with C# can be awfully frustrating: answers - all kinds of them, working, not working, up to date, deprecated - are scattered everywhere. Even the Documentation and the Scripting API can be very frustrating; and what to say about Answers? Although very useful these do not provide everything. Finding answers you need can take hours on end and most of the time end up (for me at least) in more frustration. So, I'm publishing here the bits I've learnt, first, for me as a sort of remainder, second for everyone who could need the knowledge.

    Disabling, enabling or destroying child objects

    Add the script below to the parent object:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class DisableEnable : MonoBehaviour
    5. {
    6.     void Start ()                            
    7.     {
    8.         foreach (Transform child in transform)   //This code works "as is"; no need to declare anything.
    9.         {
    10.             child.gameObject.SetActive (false);   //disabling the objects
    11.             child.gameObject.SetActive (true);    //enabling the objects
    12.             Destroy(child.gameObject);            //destroying the objects
    13.         }
    14.     }
    15. }
    The moderation team is free to move this thread if they think it's not in a suitable place. :)
     
    Last edited: Mar 3, 2019
  2. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    807
    Your experience trying to find this stuff seems pretty typical -- there are lots and lots of code examples just floating like magic spells. They give the idea that the only way to do something is to Search, then cut and paste. No one explains that scripting is computer programming, which is a skill you can learn. Then you can understand the manual and write whatever you want. In my humble opinion, that's the biggest problem with the Unity scripting community (by this I mean You-Tube, Unity Answers and various blogs.) I don't think they're trying to hide that anyone can learn to program. It's just not mentioned where people notice it.

    For example, in the manual, SetActive looks like "void SetActive(bool)". That's really all you need to know. A little programming knowledge (not even Unity or C#) says that bool means either the word true or the word false. Likewise, Destroy(gameObject) is the standard command to kill yourself. That's also all you need to know. The basics of programming say you can put that Destroy in a loop "aimed at" whatever other gameObject you like (in what you wrote, each child.)

    Even if you look at what self-taught scripters say (as opposed to a programming class, or a good book,) they started with examples, but then realized they had to learn the underlying programming concepts. They didn't just make an enormous set of book-marks to all the examples they needed.
     
    APSchmidt likes this.
  3. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Update, FixedUpdate and LateUpdate

    I'm still experiencing and learning about C#; I'm an old woman so things don't go fast. :p

    I'm trying to understand the subtleties behind the different Update functions. Awake and Start are pretty easy to understand:

    Code (CSharp):
    1.  
    2.     void Awake ()
    3.     {
    4.         print ("Awake: is called when the script instance is being loaded." +
    5.             " The script must be attached to an enabled object." +
    6.             " The script doesn't need to be enabled for the function to be called.");
    7.     }
    8.  
    9.     void Start ()
    10.     {
    11.         print ("Start: is called on the frame when a script is enabled" +
    12.             " just before any of the Update methods is called the first time.");
    13.     }
    FixedUpdate, LateUpdate and Update are less obvious. I've experienced with them and, each time they appear in the following order in the console:
    1. FixedUpdate,
    2. Update,
    3. LateUpdate (maybe that's why it's called "late"?).
    Now, what I cannot grasp is the difference between Update and LateUpdate since they are called at the same rate, here 642 times in about 10 seconds, when FixedUpdate is called a bit less often, as can be seen on this capture:

    Capture.JPG

    So, Update and LateUpdate, same thing? Also, what about the difference in performance between these two and FixedUpdate?

    When I've understood this, I've made a big progress! :D
     
    Last edited: Mar 3, 2019
  4. panoskal

    panoskal

    Joined:
    Mar 31, 2017
    Posts:
    28
    Here is the documentation link for LateUpdate :

    https://docs.unity3d.com/ScriptReference/MonoBehaviour.LateUpdate.html

    From what I understand Update and LateUpdate are called every frame, their difference is that LateUpdate is called after all Update functions have been called. This is useful when you want a piece of code to be called always last, because it is affected by changes that happen inside other Update functions.

    For example, if you want your camera to follow the player, you would want it to happen every frame. By putting the code for the camera control inside LateUpdate you ensure that it is called "Late" every frame, after the player has moved and not before.

    As for FixedUpdate, I am still trying to understand that myself.
     
    APSchmidt likes this.
  5. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Thanks. I had read the documentation and "late" makes sense since it really happens last! FixedUpdate seems to reflect our computers real graphics performance. At least, that's what I understand.
     
  6. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Localization

    Scripting Unity tutorial about localization are here, scroll down to "Live Session: Localization Tools": https://unity3d.com/learn/tutorials/s/scripting

    Full play list (click on the >| icon in each video to access the following episode):

     
    Last edited: Mar 3, 2019
  7. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    First Person Character controller: clamping the horizontal rotation of the camera

    The first person character controller that Unity Technologies gives us in their Standard Assets rotates by default by 360°. In a project, I wanted it to just rotate by 120°. I managed to do that.

    Preparation:
    1. download the latest Standard Assets and open them in Unity,
    2. to get the FPS controller only, and get it right without any error, import the following assets and leave the rest:
    Capture.JPG

    Clamping the horizontal rotation of the camera:

    The script to modify is MouseLook.cs. I proceeded by imitation, trial and errors but it works! Below are the original script:

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityStandardAssets.CrossPlatformInput;
    4.  
    5. namespace UnityStandardAssets.Characters.FirstPerson
    6. {
    7.     [Serializable]
    8.     public class MouseLook
    9.     {
    10.         public float XSensitivity = 2f;
    11.         public float YSensitivity = 2f;
    12.         public bool clampVerticalRotation = true;
    13.         public float MinimumX = -90F;
    14.         public float MaximumX = 90F;
    15.         public bool smooth;
    16.         public float smoothTime = 5f;
    17.         public bool lockCursor = true;
    18.  
    19.  
    20.         private Quaternion m_CharacterTargetRot;
    21.         private Quaternion m_CameraTargetRot;
    22.         private bool m_cursorIsLocked = true;
    23.  
    24.         public void Init(Transform character, Transform camera)
    25.         {
    26.             m_CharacterTargetRot = character.localRotation;
    27.             m_CameraTargetRot = camera.localRotation;
    28.         }
    29.  
    30.  
    31.         public void LookRotation(Transform character, Transform camera)
    32.         {
    33.             float yRot = CrossPlatformInputManager.GetAxis("Mouse X") * XSensitivity;
    34.             float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * YSensitivity;
    35.  
    36.             m_CharacterTargetRot *= Quaternion.Euler (0f, yRot, 0f);
    37.             m_CameraTargetRot *= Quaternion.Euler (-xRot, 0f, 0f);
    38.  
    39.             if(clampVerticalRotation)
    40.                 m_CameraTargetRot = ClampRotationAroundXAxis (m_CameraTargetRot);
    41.  
    42.             if(smooth)
    43.             {
    44.                 character.localRotation = Quaternion.Slerp (character.localRotation, m_CharacterTargetRot,
    45.                     smoothTime * Time.deltaTime);
    46.                 camera.localRotation = Quaternion.Slerp (camera.localRotation, m_CameraTargetRot,
    47.                     smoothTime * Time.deltaTime);
    48.             }
    49.             else
    50.             {
    51.                 character.localRotation = m_CharacterTargetRot;
    52.                 camera.localRotation = m_CameraTargetRot;
    53.             }
    54.  
    55.             UpdateCursorLock();
    56.         }
    57.  
    58.         public void SetCursorLock(bool value)
    59.         {
    60.             lockCursor = value;
    61.             if(!lockCursor)
    62.             {//we force unlock the cursor if the user disable the cursor locking helper
    63.                 Cursor.lockState = CursorLockMode.None;
    64.                 Cursor.visible = true;
    65.             }
    66.         }
    67.  
    68.         public void UpdateCursorLock()
    69.         {
    70.             //if the user set "lockCursor" we check & properly lock the cursos
    71.             if (lockCursor)
    72.                 InternalLockUpdate();
    73.         }
    74.  
    75.         private void InternalLockUpdate()
    76.         {
    77.             if(Input.GetKeyUp(KeyCode.Escape))
    78.             {
    79.                 m_cursorIsLocked = false;
    80.             }
    81.             else if(Input.GetMouseButtonUp(0))
    82.             {
    83.                 m_cursorIsLocked = true;
    84.             }
    85.  
    86.             if (m_cursorIsLocked)
    87.             {
    88.                 Cursor.lockState = CursorLockMode.Locked;
    89.                 Cursor.visible = false;
    90.             }
    91.             else if (!m_cursorIsLocked)
    92.             {
    93.                 Cursor.lockState = CursorLockMode.None;
    94.                 Cursor.visible = true;
    95.             }
    96.         }
    97.  
    98.         Quaternion ClampRotationAroundXAxis(Quaternion q)
    99.         {
    100.             q.x /= q.w;
    101.             q.y /= q.w;
    102.             q.z /= q.w;
    103.             q.w = 1.0f;
    104.  
    105.             float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan (q.x);
    106.  
    107.             angleX = Mathf.Clamp (angleX, MinimumX, MaximumX);
    108.  
    109.             q.x = Mathf.Tan (0.5f * Mathf.Deg2Rad * angleX);
    110.  
    111.             return q;
    112.         }
    113.  
    114.     }
    115. }

    and the lines I added:
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityStandardAssets.CrossPlatformInput;
    4.  
    5. namespace UnityStandardAssets.Characters.FirstPerson
    6. {
    7.     [Serializable]
    8.     public class MouseLook
    9.     {
    10.         public bool clampHorizontalRotation = true;
    11.         public float minimumY = -90f;
    12.         public float maximumY = 90f;
    13.  
    14.         public void LookRotation(Transform character, Transform camera)
    15.         {
    16.             if (clampHorizontalRotation)
    17.             {
    18.                 m_CharacterTargetRot = ClampRotationAroundYAxis (m_CharacterTargetRot);
    19.             }
    20.         }
    21.  
    22.         Quaternion ClampRotationAroundYAxis (Quaternion q)
    23.         {
    24.             q.x /= q.w;
    25.             q.y /= q.w;
    26.             q.z /= q.w;
    27.             q.w = 1.0f;
    28.  
    29.             float angleY = 2.0f * Mathf.Rad2Deg * Mathf.Atan (q.y);
    30.             angleY = Mathf.Clamp (angleY, minimumY, maximumY);
    31.             q.y = Mathf.Tan (0.5f * Mathf.Deg2Rad * angleY);
    32.  
    33.             return q;
    34.         }
    35.     }
    36. }
     
    Last edited: Mar 3, 2019
  8. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    FixedUpdate

    I was watching the Update and FixedUpdate tutorial and I noticed that something is not said in the video:

    - FixedUpdate depend on how the "time" is set in your project.

    The "time" setting can be found in Edit/Project Settings/Time; it's set by default to 0.02, so, when I call FixedUpdate in a script, the time between two FixedUpdate will always be 0.02:

    fixedupdate1.JPG
    It's interesting to note that the first Update also have the value of 0.02.

    If I modify the "time" setting to 1, the time between two FixedUpdate will also be 1:

    fixedupdate2.JPG
    It's interesting to note that the first Update will still have the value of 0.02. I don't know why but maybe someone can answer this?
     
    Last edited: Mar 3, 2019
  9. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,670
    If you are interested in the callback methods and execution order:
    https://docs.unity3d.com/Manual/ExecutionOrder.html

    Or event functions:
    https://docs.unity3d.com/Manual/EventFunctions.html

    Time and Framerate management:
    https://docs.unity3d.com/Manual/TimeFrameManagement.html
    (This discusses Update vs FixedUpdate)

    All of these come from Unity's scripting overview:
    https://docs.unity3d.com/Manual/ScriptingConcepts.html

    ... and @panoskal is correct "Scripting", "Coding" and "Programming" can be learned as a skill independent of Unity.

    Many people learn coding as a means to an end to guide Unity. Coding concepts can be learned independently of Unity and applied to Unity. C# is a standalone language that can be used to create independent applications or programs. Now, this link is somewhat stale, but could give you a place to start:
    https://forum.unity3d.com/threads/getting-started-with-coding-for-unity.113937/
     
    APSchmidt likes this.
  10. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Thank you very much @Adam-Buckner!
     
  11. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Fading a material colour in and out in time

    I'm proud, it's the first time I manage to figure out something by myself: https://stackoverflow.com/questions/43944926/lerp-the-alpha-value-of-a-color/43947418#43947418

    The question was about making the alpha layer of a material colour fade in and out in time. I knew that using Color.Lerp wouldn't work and I remembered something I had read in a scripting tutorial here; after multiple trials, I eventually came up with this, and it works!

    Set the material "rendering mode" to "transparent" first; then apply the script to the object.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class NewColour : MonoBehaviour
    6. {
    7.     //Set the material "rendering mode" to "transparent" in the inspector
    8.     public Renderer rend;
    9.  
    10.     void Start ()
    11.     {
    12.         rend = GetComponent<Renderer> ();
    13.     }
    14.  
    15.     void FixedUpdate ()
    16.     {
    17.         rend.material.color = new Color (0f, 0.5f, 1f, Mathf.PingPong(Time.time, 1));
    18.     }
    19. }
    The colour is blue RGB (0, 128, 255) and Mathf.PingPong(Time.time, 1) makes the alpha layer fade in and out. :)
     
    Last edited: Mar 3, 2019
  12. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,670
    FWIW: for this there may be some advantage to setting the material's render mode to "fade". I can't remember the exact reason, but my memory tells me that "transparent" is for making things like glass and "fade" is for fading out solid objects.

    Let me see what I can find.

    [edit]

    I found this:
    https://docs.unity3d.com/Manual/StandardShaderMaterialParameterRenderingMode.html

    ... By googling material and getting to this page:
    https://docs.unity3d.com/Manual/Materials.html

    ... and then choosing standard shader from the built in shaders section:
    https://docs.unity3d.com/Manual/shader-StandardShader.html

    ... and the paging down until I got to the material parameters.

    Might be worth a look, as all of this section looks interesting.

    Long story short, that first page on the parameters talks about the difference between "transparent" and "fade".
     
    Last edited: May 15, 2017
    APSchmidt likes this.
  13. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Thank you for the precisions!

    My object with the "fade" rendering mode, alpha layer set to 0:

    Capture.JPG

    and with the "transparent" rendering mode, alpha layer set to 0:

    Capture2.JPG
     
    Last edited: Mar 3, 2019
  14. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    For memory:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BehaviourScript : MonoBehaviour
    6. {
    7.     /*Here variables are defined.*/
    8.  
    9.     /*Use Awake () and/or Start () for initialization
    10.     of the above mentioned variables.
    11.     Custom methods can also be called in Awake () and Start ().*/
    12.  
    13.     /*Awake is called - one time only - if the script is attached
    14.     to an active game object, even if the script is not enabled.*/
    15.     void Awake ()
    16.     {
    17.         DisableObject ();
    18.     }
    19.  
    20.     /*Start is called - one time only -  if the script is enabled
    21.     and attached to an active game object.*/
    22.     void Start ()
    23.     {
    24.        
    25.     }
    26.  
    27.     /*Use the different Update methods to act on the
    28.     variables and call custom methods.*/
    29.  
    30.     /*Update is called once per frame.*/
    31.     void Update ()
    32.     {
    33.        
    34.     }
    35.  
    36.     /*FixedUpdate is called accordingly to the "time" settings
    37.     in your project (see post #8 in this thread.*/
    38.     void FixedUpdate ()
    39.     {
    40.        
    41.     }
    42.  
    43.     /*LateUpdate is called once all the other Update methods
    44.     have been successfully called.*/
    45.     void LateUpdate ()
    46.     {
    47.        
    48.     }
    49.  
    50.     /*Write custom methods below and call them in
    51.     Awake (), Start (), or one of the Update () functions.*/
    52.     void DisableObject ()
    53.     {
    54.         /*Define local (temporary) variables*/
    55.         float delay = 3f;
    56.  
    57.         print(delay);
    58.         GameObject.Destroy(gameObject, delay);
    59.     }
    60. }
     
  15. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    I just dug up this thread of mine and updated some of its content, for clarity. :)
     
  16. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    I made this simple clock tutorial; it's an ordinary clock with arms that rotate; it shows the local time of the computer. it's good and I like it but I wanted to make a digital clock. I found several tutorials out there on the web but I wanted to find a solution for myself. After experimenting with the script provided by the tutorial I eventually found out that making a digital clock was a very simple task:
    1. create a UI Text and place it wherever you want;
    2. create a C# script and reference this UI text as a private text component;
    3. attach the script to the UI text.
    Here is the script:
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4.  
    5. public class DigitalClock : MonoBehaviour
    6. {
    7.     private Text clock;
    8.  
    9.     private void Start()
    10.     {
    11.         clock = GetComponent<Text>();
    12.     }
    13.  
    14.     private void Update()
    15.     {
    16.         DateTime time = DateTime.Now;
    17.  
    18.         clock.text = DateTime.Now.ToString();
    19.     }
    20. }
    Here you go! A digital clock!

    Capture.JPG
     
  17. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    A tutorial about how to make a mirror in Unity. I made it with 2018.2 without any problem.

     
  18. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    807
    RE: fade vs. transparent. I think it's about the specular lighting.

    Fade means you want the object to become completely invisible in a magical way. To fade out. Even a 1/2-faded object should look magically 1/2 there. Whereas transparent means you want it to look like a real-world transparent object. Anyone would agree that 2nd glowing sphere represents a real fully transparent object. If we put it underwater, or in different lighting, we'd never see it. There's currently a white glare on parts of it since that's how transparent things work under strong light. A windshield is 100% transparent, but a decent game engine puts little glares on it as it turns.

    In mechanical terms, that glare is the Specular Highlight. Fade affects it, transparent doesn't. Either might be what you want, depending.
     
  19. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Yeah, that's exactly what they do. :)
     
  20. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Just used var in a script. Okay, what about it? :) I remember reading threads here about using var, how good it was or bad. At the time it just seemed to me that people who used var just knew what they were doing; I haven't changed my mind; back then though I didn't really care thinking that things would come to me if needed, when needed.

    And here I am, using var. I have this function:
    Code (CSharp):
    1.     private void StartAudio()
    2.     {
    3.         audioManager.ambientAudio.clip = audioManager.ambientClip;
    4.         audioManager.ambientAudio.loop = true;
    5.         audioManager.ambientAudio.pitch = 0.5f;
    6.         audioManager.ambientAudio.spatialBlend = 1f;
    7.     }
    I was reading it and was thinking: "four times audioManager.ambientAudio?", wow, there must be something better to do. So I wanted to create a local variable but what kind of variable? If I'm not wrong, nothing fits here (if someone knows better, please tell me! :))

    Except var!
    Code (CSharp):
    1.     private void StartAudio()
    2.     {
    3.         var ambientAudioSettings = audioManager.ambientAudio;
    4.  
    5.         ambientAudioSettings.clip = audioManager.ambientClip;
    6.         ambientAudioSettings.loop = true;
    7.         ambientAudioSettings.pitch = 0.5f;
    8.         ambientAudioSettings.spatialBlend = 1f;
    9.     }
    This script is going to be full of functions that will be on the same model. Another one:
    Code (CSharp):
    1.     public static void FootstepAudio()
    2.     {
    3.         var playerAudioSettings = audioManager.playerAudio;
    4.  
    5.         if(audioManager == null || playerAudioSettings.isPlaying)
    6.             return;
    7.  
    8.         int index = Random.Range(0, audioManager.walkingClips.Length);
    9.  
    10.         playerAudioSettings.clip = audioManager.walkingClips[index];
    11.         playerAudioSettings.playOnAwake = false;
    12.         playerAudioSettings.volume = 0.5f;
    13.         playerAudioSettings.Play();
    14.     }

    Still learning! ;)

    Edit: read further below.
     
    Last edited: Jul 14, 2019
  21. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    4,624
    I'm not good at Audio or audio programming, so I have no idea what is "audioManager".
    But
    Code (CSharp):
    1. var something = value;
    is equal to
    Code (CSharp):
    1. <type> something = value;
    where <type> is value's type.

    So if you check what audioManager.ambientAudio's type you will know what you can var be replaced. In fact, in order to know what kind of members you can have in those four lines, you have to know the type of ambientAudio.
    It's somewhat matter of taste (if you don't care about ease of change later and quick overview of your code), I like my types explicitly stated because I know what to expect from them when I change/add to code.

    So the "nothing fits here" is a false assumption. ambientAudio's type fits there. Whatever it is.
     
    APSchmidt likes this.
  22. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Thanks for the reply !

    audioManager is an instance of a script named AudioManager and ambientAudio is an AudioSource. What should replace var? :)
     
  23. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    4,624
    You just said it is an AudioSource. :)
     
  24. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    It does work. Thanks! :)

    Is there really no reason at all to use var?
     
  25. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    807
    The normal internet does a decent job with Searches like "var C#", but there's one game thing about var:

    Game programmers often used a simplified language where you didn't even declare variables, n=5 and name="cat" were good enough. Learning about int or float or string seemed overly complicated, so wasn't in the language. To catch when you spelled a variable wrong, some game languages made you declare, but only using "var n" (short for "variable"). So before Unity was a thing, game programmers were using var aas = myAudio.source. When Unity was created, it had you write scripts in UnityScript. not C#. It copied that "var" thing.

    So sometimes when you see var, it's someone showing off how they learned a new C# feature. But other times it's just a regular game programmer doing things the old-fashioned way.
     
    APSchmidt likes this.
  26. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    4,624
    In professional C# development there are two sects:
    - those who love "var" because it make them not to think about variable types, so they can concentrate on what they are writing (allegedly)
    - and those (including me), who like to see what the variable is without hovering mouse and opening an IDE, at least in languages like C# (you don't want to know what I have done in Javascript for example ;) )

    It is ultimately up to you to decide if the type means unbearable burden which you don't need or you want to see at a glance what the type is and what this variable is all about. Neither is strictly wrong, as I mentioned earlier, it is a matter of taste. We really don't have to flog the var users before we burn them at stake. No biggie.
     
    Last edited: Jul 14, 2019
    APSchmidt likes this.
  27. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    It took me half of the night (unsuccessfully) and this morning (successfully) to make it so something happens between two specific hours of the day. I had to search the web (hard) before finding how to do that; the more difficult part being "how do I make sure that what I have in plan will work for people who use a 12 hours (am/pm) format?", my computer using a 24 hours format.

    I eventually came up with the code below, but I'm not even sure that if will work for people who use a 12 h format and this is something I cannot test. I wonder if
    Code (CSharp):
    1.         Debug.Log(nightTime);
    returns (date) 10:00:00, if you are using a 12h format.

    I welcome your feedback on this. ;)

    Code (CSharp):
    1. using System;
    2. using System.Globalization;
    3. using UnityEngine;
    4.  
    5. public class SceneTimeManager : MonoBehaviour
    6. {
    7.     private void Update()
    8.     {
    9.         DateTime nightTime = DateTime.ParseExact("22:00", "HH:mm", CultureInfo.InvariantCulture);
    10.         Debug.Log(nightTime);
    11.         DateTime dayTime = DateTime.Parse("6:00");
    12.         DateTime now = DateTime.Now;
    13.  
    14.         if(now >= nightTime && now <= dayTime)
    15.         {
    16.             SetNightTime();
    17.         }
    18.     }
    19. }
     
  28. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    So, I tested my script the other day; I started the game at 00 h 47 mn and... for reasons that I should have foreseen, the script didn't work, I still got the day scene.

    The reason for that is that midnight is not 24:00 (or 12:00) for our computers, it is 00:00. Consequently, the script will never work since one of the conditions will never fill:
    • if you start the game at 22:24, now >= nightTime will fill but now <= dayTime will not since 22:24 is far over 6:00,
    • if you start the game at 1:00, now <= dayTime will fill but now >= nightTime will not since 1:00 is far below 22:00.
    The fix is easy:
    1. set the default scene to night,
    2. modify the script so that it sets the day scene between 6 am and 10 pm (6:00 and 22:00).
    Code (CSharp):
    1.     private void Update()
    2.     {
    3.         DateTime nightTime = DateTime.ParseExact("22:00", "HH:mm", CultureInfo.InvariantCulture);
    4.         DateTime dayTime = DateTime.Parse("06:00");
    5.         DateTime now = DateTime.Now;
    6.  
    7.         if(now >= dayTime && now <= nightTime)
    8.         {
    9.             SetDayTime();
    10.             Debug.Log("Setting day time!");
    11.         }
    12.     }
     
    Last edited: Jul 23, 2019
  29. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Something I never remember: how to use an array to assign a random value to some property:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class MaxParticlesSettings : MonoBehaviour
    4. {
    5.     private ParticleSystem particles;
    6.     private int[] maxParticlesToEmit = new int[] { 500, 1000, 1500 };
    7.     int index;
    8.  
    9.     private void Start()
    10.     {
    11.         particles = GetComponent<ParticleSystem>();
    12.         index = Random.Range(0, maxParticlesToEmit.Length);
    13. }
    14.  
    15.     private void Update()
    16.     {
    17.         ParticleSystem.MainModule main = particles.main;
    18.         main.maxParticles = maxParticlesToEmit[index];
    19.     }
    20. }
     
  30. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    I used the particles system as an example for this, not the best example in my opinion. I like settings random values to the number of particles emitted by fires and sparks in order to give some life to the scene. For this, I have a better script.
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class MaxParticlesSettings : MonoBehaviour
    4. {
    5.     private ParticleSystem particles;
    6.     private const int minLevelParticles = 250;
    7.     private const int maxLevelParticles = 1000;
    8.     private int levelParticles;
    9.  
    10.     private void Start()
    11.     {
    12.         particles = GetComponent<ParticleSystem>();
    13.         levelParticles = Random.Range(minLevelParticles, maxLevelParticles);
    14.  
    15.         ParticleSystem.MainModule main = particles.main;
    16.         main.maxParticles = levelParticles;
    17.     }
    18. }
     
  31. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    FPS counter and IEnumerator. I use an FPS counter in my projects; I tried several different scripts, all of them gave the same results so I picked one that I liked better and it is the FPSCounter script Annop "Nargus" Prapasapong shared on the Unity Wiki in 2012. Not much recent but it works, so...

    The script contains a coroutine and an infinite for loop, both of them I am not much familiar with.
    Code (CSharp):
    1. /********************
    2. * FPS COUNTER
    3. * Written by: Annop "Nargus" Prapasapong
    4. * Created: 7 June 2012
    5. **************************/
    6. using System.Collections;
    7. using UnityEngine;
    8. using UnityEngine.UI;
    9.  
    10. public class FPSCounter : MonoBehaviour
    11. {
    12.     public float frequency = 0.5f;
    13.  
    14.     public int FramesPerSec { get; protected set; }
    15.  
    16.     private Text counter;
    17.  
    18.     private void Start()
    19.     {
    20.         counter = GetComponent<Text>();
    21.         counter.text = "";
    22.         StartCoroutine(FPS());
    23.     }
    24.  
    25.     private IEnumerator FPS()
    26.     {
    27.         for(; ; )
    28.         {
    29.             int lastFrameCount = Time.frameCount;
    30.             float lastTime = Time.realtimeSinceStartup;
    31.             yield return new WaitForSeconds(frequency);
    32.  
    33.             float timeSpan = Time.realtimeSinceStartup - lastTime;
    34.             int frameCount = Time.frameCount - lastFrameCount;
    35.  
    36.             FramesPerSec = Mathf.RoundToInt(frameCount / timeSpan);
    37.             counter.text = FramesPerSec.ToString() + " FPS";
    38.         }
    39.     }
    40. }
     
  32. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Something else I keep forgetting and need to search for when I need it...

    How to make a raycast visible in the scene view

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class DrawRaycast : MonoBehaviour
    6. {
    7.     public bool drawDebugRaycast;
    8.     public float distance = 1.5f;
    9.  
    10.     private new Rigidbody2D rigidbody2D;
    11.     private Vector2 lookDirection = new Vector2(1, 0);
    12.     private Vector2 offset = Vector2.up * 0.5f;
    13.     private LayerMask layerMask;
    14.  
    15.     private void Start()
    16.     {
    17.         rigidbody2D = GetComponent<Rigidbody2D>();
    18.         layerMask = LayerMask.GetMask("NPC");
    19.     }
    20.  
    21.     private void Update()
    22.     {
    23.         Vector2 position = rigidbody2D.position;
    24.         RaycastHit2D raycastHit2D = Physics2D.Raycast(position + offset, lookDirection, distance, layerMask);
    25.  
    26.         if(drawDebugRaycast)
    27.         {
    28.             Color colour = raycastHit2D ? Color.magenta : Color.green;
    29.             Debug.DrawRay(position + offset, lookDirection * distance, colour);
    30.         }
    31.     }
    32. }
    The line
    Code (CSharp):
    1.             Color colour = raycastHit2D ? Color.magenta : Color.green;
    uses a ?: operator. It means that if the raycast has hit its intended target, the drawn line will be magenta, otherwise, it will be green.

    The images below illustrate the ?: operator.

    Sans-titre-2.jpg
    Sans-titre-1.jpg
     
    Last edited: Nov 8, 2019
  33. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    807
    The last line should maybe be: lookDirection.normalized * distance (add normalized)

    The issue is that recasts don't care about the length, but DrawRay does. They don't work the same. Suppose lookDirection is (15,7) -- almost 45 degrees, but not quite. And the distance is 5. Raycasts will go along (15,7) only out to 5. Going about 1/4th of that line. But DrawRay would go (15,7)*5, which is much further. Normalizing crunches it down to a standard short line, so the *5 gives a real distance of 5.
     
    APSchmidt likes this.
  34. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    My post was not about raycasts by themselves, it was about how to cast a line to make them visible. :)
    Not sure I understand that.

    I made a test, with Unity 2020.1.0a11, where I put two sprites:
    • one at 0, 0, 0,
    • one at 35.3, -28.24, 0.
    I modified the script and added a debug.log to track when the raycast hits its target or not. I noticed that the raycast (and the line) must be quite longer than the real distance between the two objects so that the hit happens.

    On the images below you can see that the message in the console confirms that the hit happened. On the other hand, if I reduce the ray distance, from 45.17 to 45.16 (image 1), the hit doesn't happen. I haven't calculated the real distance between the two objects.

    Sans-titre-1.jpg
    Sans-titre-2.jpg
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class DrawRaycast : MonoBehaviour
    6. {
    7.     public bool drawDebugRaycast;
    8.     public float distance = 22f;
    9.     public Vector2 offset = Vector2.up * 0.5f;
    10.     public Vector2 lookDirection = new Vector2(1, 1);
    11.  
    12.     private new Rigidbody2D rigidbody2D;
    13.     private LayerMask layerMask;
    14.  
    15.     private void Start()
    16.     {
    17.         rigidbody2D = GetComponent<Rigidbody2D>();
    18.         layerMask = LayerMask.GetMask("NPC");
    19.     }
    20.  
    21.     private void Update()
    22.     {
    23.         Vector2 position = rigidbody2D.position;
    24.         RaycastHit2D raycastHit2D = Physics2D.Raycast(position + offset, lookDirection, distance, layerMask);
    25.  
    26.         if(drawDebugRaycast)
    27.         {
    28.             Color colour = raycastHit2D ? Color.magenta : Color.green;
    29.             Debug.DrawRay(position + offset, lookDirection * distance, colour);
    30.         }
    31.  
    32.         if(Input.GetKeyDown(KeyCode.X))
    33.         {
    34.             RaycastHit2D hit = Physics2D.Raycast(origin: position + offset, direction: lookDirection, distance: distance, layerMask: layerMask);
    35.             if(hit.collider != null)
    36.             {
    37.                 Debug.Log("Raycast has hit the object " + hit.collider.gameObject);
    38.             }
    39.         }
    40.     }
    41. }
     
    Last edited: Nov 8, 2019
  35. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    807
    Let me rephrase that. Depending on lookDirection, the drawRay in that code will be too long or short. Sometimes much, much too long.

    With the lookDirection variable set as Vector2(1,0), the raycast and drawRay are the same. But if you changed it to (2,0), the raycast won't change, but drawRay will go twice as far, making it wrong. Raycasts and drawRay use slightly different rules for length.
     
  36. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Okay. I didn't keep my test so I won't be able to test that right now but I'll remember. :)
     
  37. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    2,768
    Well well, I don't think I ever read that in tutorials, and I've done a lot of them. I knew about the camelCase naming convention, not about the PascalCase. I had seen variables names beginning the m_ prefix in scripts but it wasn't clear that it was actually a naming convention to be used in Unity.

    Fount in the John Lemon's Haunted Jaunt tutorial at https://learn.unity.com/tutorial/pl...65ddedbc2a08d53c7acb#5caf6e8cedbc2a08d53c846a.
     
  38. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    807
    Way back, people wrote multi-word variables using an underscore, since it looked like a space: num_of_cats. In Pascal, a 30-year-old programming language, it was more common to use numOfCats. Pascal wasn't all that popular, but was adopted by some Universities for teaching, so was pretty well known. Much later, Java adopted the same style, and Java was extremely popular (this was before C# even existed. Microsoft used Visual Basic, where var names tended to be n1 or g).

    By the time someone decided to make a word for it, which isn't really needed, Camel-case seemed like a fun thing to say. PacalCase would sound weird, since no one now has heard of it, but it also sounds more official and like you're paying tribute to history. But, as an analogy, the standard knot for tying shoes has a name. Shoes are getting tied just fine by people who don't know that name or care.
     
    APSchmidt likes this.