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

How should i query entities from inside a monobehaviour

Discussion in 'Entity Component System' started by Vyvernn, Mar 28, 2021.

  1. Vyvernn

    Vyvernn

    Joined:
    Mar 3, 2020
    Posts:
    7
    So the background to my problem is that im trying to move clouds across a sky but i have different weather systems such as sunny, rainy etc. When the weather changes from cloudy to sunny i dont just destroy the clouds (which are entities). I let them go off the screen and then destroy them. This works as i can just make an EntityCommandBuffer which destroys the cloud after it's past a certain threshold. However in reverse for populating clouds i need to check that there are currently less clouds in the sky than the maximum then start populating. To do this i need to query how many cloud entities there are in my scene. i could do this from the system but that was running too slow, i imagine because it runs for every cloud in the world and when i have 4000 clouds, checking whether i need to populate more for each cloud is going to be quite slow. So instead i'm trying to query from a monobehaviour but you can't call GetEntityQuery from inside a monobehaviour it seems.

    Is there a way to do this? or more importantly i guess, is there a better way to do this than what i'm currently attempting to do?
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,580
    Your Mono Behaviour script won't offer better performance than job in the system. Tha assuming you do it in correct way.

    Please show us the job script.
     
    Vyvernn and ScriptsEngineer like this.
  3. Vyvernn

    Vyvernn

    Joined:
    Mar 3, 2020
    Posts:
    7
    Here's the job

    Code (CSharp):
    1. protected override JobHandle OnUpdate(JobHandle inputDeps)
    2.     {
    3.         //Increment time
    4.         cloudTimer += Time.DeltaTime;
    5.  
    6.         //Check Distance from player
    7.         GameObject weatherManagerParent = GameObject.FindGameObjectsWithTag("WeatherManager")[0];
    8.         WeatherManager weatherManager = weatherManagerParent.GetComponent<WeatherManager>();
    9.  
    10.         Vector3 playerPos = weatherManager.player.transform.position;
    11.         float threshold = weatherManager.currentWeather.cloudMaxDistance;
    12.         float maxCloudCount = weatherManager.currentWeather.cloudDensity * weatherManager.currentWeather.maxCloudCount;
    13.  
    14.  
    15.         EntityQuery cloudCountQuery = GetEntityQuery(ComponentType.ReadOnly<CloudComponent>());
    16.         int numOfClouds = cloudCountQuery.CalculateEntityCount();
    17.  
    18.         Vector3 direction = weatherManager.currentWeather.cloudMoveDirection;
    19.         float moveSpeed = weatherManager.currentWeather.cloudMoveSpeed;
    20.  
    21.         float cloudHeight = weatherManager.currentWeather.cloudHeight;
    22.         float cloudHeightRange = weatherManager.currentWeather.cloudHeightRange;
    23.  
    24.  
    25.  
    26.         Entities.ForEach((Entity entity, ref Translation t, ref CloudMovement constantMovement) =>
    27.         {
    28.             //Update the direction and moveSpeed of the clouds
    29.             constantMovement.Direction = direction;
    30.             constantMovement.moveSpeed = moveSpeed;
    31.  
    32.             //Check whether this cloud has gone out of the spawnrange
    33.             if (Vector3.Distance(t.Value, playerPos) > threshold)
    34.             {
    35.                 //Check that the current number of clouds doesnt exceed the maximum
    36.                 if (numOfClouds <= maxCloudCount)
    37.                 {
    38.                     //Create Random
    39.                     System.Random r = new System.Random();
    40.  
    41.                     //Generate vector in the opposite direction of cloud movement on edge of spawn
    42.                     Vector3 offset = (direction.normalized * -1) * threshold;
    43.  
    44.                     //Apply a random offset along the x&z axis
    45.                     offset.x += (direction.normalized.x * Mathf.Lerp(-threshold, threshold, (float)r.NextDouble()));
    46.                     offset.z += (direction.normalized.z * Mathf.Lerp(-threshold / 4f, threshold / 2f, (float)r.NextDouble()));
    47.  
    48.                     //Reset Height
    49.                     offset.y = cloudHeight + Mathf.Lerp(-cloudHeightRange, cloudHeightRange, (float)r.NextDouble());
    50.  
    51.                     //Set transform position to the generated vector
    52.                     t.Value = playerPos + offset;
    53.  
    54.                 }
    55.                 //If it does then destroy this cloud instead of repopulating it
    56.                 else
    57.                 {
    58.                     EntityCommandBuffer ecb = new EntityCommandBuffer();
    59.                     ecb.DestroyEntity(entity);
    60.                 }
    61.             }
    62.  
    63.         }).WithoutBurst().Run();
    64.  
    65.         //Check whether more clouds need spawning
    66.         if(numOfClouds<maxCloudCount)
    67.         {
    68.             // Randomly get how many clouds to generate (between 1 and the number that would bring the total number of clouds to the limit)
    69.             System.Random r = new System.Random();
    70.             int spawnCount = r.Next(1, (int)maxCloudCount - numOfClouds);
    71.  
    72.             for(int i = 0; i<spawnCount; i++)
    73.             {
    74.                 int cloudType = r.Next(0, weatherManager.currentWeather.cloudPrefabs.Count);
    75.                 weatherManager.SpawnCloud(cloudType, weatherManager.GenerateCloudPos());
    76.             }
    77.  
    78.  
    79.         }
    80.  
    81.  
    82.         return default;
    83.     }
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,580
    any reason for using
    Code (CSharp):
    1. .WithoutBurst()
    and
    Code (CSharp):
    1. .Run();
    ?

    You should take
    Code (CSharp):
    1. System.Random
    outside the job.
    And in fact use
    Code (CSharp):
    1. Unity.Mathematics.Random
    , which designed for jobs and burst.
    Also don't use mathf inside jobs, use unity.math.
    Vector3 should be replaced with float3.

    Code (CSharp):
    1. EntityCommandBuffer ecb = new EntityCommandBuffer();
    This should be outside the job.
    And you should be using ecb with parallel, while job also should be in parallel.

    Chances are, you may need redesign
    SpawnCloud method.
     
    Last edited: Mar 28, 2021
    MNNoxMortem and Vyvernn like this.
  5. Vyvernn

    Vyvernn

    Joined:
    Mar 3, 2020
    Posts:
    7
    As for .Run and .WithoutBurst, i simply thought that was necessary to actually run the job in a lambda function, and the .withoutburst was so i could modify the transform of the clouds to reset them. as for the rest i'll get to changing that up, thanks :)
     
  6. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,580
    Vyvernn likes this.
  7. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    436
    I think you should also use a singleton entity for your weather manager data instead of searching for a MonoBehaviour every frame.
     
    Vyvernn likes this.