Search Unity

Need Help To Understand Code

Discussion in 'Scripting' started by DulinaChandul, Oct 25, 2021.

  1. DulinaChandul

    DulinaChandul

    Joined:
    Sep 5, 2021
    Posts:
    18
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Guard : MonoBehaviour
    6. {
    7.     public float speed = 5f;
    8.  
    9.     public float waitTime = 0.3f;
    10.  
    11.     public Transform pathHolder;
    12.  
    13.     private void Start()
    14.     {
    15.  
    16.         Vector3[] wayPoints = new Vector3[pathHolder.childCount];
    17.         for (int i = 0; i < wayPoints.Length; i++)
    18.         {
    19.             wayPoints[i] = pathHolder.GetChild(i).position;
    20.         }
    21.  
    22.         StartCoroutine(followPath(wayPoints));
    23.  
    24.     }
    25.  
    26.     private IEnumerator followPath(Vector3[] waypoints)
    27.     {
    28.  
    29.         transform.position = waypoints[0];
    30.  
    31.         int targetWaypointIndex = 1;
    32.         Vector3 targetWaypoint = waypoints[targetWaypointIndex];
    33.  
    34.         while (true)
    35.         {
    36.             transform.position = Vector3.MoveTowards(transform.position, targetWaypoint, speed * Time.deltaTime);
    37.             if(transform.position == targetWaypoint)
    38.             {
    39.                 targetWaypointIndex = (targetWaypointIndex + 1) % waypoints.Length;
    40.                 Debug.Log(targetWaypointIndex);
    41.                 targetWaypoint = waypoints[targetWaypointIndex];
    42.                 yield return new WaitForSeconds(waitTime);
    43.             }
    44.  
    45.             yield return null;
    46.         }
    47.  
    48.     }
    49.  
    50.     private void OnDrawGizmos()
    51.     {
    52.         Vector3 startPosition = pathHolder.GetChild(0).position;
    53.         Vector3 prevoiusPosition = startPosition;
    54.  
    55.         foreach (Transform waypoint in pathHolder)
    56.         {
    57.             Gizmos.DrawSphere(waypoint.position, 0.3f);
    58.             Gizmos.DrawLine(prevoiusPosition, waypoint.position);
    59.             prevoiusPosition = waypoint.position;
    60.         }
    61.  
    62.         Gizmos.DrawLine(prevoiusPosition, startPosition);
    63.     }
    64.  
    65. }
    66.  
    first i apologize sorry for my Bad English

    I am have no problem with this code, But i don't no how to get next index with this code " targetWaypointIndex = (targetWaypointIndex + 1) % waypoints.Length;" i google what the meaning of "%" in programming, that said "
    Divides the left hand operand by the right hand operand and returns remainder
    "

    for example if we get the length of waypoints as 5
    i think the meaning of the code is (1(targetWayPointIndex) + 1) (it means "2") % 5 = 1;
    but in the console it shows 3, i dont know how to tell it my English is bad, sorry for that :)
     
  2. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,005
    Well, the modulo / remainder is a term from math. it specifies how much remains when you divide a number "a" by another number "b". So it's that part that can't be divided and does not give you an integer result. As we all know 10 / 5 == 2 because 5 fits 2 times into 10 and there is no remainder. However 11 / 5 is also 2 but there's a remainder of 1. That 1 could not be divided by 5. Next example is 14 / 5 which is still 2 but the remainder is now 4. Of course 15 / 5 is now 3 with a remainder of 0 again.

    If "a" and "b" are integers then

    Code (CSharp):
    1. d = a / b  // returns the integer division of a / b
    2. r = a % b // returns the remainder of the division a / b
    When you think about it, the remainder(r) is always less than the divisor (b) because if it would be as large as the divisor, it could be divided. So if you divide a number that is smaller than the divisor, the division itself would yield a 0 because the divisor does not fit into that number as it's too small. However the remainder would simply return the number as it is:

    Code (CSharp):
    1. 0 % 5 == 0
    2. 1 % 5 == 1
    3. 2 % 5 == 2
    4. 3 % 5 == 3
    5. 4 % 5 == 4
    6. 5 % 5 == 0
    So using the modulo operator which gives to just the remainder is a trick to make the index wrap around. If you have an array length of 5, you know that the highest possible index is 4 (length-1). So we can simply add 1 to the current index and take the modulo of that sum. If the sum reaches or exceeds length, it would automatically wrap around back to 0
     
  3. DulinaChandul

    DulinaChandul

    Joined:
    Sep 5, 2021
    Posts:
    18
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Piling onto Bunny's awesome wisdom, modulo is great for stepping UP through waypoints again and again in a loopy list.

    The problem is with going the other way, downwards.

    If you were instead doing:

    Code (csharp):
    1. targetWaypointIndex = (targetWaypointIndex - 1) % waypoints.Length;
    The modulo is signed and will happily return -1, -2, all the way down to
    -(waypoints.Length - 1)
    and your array dereference will be very very sad.

    One way is to use unsigned integers but those are such a colossal hassle and make a barfy mess of your code anywhere you want to use them, I really dislike using them. I always just check bounds and wrap with an if/then statement if I expect to loop bidirectionally.
     
    Bunny83 likes this.
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,005
    That's true, though there's an easy fix ^^. Since adding length to the current index does not change the value after the modulo, you can simply do this:

    Code (CSharp):
    1. // Step down
    2. index = (index + length -1) % length;
    The same could be done when stepping up as it has no effect on the outcome. It may just look more symetrical if you actually need to use both:

    Code (CSharp):
    1. // step up
    2. index = (index + length +1) % length;
    Looks crazy but works. Though if the amount you want to step up / down can vary, if you try to step down more than length you again have the same issue. There's a solution as well, though at this time it becomes quite convoluted ^^

    Code (CSharp):
    1. index = (index + length + delta % length) % length ;
    This would work with any delta, positive or negative.
     
    Kurt-Dekker likes this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    lol... if we were standing together over a beer I would shout above the din of the bar,

    "USE TWO IF STATEMENTS $@#%#$%^^!"

    :)