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

Waypoint after waypoint

Discussion in 'Scripting' started by mattukat2go, Aug 24, 2020.

  1. mattukat2go

    mattukat2go

    Joined:
    Aug 10, 2020
    Posts:
    33
    Hello everybody!

    As I'm working my way through Unity - I love it so far! - I got always more questions then answers. The most urgent on is the following: I implemented a Waypoint via this tutorial and it works fine so far but I want to add another waypoint after I reach the first one... and so on. How can I do that?

    Here is the code I used from the tutorial and I would be very grateful if someone could help me.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class Waypoint : MonoBehaviour
    7. {
    8.     private Image iconImg;
    9.     private Text distanceText;
    10.  
    11.     public Transform player;
    12.     public Transform target;
    13.     public Camera cam;
    14.  
    15.     public float closeEnoughDist;
    16.  
    17.     private void Start()
    18.     {
    19.         iconImg = GetComponent<Image>();
    20.         distanceText = GetComponentInChildren<Text>();
    21.     }
    22.  
    23.  
    24.     private void Update()
    25.     {
    26.         if (target != null)
    27.         {
    28.             GetDistance();
    29.             CheckOnScreen();
    30.         }
    31.     }
    32.  
    33.     private void GetDistance()
    34.     {
    35.         float dist = Vector3.Distance(player.position, target.position);
    36.         distanceText.text = dist.ToString("f1") + "m";
    37.  
    38.         if (dist < closeEnoughDist)
    39.         {
    40.             Destroy(gameObject);
    41.         }
    42.     }
    43.  
    44.     private void CheckOnScreen()
    45.     {
    46.         float thing = Vector3.Dot((target.position - cam.transform.position).normalized, cam.transform.forward);
    47.  
    48.         if(thing <= 0)
    49.         {
    50.             ToggleUI(false);
    51.         }
    52.         else
    53.         {
    54.             ToggleUI(true);
    55.             transform.position = cam.WorldToScreenPoint(target.position);
    56.         }
    57.     }
    58.  
    59.     private void ToggleUI(bool _value)
    60.     {
    61.         iconImg.enabled = _value;
    62.         distanceText.enabled = _value;
    63.     }
    64.  
    65.  
    66.  
    67. }
    68.  
     

    Attached Files:

  2. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,589
    Instead of having a single target, you'd want to have a List or Queue of target Transforms.
    A Queue offers the advantage that the order in which you queue the waypoints is the order in which you dequeue them. This can be something you desire or not depending on the game design, but if it's a path of waypoints you want to follow, it should be beneficial.
    https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.queue-1?view=netcore-3.1

    After reaching the current waypoint (the first element of the Queue, you can look at it using Peek()), you'd dequeue the waypoint and repeat the same process for the next (now first) waypoint in the queue.
    Once the Queue is empty you have visited all the waypoints in order and can destroy the object - even tho you could also just disable and reuse it later on instead. As a rule of thumb, you never want to destroy objects at runtime, since this creates loose references known as garbage, which will have to be collected by the garbage collector, which can cause spikes in frametimes, which is perceived as stutter.

    If you require a code example let me know.
    I personally prefer an algorithmic explanation as it leaves implementation details open.
     
  3. mattukat2go

    mattukat2go

    Joined:
    Aug 10, 2020
    Posts:
    33
    Hey! This sounds exactly like me thing! And I would love the get your code, since I'm totally depending on C# Tutorials... :(
     
  4. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,589
    I wrote the changes in the forum editor so there may be some typos:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. public class Waypoint : MonoBehaviour
    6. {
    7.     private Image iconImg;
    8.     private Text distanceText;
    9.     public Transform player;
    10.     public Camera cam;
    11.     public float closeEnoughDist;
    12.     public List<Transform> inspectorTargets;
    13.     private Queue<Transform> targets;
    14.  
    15.     private void Start()
    16.     {
    17.         iconImg = GetComponent<Image>();
    18.         distanceText = GetComponentInChildren<Text>();
    19.  
    20.         // Since to my knowledge Queue does not show up in the inspector,
    21.         // i gave you a List 'inspectorTargets' where you can put targets through the inspector.
    22.         // That's its only purpose. If you fill the Queue through code you can remove that part.
    23.         targets = new Queue(inspectorTargets.ToArray());
    24.     }
    25.     private void Update()
    26.     {
    27.         if (targets != null && targets.Count > 0)
    28.         {
    29.             GetDistance();
    30.             CheckOnScreen();
    31.         }
    32.     }
    33.     private void GetDistance()
    34.     {
    35.         float dist = Vector3.Distance(player.position, targets.Peek().position);
    36.         distanceText.text = dist.ToString("f1") + "m";
    37.         if (dist < closeEnoughDist)
    38.         {
    39.             targets.Dequeue();
    40.             if(targets.Count == 0){
    41.                 gameObject.SetActive(false); // This is optional. Could destroy. Or let it run.
    42.             }
    43.         }
    44.     }
    45.     private void CheckOnScreen()
    46.     {
    47.         float thing = Vector3.Dot((targets.Peek().position - cam.transform.position).normalized, cam.transform.forward);
    48.         if(thing <= 0)
    49.         {
    50.             ToggleUI(false);
    51.         }
    52.         else
    53.         {
    54.             ToggleUI(true);
    55.             transform.position = cam.WorldToScreenPoint(targets.Peek().position);
    56.         }
    57.     }
    58.     private void ToggleUI(bool _value)
    59.     {
    60.         iconImg.enabled = _value;
    61.         distanceText.enabled = _value;
    62.     }
    63. }
    I hope this runs as is, cant check right now. You should work on improving your coding skills tho, as you will never find a script just like you need it, and will always be required to do little changes here and there. A great place to start would be the Unity introductions, or the Sebastian Lague youtube series on Gamedevelopment using Unity + C#.
     
  5. mattukat2go

    mattukat2go

    Joined:
    Aug 10, 2020
    Posts:
    33
    Thank you very much! I'll try that! I'll definitely going to work on that. It's just my week number 2 or so in Unity!
     
  6. mattukat2go

    mattukat2go

    Joined:
    Aug 10, 2020
    Posts:
    33
    Hey, I tried it but sadly I get this error. Could you please have another look?
    Best regards!
     

    Attached Files:

  7. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,589
    I just missed to add the type of the Queue there, my fellow german ;)
    Code (CSharp):
    1. targets = new Queue<Transform>(inspectorTargets.ToArray());
     
  8. mattukat2go

    mattukat2go

    Joined:
    Aug 10, 2020
    Posts:
    33
    Works like a charm - oder auch vielen Dank!
     
    Yoreki likes this.