Search Unity

Raycasting, Rigidbody questions

Discussion in 'Entity Component System' started by andynayrb, Mar 12, 2019.

  1. andynayrb

    andynayrb

    Joined:
    Feb 28, 2019
    Posts:
    25
    So I am trying to do some Raycasting experiments to eventually lead to some shooting and AI for something to follow me around. First thing I found that I can add a Rigidbody to an Entity, but I can't use it in a System (Job), am I understanding this correctly? So I need to use RaycastingCommand instead? I am 95% sure that I can use RaycastingCommand in ECS. However I also think that I understand that I can't do it inside a Job? I has to be in its own special job. If any of the above is incorrect please feel free to point out my error.

    So if I have a job that is checking to see if I press the fire button, how can I then call the RaycastingCommand to see if I hit something?

    This seems like it would be so simple, I am sure I am overlooking something. I am 99% sure this can be done using "pure" ecs and the job system. Part of the learning curve of learning a new way of doing things I guess.

    On top of that, if I can attach a Rigidbody with no issues to an entity, I should be able to do things with it in my systems. Something just isn't clicking here for me and it is really annoying me.

    Anyhow, thanks for any help that someone wants to throw my way.
     
  2. Abbrew

    Abbrew

    Joined:
    Jan 1, 2018
    Posts:
    417
    RaycastCommand checks for collisions with Colliders, not RigidBody, although you should have both on relevant entities if the entity moves. The NativeArray<RaycastHit> contains information on what your RaycastCommand hit. Unfortunately, at this time you cannot call raycastHit.collider or raycastHit.transform inside of a job. All you can do is verify that the raycast hit something through calling raycastHit.point.Equals(default(Vector3)). The Unity team might make Collider, Transform, and other fields of RaycastHit available inside jobs in the future
     
  3. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    Until then if somebody want to detect collisions must do their own implementation.
    There are a few posts around the forum about this. For instance this one is a fast and easy solution to start with.
     
  4. ilih

    ilih

    Joined:
    Aug 6, 2013
    Posts:
    1,416
    Here is an example:
    • create commands for RaycastCommand
    • run RaycastCommand job
    • process results
    Code not tested, but should work.
    Code (CSharp):
    1.     using Unity.Collections;
    2.     using Unity.Entities;
    3.     using Unity.Mathematics;
    4.     using Unity.Transforms;
    5.     using UnityEngine;
    6.     using System;
    7.  
    8.     public class HitSystem : ComponentSystem, IDisposable
    9.     {
    10.         ComponentGroup bullets;
    11.  
    12.         protected override void OnCreateManager()
    13.         {
    14.             bullets = GetComponentGroup(ComponentType.ReadOnly<Bullet>(), ComponentType.ReadOnly<Translation>(), ComponentType.ReadOnly<Rotation>());
    15.         }
    16.  
    17.         protected override void OnUpdate()
    18.         {
    19.             // create commands
    20.             var bullets_count = bullets.CalculateLength();
    21.             var hits = 1;// hits per one bullet
    22.             var hit_distance = 0.5f; // should be bullet speed * deltaTime
    23.             var commands = new NativeArray<RaycastCommand>(bullets_count, Allocator.TempJob);
    24.             var results = new NativeArray<RaycastHit>(bullets_count * hits, Allocator.TempJob);
    25.  
    26.             var index = 0;
    27.             ForEach((ref Translation translation, ref Rotation rotation) => {
    28.                 commands[index] = new RaycastCommand(translation.Value, math.forward(rotation.Value), distance: hit_distance, maxHits: hits);
    29.                 index++;
    30.             }, bullets);
    31.  
    32.             // run raycast job
    33.             var handle = RaycastCommand.ScheduleBatch(commands, results, 64, default);
    34.             handle.Complete();
    35.  
    36.             // process results
    37.             for (int i = 0; i < results.Length; i++)
    38.             {
    39.                 var hit = results[i];
    40.                 if (hit.transform != null)
    41.                 {
    42.                     // process hit
    43.                     Debug.Log("hit: " + hit.transform, hit.transform);
    44.                 }
    45.             }
    46.  
    47.             results.Dispose();
    48.             commands.Dispose();
    49.         }
    50.     }
    51.  
     
    siggigg likes this.
  5. Abbrew

    Abbrew

    Joined:
    Jan 1, 2018
    Posts:
    417
    The post does solve the problem of detecting collisions, but not within a job. Because of that JobHandle.Complete must be called before accessing raycastHit.transform or collider. This eliminates a lot of the parallelism that warrants the use of jobs in the first place
     
  6. andynayrb

    andynayrb

    Joined:
    Feb 28, 2019
    Posts:
    25
    I guess when you word a question as poorly as I did you will get answers that are not exactly what you are looking for. Granted the replies were very helpful and informative. So thank you all who responded.

    So this has me wondering what a Raycast actually is, behind the scene? Is it just the process of moving in a straight line from a starting point to an end point, and checking to see if something (a collider) is at any of those points? If something is there it reports back to the sender? If this is a correct understanding, this seems like something that would be pretty simple to set up custom inside a job. Am I over simplifying it?

    To see if it hit anything would simply involve searching the positions of all the entities that have a specific component in them, does that seem right? So you wouldn't even need a collider. And you could send back any information that I would want from the target entity.

    So use like a localtoworld.forward and check the entity list if something is there.

    Maybe this will give me something to toy around with later. Am I way off base here?
     
  7. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    The basic flow is first you control your projectiles manually, ie you calculate their paths. Then every frame you raycast from the last projectile position to it's current position. Finally you iterate over the raycast results in the main thread to check if they hit (via checking if the result collider is not null).

    You can do all of this so iterating over the results is the only thing on the main thread. I've tried other approaches such as using spatial structures and custom hit detection within jobs, but those quickly degenerate into being far slower if you scale up the number of projectiles and colliders.

    The code to do this well is fairly involved of course, but that's the basic approach I've found to perform the best at low 5 figures of projectiles per frame.