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

Question Pulling from Scrips into a list

Discussion in 'Scripting' started by Thundrbug, Jul 12, 2023.

  1. Thundrbug

    Thundrbug

    Joined:
    Sep 21, 2022
    Posts:
    15
    Hi all, so i have a little racing game im working on and its mostly done im just having some trouble with handling the position of the cars as they race around.

    The tracks are covered in checkpoint and the cars each have a "car" script on them. Each time a car passes a checkpoint in the correct order it updates a few variables on the "car" script. These variables are lastCheckpointPassed and splitTime. It will also update a lapsCompleted variable if the car goes through the last checkpoint on the lap. Each car is also given a unique car number on spawning in.

    My idea to handle the position was to have a script running on the track itself which i have called OrderHandler. This would then pull the variables into itself each time a checkpoint is passed by a car and simply order this by lapsCompleted > lastCheckPointPassed > splitTime to find the current running order. This is then picked up by a UI element leaderboard which swaps the positions of the cars based on the order of this list.

    However i am pretty much stumped by how to actually do this. If anyone can shed light on this or point me to a video etc it would be greatly appreciated. Happy to provide more details if needed.

    Thanks in advance.
     
  2. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    Write a method
    determineOrderWithinCheckpoint(checkpoint, cars)
    to your track that takes a list of cars and assumes they have all passed the same checkpoint and are level in terms of checkpoints. The method then returns the order of these cars, calculating it in some way based on the position of the car and the shape of the track.

    Then write a method to your track called
    determineOrderInRace(cars)
    that returns a list of cars in their order in race. This method will first sort the cars based on laps completed and the number of checkpoints passed. Then it will call determineOrderWithinCheckpoint to sort those cars that have the same laps and checkpoints.

    So the final solution is a 3-layer ordering based on first lap, then checkpoint, and finally the actual distance on track within a checkpoint.
     
    Last edited: Jul 12, 2023
    Chubzdoomer likes this.
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,495
    Your car class can implement the IComparable interface and provide a CompareTo method which would indicate how to sort two cars. Once that's done you can simply put all cars in a List and call Sort on it to sort it.

    Of course the CompareTo method returns which of the two objects should be higher, lower or equal. If the return value is negative this object should come before the one tested / passed to the CompareTo method. When you return a positive number it means the object passed in should come before this one. When you return 0 they are exactly equal.

    That method could do the comparisons one after the other. So first you compare lapsCompleted and return either -1 or +1 depending on which is further, If the lap counts are equal, you simply check the next thing and do the same thing, return -1 or +1. When all things are the same, you just return 0 at the very end since they are exactly the same.
     
    Chubzdoomer and KillDashNine like this.
  4. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    I was about to suggest this more elegant solution myself, but as he was already stumped about how to order things, I figured it won't make life any easier. The implementation needs the same logic anyway.<3
     
  5. Thundrbug

    Thundrbug

    Joined:
    Sep 21, 2022
    Posts:
    15
    Thanks for the replies. I may not have been super clear with my first post. I understand the logic of what i need to do im just not sure how to code it and the guides ive tried to follow just confused me even more tbh.

    So just to simplify it for me, if i have say 8 cars on the track and wanted to get the lastCheckpointPassed variable from each car and place it in a list in the OrderHandler script and then sort this list. What would the structure of my code look like?

    Thanks again.
     
  6. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    You can get your car scripts for example with
    GameObject.FindObjectsOfType<Car>()
    . Question is, when do you want to update your UI? When cars overtake one another, or at checkpoints? Your splitTime will not give you an accurate reading on the current situation but only the reading at last checkpoint. Any racing games I've played show a live order that updates right when you overtake or get overtaken.

    Your UI element shouldn't pick up stuff but you should push the update to your UI elements whenever the data is updated. And this push should be done when the order changes, hence my earlier question. You can run the "determine order" code when any car reaches any checkpoint, for example. Just you shouldn't run it every frame because no reason.

    How to push it? Depends on how you've built your UI in terms of eventing. But basically you send the event from your game, and this then ends up in your UI controller code.
     
    Last edited: Jul 12, 2023
  7. Thundrbug

    Thundrbug

    Joined:
    Sep 21, 2022
    Posts:
    15
    Thanks again for the reply. Im only looking to update the UI at checkpoints, so if car1 was to pass checkpoint 10 after car2, the UI would move Car2 into first place. Anything more complex than this is beyond me at this point i feel.

    But if we ignore the UI for a moment, ill worry about that later lol, to just go back to basics and all i want to do is print a list of lastCheckPoint passed to the console how would i use the GameObject.FindObjectsOfType<Car>() as part of this to compile a list?

    So in its simpliest all i wantto do is, in the OrderHandler script, write something that collects together all the lastCheckPoint passed variables from each of the cars and put them in a list and print it to console. Once i get that I think the rest will make a lot more sense to me.
     
  8. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,131
    If you forget about ooo, simple global array with one “checkpoint” item per car and then write directly into it at the respective car position…
     
  9. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    C#:
    Code (CSharp):
    1. foreach (var car in GameObject.FindObjectsOfType<Car>()) {
    2.     Debug.Log(car.lastCheckPoint, car.gameObject);
    3. }
    You want a list? Use System.Linq.

    Code (CSharp):
    1. GameObject.FindObjectsOfType<Car>().ToList()
    TBH I find it difficult to see how you've managed to write a racing game "mostly done" without elementary code like this
     
  10. Thundrbug

    Thundrbug

    Joined:
    Sep 21, 2022
    Posts:
    15
    Thanks again and i dont know honestly, i have just been learning the c# and unity, as and when i need it and this just hasnt come up before in this kind of way. Im not sure why im finding this bit so hard to grasp though as ive not had much trouble with anything else.
     
  11. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,495
    Just to give an example how you could implement the sorting

    Code (CSharp):
    1.     public class Car : MonoBehaviour, IComparable<Car>
    2.     {
    3.        public int lapsCompleted;
    4.        public int lastCheckpointPassed;
    5.        public float splitTime;
    6.        // [ ... ]
    7.        public int CompareTo(Car aOther)
    8.        {
    9.            if (lapsCompleted > aOther.lapsCompleted)
    10.                return -1;
    11.            if (lapsCompleted < aOther.lapsCompleted)
    12.                return 1;
    13.            if (lastCheckpointPassed > aOther.lastCheckpointPassed)
    14.                return -1;
    15.            if (lastCheckpointPassed < aOther.lastCheckpointPassed)
    16.                return 1;
    17.            if (splitTime > aOther.splitTime)
    18.                return -1;
    19.            if (splitTime < aOther.splitTime)
    20.                return 1;
    21.            return 0;
    22.        }
    23.     }
    24.  
    This should allow cars to be sorted by the conditions you mentioned. All you have to do is get all Car references in a generic
    List<Car>
    and call Sort(); on that List:
    Code (CSharp):
    1.  
    2. public List<Car> cars = new List<Car>();
    3.  
    4. // [ ... ]
    5. cars.Sort();


    Here's an abstracted example on dot net fiddle. Of course in your case you would deal with MonoBehaviours instead and your variables are of course adjusted by your game.
     
  12. Thundrbug

    Thundrbug

    Joined:
    Sep 21, 2022
    Posts:
    15
    Thanks very muchly :). Seeing the examples help me a lot with understanding it all.