Search Unity

Multiplayer Raycast Shooting

Discussion in 'Scripting' started by GameScience, Sep 17, 2014.

  1. GameScience

    GameScience

    Joined:
    Dec 20, 2013
    Posts:
    32
    I need a bit of help with using Raycast Layers in my multiplayer project. The setup is authoritative, so when you fire your gun it sends a message to the server, the server casts a ray to find out what you hit, sends the damage message to that object (still on server side) which calculates damage and then updates the health value across all clients.

    In the game you control a pirate ship with musketeers standing on the deck. Each of them does the firing when you press the mouse, but I need their raycasts to ignore the ship itself. At first I thought I could just make each ship be in a layer called "unit_mine" on the local machine and be in the "unit_other" layer on everyone else's, but this won't work if I calculate gunshots on the server (which is the best way).

    How could I make it so the raycast will ignore only the ship on which the musketeer is standing? (preferably without making as many layers as their are players in the game and moving them all to their own layer, unless that's the best way to do it.)
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Use RaycastAll, sort the returned hits by distance (maybe they already are?), and use the first one that isn't the ship the shooter belongs to.
     
    GameScience likes this.
  3. GameScience

    GameScience

    Joined:
    Dec 20, 2013
    Posts:
    32
    Ah, that just might do it. Thanks muchly!
     
  4. BmxGrilled

    BmxGrilled

    Joined:
    Jan 27, 2014
    Posts:
    239
    you could do a recursive raycast, checking what object you hit, if the object you hit is tagged "Player" e.g. you can recast the ray from that point in the same direction, and it'll return the opposite hit, ignoring your player object.

    e.g. I created this class to make passive ray casting easier.
    Code (CSharp):
    1. //PassiveRaycast.cs
    2. //C#
    3. using UnityEngine;
    4.  
    5. public sealed class PassiveRaycast
    6. {
    7.     public readonly Ray ray;                    //the ray that was cast
    8.     public readonly float distance;                //how far
    9.     public readonly string ignoreTag;            //the tag to ignore
    10.  
    11.     public readonly Vector3 hitPoint;            //the Vector3 point where the raycast ends
    12.     public readonly RaycastHit hit;                //the RaycastHit object returned from the raycast
    13.     public readonly PassiveRaycast nextCast;    //if we didn't hit anything, this will be the next cast
    14.  
    15.     public readonly int steps;                    //the number of steps it took to get to this raycast
    16.     public readonly int maxSteps;                //the maximum number of steps allowed
    17.  
    18.     private bool _hit;        //used to convert this class to bool conditional, set by the Raycast function
    19.  
    20.     public PassiveRaycast endCast
    21.     {//gets the last cast in this rayCast
    22.         get
    23.         {//WARNING: this is recursive, if maxSteps is set too high, this will cause a stack overflow exception
    24.             if (nextCast != null) { return nextCast.endCast; }
    25.             return this;
    26.         }
    27.     }
    28.  
    29.     public PassiveRaycast(Ray ray, string ignoreTag, int maxSteps = 5, float distance = float.PositiveInfinity, int steps = 0)
    30.     {//creates a passive raycast, ignoring the tag defined by ignoreTag
    31.         this.ray = ray;                //store the ray
    32.         this.distance = distance;    //store the distance
    33.         this.ignoreTag = ignoreTag;    //store the tag to be ignored
    34.         this.steps = steps;            //store the steps
    35.         this.maxSteps = maxSteps;    //store the maxSteps
    36.         _hit = Physics.Raycast(ray, out hit, distance);        //perform the raycast
    37.         if (_hit)
    38.         {//we hit something
    39.             if (hit.transform.tag == ignoreTag)
    40.             {//the tag is to be ignored
    41.                 if (steps < maxSteps)
    42.                 {//we're safe from overflow
    43.                     hitPoint = hit.point;        //set the hitPoint to where the raycast ended
    44.                     //perform recursive raycast
    45.                     nextCast = new PassiveRaycast(ray, ignoreTag, maxSteps, distance, steps + 1);
    46.                 }
    47.                 else
    48.                 {//we can't do anymore raycasts
    49.                     hitPoint = ray.origin + (ray.direction * distance);        //set the hitPoint to where the raycast ended
    50.                 }
    51.             }
    52.         }
    53.         else
    54.         {//we hit nothing
    55.             hitPoint = ray.origin + (ray.direction * distance);        //set the hitPoint to where the raycast ended
    56.         }
    57.     }
    58.  
    59.     public static implicit operator bool(PassiveRaycast pr)
    60.     {//allows you to do if(PassiveRaycast) { We hit something! }
    61.         return pr._hit;
    62.     }
    63.  
    64.     public void DrawDebug(Color startColor, Color endColor)
    65.     {//renders the entire raycast from start to finish
    66.         Color color = Color.Lerp(startColor, endColor, steps / (float)maxSteps);
    67.         Debug.DrawLine(ray.origin, ray.origin + (ray.direction * distance), color);
    68.         //WARNING: this is recursive, if maxSteps is set too high, this will cause a stack overflow exception
    69.         if (nextCast != null) { nextCast.DrawDebug(startColor, endColor); }
    70.     }
    71. }
    72.  
    Example use is:

    Code (CSharp):
    1. //PassiveRayTest.cs
    2. //C#
    3. using UnityEngine;
    4. using System.Collections;
    5.  
    6. public class PassiveRayTest : MonoBehaviour
    7. {
    8.     public bool test = false;
    9.  
    10.     private PassiveRaycast raycast;
    11.  
    12.     void OnValidate()
    13.     {//this works in the editor, simply check the test checkbox
    14.         if (test)
    15.         {
    16.             //new PassiveRaycast(Ray ray, string ignoreTag, int maxSteps = 5, float distance = float.PositiveInfinity, int steps = 0);
    17.             raycast = new PassiveRaycast(new Ray(transform.position, transform.forward), "Player");
    18.             PassiveRaycast endcast = raycast.endCast;
    19.             if (endcast)
    20.             {//we hit something
    21.                 Debug.Log("hit: "+endcast.hit.transform.name);
    22.                 if (raycast)
    23.                 {//we hit something, but ignored it
    24.                     Debug.Log("ignored: "+raycast.hit.transform.name);
    25.                     raycast = raycast.nextCast;
    26.                     while (raycast != null)
    27.                     {
    28.                         if (raycast && raycast != endcast)
    29.                         {//we hit something, but ignored it
    30.                             Debug.Log("ignored: "+raycast.hit.transform.name);
    31.                         }
    32.                         raycast = raycast.nextCast;
    33.                     }
    34.                 }
    35.             }
    36.             else
    37.             {//we hit nothing
    38.                 if (raycast)
    39.                 {//we hit something, but ignored it
    40.                     Debug.Log("ignored: "+raycast.hit.transform.name);
    41.                     raycast = raycast.nextCast;
    42.                     while (raycast != null)
    43.                     {
    44.                         if (raycast)
    45.                         {//we hit something, but ignored it
    46.                             Debug.Log("ignored: "+raycast.hit.transform.name);
    47.                         }
    48.                         raycast = raycast.nextCast;
    49.                     }
    50.                 }
    51.                 else
    52.                 {
    53.                     Debug.Log("no hit!");
    54.                 }
    55.             }
    56.             test = false;
    57.         }
    58.     }
    59.  
    60.     void Update()
    61.     {//draw the whole raycast
    62.         raycast.DrawDebug(Color.green, Color.red);
    63.     }
    64. }
    65.  
    I hope this helps! :)
     
    GameScience likes this.
  5. GameScience

    GameScience

    Joined:
    Dec 20, 2013
    Posts:
    32
    @TwixEmma,

    Wow, what a robust solution! I'll have to add this to my scripting library. Thanks a bunch!
     
  6. Fraconte

    Fraconte

    Joined:
    Dec 6, 2013
    Posts:
    327
    Lot of work for a raycast... but seems good! :)